在 32 位模式下写入显存失败

Failing to write to video memory in 32 bit mode

我一直在研究和编写引导加载程序。为了切换到 32 位模式,我使用了本教程:https://www.youtube.com/watch?v=pXzortxPZR8&list=PLxN4E629pPnKKqYsNVXpmCza8l0Jb6l8-&index=4

它说要写入您可以使用的显存

mov [0xb8000], byte 'A'

这实际上并没有写任何东西。我知道代码已成功由阶段 1 引导加载程序加载,因为 nextStage 文本正在写入屏幕,同时它仍处于 16 位模式。这个错误是因为我的代码写入内存还是我没有成功切换到 32 位模式?

[bits 16]
[org 0x7e00]

mov bx, nextStage
call print

;Enable A20 bit, allowing memory > 1Mib
in al, 0x92
or al, 2
out 0x92, al

;GDT = Global Descriptor Table
;Defines memory layout
;Works with sections of memory, we need 3

;Required for some weird reason
GDTNullSeg:
    dd 0x0
    dd 0x0

;Defines segment for storing code
GDTCodeSeg:
    dw 0xFFFF       ;Limit
    dw 0x0000       ;Base (low)
    db 0x00         ;Base (medium)
    db 0b10011010   ;Flags
    db 0b11001111   ;Flags + Upper Limit
    db 0x00         ;Base (high)

;Defines segment for storing data
GDTDataSeg:
    dw 0xFFFF
    dw 0x0000
    db 0x00
    db 0b10010010
    db 0b11001111
    db 0x00

;This is how code and data are seperated so they can be stored in the same place in a von neumnan architecture

GDTEnd:

;What is passed to CPU register when GDT is passed, describes GDT
descriptorGDT:
    GDTSize:
        ;GDT size
        dw GDTEnd - GDTNullSeg - 1
        ;GDT address
        dd GDTNullSeg

GDTCodeSegSize equ GDTCodeSeg - GDTNullSeg
GDTDataSegSize equ GDTDataSeg - GDTNullSeg

cli
lgdt [descriptorGDT]
mov eax, cr0
or eax, 1
mov cr0, eax
;Far jump, GDTCodeSeg is the segment to jump too, startProtectedMode is the offset (location to jump to in that segment)
;Needed to flush cpu pipelines as if we are changing mode while unknown things are happerning it could lead to unexpected results
jmp GDTCodeSeg:startProtectedMode

jmp $

%include "src/print.asm"

nextStage: db "Successfully entered 2nd stage bootloader.", 0

[bits 32]
startProtectedMode:
    ;Before anything else we need to point segment registers to new data defined in GDT
    mov ax, GDTDataSeg
    mov ds, ax
    mov ss, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    ;Redefine stack pointer to larger value now we have 4GiB of memory to work with
    mov ebp, 0x90000
    mov esp, ebp

    mov al, 'A'
    mov ax, 0x0F
    mov [0xb8000], ax

    jmp $

times 512-($-$$) db 0

编辑: 根据 Sep Rolands 的回答,我移动了 GDT 定义并更改了写入视频内存代码,导致:

---

jmp $

%include "src/print.asm"
%include "src/GDT.asm"

stage2Info: db 0xA, 0xD, "Successfully entered stage 2 bootloader.", 0

---

    ;mov esp, ebp

    mov ax, 0x0F41
    mov [0xb8000], ax

    jmp $

---

但是这会导致启动循环。

一旦您的代码打印了 nextStage 消息并启用了 A20,执行将在 GDT 数据中失败 !结果不可预测。
要么将这些数据项放在别处,要么将 jmp 插入 cli 指令。

正确代码:

mov ax, 0x0F41   ; BrightWhiteOnBlack 'A'
mov [0xb8000], ax

32 位模式的 jmp 指令不正确:

jmp GDTCodeSeg:startProtectedMode

应该是:

jmp GDTCodeSegSize:startProtectedMode

还有这个类似的问题:

mov ax, GDTDataSeg

应该是:

mov ax, GDTDataSegSize