【发布时间】:2017-09-12 07:07:39
【问题描述】:
以下从 32 位保护模式(启用 A20)转换到 64 位长模式的代码似乎给我带来了问题。我将 1GiB 页面从 0x00000000 映射到 0x3fffffff;启用 PAE;启用 EFER MSR 中的长模式位;安装 GDT;启用分页;然后对我的 64 位入口点进行模拟 FAR JMP:
lea eax, [PML4]
mov cr3, eax
mov eax, cr4
or eax, 100000b
mov cr4, eax
mov ecx, 0xc0000080
rdmsr
or eax, 100000000b
wrmsr
mov eax, cr0
mov ebx, 0x1
shl ebx, 31
or eax, ebx
mov cr0, eax
call gdt64_install
push 8
push longmode
retf ;<===================== faults here
当执行RETF 指令但似乎没有返回任何错误时,BOCHS 中的程序三重错误。如果我在跳转之前输入info tab,我会得到:
0x00000000-0x3fffffff -> 0x000000000000-0x00003fffffff
在我看来分页正在工作。这是sreg 输出:
es:0x0010, dh=0x00cf9300, dl=0x0000ffff, valid=1
Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
cs:0x0008, dh=0x00cf9b00, dl=0x0000ffff, valid=1
Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Non-Conforming, Accessed, 32-bit
ss:0x0010, dh=0x00cf9300, dl=0x0000ffff, valid=31
Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
ds:0x0010, dh=0x00cf9300, dl=0x0000ffff, valid=31
Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
fs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
gs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
ldtr:0x0000, dh=0x00008200, dl=0x0000ffff, valid=1
tr:0x0000, dh=0x00008b00, dl=0x0000ffff, valid=1
gdtr:base=0x0000000000008252, limit=0x1f
idtr:base=0x0000000000000000, limit=0x3ff
我的 GDT 条目是:
gdt64_install:
lgdt[GDT_addr]
ret
GDT_addr:
dw (GDT64_end - GDT64) - 1
dd GDT64
GDT64:
dd 0, 0
dd 0xffff ; segment limit
dd 0xef9a00
dd 0xffff ; segment limit
dd 0xef9200
dd 0, 0
GDT64_end:
我使用PML4 and PDP的页表结构定义为:
align 4096 ;;align to 4 KB
PML4:
dq 0 or 1b or 10b or PDP;;preset bit, r/w bit
dq 511 dup(PDP or 10b)
PDP:
dq 0 or 1b or 10000000b ;;dq zero, because we map memory from start so 0x0000, present bit
;;PDPE.PS to indicate 1gb pages
dq 511 dup(10000000b)
任何想法为什么它可能是三重故障?
我的项目副本可以在Github找到
【问题讨论】:
-
哇哦,有人真的在写
cr寄存器。尊重。 -
@harold 在 32 位保护模式下带有 FAR RET 一个 32 位 DWORD 将从堆栈中弹出到 CS 并丢弃前 16 位。然后将下一个 DWORD 弹出到 EIP 中。虽然我只是像你说的那样使用 JMP,但我不认为错误是用他的 FAR RET 构造返回地址。
-
您有一个项目可以使用您的所有代码吗?由于您没有向我们展示一个最小的完整可验证示例,因此很难解决问题。
-
@MichaelPetch 一切都位于我朋友的 github 上,我们今天提交了最新的代码:github.com/cuaox/RIOS 他问我是否想帮忙,我正在尝试做一些分页,但是,有些事情是不工作
标签: assembly x86 x86-64 paging osdev