abstractmath wrote:Also, how can I roll my own bootloader code within the MBR? Any clarification on these questions would be much appreciated, thanks!
If I may, I would like to expand on the answers that have been given.
The BIOS has absolutely no idea, nor does it care what the first sector of the disk is, other than if the sector has the correct Signature at offset 510. Some BIOSes also check the first few bytes of the sector for valid code, but this is not standard.
With this in mind, the first sector on the disk can be anything you want, though most of the time, for Legacy Boot machines, this is a MBR.
The purpose of the MBR is simply to:
1) move out of the way
2) find a valid partition entry
3) load the first sector of the found partition
4) jump to it
The code must inspect the four entries within its already loaded data (offset 0x1BE of this sector), as well as account for extended partitions. There never was a standard specification stating exactly how an extended partitioned drive was to be formatted. For example, most took the idea that you could have one valid partition entry and one valid extended partition entry per partition table. However, this was/is not set in stone (as far as I remember). Most commercial OSes of that time did it this way.
However, this doesn't mean that you can't have three valid partition entries, each pointing to a partition (within the range limit of course) and then have a single extended partition entry, pointing to a table of four more entries. Doing something like this should be perfectly valid, however not the normal way of doing it.
Your MBR code should gracefully bow out if it didn't find a valid/bootable partition entry as well as display disk read errors, if any.
It is common for the MBR to only occupy one 512-byte sector, and nothing more. With 512 bytes, minus (16 * 4) + 2 bytes, you have enough space to do almost anything you would need to in a MBR.
I have a (somewhat older) version of my MBR code at
https://github.com/fysnet/FYSOS/blob/ma ... sc/mbr.asm that is able to use CHS addressing or LBA addressing, depending on the build flags. It uses a stack of 512-byte blocks to parse the extended partition table(s), allowing for multiple nested partition entries (up to 65536 bytes of stack space).
Once you have a working MBR, and it can load the first sector of your partition, usually called a Partition Boot Record (PBR), you now need a valid PBR.
The PBR is specific to the file system it resides on. However, it needs a few notes:
1) The PBR needs some way to know where is resides--the base LBA of this partition. This is usually done with a BPB, like in the FAT file systems, for example.
2) It may need to load extra sectors since the 512 bytes your MBR loaded may not be enough. One huge mistake some newbies have made is to put their "read_from_disk" code in the sectors yet to be read. Your "read_from_disk" code *must* reside within the first 512 bytes, including any data it might need to do so.
3) This PBR will usually parse the file system to find a loader file. This may have a few requirements, such as the loader file must be in the root directory. However, if you feel ambitious enough, you can write your PBR to search sub directories as well.
It is not necessary, but just a few thoughts.
1) The MBR (obviously) must be written in assembly.
2) the PBR (obviously) must be written in assembly.
3) however, the loader does not. My loader is 90% ANSI C.
Since my loader is in ANSI C, it is much easier to maintain. My loader also is written for all of the file systems I support. I then simply give it a build flag to only include the specific file system I need. This way, the loader does the same thing for all file systems.
My loader searches in the Root directory ('\'), the '\BOOT' sub-directory, and then finally, the '\SYSTEM\BOOT' sub-directory for the kernel file(s) and other files needed.
Each of these kernel file(s) have a header at the beginning of the file telling the loader any information about the file.
1) is it the kernel file? (if so, where to jump to after loaded)
2) where to load into memory.
3) is this a mandatory file (i.e.: if not a valid file/didn't read all of file, can we continue?)
4) compression type. (i.e.: these files can be compressed to save disk space)
This way the loader file only has to have a list of filenames to load. Nothing more. The loader file doesn't care about things like kernels, drivers, etc. It only cares about what the header of these files, tell it.
You don't have to build you project like this, but this is just a way you might think about it.
Remember, maintainability is/will be a key factor when your project gets more advanced. Right now, simplicity is the key. However, when your project gets to be hundreds of files, if not thousands, maintainability will be a must.
Hope this helps,
Ben
-
http://www.fysnet.net/osdesign_book_series.htm