A project describing my process of making (or failing to make) my own OS
I'll be changing each of these documents as I go to keep the most relevant/useful information. I'd like this to support me (and hopefully others) in being able to reproduce this project.
The main idea of this project is to make an operating system from scratch1, with no prebuilt classes or objects or anything like that, simply creating the binary files that'll run on a new empty machine. Of course, I'm not quite insane enough to work in plain binary (at least, not yet [foreshadowing]), but I don't want to use any tools/languages beyond x86 assembly to create this OS.
In the old files, I started my process by using a tutorial on the OSDev website. That tutorial, however, assumed the reader wanted to create an OS using C/C++ as their primary programming language, and included many steps specific to that.
Instead, I want to use only assembly (why?), which somehow manages to make the earliest steps of OS development a little easier.
Future me here! This is barely true. It very rapidly gets to be annoying for some required steps.
After learning OSDev didn't have the tutorial I wanted, I began researching what I needed to do to get an assembly bootloader working (since by the end of that tutorial I learned I would need one). The first useful page I came across was the WikiBook for x86 Assembly bootloaders, which contains a sample bootloader for an x86 OS. As this sample was designed for NASM, and I had already heard good things about it as an assembler, I chose it as the assembler for this project. I explain downloading and setting it up in setup.md. Similarly, I wanted to use an emulator for the start of this project (so I don't break any hardware). As mentioned by both OSDev and the WikiBook, QEMU was one of the best emulators to use (its setup is also described in setup.md).
Along with NASM and QEMU, I need some sort of editor for the code itself. I decided on VS Code, as it's easy to use and comes with tools that make the whole process much easier (most notably including GitHub committing features and different command lines). Another goal I have as part of this project, however, is to make my own assembly editor.
this may or may not be moved to a separate file later on
After getting my tools ready, I wanted to immediately get into running my own code. To get started, I decided to find out how to get the sample bootloader working. As the WikiBook stated, I need to first assemble the code into binary using NASM, and then test it using an emulator like QEMU. I found out how to get those running given my setup, which resulted in os.bat:
"C:\Program Files\nasm\nasm" -f bin boot.asm -o boot.bin
"C:\Program Files\qemu\qemu-system-i386" -drive file=boot.bin,index=0,format=raw -display gtk,zoom-to-fit=onSurprisingly, this was all it took to get a working bootloader. After executing os.bat, QEMU opened and displayed my OS, which according to the sample was filling the screen with copies of Hello, World! and looping at the screen's edges.
The more detailed process of my first rendering experiments is at experiments/first.md. There's a lot there, but here's the key takeaways I got:
- I made custom methods to write characters to a console-like layout
- I figured out how to convert byte data to characters to write on screen (ex: displaying
0xFFin text)- I also converted to decimal, so that I could read certain numbers better
- I got basic pixel rendering working using VGA
- I attempted to get VGE video modes working, but was stuck as it didn't work
- I found how to list VESA video modes and their options (more on them later)
- I thought I figured out how to use a video mode, but realized I actually needed protected mode
- This is further explained in the next section
If you were somehow following along as I was working on this project, you would realize that there was a long break between this commit and the previous (significant) ones. This is because I have struggled to figure out why my pixel rendering works very slowly, and only in QEMU (not in any other emulators).
It turns out that in order to reference memory required for 1920x1080 rendering, you need to be using protected mode, but QEMU somehow ignores this requirement sometimes (??? no idea what's actually going on really).
Footnotes
-
I guess it's not entirely from scratch if I use example code, but I've ended up replacing most of it in my experimentation/updates anyway. ↩