简单内核不会在GRUB中引导

时间:2021-10-26 08:54:04

I'm learning a bit of OS development from OSDev.org. I have a kernel and I'm trying to boot in GRUB Legacy (0.97) using qemu. However, when I type kernel 200+9, I get the message

我正在从OSDev.org上学习一些操作系统开发。我有一个内核,我正在尝试使用qemu引导GRUB Legacy(0.97)。然而,当我输入内核200+9时,我得到了消息

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

This is what I expect except for the (bad) part. If I type boot now GRUB just hangs.

这是我所期望的,除了(不好的)部分。如果我现在键入boot, GRUB只是挂起。

I think the numbers 0x100000, 0x44, 0x4008 stand for the .text segment start address, the .bss start address, and the .bss section size, respectively. I think this because running objdump -h on the kernel image gives this output:

我认为数字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

So you can see that the numbers I mentioned almost match up. The issue is that instead of 100044, the start of .bss is just 44. And I think this is the reason why GRUB is saying bad. I can't have a section below 1 MB in memory (low memory). But objdump is telling me my sections are above that threshold, so I don't know what's wrong. Anyway, I'll paste my code below, it's relatively short. Although my question is probably very basic if you've done OS dev before, so the code might be extraneous.

你可以看到我提到的数字几乎是一致的。问题是,不是100044,而是。bss的开始是44。我认为这就是为什么食物不好的原因。内存中不能有小于1 MB的部分(低内存)。但是objdump告诉我,我的section在这个阈值之上,所以我不知道哪里出错了。无论如何,我将在下面粘贴我的代码,它相对较短。尽管我的问题可能非常基础,如果您以前做过OS dev,那么代码可能是多余的。

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

Below is my custom linker script:

下面是我的自定义链接器脚本:

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)
    }
}

And finally, I build the kernel with the following lines:

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

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

Where stage1 and stage2 are file from GRUB Legacy and pad is any 750 byte file (So stage1+stage2+pad have a file size of 102400 bytes, or 200 blocks, which is why I boot with kernel 200+9).

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

Finally, I run the kernel in qemu:

最后,我在qemu运行内核:

qemu-system-x86_64 -fda floppy.img

1 个解决方案

#1


22  

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

+1关于所有细节的好问题,谢谢。

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.

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

#1


22  

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

+1关于所有细节的好问题,谢谢。

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.

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