使用GRUB 2而不是GRUB 0.97引导时,内核会引发GPF异常

时间:2018-01-12 12:02:02

标签: c x86 osdev grub grub2

我正在尝试从GRUB 0.97(stage2_eltorito)切换到GRUB 2,生成启动操作系统的ISO映像。但是,我面临一个特殊的错误。为了给出一些上下文,我最近设置了一些异常处理ISR和两个IRQ:一个用于键盘输入,一个用于计时器滴答。使用GRUB Legacy启动时,内核工作正常,键盘输入也可以工作。当使用GRUB 2引导时,由于某种原因,内核会捕获常规保护错误异常并暂停系统。我已经多次校对我的代码,我无法在任何可能导致此GPF错误的地方找到错误。我的问题是什么,如何解决?这是内核的Assembly入口点,包括Multiboot标头:

extern toc
extern init
extern kmain
extern load_gdt

global start32

MBALIGN equ 1<<0
MEMINFO equ 1<<1
MAGIC_NUMBER equ 0x1BADB002
FLAGS equ MBALIGN | MEMINFO
CHECKSUM equ -(MAGIC_NUMBER + FLAGS)

section .text
align 4
dd MAGIC_NUMBER
dd FLAGS
dd CHECKSUM

start32:
    call load_gdt

    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    mov esp, 0x9c000

    call init
    push ebx
    call kmain

(我不认为这是一个多重启动问题,因为内核实际上在两种情况下都能完美加载) 这里提到的load_gdt和相关标签(我认为这可能是问题的一部分)

global toc
global load_gdt

section .text
load_gdt:
    lgdt[toc]
    ret
section .rodata
gdt32:
    dd 0
    dd 0

    dw 0x0FFFF
    dw 0
    db 0
    db 0x9A
    db 0xCF
    db 0

    dw 0x0FFFF
    dw 0
    db 0
    db 0x92
    db 0xCF
    db 0
gdt_end:
toc:
    dw gdt_end - gdt32 - 1
    dd gdt32 

设置操作系统的init()函数(当然是在创建initrd之前)

#include <kernel.h>

void init()
{
    interrupt_disable();
    terminal_init(LGREEN, BLACK);

    idt_install();
    isr_install();
    irq_install();
    interrupt_enable();
    timer_install();
    keyboard_install();
    return;
}

当然,我的kmain

#include <kernel.h>
#include <multiboot.h>

char logo[1024] = {
":::::::::::///oyhhyo//:::::::::::/:\n" \
"://////////+yNNmhysoo+////////////:\n" \
"::/://:://yNdy+//::::::+o/:://////:\n" \
"::////://sNdy+//::-:-:::++/://////:\n" \
"::::::://dmdyo/:::::--::++/::::::::\n" \
":::::::/+mdhhysoo+:/++//+y/::::::::\n" \
":::::::/oddyooo+/o//+so+/o/::::::::\n" \   
"+       =     =   + +    +    +++++     Welcome to LunaOS!\n" \
"+       =     =   +   +  +    +===+     A simple 32-bit operating system\n" \
"+       =     =   +    + +    +   +     Written soley by Safal Aryal\n" \
"++++++  = = = =   +      +    +   +     All components of this OS,\n" \
":::::::/+hhyo///+s///::/+//::::::::     are in the public domain!\n" \
"::::::://oshs+/+hdhs+/////:::::::::     (excluding the GRUB bootloader)\n" \
"::::::::/++so+shdyhys+////:::::::::     Type `help` for a list of commands\n" \
"::::::::/+o++oosso++/+/:/::::::::::\n" \
":::::::/ossssysoso+//+/:/::::::::::\n" \
":::://ohysosysso+oo/:///:::::::::::\n" \
"::::--:/ssyoshhsoo+/::+:/-:::::::::\n" \
":::-----:+shysdyo/-.`-/::--:----:::\n" \
"--::------:+sssyo/.`.:/:----::-----\n" \
"-::/:--::-::---//////--------::----\n" \
};

void kmain(multiboot_info_t *mbd, uint32_t magic)
{
    uint32_t mmap;

    if((mbd->flags >> 6) & 1) {
        mmap = mbd->mmap_addr;
    }    
    terminal_puts(logo);
    terminal_puts("SHELL> ");

    for(;;){asm volatile("sti"); asm volatile ("hlt");};
}

提前致谢! (注意:multiboot_info_t在我用来访问内存映射的Multiboot头中定义,通过将EBX推送到kernel.asm中的堆栈,将指向其类型的指针作为参数传递给kmain)
P.S:kvm -kernel似乎有用......

0 个答案:

没有答案