c - 方法执行时 QEMU 崩溃

标签 c operating-system kernel qemu

我编写了非常简单的 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: 尝试在 RAM 或 ROM 之外的 0xf4000010 处执行代码

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 

我的 Bootstrap .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 

我哪里错了?

最佳答案

这些症状表明您的堆栈内存设置不正确 - 当函数有足够的参数时,其中一些参数必须放在堆栈上而不是全部放在寄存器中,看起来就会出现问题。来自 QEMU 的消息告诉您,您的虚拟机尝试从其中没有 RAM 的物理地址执行。您应该能够使用调试日志记录选项(-d in_asm,exec,cpu,int -D qemu.log)调试到底出了什么问题,以查看CPU实际上做了什么才能到达它尝试执行的位置地址无效。

请注意,虽然 QEMU 错误消息看起来有点像“QEMU 崩溃”,但它始终表明存在 guest 操作系统错误。

关于c - 方法执行时 QEMU 崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28385134/

相关文章:

r - 如何设置自定义 R 安装以在 Jupyter 中使用 rpy2?

linux - 运行 make 时显示 make ** no target.stop

c - timer_gettime 不适用于多个计时器

比较 2 个字符串,一个在结构中,另一个不是 C 编程

linux - 从Linux操作系统中获得独特的值(value)

java - "the memory requested by JVM from the OS has to be contiguous"是什么意思?

windows - 哪些字符可以安全地命名文件和目录?

无法在赋值中将 'float*' 转换为 'float'

我们能否将 CUDA 或 OpenCL 的速度与 CPU 性能进行比较?

c - Linux 中的页表遍历