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



我一直在研究和编写一个引导加载程序。为了切换到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 roland的回答,我已经移动了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数据中执行失败。! 结果是不可预测的。
要么将这些数据项放在其他地方,要么在cli指令中插入jmp

正确的代码:

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

jmp指令为32位模式错误:

jmp GDTCodeSeg:startProtectedMode

应:

jmp GDTCodeSegSize:startProtectedMode

还有这个类似的问题:

mov ax, GDTDataSeg

应:

mov ax, GDTDataSegSize