在x86内核中删除身份映射的问题

问题描述 投票:1回答:1

我正在做一些操作系统开发,这是我的目标。我已启用分页,并想删除身份映射。以前,我有两个映射,0-4M的身份映射和虚拟地址0xC0000000的内核映射到物理地址1M。我的引导程序会在跳转到内核之前执行此操作,并且内核有责任删除身份映射。我的堆栈指针现在的值为0x90000。我的策略如下:

进入内核后,我使用递归页表访问页目录和所有其他页表(获得其虚拟地址:What happens when you lose the virtual address of the page directory?)。递归页表:页目录的最后一个条目指向自身。

我想重新映射堆栈并为其提供一个虚拟地址。由于递归页面技术使用0xFFC00000-0xFFFFFFFF,因此我将0xFFC00000用作堆栈的虚拟地址,并将其映射到0x90000物理地址。

然后我重新初始化gdt。

现在我的系统状态是:

(qemu) info registers 
EAX=000241a0 EBX=c00019de ECX=00000001 EDX=000241a0
ESI=00008137 EDI=00103800 EBP=ffc00000 ESP=ffc00000
EIP=c00019de EFL=00000087 [--S--PC] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     c0004100 00000027
IDT=     00000000 000003ff
CR0=80000011 CR2=00000000 CR3=0009c000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 
DR6=ffff0ff0 DR7=00000400
EFER=0000000000000000
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000

堆栈重映射代码:

STACK equ 0xFFC00000
STACK_PHY equ 0x90000

global refresh_stack ;A solution for switching stacks

refresh_stack:
    mov ebx,[esp] ;Return address
    mov esp,STACK
    mov ebp,STACK
    jmp ebx

我想这样删除身份映射:

void remove_identity_map()  //This would remove the 4M identity map
{
         if (entry_is_present(_page_directory[0]))
                _page_directory[0] = 0;  //Unmapping the whole of 4M

         flush_tlb();
}

哪里flush_tlb:

flush_tlb:
    mov eax,cr3
    mov cr3,eax
    ret

一个最小的可复制示例(大致)

void kmain()
{
set_recursive_map();
refresh_stack();
install_gdt(); //The standard 4 entries Data/Code * User/kernel
remove_identity_map();
   .......
   .......
}

出错的地方是当我flush_tlb()。如果我注释掉该行,代码将按预期工作,但是我们将看到缓存的副本。但是,当我保留它时,系统(仿真器)将从BIOS重新启动! (三重错误???)

而且,我正在使用qemu,在刷新tlb之后,我尝试使用for(;;);将qemu-monitor用作info tlb ...似乎没有被刷新。之前的所有条目都存在。.

我可能在哪里出错?

注意:当我用gdb调试(单步执行)时,刷新tlb后可以访问地址0xFFC00000 ... [但是]确实有道理,我只是删除了页面目录项对应于页表0 ..更新:我还没有做的一个映射就是视频内存!对于文本模式,我仍在访问0xB8000。由于我的异常处理程序也会打印到屏幕上,因此这肯定是三重错误的根源!!

我正在做一些操作系统开发,这是我的目标。我已启用分页,并想删除身份映射。以前,我有两个映射,0-4M的身份映射和位于...

memory-management x86 kernel paging osdev
1个回答
0
投票
好吧,好像我忘了重新映射视频内存!我仍在为VGA文本模式访问0xb8000。问题的原因是我没有发现1M以下的访问权限。如果有的话,我不会问一个问题;)。
© www.soinside.com 2019 - 2024. All rights reserved.