【发布时间】:2015-04-07 17:43:11
【问题描述】:
我编写了一个非常简单的 C 内核和一个引导加载程序。我正在像这样在 QEMU 中加载内核:
qemu-system-i386 kernel.image
当我加载内核并从实模式切换到保护模式(该步骤成功完成)并且main方法开始执行其他方法时
void foo(int a, int b, int c, int d, int e) {return;}。但它的执行会导致 QEMU 崩溃。但是,如果我为 void foo(int a, int b, int c, int d) {return;} 重写 foo 方法 - 一切都会好起来的。这是错误信息:
(qemu) qemu: fatal: 试图在 0xf4000010 处的 RAM 或 ROM 之外执行代码
EAX=ffffffff EBX=00001000 ECX=00000000 EDX=00000000
ESI=00000000 EDI=00000000 EBP=ae00008f ESP=00008fcd
EIP=f4000010 EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT= 00007c75 00000017
IDT= 00000000 000003ff
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000000 CCD=00008fc5 CCO=INCL
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=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000
我的引导程序.S
KERNEL_OFFSET equ 0x1000
[org 0x7c00]
[bits 16]
mov bp, 0x8000
mov sp, bp
mov bx, bootstring
call print
mov [BOOT_DRIVE], dl
mov dh, 3h
mov bx, KERNEL_OFFSET
call load_kernel
call enable_A20
call init_protected
loop:
jmp loop
bootstring: db "Loading...", 0
BOOT_DRIVE: db 0
print:
mov ah, 0xE
mov al, [bx]
cmp al, 0
jz print_done
int 0x10
inc bx
jmp print
print_done:
ret
load_kernel:
push dx
mov ah, 0x02
mov al, dh
mov ch, 0
mov cl, 2
mov dh, 0
int 0x13
jc load_error
pop dx
cmp al, dh
jne load_error
ret
load_error:
mov bx, load_err_msg
call print
jmp $
enable_A20:
cli
call a20wait
mov al, 0xAD
out 0x64, al
call a20wait
mov al, 0xD0
out 0x64, al
call a20wait2
in al, 0x60
push eax
call a20wait
mov al, 0xD1
out 0x64, al
call a20wait
pop eax
or al, 2
out 0x60, al
call a20wait
mov al, 0xAE
out 0x64, al
call a20wait
sti
ret
a20wait:
in al, 0x64
test al, 2
jnz a20wait
ret
a20wait2:
in al, 0x64
test al, 1
jz a20wait2
ret
load_err_msg: db "Cannot load from disk", 0
gdt:
gdt_null:
dd 0
dd 0
gdt_cs:
dw 0xffff
dw 0
db 0
db 10011010b
db 11001111b
db 0
gdt_ds:
dw 0xffff
dw 0
db 0
db 10010010b
db 11001111b
db 0
gdt_end:
gdt_desc:
dw gdt_end - gdt - 1
dd gdt
CODE_SEG equ gdt_cs - gdt
DATA_SEG equ gdt_ds - gdt
[bits 16]
init_protected:
cli
xor ax, ax
mov ds, ax
mov es, ax
mov ax, 0x9000
mov ss, ax
mov sp, 0xFFFF
lgdt [gdt_desc]
mov eax, cr0
or eax, 0x1
mov cr0, eax
jmp CODE_SEG:start_protected
[bits 32]
start_protected:
mov ax, DATA_SEG
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, 0x9000
call KERNEL_OFFSET
times 510 -( $ - $$ ) db 0
dw 0xAA55
我哪里错了?
【问题讨论】:
-
您真的希望我们在不给我们您的内核的情况下调试您的内核吗?显然,您以某种方式违反了保护措施,但实际上无法判断。
-
真的吗?你是认真的吗?给我们内核的代码。
-
@MarcusMüller 抱歉,我编辑了帖子;)
-
我不知道你的问题,但我觉得你计算段选择器的方式有点奇怪:
DATA_SEG equ gdt_ds - gdt。这只是一个索引。没有 TI 和 RPL 字段。并且索引不应该是基于字节的;第一个段描述符应该是 0,第二个应该是 1,依此类推。
标签: c operating-system kernel qemu