Assembly 为什么在Bochs上寻呼不工作并且获取物理地址不可用错误

Assembly 为什么在Bochs上寻呼不工作并且获取物理地址不可用错误,assembly,x86,paging,bootloader,Assembly,X86,Paging,Bootloader,我有以下汇编代码为长模式设置分页 org 0x7e00 bits 32 mov eax, 0x08000008 mov cr3, eax pml4t: mov dword [0x8000], 0x0900000f mov dword [0x8004], 0x0 pdpt: mov dword [0x9000], 0x0a00000f mov dword [0x9004], 0x0 pdt: mov dword [0xa000], 0x0b00000f mov dword [0xa004],

我有以下汇编代码为长模式设置分页

org 0x7e00

bits 32

mov eax, 0x08000008
mov cr3, eax

pml4t:
mov dword [0x8000], 0x0900000f
mov dword [0x8004], 0x0
pdpt:
mov dword [0x9000], 0x0a00000f
mov dword [0x9004], 0x0
pdt:
mov dword [0xa000], 0x0b00000f
mov dword [0xa004], 0x0
pt:
mov eax, 0x200
mov ebx, 0x0000000f
mov ecx, 0xb000
next_entry:
mov dword [ecx], ebx
add ecx, 0x4
mov dword [ecx], 0x0
add ebx, 0x1000000      ;add 4096 to the adress pointed to by ebx (the next physical page)
add ecx, 0x4
sub eax, 0x1
cmp eax, 0x0
jne next_entry

mov eax, cr4            ;enable PAE-paging
or eax, 1 << 5
mov cr4, eax

mov ecx, 0xC0000080     ;set long mode bit in EFER MSR
rdmsr
or eax, 1 << 8
wrmsr

mov eax, cr0            ;enable paging
or eax, 1 << 31
mov cr0, eax

halt:
hlt
jmp halt
我为每个表设置一个条目,直到到达最后一个包含512个条目的表。它应该有2MB的内存

如调试器中所示,CR3是引用内存中地址0x8000的
0x000000000800008
。如Intel文档中所述(请参阅第4章中关于IA-32e分页的内容)

在CR3中,除第3位外,所有位均为零,因此我启用了直写。PML4表的地址从第12位开始,找到的地址是0x8000

如果我在Bochs调试器中使用
xp/512bx 0x8000
,它会在第一个表(0x8000)中显示内存,其内容如下:

<bochs:5> xp /4096bx 0xb000
[bochs]:
0x000000000000b000 <bogus+       0>:    0x0f    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x000000000000b008 <bogus+       8>:    0x0f    0x00    0x00    0x01    0x00    0x00    0x00    0x00
0x000000000000b010 <bogus+      16>:    0x0f    0x00    0x00    0x02    0x00    0x00    0x00    0x00
0x000000000000b018 <bogus+      24>:    0x0f    0x00    0x00    0x03    0x00    0x00    0x00    0x00
0x000000000000b020 <bogus+      32>:    0x0f    0x00    0x00    0x04    0x00    0x00    0x00    0x00
0x000000000000b028 <bogus+      40>:    0x0f    0x00    0x00    0x05    0x00    0x00    0x00    0x00
0x000000000000b030 <bogus+      48>:    0x0f    0x00    0x00    0x06    0x00    0x00    0x00    0x00
0x000000000000b038 <bogus+      56>:    0x0f    0x00    0x00    0x07    0x00    0x00    0x00    0x00
0x000000000000b040 <bogus+      64>:    0x0f    0x00    0x00    0x08    0x00    0x00    0x00    0x00
0x0000000000008000:0x0f 0x00 0x00 0x09 0x00 0x00 0x00 0x00 0x00 0x00 0x00

结果是小尾数形式的
00f00090000
,在可读的大尾数形式中转换为
00000900000f

条目的格式类似于CR3(地址从第12位开始)。此处引用的地址是0x9000

如果我在Bochs调试器中使用
xp/512bx 0x9000
,它会在第二个表(0x9000)中显示内存,其内容如下:

<bochs:5> xp /4096bx 0xb000
[bochs]:
0x000000000000b000 <bogus+       0>:    0x0f    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x000000000000b008 <bogus+       8>:    0x0f    0x00    0x00    0x01    0x00    0x00    0x00    0x00
0x000000000000b010 <bogus+      16>:    0x0f    0x00    0x00    0x02    0x00    0x00    0x00    0x00
0x000000000000b018 <bogus+      24>:    0x0f    0x00    0x00    0x03    0x00    0x00    0x00    0x00
0x000000000000b020 <bogus+      32>:    0x0f    0x00    0x00    0x04    0x00    0x00    0x00    0x00
0x000000000000b028 <bogus+      40>:    0x0f    0x00    0x00    0x05    0x00    0x00    0x00    0x00
0x000000000000b030 <bogus+      48>:    0x0f    0x00    0x00    0x06    0x00    0x00    0x00    0x00
0x000000000000b038 <bogus+      56>:    0x0f    0x00    0x00    0x07    0x00    0x00    0x00    0x00
0x000000000000b040 <bogus+      64>:    0x0f    0x00    0x00    0x08    0x00    0x00    0x00    0x00
0x0000000000009000:0x0f 0x00 0x00 0x0a 0x00 0x00 0x00 0x00 0x00 0x00

结果是小尾端的
0f000a0000
,在大尾端的翻译为
0000a000f

引用的地址是0xa000

如果我在Bochs调试器中使用
xp/512bx 0xa000
,它会在第三个表(0xa000)中显示内存,其内容如下:

<bochs:5> xp /4096bx 0xb000
[bochs]:
0x000000000000b000 <bogus+       0>:    0x0f    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x000000000000b008 <bogus+       8>:    0x0f    0x00    0x00    0x01    0x00    0x00    0x00    0x00
0x000000000000b010 <bogus+      16>:    0x0f    0x00    0x00    0x02    0x00    0x00    0x00    0x00
0x000000000000b018 <bogus+      24>:    0x0f    0x00    0x00    0x03    0x00    0x00    0x00    0x00
0x000000000000b020 <bogus+      32>:    0x0f    0x00    0x00    0x04    0x00    0x00    0x00    0x00
0x000000000000b028 <bogus+      40>:    0x0f    0x00    0x00    0x05    0x00    0x00    0x00    0x00
0x000000000000b030 <bogus+      48>:    0x0f    0x00    0x00    0x06    0x00    0x00    0x00    0x00
0x000000000000b038 <bogus+      56>:    0x0f    0x00    0x00    0x07    0x00    0x00    0x00    0x00
0x000000000000b040 <bogus+      64>:    0x0f    0x00    0x00    0x08    0x00    0x00    0x00    0x00
0x000000000000a000:0x0f 0x00 0x00 0x0b 0x00 0x00 0x00 0x00 0x00 0x00

结果是小尾端的
0f000b0000
,在大尾端的翻译为
0000b00000f

引用的地址是0xb000

如果我在Bochs调试器中使用
xp/4096bx 0xb000
,它会在最后一个表(0xb000)中显示内存,其内容如下:

<bochs:5> xp /4096bx 0xb000
[bochs]:
0x000000000000b000 <bogus+       0>:    0x0f    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x000000000000b008 <bogus+       8>:    0x0f    0x00    0x00    0x01    0x00    0x00    0x00    0x00
0x000000000000b010 <bogus+      16>:    0x0f    0x00    0x00    0x02    0x00    0x00    0x00    0x00
0x000000000000b018 <bogus+      24>:    0x0f    0x00    0x00    0x03    0x00    0x00    0x00    0x00
0x000000000000b020 <bogus+      32>:    0x0f    0x00    0x00    0x04    0x00    0x00    0x00    0x00
0x000000000000b028 <bogus+      40>:    0x0f    0x00    0x00    0x05    0x00    0x00    0x00    0x00
0x000000000000b030 <bogus+      48>:    0x0f    0x00    0x00    0x06    0x00    0x00    0x00    0x00
0x000000000000b038 <bogus+      56>:    0x0f    0x00    0x00    0x07    0x00    0x00    0x00    0x00
0x000000000000b040 <bogus+      64>:    0x0f    0x00    0x00    0x08    0x00    0x00    0x00    0x00
xp/4096bx 0xb000
[bochs]:
0x000000000000b000:0x0f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x000000000000b008:0x0f 0x00 0x00 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x000000000000b010:0x0f 0x00 0x00 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x000000000000b018:0x0f 0x00 0x00 0x03 0x00 0x00 0x00 0x00 0x00 0x00
0x000000000000b020:0x0f 0x00 0x00 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x000000000000b028:0x0f 0x00 0x00 0x05 0x00 0x00 0x00 0x00 0x00 0x00
0x000000000000b030:0x0f 0x00 0x00 0x06 0x00 0x00 0x00 0x00 0x00 0x00
0x000000000000b038:0x0f 0x00 0x00 0x07 0x00 0x00 0x00 0x00 0x00 0x00
0x000000000000b040:0x0f 0x00 0x00 0x08 0x00 0x00 0x00 0x00 0x00 0x00
第一个条目是
0x0f 0x00 0x00 0x00 0x00 0x00 0x00 0x00
,它在big-endian中转换为
000f
。它引用地址0x0。这意味着
0x00 01 23
的虚拟地址应该映射到物理RAM中的0x123。它应该是2MB内存的身份映射

第八个条目是
0x0f 0x00 0x00 0x07 0x00 0x00 0x00 0x00
,它转换为
00 00 00 07 00 0f
。这应该引用从地址0x7000开始的物理4KB页面

如果我使用地址0x7e91,它将转换为
0x007E91
。该地址现在应该是虚拟的,因为已启用分页。它引用指向0x9000的PLM4条目0。它引用指向0xa000的PDPT条目0。它引用指向0xb000的PDT条目0。它引用页面表的第7项(第8项),该项指向0x7000。最后12位(0xe91)是页面中的偏移量。因此,虚拟地址应该是标识映射的,因为0x7e91转换为0x7e91

问题如下

为什么我的分页实现不起作用

我是否遗漏了内存中的位顺序(小端对大端)

为什么应该包含导致页面错误的虚拟地址的CR2包含0x80

我错过了什么吗

正如英特尔文档中所述

11:5 Ignored
M–1:12 Physical address of ...
这一描述似乎具有误导性:

在早期的x86-32 CPU中,CR3的CR3(而不是CR3的位[32:12])是页目录表的指针(物理地址)

由于该地址的低位12位必须始终为0,因此其中一些位(PCD和PWT)在以后的CPU中用于其他目的


如果64位模式仍然如此,
CR3=0x800008
不会指定地址
0x8000
,而是在启用分页后立即指定地址
0x8000000

是否尝试查看BOCHS命令
信息选项卡
显示的内容。这将转储虚拟到物理内存映射。如果显示引导加载程序以使其成为一个。CR3应使用物理地址加载。您的PML4T位于地址0x00008000,因此应该加载到CR3I中。我认为CR2不包含故障地址的原因是因为存在三重故障。我认为CR2没有设置为双故障或三故障。是的,
CR3&0xFF…FF000
仍然是64位模式下的物理地址。i、 e.页拆分上方的位是页码,以页而不是字节计数。原始的386手册仅将CR3的位[31:12]定义为PDBR(页目录基寄存器)。CR3的位[11:0]被标记为保留。当前文档与此并不矛盾。问题中的代码错误的不仅仅是CR3,所有PTE都有相同的问题。谢谢您的回答。当我再次使用计算机时,我会试试的。我现在不在。但这似乎是合乎逻辑的。这就是为什么页面必须位于