2

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.

Community
  • 1
  • 1
Naveen
  • 7,944
  • 12
  • 78
  • 165
  • During boot of the Virtual machine did you hit F12 and tell it you anted to boot from the CD-ROM? – Michael Petch Apr 12 '17 at 13:26
  • I suspect though your issue is probably related to the stack.You create a 2mb stack which is pretty big. Because it is in the BSS section the multiboot loader will zero it out. The problem in some environments is that such a large BSS segment can cause the multboot loader to fail while loading and processing your kernel. If the stack is the issue, try as an experiment setting the size to 2k (2048 bytes) rather than 2mb. Does it work? (ie change it to: `.section .bss` `.space 2*1024` ) – Michael Petch Apr 12 '17 at 13:49
  • You should try with `qemu` to see if your kernel is okay or not. Probably first check the binary (.bin) , then check the .iso. – rakib_ Apr 12 '17 at 14:04
  • @rakib_ : 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. – Naveen Apr 12 '17 at 16:18
  • @MichaelPetch : I reduced the stack size to 2KB and it worked !!! So, here we have some good learning. Can you please post it as an answer with some good links (if you have), to read further. Thanks. – Naveen Apr 12 '17 at 16:41
  • As suggested in the video comments I tried the `command sudo apt-get install grub-pc-bin` and it actually worked, even with 2MiB stack. Ubuntu 16.04 – eddie Jun 06 '17 at 05:32

2 Answers2

2

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.

0

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:
Michael Petch
  • 46,082
  • 8
  • 107
  • 198
  • I tried the 2KB on 1 machine and it works, whereas same size crashes on other machine with same OS (64 KB works for this one though). Could be difference of VirtualBox or other things. – Naveen Apr 13 '17 at 03:44
  • Can you please share some good tutorial (if you know) on introduction to kernel bootstrapping, BSS, stacks, etc. I want to explore more. Thanks. – Naveen Apr 13 '17 at 03:46
  • @InsaneCoder [OS Dev Wiki](http://wiki.osdev.org/Main_Page) is probably your best bet – Michael Petch Apr 13 '17 at 03:52