You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跳转至保护模式时Boot Loader崩溃问题求助

启动Boot Loader进入32位模式时触发通用保护故障的问题

我在学习制作可运行的Boot Loader以启动C语言编写的内核,目前卡在执行远跳转进入32位代码(jmp CODE_SEG:init_32)的环节,执行到此处就崩溃。我使用GNU汇编器as编写代码,通过.intel_syntax切换为熟悉的Intel指令格式,此前所有步骤均正常。

Boot Loader代码

.intel_syntax

.extern kernel_entry
.globl _start

.macro printstat a
    push %ax
    mov %ah, 0x0e
    mov %al, \a
    int 0x10
    pop %ax
.endm

.macro printdblstat a, b
    push %ax
    mov %ah, 0x0e
    mov %al, \a
    int 0x10
    mov %al, \b
    int 0x10
    pop %ax
.endm 

.code16
.section .text
 
.extern kernel_entry
KERNEL_ADDRESS = kernel_entry
STACK = 0x9000

_start: 
mov drive, %dl

# setup stack
mov %bp, STACK 
mov %sp, %bp

call load_drive
jmp GDT_init

# ;;;;;;;;;; Drive loader ;;;;;;;;;;
load_drive:
    mov %al, 2  # read number of sectors (2)
    mov %ah, 0x02 # read mode

    mov %cl, 0x02 # start from sector 2 (sector 1 is boot sector)
    mov %ch, 0x00 # cylinder 0
    mov %dl, drive
    mov %dh, 0x00 # head 0

    # dl = drive number is set as input to disk_load
    # es:bx = buffer pointer is set as input as well
 
    mov %bx, 0x1000 # load into addr
    int 0x13      # BIOS interrupt (read disk)
    jc disk_error # check carry bit for error
    
    mov %dl, drive     # disk
    cmp %al, 2 # read 2 sectors?
    ret

    # sector error
    mov %bl, %al
    printstat %bl
    printdblstat 'E', '1'
    jmp .

    # disk error
    disk_error:
    printdblstat 'E', '2'
    jmp .

# ;;;;

# ;;;;;;;;;;; GDT ;;;;;;;;;;;;
.section .data
.align 8
drive: .byte 0 

gdt_start: 
    .4byte 0x0,0x0
gdt_code:
    .byte 0xFF,0xFF,0x0,0x0,0x0,0b10011010,0b11001111,0x0
gdt_data:
    .byte 0xFF,0xFF,0x0,0x0,0x0,0b10010010,0b11001111,0x0
gdt_video:
    .byte 0xFF,0xFF,0x0,0x80,0x0B,0b10010010,0b01000000,0x0
gdt_end:
gdt_descriptor:
    .word gdt_end - gdt_start - 1 # size (16 bit)
    .4byte gdt_start # address (32 bit)
CODE_SEG = gdt_code - gdt_start
DATA_SEG = gdt_data - gdt_start
VIDEO_SEG = gdt_video - gdt_start
.section .text

# ;;;;;;;;;; Init GDT ;;;;;;;;;;
GDT_init:  
    lgdt gdt_descriptor
    
    xor %ax, %ax
    mov %ds, %ax
    mov %ss, %ax

    in %al,0x70
    or %al,0x80
    out 0x70, %al # nonmasked interrupts
    
    in %al,0x92
    or %al,2
    out 0x92, %al # A20 line

    cli 

    mov %eax, %cr0
    or %al, 0x1 # protected mode
    mov %cr0, %eax

    jmp CODE_SEG:init_32 # <================================== crashes here

# ;;;;;;;;;;; 32 bit mode ;;;;;;;;;;
.code32
.align 32
init_32:
    mov %ax, DATA_SEG
    mov %ds, %ax
    mov %ss, %ax
    mov %es, %ax
    mov %fs, %ax
    mov %gs, %ax

    mov %ebp, STACK
    mov %esp, %ebp

    call kernel_entry
    hlt

.space 510-(.-_start)
.word 0xAA55 # magic number

QEMU -d cpu-reset 日志输出

CPU Reset (CPU 0)
EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000663
ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000000
EIP=0000fff0 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0000 00000000 0000ffff 00009300
CS =f000 ffff0000 0000ffff 00009b00
SS =0000 00000000 0000ffff 00009300
DS =0000 00000000 0000ffff 00009300
FS =0000 00000000 0000ffff 00009300
GS =0000 00000000 0000ffff 00009300
LDT=0000 00000000 0000ffff 00008200
TR =0000 00000000 0000ffff 00008b00
GDT=     00000000 0000ffff
IDT=     00000000 0000ffff
CR0=60000010 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 
DR6=ffff0ff0 DR7=00000400
CCS=00000000 CCD=00000000 CCO=DYNAMIC
EFER=0000000000000000
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=0000000000000000 0000000000000000 XMM01=0000000000000000 0000000000000000
XMM02=0000000000000000 0000000000000000 XMM03=0000000000000000 0000000000000000
XMM04=0000000000000000 0000000000000000 XMM05=0000000000000000 0000000000000000
XMM06=0000000000000000 0000000000000000 XMM07=0000000000000000 0000000000000000
Triple fault

QEMU -d int 日志输出

check_exception old: 0xd new 0xd
     1: v=08 e=0000 i=0 cpl=0 IP=0000:00007c70 pc=00007c70 SP=0000:00009000 env->regs[R_EAX]=00000011
EAX=00000011 EBX=00001000 ECX=00000002 EDX=00000080
ESI=00000000 EDI=00000000 EBP=00009000 ESP=00009000
EIP=00007c70 EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0000 00000000 0000ffff 00009300 DPL=0 DS16 [-WA]
CS =0000 00000000 0000ffff 00009b00 DPL=0 CS16 [-RA]
SS =0000 00000000 0000ffff 00009300 DPL=0 DS16 [-WA]
DS =0000 00000000 0000ffff 00009300 DPL=0 DS16 [-WA]
FS =0000 00000000 0000ffff 00009300 DPL=0 DS16 [-WA]
GS =0000 00000000 0000ffff 00009300 DPL=0 DS16 [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     00000000 00000000
IDT=     00000000 000003ff
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 
DR6=ffff0ff0 DR7=00000400
CCS=00000002 CCD=00000011 CCO=LOGICB
EFER=0000000000000000
check_exception old: 0x8 new 0xd

编译命令

gcc -Wl,--oformat=binary -Wl,\
-Ttext=0x7c00 -Wl,--build-id=none -Wl,-melf_i386 \
-nostartfiles -nostdlib -fno-pie -O0 -ffreestanding \
-m32 -o /tmp/lima/final.bin bootloader/boot.s kernel/entry.c

根据CPU故障码0xd,这是通用保护故障(General Protection Fault),随后触发了三重故障。请问这是GDT配置错误导致的吗?还是有其他可能的原因?


内容的提问来源于stack exchange,提问作者Sir Archibald Humphrey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 09:08:08