Build your own operating system-part01

By any standard of measure, an operating system is the most critical software installed on a computer. Not only does an operating system act as the administrator of many computer processes, but it also allows users to harness the power of the various sound, graphics and memory assets within the computer’s hardware infrastructure. For the vast majority of users today, a computer would be useless if it did not include some form of an operating system.

Popular technology culture has introduced most of us to one of the two major operating systems in use: macOS and the Windows operating system.

Although these systems function in uniquely different ways, the services they provide to users are relatively similar.

So, ever do you want to build an operating system? Lets try this out…..Developing an OS is no easy task. This article will help you to set up your development environment and booting a very small OS step by step.

01.TOOLS

#1 Quick setup

I use ubuntu as the operating system for doing this OS development. If your pc doesn’t run ubuntu bellow link will help you to set up an ubuntu virtual environment:https://www.youtube.com/watch?v=x5MhydijWmc&t=674s

Once Ubuntu is installed, either physical or virtual, the following packages should be installed using apt-get:

sudo apt-get install build-essential nasm genisoimage bochs bochs-sdl

#2 Programming Languages

The operating system will be developed using the C programming language, using GCC. The code will make use of one type attribute that is specific for GCC:

__attribute__((packed))

#3 Host Operating System

All the code examples assumes that the code is being compiled on a UNIX like operating system. All code examples have been successfully compiled using Ubuntu versions 11.04 and 11.10.

#4 Build System

Make has been used when constructing the Makefile examples.

#5 Virtual Machine

When developing an OS it is very convenient to be able to run your code in a virtual machine instead of on a physical computer, since starting your OS in a virtual machine is much faster than getting your OS onto a physical medium and then running it on a physical machine. Bochs is an emulator for the x86 (IA-32) platform which is well suited for OS development due to its debugging features.

02. BOOTING

Booting an operating system consists of transferring control along a chain of small programs, each one more “powerful” than the previous one, where the operating system is the last “program”. See the following figure for an example of the boot process:

#1 BIOS

Basic Input Output System (BIOS) stored on a read-only memory chip on the motherboard of the computer. The task of this program is to start the computer system after its power on. It will load some basic function instructions for hardware. And then it will transfer control to the bootloader.

#2 Bootloader

The bootloader’s task is to transfer control to us, the operating system developers, and our code. The bootloader is often split into two parts: the first part of the bootloader will transfer control to the second part, which finally gives control of the PC to the operating system. In this existing bootloader will be used: the GNU GRand Unified Bootloader (GRUB).The operating system can be constructed using GRUB as an ‘.ELF’ executable, which will be loaded into the correct memory location by GRUB.

#3 The Operating System

GRUB will transfer control to the operating system by jumping to a position in memory. Before the jump, GRUB will look for a magic number to ensure that it is actually jumping to an OS and not some random code. This magic number is part of the multiboot specification which GRUB adheres to. Once GRUB has made the jump, the OS has full control of the computer.

03. Hello world to OS development

This will describe how to implement of the smallest possible OS that can be used together with GRUB. The only thing the OS will do is write 0xCAFEBABE to the eax register

#1 Compiling the Operating System

Save the following code in a file called loader.s:

global loader                   ; the entry symbol for ELF

MAGIC_NUMBER equ 0x1BADB002 ; define the magic number constant
FLAGS equ 0x0 ; multiboot flags
CHECKSUM equ -MAGIC_NUMBER ; calculate the checksum
; (magic number + checksum + flags should equal 0)

section .text: ; start of the text (code) section
align 4 ; the code must be 4 byte aligned
dd MAGIC_NUMBER ; write the magic number to the machine code,
dd FLAGS ; the flags,
dd CHECKSUM ; and the checksum

loader: ; the loader label (defined as entry point in linker script)
mov eax, 0xCAFEBABE ; place the number 0xCAFEBABE in the register eax
.loop:
jmp .loop ; loop forever

This file can be compiled into a 32 bits ELF object file with the following command:

nasm -f elf32 loader.s

#2 Linking the Kernel

To load the kernel to the memory, we need the following linking script.

ENTRY(loader)                /* the name of the entry label */

SECTIONS {
. = 0x00100000; /* the code should be loaded at 1 MB */

.text ALIGN (0x1000) : /* align at 4 KB */
{
*(.text) /* all text sections from all files */
}

.rodata ALIGN (0x1000) : /* align at 4 KB */
{
*(.rodata*) /* all read-only data sections from all files */
}

.data ALIGN (0x1000) : /* align at 4 KB */
{
*(.data) /* all data sections from all files */
}

.bss ALIGN (0x1000) : /* align at 4 KB */
{
*(COMMON) /* all COMMON sections from all files */
*(.bss) /* all bss sections from all files */
}
}

Save the linker script into a file called link.ld. The executable can now be linked with the following command:

ld -T link.ld -melf_i386 loader.o -o kernel.elf

The final executable will be called kernel.elf.

#3 Obtaining GRUB

We use the the GRUB Legacy stage2_eltorito bootloader. The binary file can be downloaded from:

https://github.com/pasanlk/skyOS/raw/setup_booting_os/stage2_eltorito

Copy the file stage2_eltorito to the folder that already contains loader.s and link.ld.

#4 Building an ISO Image

The executable must be stored on a medium that a virtual or physical machine can read. For that, we will be using ISO image files in our project. So we create the kernel ISO image with the program genisoimage.A folder must first be created that contains the files that will be on the ISO image. The following commands create the folder and copy the files to their correct places:

mkdir -p iso/boot/grub              # create the folder structure
cp stage2_eltorito iso/boot/grub/ # copy the bootloader
cp kernel.elf iso/boot/ # copy the kernel

A configuration file menu.lst for GRUB must be created. This file tells GRUB where the kernel is located and configures some options:

default=0
timeout=0
title os
kernel /boot/kernel.elf

Place the file menu.lst in the folder iso/boot/grub/. The contents of the iso folder should now look like the following figure:

iso
|-- boot
|-- grub
| |-- menu.lst
| |-- stage2_eltorito
|-- kernel.elf

The ISO image can then be generated with the following command:

genisoimage -R                              \
-b boot/grub/stage2_eltorito \
-no-emul-boot \
-boot-load-size 4 \
-A os \
-input-charset utf8 \
-quiet \
-boot-info-table \
-o os.iso \
iso

For more information about the flags used in the command, see the manual for genisoimage.

The ISO image os.iso now contains the kernel executable, the GRUB bootloader and the configuration file.

#5 Running Bochs

Now we can run the OS in the Bochs emulator using the os.iso ISO image. Bochs needs a configuration file to start and an example of a simple configuration file is given below:

special note:sometimes you have to change display_library: sdl to display_library: sdl2

megs:            32
display_library: sdl
romimage: file=/usr/share/bochs/BIOS-bochs-latest
vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest
ata0-master: type=cdrom, path=os.iso, status=inserted
boot: cdrom
log: bochslog.txt
clock: sync=realtime, time0=local
cpu: count=1, ips=1000000

You might need to change the path to romimage and vgaromimage depending on how you installed Bochs. More information about the Bochs config file can be found at Boch’s website [23].

If you saved the configuration in a file named bochsrc.txt then you can run Bochs with the following command:

bochs -f bochsrc.txt -q

Bochs should now be running and presenting a console with some information on it. Quit Bochs and display the log generated by Bochs with the command below:

cat bochslog.txt

The contents of the registers of the CPU replicated by Bochs should now appear somewhere in the output. Your OS has successfully booted if you see RAX=00000000CAFEBABE or EAX=CAFEBABE in the output.

Reference: https://littleosbook.github.io/

Following is the Github repository for this process: pasanlk/skyOS at setup_booting_os (github.com)

software engineering undergraduate university of kelaniya