gpt4 book ai didi

assembly - 跳转到 64 位长模式时出现三重故障

转载 作者:行者123 更新时间:2023-12-01 03:23:34 26 4
gpt4 key购买 nike

以下从 32 位保护模式(启用 A20)转换为 64 位长模式的代码似乎给我带来了问题。我将 1GiB 页面从 0x00000000 标识映射到 0x3fffffff;启用 PAE;启用 EFER MSR 中的 longmode 位;安装 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 上找到

最佳答案

主要问题是您的 GDT 似乎是为 32 位设计的。对于 64 位描述符,您需要设置 64 位描述符位。来自 OSDev wiki我们可以看到 GDT 的布局以及标志和访问位:

enter image description here

enter image description here

如维基中所述,这些更改适用于 64 位描述符:

x86-64 Changes

  • 'L' bit (bit 21, next to 'Sz') is used to indicate x86-64 descriptor
  • 'Sz' bit (bit 22) has to be 0 when the 'L' bit is set, as the combination Sz = 1, L = 1 is reserved for future use (and will throw an exception if you try to use it)


出于性能原因,英特尔还建议在 8 字节边界上对齐 GDT。在 64 位描述符中,base 和 limit 应该设置为 0。如果您打算稍后从 64 位模式使用 GDT 表,您将需要更改 dd GDT64成为一个四字。考虑到这些,我修改了你的 GDT 使其更具可读性:
    GDT_addr:
dw (GDT64_end - GDT64) - 1
dq GDT64 ; Use quadword so we can use this GDT table
; from 64-bit mode if necessary

align 8 ; Intel suggests GDT should be 8 byte aligned

GDT64: ; Global Descriptor Table (64-bit).

; 64-bit descriptors should set all limit and base to 0
; NULL Descriptor
dw 0 ; Limit (low).
dw 0 ; Base (low).
db 0 ; Base (middle)
db 0 ; Access.
db 0 ; Flags.
db 0 ; Base (high).

; 64-bit Code descriptor
dw 0 ; Limit (low).
dw 0 ; Base (low).
db 0 ; Base (middle)
db 10011010b ; Access (present/exec/read).
db 00100000b ; Flags 64-bit descriptor
db 0 ; Base (high).

; 64-bit Data descriptor
dw 0 ; Limit (low).
dw 0 ; Base (low).
db 0 ; Base (middle)
db 10010010b ; Access (present/read&write).
db 00100000b ; Flags 64-bit descriptor.
db 0 ; Base (high).
GDT64_end:

其他观察

您可以使用它来转换到 64 位长模式:
push 8
push longmode
retf

虽然这有效,但如果您使用 FASM 或 NASM,使用 FAR JMP 会容易得多。如果您仍处于 32 位模式:
jmp 0x08:longmode

由于某些 early AMD64 processor types 在 64 位代码中执行一次 FAR JMP 存在问题不支持 JMP mem16:64 .使用 PUSH/RETF 方法使代码更具通用性。在 64 位长模式下执行一次这样的 FAR JMP 只会在极少数情况下使用。

您的代码中还有另一个关于读取扇区的问题。我发现并非所有代码和数据都被读入内存。在您的 exread.inc你定义:
SECTOREAD equ 20

我发现当我建立你的软盘镜像时,文件大小是 13976。那是 28 个扇区(512*28=14336)。您的值(value) 20阅读不够。确保这对您来说不是问题,如果需要,请阅读更多部门。

与手头的问题无关,我在您的 Makefile 中注意到你有:
qrun: deploy_all
qemu-system-i386 kernel.bin

如果你想在 QEMU 中运行 64 位代码,你需要使用 qemu-system-x86_64不是 qemu-system-i386 .我发现这更有用:
qrun: deploy_all
qemu-system-x86_64 -fda floppy.bin -no-shutdown -no-reboot -d int
-no-shutdown -no-reboot -d int选项对于调试很有用。它会导致 QEMU 在三重故障时无法重启和关闭。 -d int提供有关引发的中断和异常的有用信息。

关于assembly - 跳转到 64 位长模式时出现三重故障,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43438363/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com