InsaneCoder
InsaneCoder

Reputation: 8288

Unable to boot a custom kernel in VirtualBox : "could not read from boot medium"

I followed the tutorial series on Write your own operating system in 1 hour to create a basic OS to print just "Hello World" with just 4 files : Makefile, kernel.cpp, loader.s and linker.ld.

I am creating a mykernel.iso file but when I boot it into VirtualBox, I get the error "Could not read from boot medium : System halted". I confirmed that the .iso file is linked with my machine instance. Looks like there is some other problem in the code perhaps.

Here is my 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

Here is the 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);
}

Here is the 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:

Here is the linker.ld :

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

My development environment is Linux Mint 18.1 64-bit with virtualbox installed. My code almost matches the code of the tutor in the series, still I am not able to boot in the virtual machine.

EDIT

I tried with qemu-system-i386 -kernel mykernel.bin and it works fine with a message Hello World.That means there is some problem with VirtualBox environment and configurations.

Upvotes: 2

Views: 1202

Answers (2)

Kashif Minhaj
Kashif Minhaj

Reputation: 83

I ran into the same problem. Just installing grub-pc-bin and recompiling the kernel made it boot successfully on virtual box.

sudo apt-get install grub-pc-bin

Also, I didn't have to change the BSS segment size.

Upvotes: 2

Michael Petch
Michael Petch

Reputation: 47613

I have no official source for this answer. It is actually based on experience and other questions I have seen on Stackoverflow and some findings I have made.

It appears if you create large kernel bootstrap stacks in the BSS segment it causes GRUB to crash in some environments and not others. This often happens when the total size of the BSS segment seems to reach about 2mb. Virtualbox seems to be a particular case where the issue seems to arise. Issues in Virtualbox seems to vary depending on the version and the virtual hardware configuration being used.

The stack you create in your loader.s to bootstrap your C++ environment doesn't need to be all that big. Once you get your memory management and allocators in place you can reserve area for a larger kernel stack and set SS:ESP to it at that time.

To that end you should consider changing:

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

To something 1mb or smaller. I'd probably go with something like 64kb:

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

Upvotes: 0

Related Questions