这个问题是我在 GDT 下使用选择器在 x86 保护模式下定义了一个数据和堆栈段。当 jmp 进入保护模式时,似乎我可以访问数据部分,但在推送 eax 时会崩溃。请参阅以下代码:
%include "../inc/descriptor.asm"
%include "../inc/define.asm"
org 7c00h
jmp begin
; -----------------------------------------------------------------------
; Const variable
STACK_BASE EQU 1000000h ; 16M
DATA_BASE EQU 2000000h ; 32M
STACK_SIZE EQU 8000h ; 32K
STACK_LIMIT EQU 1008000h ; 16M + 32K
DATA_SIZE EQU 100000h ; 1M
; GDT and LDT
; Descriptor base limit property
[SECTION .gdt]
GDT: Descriptor 0, 0, 0
LDT_CODE32: Descriptor 0, SEG_CODE32_LEN - 1, DA_C + DA_32
LDT_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW
LDT_STACK: Descriptor STACK_BASE, STACK_SIZE - 1, DA_DRWA + DA_B
LDT_DATA: Descriptor DATA_BASE, DATA_SIZE - 1, DA_DRW
GDTLEN EQU $ - GDT
GDTPTR DW GDTLEN - 1
DD 0
; Selectors
SLT_CODE32 EQU LDT_CODE32 - GDT
SLT_VIDEO EQU LDT_VIDEO - GDT
SLT_STACK EQU LDT_STACK - GDT
SLT_DATA EQU LDT_DATA - GDT
; -----------------------------------------------------------------------
; Real mode code
[SECTION .s16]
[BITS 16]
begin:
mov ax, cs
mov ds, ax
; init 32 bits code section descriptor
xor eax, eax
mov ax, cs
shl eax, 4
add eax, code32
mov word [LDT_CODE32 + 2], ax
shr eax, 16
mov byte [LDT_CODE32 + 4], al
mov byte [LDT_CODE32 + 7], ah
; prepare for loading gdtr
xor eax, eax
mov ax, ds
shl eax, 4
add eax, GDT
mov dword [GDTPTR + 2], eax
lgdt [GDTPTR]
cli
in al, 92h
or al, 10b
out 92h, al
mov eax, cr0
or eax, 1
mov cr0, eax
jmp dword SLT_CODE32:0
; protected mode code
[SECTION .s32]
[BITS 32]
code32:
mov ax, SLT_VIDEO
mov gs, ax
mov ax, SLT_STACK
mov ss, ax
mov esp, STACK_LIMIT - 16
mov ax, SLT_DATA
mov ds, ax
mov eax, 012345678h
xor edx, edx
mov [edx], eax
mov edx, [edx]
push eax ; **<= crashed here.**
; ---------------------------------
; PREPARE DEBUG CHAR
mov ax, SLT_VIDEO
mov gs, ax
mov bh, 0ch
mov bl, 'B'
mov esi, (80 * 1 + 1) * 2
mov [gs:esi], bx
jmp $
; ; END OF PREPARE DEBUG CHAR
; ---------------------------------
push eax
pop ebx
mov eax, DATA_BASE
mov dword [eax], ebx
mov edi, 0
mov esi, (80 * 1 + 1) * 2
call PRINT_DWORD
jmp $
; ---------------------------------
; ; PREPARE DEBUG CHAR
; mov ax, SLT_VIDEO
; mov gs, ax
; mov bh, 0ch
; mov bl, 'B'
; mov esi, (80 * 1 + 1) * 2
; mov [gs:esi], bx
; jmp $
; ; END OF PREPARE DEBUG CHAR
; ---------------------------------
SEG_CODE32_LEN EQU $ - code32
times 290 - ($ - $$) db 0
dw 0xaa55
; command reference:
; nasm protected_mode.asm -o pm.bin
; dd if=pm.bin of=pm.img bs=512 count=1
描述符.asm:
;
; Descriptor base, limit, attr
; base: dd
; limit: dd low 20 bits available
; attr: dw low nibble of higher byte always 0
;
%macro Descriptor 3
dw %2 & 0FFFFh
dw %1 & 0FFFFh
db (%1 >> 16) & 0FFh
dw ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh)
db (%1 >> 24) & 0FFh
%endmacro
;
定义.asm:
;
DA_32 EQU 4000h
DA_DRW EQU 92h
DA_DRWA EQU 93h
DA_C EQU 98h
DA_B EQU DA_32
DA_ELEMENT_4K EQU 8000h
;
; Paging Entry Attribute
PG_P EQU 1
PG_RW_W EQU 2
PG_US_U EQU 4