设置全局描述符表和保护模式后不断重启 [英] Constant reboot after setting up the Global Descriptor Table and protected mode

查看:183
本文介绍了设置全局描述符表和保护模式后不断重启的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须对GDT setup和切换到protected mode的地方做错了,因为它一直不断地重新启动.

I must have done something wrong with the GDT setup and the switch to protected mode because it keeps constantly rebooting.

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

Here is my kernel.asm that should setup the GDT and switch to 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,然后跳到那里.

My bootloader.asm loads 10 sectors to 0x1000:0x000 and then jumps there.

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

I test the code with the commands:

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

我的错在哪里?

推荐答案

由于我只能假设您已正确将扇区读入内存中0x1000:0x0000,所以我只能指出kernel.asmgdt.inc中的潜在问题.

Since I can only assume you have read the sectors into memory at 0x1000:0x0000 correctly I can only point out potential problems in kernel.asm and gdt.inc.

如果您是使用jmp 0x1000:0x0000进入内核阶段的(我怀疑是这种情况),那么在kernel.asm中您错误地设置了 DS ES 段注册了错误的值.在这种情况下,您需要将这两个寄存器设置为0x1000,而不是0x0000.这段代码:

If you reached the kernel stage with jmp 0x1000:0x0000 (I suspect this is the case) then in kernel.asm you incorrectly set the DS, and ES segment registers to the wrong value. In that case you will need to set those two registers to 0x1000, not 0x0000. This code:

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

需要更改为:

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


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


The next major problem you have is that the GDT record (inside toc) takes a linear address. A linear address in real mode is the same thing as a physical address. From the instruction set manual it says:

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

The source operand specifies a 6-byte memory location that contains the base address (a linear address) and the limit (size of table in bytes) of the global descriptor table (GDT)

您为kernel.asm使用的 ORG 为0x0000(因为您没有指定一个),因此 NASM 假定生成的所有偏移量均以0x0000为底,包括标签gdt_data.因此,当您执行此操作时:

You have used an ORG of 0x0000 (since you didn't specify one) for kernel.asm so NASM assumes all offsets generated are from a base of 0x0000 including the label gdt_data. So when you do this:

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应该看起来像这样以补偿:

gdt_data will be some small offset just above 0x0000. In physical memory your GDT record is actually at 0x1000:0x0000+(small offset). 0x1000:0x0000 in physical (linear) memory is (0x1000<<4)+0x0000 = 0x10000 so you need to add that to gdt_data. Your toc should look like this to compensate:

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


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


The next issue you have is that you don't actually switch the protected mode flag on. You have this:

    mov eax,cr0
    or eax,1

应该是:

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

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

You need to update the protected mode bit in the CR0 register after you set the bit to 1.

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

Related to the GDT issue, you have created GDT entries for the code segment from an offset of 0x00000000 which encompass the entire 4gb address space. This is correct. Again though, since NASM created offset from 0x0000 and your code is actually loaded at 0x1000:0x0000 (physical address 0x10000) you need to add 0x10000 to the value of stage3 label in the JMP that finally sets up protected mode. As well, because we are encoding a value that is above 0xFFFF we need to force NASM to use a 32-bit operand so we use the dword qualifier on the JMP. You have this:

jmp 08h:Stage3

应该是这样:

jmp dword 08h:Stage3+0x10000

这篇关于设置全局描述符表和保护模式后不断重启的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆