24

我正在从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

所以你可以看到我提到的数字几乎匹配。问题是 .bss 的开头不是 100044,而是 44。我认为这就是 GRUB 说不好的原因。我的内存(内存不足)中不能有低于 1 MB 的部分。但是 objdump 告诉我我的部分高于该阈值,所以我不知道出了什么问题。无论如何,我将在下面粘贴我的代码,它相对较短。尽管如果您以前做过操作系统开发,我的问题可能是非常基本的,所以代码可能是无关的。

;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
4

1 回答 1

24

+1 for nice question with all the details, thank you.

At least on my machine the generated kernel.bin comes out as 4869 bytes, which only fits in 10 sectors not 9. Also, the VGA text memory is at 0xb8000 not 0xb800 (one more zero - 0xb800 is the real mode segment, has to be multiplied by 16). With those little adjustments it works fine here.

于 2013-01-14T15:05:28.620 回答