Wondering what the best practice is regarding loading a kernel.
I figure I'll eventually have to write a protected mode disk-reading driver at some point, so I might as well get it out of the way now. Is this a headache that I don't need to endure right now? Am I better off loading my whole kernel in a20 enabled real mode and then copying it in place once I'm in protected mode?
Loading Kernel from real mode or protected mode
-
Octocontrabass
- Member

- Posts: 6248
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Loading Kernel from real mode or protected mode
Best practice is to use an existing bootloader. Existing bootloaders have already been debugged, and you can get UEFI support for free.
But if you're going to write your own bootloader, best practice is to rely on the firmware to read the disk.
You'd need more than one driver, since the firmware knows how to boot from more than one type of disk. And you wouldn't want to reuse those drivers for your kernel, since good drivers tend to rely on kernel APIs that are difficult to implement in a bootloader, so you either end up completely rewriting those drivers for your kernel and maintaining two sets of drivers, or you end up turning your bootloader into an entire OS by itself (which will then need its own bootloader).
The BIOS has INT 0x15 AH=0x87 for copying stuff above 1MB in real mode.
Re: Loading Kernel from real mode or protected mode
As always, Octocontrabass has some good points.
One thing to remember, the legacy firmware has only read a single 512-byte sector into memory. Without using this legacy firmware, there is no other way to load additional sectors without writing some kind of driver. Therefore, your driver would have to be written in less than 512 bytes, almost impossible to do, and extremely impossible to do correctly.
The UEFI firmware has the ability to read from (FAT) volumes, as opposed to sectors only, like the Legacy firmware does.
Some may disagree, but I believe, as a hobby builder, you should write your own bootloader code, for the learning experience. You learn very little using an existing loader. However, as stated, using an existing loader gets you to the kernel development from the start.
Ben
- https://www.fysnet.net/osdesign_book_series.htm
One thing to remember, the legacy firmware has only read a single 512-byte sector into memory. Without using this legacy firmware, there is no other way to load additional sectors without writing some kind of driver. Therefore, your driver would have to be written in less than 512 bytes, almost impossible to do, and extremely impossible to do correctly.
The UEFI firmware has the ability to read from (FAT) volumes, as opposed to sectors only, like the Legacy firmware does.
Some may disagree, but I believe, as a hobby builder, you should write your own bootloader code, for the learning experience. You learn very little using an existing loader. However, as stated, using an existing loader gets you to the kernel development from the start.
Ben
- https://www.fysnet.net/osdesign_book_series.htm
Re: Loading Kernel from real mode or protected mode
I just used the first sector to write BPB headers and read stage 2 off reserved sectors, no driver. Stage 2 is where I'm planning to enter protected mode and read the kernel as that has a 31 sector limit, which should be enough to get me up and running at least.
Also I am writing my own bootloader as this is a hobby project originally as a way of teaching myself x86 assembly, using GRUB or something would skip all that.
For now I'm just targeting legacy BIOS i386.
Re: Loading Kernel from real mode or protected mode
Without sounding like I am discouraging you from doing that, here are two advantages to do it slightly different.bbqribs wrote: ↑Mon Sep 15, 2025 11:23 am I just used the first sector to write BPB headers and read stage 2 off reserved sectors, no driver. Stage 2 is where I'm planning to enter protected mode and read the kernel as that has a 31 sector limit, which should be enough to get me up and running at least.
First, since you state you will have a BPB, you are using FAT, correct? There are some systems (though very few today) that assume the reserved area of a FAT volume is a single sector. Not much a big deal today, but was in the past.
Second, I suggest that you create your 2nd stage loader as a file in the root directory. If you can assume the root directory and the file name, with a little bit of effort, you can write a FAT loader within the almost 475 bytes remaining in the first sector of the volume that will find and load the file. This gives the advantage that when you update the code, you can simply write to the media as a file. No need to write as sectors, and you don't have the 31-sector limit you mention.
To contradict my first comment, I did this in three sectors, but by doing so, I had plenty of space for error handling, checked for a 32-bit machine, checked for BIOS Extended Disk services, allowed fragmented files, as well as the code first looked for the loader file in the root directory. If not found, it tried the \BOOT directory, and finally if not found, it tried the \SYSTEM\BOOT directory. Not really a big deal since your first stage loader should know where your second stage loader is, right? But as an example, it shows that it can be done within the first few sectors of the volume and in assembly.
I won't point you to that code, because it would be too easy to "steal" it, not saying that you would, but it is quite easy to copy, paste, and modify to fit your needs, am I wrong? :-)
There is another advantage to this technique. If your compiler is capable of making a (somewhat) flat executable, the second stage can be written in a higher-level language. Even a simple DOS .EXE file can be easily loaded and "jumped to".
Ben
- bellezzasolo
- Member

- Posts: 163
- Joined: Sun Feb 20, 2011 2:01 pm
Re: Loading Kernel from real mode or protected mode
BenLunt wrote: ↑Mon Sep 15, 2025 11:04 am As always, Octocontrabass has some good points.
One thing to remember, the legacy firmware has only read a single 512-byte sector into memory. Without using this legacy firmware, there is no other way to load additional sectors without writing some kind of driver. Therefore, your driver would have to be written in less than 512 bytes, almost impossible to do, and extremely impossible to do correctly.
The UEFI firmware has the ability to read from (FAT) volumes, as opposed to sectors only, like the Legacy firmware does.
Some may disagree, but I believe, as a hobby builder, you should write your own bootloader code, for the learning experience. You learn very little using an existing loader. However, as stated, using an existing loader gets you to the kernel development from the start.
Ben
- https://www.fysnet.net/osdesign_book_series.htm
My most recent iteration I just went straight to UEFI, but I still had an OS Loader component... The primary thing it did was load the kernel to the intended high addresses (UEFI loads low), load the configuration file, set video mode, and dynamically link some kernel modules in. The config file could specify boot drivers to include in this.
Whoever said you can't do OS development on Windows?
https://github.com/ChaiSoft/ChaiOS
https://github.com/ChaiSoft/ChaiOS
Re: Loading Kernel from real mode or protected mode
UEFI is almost always 64-bit, and so will transfer control in long mode. If your OS is 64-bit, this would be fine, but for a protected mode OS, you will need an additional layer that switches the processor to protected mode. For BIOS, you always know the processor is in real-mode, so the initialization is always the same.
Re: Loading Kernel from real mode or protected mode
I do something very similar, one difference being that I don't load into high memory. The way I manage memory, there is no need. I have three "segments" of memory. One is below 1Meg, just in case. One is below 16Meg for legacy hardware, and then the last is the remaining up to 32-gig, whether the memory is physically present or not. Except for those three exceptions, nothing relies on where it is in memory.bellezzasolo wrote: ↑Tue Sep 16, 2025 9:56 amMy most recent iteration I just went straight to UEFI, but I still had an OS Loader component... The primary thing it did was load the kernel to the intended high addresses (UEFI loads low), load the configuration file, set video mode, and dynamically link some kernel modules in. The config file could specify boot drivers to include in this.
When it comes to real hardware, I agree that it will almost always be 64-bit. However, with emulators, it can be either 64- or 32-bit. Therefore, my code requires 64-bit UEFI, but I have written a small stub for 32-bit UEFI which states a 64-bit system is required, then draws and allows the user to play increasingly challenging levels of Tetris. Very similar to what I did in case a Legacy BIOS is used.