简单内核无法在GRUB中启动

时间:2013-01-14 02:52:25

标签: assembly kernel qemu osdev grub

我正在从OSDev.org学习一些操作系统开发。我有一个内核,我正在尝试使用qemu在GRUB Legacy(0.97)中启动。但是,当我输入kernel 200+9时,我会收到消息

[Multiboot-elf, <0x100000:0x80:0x4008>(bad), entry=0x10000c]

这是我所期望的,除了(坏)部分。如果我现在输入boot,GRUB就会挂起。

我认为数字0x100000,0x44,0x4008分别代表.text段起始地址,.bss起始地址和.bss段大小。我认为这是因为在内核映像上运行objdump -h会产生以下结果:

kernel.bin:     file format elf32-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000044  00100000  00100000  00001000  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .bss          00004008  00100044  00100044  00001044  2**2
                  ALLOC

所以你可以看到我提到的数字几乎匹配。问题是,而不是100044,.bss的开头只有44个。我认为这就是GRUB说错的原因。我的内存不足1 MB(低内存)。但objdump告诉我我的部分超过了这个门槛,所以我不知道出了什么问题。无论如何,我会在下面粘贴我的代码,它相对较短。虽然我的问题可能是非常基本的,如果你以前做过OS开发,所以代码可能是无关紧要的。

;loader.s - contains the multiboot header for grub and calls the main kernel method

global loader                           ; making entry point visible to linker
global magic                            ; we will use this in kmain
global mbd                              ; we will use this in kmain

extern kmain                            ; kmain is defined in kmain.cpp

; setting up the Multiboot header - see GRUB docs for details
MODULEALIGN equ  1<<0                   ; align loaded modules on page boundaries
MEMINFO     equ  1<<1                   ; provide memory map
FLAGS       equ  0x03;MODULEALIGN | MEMINFO  ; this is the Multiboot 'flag' field
MAGIC       equ  0x1BADB002             ; 'magic number' lets bootloader find the header
CHECKSUM    equ -(MAGIC + FLAGS)        ; checksum required

section .text

loader:

align 4
    dd MAGIC
    dd FLAGS
    dd CHECKSUM

; reserve initial kernel stack space
STACKSIZE equ 0x4000                    ; that's 16k.

    mov  esp, stack + STACKSIZE         ; set up the stack
    mov  [magic], eax                   ; Multiboot magic number
    mov  [mbd], ebx                     ; Multiboot info structure

    call kmain                          ; call kernel proper

    cli
.hang:
    hlt                                 ; halt machine should kernel return
    jmp  .hang

section .bss

align 4
stack: resb STACKSIZE                   ; reserve 16k stack on a doubleword boundary
magic: resd 1
mbd:   resd 1

// kernel.c - Contains the main kernel method

void kmain() {
  extern unsigned int magic;

  if (magic != 0x2BADB002) {
    // Something went wrong
  }

  volatile unsigned char *videoram = (unsigned char *) 0xB800;
  videoram[0] = 65;
  videoram[1] = 0x07;
}

以下是我的自定义链接描述文件:

ENTRY (loader)

SECTIONS {
    . = 0x00100000;

    .text ALIGN (0x1000) : {
        *(.text)
    }

    .rodata ALIGN (0x1000) :
    {
        *(.rodata*)
    }

    .data ALIGN (0x1000) :
    {
        *(.data)
    }

    .bss :
    {
        sbss = .;
        *(COMMON)
        *(.bss)
        ebss = .;
    }

    /DISCARD/ : {
        *(.eh_frame)
        *(.comment)
    }
}

最后,我用以下几行构建内核:

nasm -f elf -o loader.o loader.s
gcc -c -o kernel.o kernel.c
ld -T linker.ld -o kernel.bin loader.o kernel.o
cat stage1 stage2 pad kernel.bin > floppy.img

其中stage1和stage2是来自GRUB Legacy的文件,pad是任何750字节文件(因此stage1 + stage2 + pad的文件大小为102400字节,或200块,这就是我使用内核200 + 9启动的原因)。

最后,我在qemu中运行内核:

qemu-system-x86_64 -fda floppy.img

1 个答案:

答案 0 :(得分:23)

+1以获取所有细节的好问题,谢谢。

至少在我的机器上,生成的kernel.bin为4869字节,仅适用于10个不是9的扇区。此外,VGA文本内存为0xb8000而不是0xb800(一个零 - 0xb800是实模式段,必须乘以16)。通过这些小调整,它在这里工作正常。