加载全局描述符表会导致错误

发布于 2025-02-04 15:34:20 字数 2073 浏览 2 评论 0原文

我的引导加载程序上有一个子例程“ switch32”,应该将过渡到32位保护模式,但是lgdt指令似乎会造成麻烦。这是代码 “ switch32.asm”:

gdt_start:

gdt_null:
    dq 0x0
gdt_code:
    dw 0xFFFF   ;Lower 16 bits of limit
    dw 0x0000   ;Lower 16 bits of base address
    db 0x00     ;Middle 8 bits of base address
    db 10011010b;Access byte: present=1,privilege=00,type=1,exec=1,comform=0,read=1,acc=0
    db 0100111b ;High 4 bits = flags, Low 4 bits = last nibble of limit (20 bits)
    db 0x00     ;Higher 8 bits of base address (32 bits)

gdt_data:
    dw 0xFFFF   ;Lower 16 bits of limit
    dw 0x0000   ;Lower 16 bits of base address
    db 0x00     ;Middle 8 bits of base address
    db 10010010b;Access byte: present=1,privilege=00,type=1,exec=0,dir=0,write=1,acc=0
    db 0100111b ;High 4 bits = flags, Low 4 bits = last nibble of limit (20 bits)
    db 0x00     ;Higher 8 bits of base address (32 bits)

gdt_end:        

gdtr_data:  ;The data to pass to the GDTR register (lower word=size of GDT, higher dword=address of GDT)
    dw gdt_end - gdt_start - 1 ;16 bit size of GDT
    dd gdt_start               ;Address to start of GDT

CODE_SEGMENT equ gdt_code - gdt_start   ;Index of code segment descriptor
DATA_SEGMENT equ gdt_data - gdt_start   ;Index of data segment descriptor

switch32:
    pusha
    cli ;Disable interrupts
    lgdt [gdtr_data]

    ;Set first bit (protected mode enable) in control register 0
    mov eax,cr0
    or eax,0x1
    mov cr0,eax

    jmp CODE_SEGMENT:post_flush       ; 'fake' far jump to trick CPU into flushing pipeline to prevent nasty exceptions
                                      ; according to intel manual, CS register is implicitly set to far JMP's selector
post_flush:
    [bits 32]
    mov eax,DATA_SEGMENT
    mov ds,eax 
    mov ss,eax 
    mov es,eax
    mov fs,eax
    mov gs,eax

    popa
    ret

我正在使用qemu,每当调用子例程时,屏幕开始闪烁,没有任何超过lgdt指令,我很确定这意味着有一个CPU错误。该错误来自lgdt指令,但对于原因,我毫无意义。我是否将正确的数据传递给GDTR寄存器?还是我的整个GDT设置错误?

我正在将Intel I386程序员手册和全球描述符表中的Osdev Wiki文章用作资源,并且根据我阅读的内容设置了GDT。

I have a subroutine 'switch32' on my bootloader which is supposed to make the transition to 32 bit protected mode, however the lgdt instruction seems to be causing trouble. Here is the code for
"switch32.asm":

gdt_start:

gdt_null:
    dq 0x0
gdt_code:
    dw 0xFFFF   ;Lower 16 bits of limit
    dw 0x0000   ;Lower 16 bits of base address
    db 0x00     ;Middle 8 bits of base address
    db 10011010b;Access byte: present=1,privilege=00,type=1,exec=1,comform=0,read=1,acc=0
    db 0100111b ;High 4 bits = flags, Low 4 bits = last nibble of limit (20 bits)
    db 0x00     ;Higher 8 bits of base address (32 bits)

gdt_data:
    dw 0xFFFF   ;Lower 16 bits of limit
    dw 0x0000   ;Lower 16 bits of base address
    db 0x00     ;Middle 8 bits of base address
    db 10010010b;Access byte: present=1,privilege=00,type=1,exec=0,dir=0,write=1,acc=0
    db 0100111b ;High 4 bits = flags, Low 4 bits = last nibble of limit (20 bits)
    db 0x00     ;Higher 8 bits of base address (32 bits)

gdt_end:        

gdtr_data:  ;The data to pass to the GDTR register (lower word=size of GDT, higher dword=address of GDT)
    dw gdt_end - gdt_start - 1 ;16 bit size of GDT
    dd gdt_start               ;Address to start of GDT

CODE_SEGMENT equ gdt_code - gdt_start   ;Index of code segment descriptor
DATA_SEGMENT equ gdt_data - gdt_start   ;Index of data segment descriptor

switch32:
    pusha
    cli ;Disable interrupts
    lgdt [gdtr_data]

    ;Set first bit (protected mode enable) in control register 0
    mov eax,cr0
    or eax,0x1
    mov cr0,eax

    jmp CODE_SEGMENT:post_flush       ; 'fake' far jump to trick CPU into flushing pipeline to prevent nasty exceptions
                                      ; according to intel manual, CS register is implicitly set to far JMP's selector
post_flush:
    [bits 32]
    mov eax,DATA_SEGMENT
    mov ds,eax 
    mov ss,eax 
    mov es,eax
    mov fs,eax
    mov gs,eax

    popa
    ret

I'm using qemu and whenever the subroutine is called, the screen starts blinking and nothing past the lgdt instruction is executed, I'm pretty sure that means there is a CPU error. The error is coming from the lgdt instruction but i'm clueless as to why. Am I passing the right data to the GDTR register? or is my entire GDT set up wrong?

I'm using the intel i386 programmer manual and the osdev wiki article on the Global Descriptor Table as resources and I set up my GDT according to what I've read.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文