You might think I’m crazy, but I’m into this thing “Write your own OS”. I have some commercial ideas on how and why, but I’m willing to share my knowledge of what I’ve found so far. This is the first one in the series, as I’m currently researching stuff and wanted to write them down for others like me.
For starters, it’s more about running your own code directly on CPU, once the PC is turned on, without any underlying OS, than writing OS itself. But the grand master plan still remains – to create my own OS.
As for every project, we need a plan on what we’re trying to achieve. My plan is:
- Target modern architecture – I’m going to target Intel64 (I’ve my eye on Ivy Bridge, 3rd gen Core i5 CPU with integrated Intel HD 4000 GPU and B75 Express chipset);
- Avoid legacy, drop it as fast as you can. You can even skip the Protected mode and jump directly to Long mode;
- Jump to C as soon as possible – I’m afraid of Assembly language
- Forget old interfaces like PCI, IDE, PS/2, Serial/Parallel ports. Why does every tutorial still use such an ancient device as Floppy? And even if my plan comes together – forget Basic Input Output System (BIOS), long live Unified Extensible Firmware Interface (UEFI). For now i’m targeting only modern interfaces – PCIe, SATA, USB;
- Avoid the use of GRUB or any other multiboot bootloader – make my own and allow only my own OS on the system – yeah that’s ego centric decision, but I’m going to use CPU for my self and this blog is all about getting from power button directly to my C code executed as the only code on the CPU.
Further plans for my OS – these considerations will not be covered here, but I’m writing them down, just to show you some crazy ideas of mine:
- Use C, C++ and some popular scripting language (Currently I have my eyes on Python or interpreted C). C for kernel and core routines, C++ for GUI and other stuff that’s easier to use with object-oriented abstraction. Scripting language for user space, so that you could write apps easier, without compilation, with deep integration in to OS;
- URI based system with schema drivers. For example file://localhost/my_documents/ or just /my_documents/ in the file browser;
- No Unix directory tree. I hate it – it does not say anything to a user – when I first started using Linux I didn’t know that /etc is to store configuration files, and I still don’t understand the meaning and differences between /bin, /usr/bin and /usr/local/bin. It should be clear:
- /applications – here we’ll install user space applications
- /configuration – here we’ll save all the user space configuration files
- /documents – here we’ll save all the user’s documents
- /system – this is the system directory – this directory is not accessible by anyone else than drivers and kernel
- /system/configuration – here we’ll save all the system configuration
- /system/devices – this is the directory where you can get access to some devices
- No POSIX - as I have some ideas of my own on how to create APIs. POSIX could be an abstraction layer over my APIs for sake of compliance. For example no stdlib or stdio by default. Instead of malloc() – i’d prefer something called void *memory_allocate(size_t size, permission_t perm) with some specific permissions (like weather this memory block can be shared across threads or processes) and instead of fopen() i’d prefer handle_t *file_open(char *uri, mode_t mode) where mode is not a character, but some kind of a structure. It’s more about the taste of the API naming;
- Last but not least – GUI from the start. Tell BIOS to display a cute logo and try to avoid any flickering – so that logo is faded out only when kernel has readied it’s video processing drivers. (I know that you can read from video memory as well as you can write). Yeah – Apple style!
What I’ve found out so far:
- Boot sequence:
- Master Boot Record (MBR);
- Bootloader – the program that takes it over from MBR and loads your Kernel;
- How to write your own MBR and write it to Disk on windows. I’ve written a small utility in Visual C++ that allows directly to read/write from disk (download here, source included for Visual Studio 2010 Express);
- How to write bare bones C kernel entry point.
- How to write “naked” functions on Windows in Visual Studio
Missing link - I still don’t know how to properly step from MBR to Bootloader to Kerlen, that is – write your own MBR code that would load bootloader, pass the execution to bootloader that would load and pass execution to bare bones C kernel:
- What exactly is Global Descriptor Table (GDT) and Interrupt Descriptor Table (IDT), and how it looks in C and Assembly?
- How and when, and again how, if when is later (for example in Long Mode or Protected Mode) to set up all this GDT and IDT stuff. They say you have to set it up before the kernel. Then they say you can set it up with dummy values and set it up later in kernel. Then they say, that to set it up, you have to be in Real Mode, so your kernel (which might be way over 1Mb of real mode space), needs to switch between modes. And then if your kernel is over 1Mb, you can’t access memory locations after 1Mb, and so on… It’s confusing, but I’m going to find it out and post it here later on.
- How to handle Interrupts in C? Will they perform as callbacks that await some return values or do I have to use inline assembly to process them correctly;
- Is it possible to write MBR in C? I do understand that you still have to set ORG to 7c00h, and use some specific assembly instructions, but if they could be wrapped in C using inline assembly and C entry point can be glued with few lines of assembly code, why not?
Usefull tools and must read
Here is the list of tools I’m going to use:
- Visual C++ 2010 Express Edition - I’m using Windows XP, so there’s no VS2012 Express for me
- Netwide Assembler
- Bochs – x86 emulator, so that you don’t have to write to disk, connect it , boot up, see error, shut down, rewrite your kernel, write to disk … (you got it)
- Cygwin – just in case you need some great Unix tools on Windows
- Definitely OSDev Wiki – it has some great tutorials and hacks, although the attitude all over there is “wannabe rough-and-tough”. Then again these people there are coping with some kind of madness after what they’ve gone through
- I’m currently reading this tutorial from JamesM – it’s marked as “Hard. Good luck”, but it explained some things to me quite well.
Huston we have a problem.
On the side note - It’s 21st century, but our PCs are still booting up as old-fart Intel 8086. It’s been 33 years, but our computers are still booting up like it’s 1979. Why the heck Intel, why? Actually I have a suggestion for transition phase – just add a jumper to the motherboard and create some kind of Super Mode (just like Real Mode, but with full 64-bit memory and instruction support). When the jumper is connected we have the old Real Mode, but once all the OSes are ready to do some modern booting, disconnect the jumper and run Super Mode instead. This way, modern OS boot-loader can easily work with all the resources on the computer, and not some A20 gates and jumps from Real Mode to Protected Mode. And then there’s BIOS and 512 byte MBR. I know that 512 bytes is enough to look up a partition on the disk and load some boot-loader code. And then there’s x86 memory layout with some holes, so you can’t just read up some 900Kb from disk directly into memory without crashing.
Anyhow that’s the world we’re living in, we have to cope with it and we have to do a lot of tricks to create our OS as modern as possible.