Journey to the Core of the Computer!

Alright, it’s been quite a while! With the ‘completion’ of a basic bare-metal programming model, this blog describes my journey in Operating Systems development, from a simple bare-metal program to an almost cross-hosted operating system, all built from scratch! Along the way, I got a glimpse of why operating systems work and why developing an operating system in one of the toughest tasks there is. Working with something so low-level is exciting and enriching. Via this blog, I want to share my journey with the readers and discuss the ups and downs related to such low-level development, and hopefully spur the reader to take an interest in this field. 😄

Getting Started

Here begins our adventure! Where we construct this low-level software from scratch, learning and exploring hardware architecture and organization as we proceed.

My journey!

The Bootloader

However, being a rebel, I decided to make my very own tiny bootloader for KSOS: a lot of assembly language, a lot of work, and a lot of pain. However, it was one of the most rewarding experiences of this project, as I could clearly see and appreciate the effect of every bit of instruction (pun intended 😛) in software. Dr. Nick Blundell’s book helped a lot in making my bootloader.

The bootloader is a pretty sweet one! It’s written purely in x86 assembly and has some really nice features, like a mini parser for a FAT filesystem. The bootloader parses the filesystem to read the kernel from the disk and load it into memory. Although making the FAT filesystem parser was one of the most challenging tasks, in the end, it was all worth it. 😃

However, moving forward, I would like to port over to something ready-made like GRUB: it’s well documented, portable, and very reliable. It’s such a beast that it gives operating systems a run for their money!

Okay, maybe a lot more than 4 times.

The Kernel

To have an understanding of this linking process and C-assembly mixture, I had to spend quite a lot of time analyzing the generated binaries and how they transformed on linking. This was one of the biggest struggles of the project, and to be frank, it’s not that easy to look at binary code without wanting to kill yourself every five minutes. 😭

Testing out this tiny ‘kernel’ was simple. I wrote a few simple routines for writing to the screen (printf-ish C routines). You read it right; I made my own printf statement! I could write messages on the screen, change the colors to something fancy, and a lot of other cool stuff.

Soon, I wrote specialized modules for necessary memory management, interrupt handling, and fundamental device drivers, about which I’ll get back to later!

Build System

In a project like OS development, where one builds everything from scratch, they must maintain a clean codebase with an efficient build system, i.e., some automated way to compile, assemble, link, install, etc. all of their modules. Moreover, this isn’t like application/web development with ‘pretty’ IDEs and extreme framework support. We ARE the framework! One needs to put careful thought and action regarding the management of this build system, since messing up here is very costly!

Therefore, a significant amount of my time was spent in structuring and restructuring my codebase and build system, from simple shell scripts to complicated makefiles for the operating system. Right now, the build system uses a combination of makefiles and a shell script for efficiency and is heavily inspired by the Meaty Skeleton Page on OSDev wiki.

Perhaps something to further explore in the future would be some other third-party open-source build systems like CMake, Autoconf, etc., and to port them to our project.

Kernel Modules

Memory Management

The target was simple. The kernel has complete control over the memory. If you want to access memory, ask the kernel. If you ask politely enough, you’ll get a chunk. See, simple!

Thus, I made a simple physical memory manager (page frame allocator) followed by a virtual memory manager, which provided essential functions for memory allocation, deallocation, and remapping.

This phase wasn’t without its struggles! When I say dealing with memory, it kind of means tracking every addressable byte in memory in software. A little slip up somewhere meant that I had to spend hours debugging the kernel to find the culprit. I had to control the linking process even more intimately. In case you don’t believe the struggles, there was a bug that ended up treating code as data and ended up modifying the semantics of the kernel itself! You wouldn’t want your program behaving unexpectedly because it modifies itself when it runs, would you?

Higher Half Kernel Map

Following this, I initialized the kernel properly and used the virtual memory manager to map it to the virtual address 0xC000000. This is pretty standard, and many modern operating systems do this “higher half” kernel map. A higher half kernel is used for consistent interrupt handling when multitasking in user — mode. With this mapping implemented, multi-tasking is now a possibility, and something which we plan on adding for the next version of KSOS!

Interrupt Handling

I had to spend quite a lot of time reading the actual Intel manuals to understand how interrupts worked on the x86 architecture. Implementation of good interrupt routines requires a sound understanding of assembly programming too — doesn’t everything? 😉

Moreover, reading the ~5000-page Intel Manual is HARD and requires experience! Fret not, if you properly spend time reading and researching about such low-level development, you will eventually understand the relevant texts you need from the manual.

Keyboard Driver

This keyboard driver was quite simple! All that was needed to be done was ‘translation’ of information about key presses and releases sent by the keyboard into whatever form we wanted. For example, if the keyboard sends a code that says ‘letter A pressed’, we interpret that the user wants to type the letter ‘A’ and output the ASCII code for ‘A’.

Kernel-Level Shell

Conclusion

You can run and test KSOS via this repository. There’s still a lot of work left to do, especially in areas of process management (multitasking!) and allowing users to write their very own code modules. Do feel free to contribute! We’ll also be releasing blogs highlighting the various core aspects of KSOS in the coming weeks, so stay tuned for more!

Until next time!
Suraaj

--

--

We are a bunch of enthusiastic students who aim at uniting the computing fraternity at IIT Roorkee under one tag.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
ACM Roorkee

We are a bunch of enthusiastic students who aim at uniting the computing fraternity at IIT Roorkee under one tag.