Writing your own Operating System

Writing your own Operating System

Image for post

Writing your own operating is the most tedious programming task. You have to build software from the scratch. That means no libraries, no memory management or any other high-level programming features. Before writing operating system you should know how operating systems kick start.

The process of starting the operating system kernel

Image for postStarting Process of Computer

The Main board has special program called BIOS. At the start of the computer BIOS program is loaded into the ram. Then the Instruction Pointer of the CPU is set to this BIOS program. BIOS program reads the hard drive and loads the boot loader into the ram and sets instruction pointer to ram. Then boot loader executes and it reads the kernel from hard drive and loads it into the RAM.

The boot loader doesn?t set the stack pointer. So an operating system written in C++ there should be a method to set the stack pointer and then call the main function of the C++ program. Hence the Kernel of the OS should contains two programs. One is loader written in Assembly this can set the stack pointers and load the operating system into memory. Then the operating system written in C++.

Image for postOperating System Kernel Development Steps

As the first step let?s create four files. As in the diagram it needs loader.s kernel.cpp and to link those to it needs linker.d file and to automate the process it needs a Makefile.

Image for post

Kernel.cpp

The starting point of the kernel is kernelMain. We have made it extern ?C? so that the compiler will not change the name of the function. So we can call it from the assembly file using the exact same name.

In the our operating system we still can?t use the C++ libraries. So there is no printf function we can use. We have to implement the printf function by ourselves. The logic behind the printf function is that the monitor will print anything that is inserted into 0xb8000 memory location. So we just have to insert the text into that memory location.

void printf(char* str){ static unsigned short* VideoMemory=(unsigned short*)0xb8000; for(int i=0; str[i]!=”;++i){ VideoMemory[i]=(VideoMemory[i] & 0xFF00)|str[i]; } }extern “C” void kernelMain(void* multiboot_structure, uint32_t magicnumber){ printf(“Hello World”); while(1);}

loader.s

This is the basic code for the loader assembly file. kernelMain is the starting point of our kernel. This code will set the stack pointer and will call the kernelMain function in our cpp file.

.section .text.extern kernelMain.global loaderloader: mov $kernel_stack, %esp //setting the stack pointer call kernelMain //calling the kernelMain_stop: //extra precaution to keep running cli hlt jmp _stop.section .bss kernel_stack:

The above code has several major issues.

1. When kernel_stack is filled, it is filled from right hand side to left hand side. So it will replace some important content in kernelMain. To avoid that we should keep some space in the memory in between kernelMain and kernel stack.

.space 2*1024*1024;

This is used to add some space.

2. Boot loader will not identify this file as a kernel if we don?t set a special mark to say that it is a kernel. So we have to put a magic number in the kernel file and that is 0x1badb002.

.set MAGIC, 0x1badb002.set FLAGS, (1<<0 | 1<<1).set CHECKSUM, -(MAGIC + FLAGS).section .multiboot // setting our magic number .long MAGIC .long FLAGS .long CHECKSUM.section .text.extern kernelMain.extern callConstructors.global loaderloader: mov $kernel_stack, %esp call callConstructors push %eax push %ebx call kernelMain_stop: cli hlt jmp _stop.section .bss .space 2*1024*1024;kernel_stack:

Linker file

The linker file will combine the above two files into a one.

ENTRY(loader)OUTPUT_FORMAT(elf32-i386)OUTPUT_ARCH(i386:i386)SECTIONS{ . = 0x0100000; .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) }}

The Makefile should be as follows

You should include the Makefile to give instructions to compile the Assembly files cpp files and then to link them.

The Makefile contains instructions to create an iso file and then run it in the VirtualBox.

You can find the full source code from this link.

chamathabeysinghe/MyOS

Contribute to MyOS development by creating an account on GitHub.

github.com

Run appropriate make command to execute instructions. (If you have installed VirtualBox use make run command to run os in VirtualBox)

23