C++ 无法在VirtualBox中启动自定义内核:“0”;无法从启动介质中读取“;

C++ 无法在VirtualBox中启动自定义内核:“0”;无法从启动介质中读取“;,c++,x86,virtualbox,osdev,grub,C++,X86,Virtualbox,Osdev,Grub,我按照教程系列创建了一个只打印“Hello World”的基本操作系统,其中只有4个文件:Makefile、kernel.cpp、loader.s和linker.ld 我正在创建一个mykernel.iso文件,但当我将其引导到VirtualBox中时,我收到错误“无法从引导介质读取:系统已停止”。我确认.iso文件已链接到我的机器实例。看起来代码中可能还有其他问题 这是我的Makefile: #we need to tell the compiler to stop assuming that

我按照教程系列创建了一个只打印“Hello World”的基本操作系统,其中只有4个文件:
Makefile
kernel.cpp
loader.s
linker.ld

我正在创建一个
mykernel.iso
文件,但当我将其引导到VirtualBox中时,我收到错误“无法从引导介质读取:系统已停止”。我确认
.iso
文件已链接到我的机器实例。看起来代码中可能还有其他问题

这是我的Makefile:

#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
这是
加载程序.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:
我的开发环境是安装了virtualbox的Linux Mint 18.1 64位。我的代码几乎与该系列教程中的代码匹配,但我仍然无法在虚拟机中启动

编辑


我试过使用
qemu-system-i386-kernel mykernel.bin
,它可以很好地处理一条消息
Hello World
。这意味着VirtualBox环境和配置存在一些问题。

我没有这个答案的官方来源。这实际上是基于我在Stackoverflow上看到的经验和其他问题以及我的一些发现

如果在BSS段中创建大型内核引导堆栈,则会导致GRUB在某些环境中崩溃,而不是在其他环境中崩溃。这通常发生在BSS段的总大小似乎达到2mb左右时。Virtualbox似乎是出现问题的一个特例。Virtualbox中的问题似乎因所使用的版本和虚拟硬件配置而异

<>你在你的代码>加载程序.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:

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

sudo apt-get install grub-pc-bin

另外,我不必更改BSS段的大小。

在虚拟机引导期间,您是否点击F12并告诉它您准备从CD-ROM引导?我怀疑您的问题可能与堆栈有关。您创建了一个2mb的堆栈,它相当大。因为它位于BSS部分,所以多重引导加载程序会将其归零。某些环境中的问题是,如此大的BSS段可能会导致multboot加载程序在加载和处理内核时失败。如果堆栈是问题所在,请尝试将大小设置为2k(2048字节)而不是2mb。它有用吗?(即将其更改为:
.section.bss
.space 2*1024)您应该尝试使用
qemu
,看看您的内核是否正常。可能先检查二进制文件(.bin),然后再检查.iso。@rakibƅ:我尝试了
qemu-system-i386-kernel-mykernel.bin
,它可以在消息
Hello World
中正常工作。这意味着VirtualBox环境和配置存在一些问题。@MichaelPetch:我将堆栈大小减少到2KB,效果很好!!!所以,这里我们有一些很好的学习。你能不能把它作为一个答案和一些好的链接(如果你有),以进一步阅读。谢谢。我在一台机器上试用了2KB,它可以正常工作,而在另一台操作系统相同的机器上同样大小的崩溃(不过64 KB适用于这台机器)。可能是VirtualBox或其他东西的不同之处。请分享一些关于内核引导、BSS、堆栈等介绍的好教程(如果你知道的话)。我想了解更多。谢谢。@Inasecoder可能是你最好的选择
.section .bss
.space 64*1024 #64KB  for stack to grow towards left side
kernel_stack:
sudo apt-get install grub-pc-bin