无法在VirtualBox中启动自定义内核:“无法从启动媒体读取”

时间:2017-04-12 13:01:30

标签: c++ x86 virtualbox osdev grub

我按照Write your own operating system in 1 hour上的教程系列创建了一个基本的操作系统,只用4个文件打印“Hello World”:Makefilekernel.cpploader.s和{ {1}}。

我正在创建一个linker.ld文件但是当我将其启动到VirtualBox时,我收到错误“无法从启动媒体读取:系统暂停”。我确认mykernel.iso文件与我的机器实例链接。看起来代码中还有其他一些问题。

这是我的Makefile:

.iso

以下是#we need to tell the compiler to stop assuming that this will be executed inside an OS CPPPARAMS = -m32 -fno-use-cxa-atexit -nostdlib -fno-builtin -fno-rtti -fno-exceptions -fno-leading-underscore ASPARAMS = --32 LDPARAMS = -melf_i386 objects = loader.o kernel.o %.o: %.cpp g++ $(CPPPARAMS) -o $@ -c $< %.o: %.s as $(ASPARAMS) -o $@ $< mykernel.bin: linker.ld $(objects) ld $(LDPARAMS) -T $< -o $@ $(objects) install: mykernel.bin sudo cp $< /boot/mykernel.bin mykernel.iso: mykernel.bin mkdir iso mkdir iso/boot mkdir iso/boot/grub cp $< iso/boot/ echo 'set default=0' > iso/boot/grub/grub.cfg echo 'set timeout=0' >> iso/boot/grub/grub.cfg echo '' >> iso/boot/grub/grub.cfg echo 'menuentry "My Personal OS" {' >> iso/boot/grub/grub.cfg echo 'multiboot /boot/mykernel.bin' >> iso/boot/grub/grub.cfg echo 'boot' >> iso/boot/grub/grub.cfg echo '}' >> iso/boot/grub/grub.cfg grub-mkrescue --output $@ iso rm -rf iso clean: rm -rf iso rm *.o rm mykernel.iso rm mykernel.bin

kernel.cpp

以下是void printf(char *str) { unsigned short *VideoMemory = (unsigned short*)0xb8000; for(int i=0;str[i] != '\0';i++) VideoMemory[i] = (VideoMemory[i] & 0xFF00) | str[i]; } typedef void (*constructor)(); extern "C" constructor start_ctors; extern "C" constructor end_ctors; extern "C" void callConstructors() { for(constructor * i=&start_ctors;i!=&end_ctors;i++) (*i)(); } extern "C" void kernelMain(void * multiboot_structure, unsigned int magic_number) { printf("Hello World!"); //we do not want to exit from the kernel while(1); }

loader.s

以下是.set MAGIC, 0x1badb002 .set FLAGS, (1<<0 | 1<<1) .set CHECKSUM, -(MAGIC + FLAGS) .section .multiboot .long MAGIC .long FLAGS .long CHECKSUM .section .text .extern kernelMain .extern callConstructors .global loader loader: mov $kernel_stack, %esp call callConstructors push %eax #AX register has the pointer of multiboot structure stored by bootloader push %ebx #BX register has the magic number call kernelMain #double check to not come out of the kernel, creating one more loop _stop: cli hlt jmp _stop .section .bss .space 2*1024*1024 #2MB for stack to grow towards left side kernel_stack:

linker.ld

我的开发环境是Linux Mint 18.1 64位,安装了virtualbox。我的代码几乎与系列中的导师代码相匹配,但我仍然无法在虚拟机中启动。

修改

我尝试使用ENTRY(loader) OUTPUT_FORMAT(elf32-i386) OUTPUT_ARCH(i386:i386) SECTIONS { . = 0x100000; .text : { *(.multiboot) *(.text*) *(.rodata) } .data : { start_ctors = .; KEEP(*(.init_array)); KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*))); end_ctors = .; *(.data) } .bss : { *(.bss) } /DISCARD/ : { *(.fini_array*) *(.comment) } } ,它可以正常处理消息qemu-system-i386 -kernel mykernel.bin。这意味着VirtualBox环境和配置存在一些问题。

2 个答案:

答案 0 :(得分:1)

我遇到了同样的问题。只需安装grub-pc-bin并重新编译内核,就可以在虚拟机上成功启动。

sudo apt-get install grub-pc-bin

另外,我没有必要改变BSS段的大小。

答案 1 :(得分:-1)

我没有这个答案的官方消息来源。它实际上是基于我在Stackoverflow上看到的经验和其他问题以及我所做的一些调查结果。

如果您在 BSS 段中创建大型内核引导程序堆栈,则会导致 GRUB 在某些环境中崩溃,而不会在其他环境中崩溃。当 BSS 段的总大小似乎达到约2mb时,通常会发生这种情况。 Virtualbox似乎是一个特殊情况,似乎出现了这个问题。 Virtualbox中的问题似乎取决于所使用的版本和虚拟硬件配置。

您在loader.s中创建的用于引导 C ++ 环境的堆栈并不需要那么大。一旦你的内存管理和分配器到位,你可以为更大的内核堆栈预留区域,并在那时将 SS:ESP 设置为它。

为此你应该考虑改变:

.section .bss
.space 2*1024*1024 #2MB  for stack to grow towards left side
kernel_stack:

1mb或更小的东西。我可能会选择像64kb这样的东西:

.section .bss
.space 64*1024 #64KB  for stack to grow towards left side
kernel_stack: