I've been working off and on for the past 13 months on a hobby operating system. I put some of the initial code up on
github but I haven't updated that repo in a long time. I've made a lot
of progress, but haven't gotten anything to a state where I dare share it.
The bootloader portion is what gave me the most grief by far. There are not exactly a lot of resources concerning producing one's own bootloader. Most would consider it ancillary to OS development and easily avoided by use of an open source offering. I chose to write my own, since I was interested in all aspects of hobby OS development, not just the kernel.
Anyways, the bootloader was quite a pain to get going (I say going since I'm sure it will need tweaking) and I wanted to write some thoughts and things I learned during the process of writing my own bootloader for my operating system.
I decided early on to only support modern hardware. This means x86 64 bit support only on IBM/PC clones. The implementation of the bootloader relies heavily on the attributes of the platform, and on decisions made by designers several decades ago. For example consider one of the simplest bootloaders possible
This code simply identifies itself as a bootsector, and does nothing (its an infinite loop). The hex signature 0xAA55 at the end of the 512 byte sector is key. Why? Its a legacy requirement; the BIOS POST sequence expects to find this signature in the boot sector. Evidently some modern BIOSes have shed this requirement, but not all have, so its certainly not a bad idea to include it. Once the BIOS finds the boot sector, it loads the sector into a well known address, usually 0x0000:0x7C00, although some will load to 0x07C0:0x0000 which resolves to the same address physical memory address. Its good practice to enforce the segment address with an ORG statement like so:
Once the boot sector is copied to RAM, a lot of work is still needed to actually boot the operating system. Since my goal is a 64 bit OS, this means I need to enable long mode (or 64 bit mode). To do so, some setup needs to take place:
The bootloader portion is what gave me the most grief by far. There are not exactly a lot of resources concerning producing one's own bootloader. Most would consider it ancillary to OS development and easily avoided by use of an open source offering. I chose to write my own, since I was interested in all aspects of hobby OS development, not just the kernel.
Anyways, the bootloader was quite a pain to get going (I say going since I'm sure it will need tweaking) and I wanted to write some thoughts and things I learned during the process of writing my own bootloader for my operating system.
I decided early on to only support modern hardware. This means x86 64 bit support only on IBM/PC clones. The implementation of the bootloader relies heavily on the attributes of the platform, and on decisions made by designers several decades ago. For example consider one of the simplest bootloaders possible
BITS 16
jmp $
TIMES 510-($-$$) DB 0
DW 0xAA55
This code simply identifies itself as a bootsector, and does nothing (its an infinite loop). The hex signature 0xAA55 at the end of the 512 byte sector is key. Why? Its a legacy requirement; the BIOS POST sequence expects to find this signature in the boot sector. Evidently some modern BIOSes have shed this requirement, but not all have, so its certainly not a bad idea to include it. Once the BIOS finds the boot sector, it loads the sector into a well known address, usually 0x0000:0x7C00, although some will load to 0x07C0:0x0000 which resolves to the same address physical memory address. Its good practice to enforce the segment address with an ORG statement like so:
BITS 16
ORG 0x0000
jmp $
TIMES 510-($-$$) DB 0
DW 0xAA55
Once the boot sector is copied to RAM, a lot of work is still needed to actually boot the operating system. Since my goal is a 64 bit OS, this means I need to enable long mode (or 64 bit mode). To do so, some setup needs to take place:
- Load the kernel to a well known address in memory
- Setup a page table
- Setup the interrupt descriptor table (IDT)
- Setup the global descriptor table (GDT)
- Enable long mode
- Jump to the kernel
OS Dev
Bootloader
Assembly