首页 文章

设置全局描述符表和保护模式后不断重新启动

提问于
浏览
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

我的错在哪里?

1 回答

  • 2

    因为我只能假设你已经正确地将扇区读入存储器0x1000:0x0000,所以我只能指出 kernel.asmgdt.inc 中的潜在问题 .


    代码问题

    If 你用 jmp 0x1000:0x0000 到达内核阶段(我怀疑是这种情况)然后在 kernel.asm 中你错误地设置了DS,并且ES段注册到了错误的值 . 在这种情况下,您需要将这两个寄存器设置为0x1000,而不是0x0000 . 这段代码:

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

    需要改为:

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

    您遇到的下一个主要问题是GDT记录(在 toc 内)采用线性地址 . 实模式中的线性地址与物理地址相同 . 从说明书手册中可以看出:

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

    您已经为 kernel.asm 使用了OR0000 0x0000(因为您没有指定一个),因此NASM假定生成的所有偏移都来自0x0000的基数,包括标签 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)处加载的,因此需要在最终设置保护模式的JMP中为 stage3 label的值添加0x10000 . 同样,因为我们正在编码一个高于0xFFFF的值,我们需要强制NASM使用32位操作数,所以我们在 JMP 上使用 dword 限定符 . 你有这个:

    jmp 08h:Stage3
    

    它应该是这样的:

    jmp dword 08h:Stage3+0x10000
    

相关问题