1

GDT setup我一定是在和切换到时做错了,protected mode因为它不断地重新启动。

这是我kernel.asm应该设置GDT并切换到protected mode

    bits 16

    jmp main
    %include "gdt.inc"

    main:
        cli
        xor ax,ax
        mov ds,ax
        mov es,ax
        mov ax,0x9000
        mov ss,ax
        mov sp,0xffff
        sti

        call InstallGDT

        cli
        mov eax,cr0
        or eax,1
        jmp 08h:Stage3

    bits 32
    Stage3:

        mov ax,0x10
        mov ds,ax
        mov ss,ax
        mov es,ax
        mov esp,90000h

    Stop:

        mov byte [0xb8000],'A'
        cli
        hlt

还有gdt.inc

bits 16
InstallGDT:

    cli
    pusha
    lgdt   [toc]
    sti
    popa
    ret
gdt_data:
    dd 0
    dd 0

    dw 0ffffh
    dw 0
    db 0
    db 10011010b
    db 11001111b
    db 0

    dw 0ffffh
    dw 0
    db 0
    db 10010010b
    db 11001111b
    db 0
end_of_gdt:
toc:
    dw end_of_gdt - gdt_data -1
    dd gdt_data

bootloader.asm加载 10 个扇区0x1000:0x000,然后跳到那里。

我使用以下命令测试代码:

nasm -f bin -o bootloader.bin bootloader.asm
nasm -f bin -o kernel.bin kernel.asm
cat bootloader.bin kernel.bin>OS.bin
qemu-system-i386 OS.bin

我的错在哪里?

4

1 回答 1

2

由于我只能假设您已正确地将 0x1000:0x0000 处的扇区读入内存,因此我只能指出kernel.asm和中的潜在问题gdt.inc


代码问题

如果您到达内核阶段jmp 0x1000:0x0000(我怀疑是这种情况),那么kernel.asm您错误地将DSES段寄存器设置为错误的值。在这种情况下,您需要将这两个寄存器设置为 0x1000,而不是 0x0000。这段代码:

    xor ax,ax
    mov ds,ax
    mov es,ax

需要改为:

    mov ax,0x1000
    mov ds,ax
    mov es,ax

您遇到的下一个主要问题是GDT记录(内部toc)采用线性地址。实模式下的线性地址与物理地址相同。从指令集手册中它说:

源操作数指定一个 6 字节的内存位置,其中包含全局描述符表 (GDT) 的基地址(线性地址)和限制(以字节为单位的表大小)

您使用了0x0000 的ORG(因为您没有指定一个),kernel.asm因此NASM假定所有生成的偏移量都来自 0x0000 的基础,包括 label gdt_data。所以当你这样做时:

toc:
dw end_of_gdt - gdt_data -1
dd gdt_data

gdt_data将是略高于 0x0000 的一些小偏移量。在物理内存中,您的GDT记录实际上位于 0x1000:0x0000+(小偏移量)。物理(线性)内存中的 0x1000:0x0000 为(0x1000<<4)+0x0000 = 0x10000 因此您需要将其添加到gdt_data. 你toc应该看起来像这样来补偿:

toc:
dw end_of_gdt - gdt_data -1
dd gdt_data+0x10000

您遇到的下一个问题是您实际上并没有打开保护模式标志。你有这个:

    mov eax,cr0
    or eax,1

它应该是:

    mov eax,cr0
    or eax,1
    mov cr0, eax

将位设置为 1 后,您需要更新CR0寄存器中的保护模式位。


GDT问题相关,您已经从 0x00000000 的偏移量创建了代码段的GDT条目,该偏移量包含整个 4gb 地址空间。这是对的。同样,由于NASM创建了从 0x0000 开始的偏移量,并且您的代码实际上是在 0x1000:0x0000(物理地址 0x10000)加载的,您需要将 0x10000 添加到JMP中最终设置保护模式的stage3标签值中。同样,因为我们正在编码一个高于 0xFFFF 的值,所以我们需要强制NASM使用 32 位操作数,所以我们在. 你有这个:dwordJMP

jmp 08h:Stage3

应该是这样的:

jmp dword 08h:Stage3+0x10000
于 2016-12-23T17:54:23.040 回答