0

I am trying to switch from GRUB 0.97 (stage2_eltorito) to GRUB 2, generating an ISO image that boots the operating system. However, I am facing a peculiar error. Just to give some context, I have recently set up some exception handling ISRs and two IRQs: one for keyboard input, one for timer ticks. When booted with GRUB Legacy, the kernel works fine, and the keyboard input also works. When booting with GRUB 2, for some reason, the kernel catches a General Protection Fault exception and halts the system. I have proofread my code multiple times and I cannot find an error in it anywhere that may cause this GPF error. What is my problem, and how can it be fixed? Here is the Assembly entry point of the kernel, including the Multiboot header:

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

(I don't think this a Multiboot issue, as the kernel actually loads perfectly in both cases) The load_gdt and associated labels mentioned here (as I think this may be part of the issue)

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 

The init() function that sets the OS up (before I make an initrd, of course)

#include <kernel.h>

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

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

And of course, my 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");};
}

Thanks in advance! (Note: multiboot_info_t is defined in the Multiboot header which I use to access the memory map, a pointer to its type is passed as a parameter to kmain by pushing EBX to the stack in kernel.asm)
P.S: kvm -kernel seems to work...

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
  • 1
    Why not enable interrupts after timer and keyboard install? – stark Jan 12 '18 at 12:23
  • Maybe GRUB2 uses the [Multiboot2 spec](https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html)? While it seems you are using the [0.6.96 one](https://www.gnu.org/software/grub/manual/multiboot/multiboot.html) – Margaret Bloom Jan 12 '18 at 12:51
  • @MargaretBloom I heard that GRUB2 also boots multiboot1 kernels though? Even the OSDev wiki uses it in their Bare Bones guide – Safal Aryal Jan 12 '18 at 12:57
  • @stark changing it has no effect :( – Safal Aryal Jan 12 '18 at 12:59
  • That should be the case, the signatures are differents. I didn't notice that before. – Margaret Bloom Jan 12 '18 at 12:59
  • How do you compile and link those files? – Margaret Bloom Jan 12 '18 at 13:32
  • You are loading your gdt *before* the multiboot has the chance to hand off that seems not quite right. – Ahmed Masud Jan 12 '18 at 13:35
  • @Ahmes Masud where should I load it? – Safal Aryal Jan 12 '18 at 13:38
  • @margaret bloom I use a Makefile – Safal Aryal Jan 12 '18 at 13:39
  • can you share your idt_install? – Ahmed Masud Jan 12 '18 at 13:46
  • i'm not sure if the last comment worked and went through, but here is the link to exact file @AhmedMasud https://github.com/safsom/lunaos/blob/master/kernel/src/idt.c – Safal Aryal Jan 12 '18 at 14:17
  • I never saw this question originally (it is a year and a half old), but you are missing one important thing. After you load the GDT with LGDT you correctly set all the selector registers except one important one: _CS_. If _CS_ isn't set this can cause issues. To fix it. Before you do `mov ax, 0x10` `mov ds, ax` do a FAR JMP to the next instruction to set CS. Do something like `jmp 0x08:.setcs` and then a label `.setcs:` on the next line.This will effectively FAR JMP to the next instruction AND set _CS_ to 0x08 as well. – Michael Petch May 02 '19 at 17:42

0 Answers0