Hii,
Antti wrote:For me, this version ("MBR understands GPT") sounds the most sensible one that
I should implement and intuition backs this up. If I tried to implement the goals listed above, it would guarantee that I ended up having nothing. Besides, it would not be "my style" to excercise so much policy on this partition scheme. Perhaps this is one of the many reasons I should just follow the industry standard (that exists) and cause as little controversy as possible. And still support all the "four" scenarios.
OK, let's estimate code size.
The first thing MBR should do is some basic setup (set segment registers, set a sane stack, etc). Let's call that 10 bytes.
The next thing MBR should do is check if there's a video card, and if there is make sure the video mode is text mode to ensure that any error messages are displayed correctly. The simplest way to do this is to always set the video mode, but that's ugly (leads to "excessive screen flashing" during boot when too many things set a new video mode). Instead I use code to check if there's a video card; then check the current video mode, and then set the mode if and only if it wasn't already in text mode. I also disable the cursor (it should only be visible when software is waiting for user input) and make sure the video mode is using "16 background colours" and not "8 background colours with blinking". The other thing I do is get "display page number" (because you have to know what that is to be able to print text properly). Some of these things can be skipped (more if you're happy with poor quality code); but for now let's allow about 50 bytes for video setup.
The next thing you'll need to do is try to figure out the relationship between "BIOS LBA that uses 512-byte sectors" and "GPT LBA that may not use 512-byte sectors". I think this ends up being a crude brute force search. Basically, assume that GPT uses 512-byte sectors and try to find the GPT header at "BIOS LBA 1", and if it's not there assume GPT uses 1024-byte sectors (such that "GPT LBA 1 = 1024/512 = BIOS LBA 2") and try to find the GPT header at "BIOS LBA 2", and keep doing that (doubling the "BIOS LBA" for each attempt) until you hit some maximum (maybe "max. of 65536-byte sectors for GPT" would be enough future proofing). Alternatively you could do something smarter (e.g. start with 512-byte sectors then try 4096-byte sectors to get the most likely cases out of the way early; then fall back to brute force search for unlikely cases). Anyway, let's allow about 70 bytes for this.
You'll also want some code to check a potential GPT header (is the "EFI PART" signature correct, is the header size sane, is the CRC32 correct, etc). I'd probably want to use several hundred bytes for this alone (to check everything as thoroughly as possible), but for now let's allow about 100 bytes.
Of course you'll also want some "disk IO" code - detect if "int 0x13 extensions" exists, do CHS->LBA conversion, do "GPT LBA -> BIOS LBA" conversion, handle retries, handle errors, etc. I very much like having good error messages (e.g. so the user can tell the difference between "programmer mistake" and "media removed" and "faulty device"), but maybe acceptable code is asking too much given the space limitations. Let's maybe allow another 80 bytes for this anyway.
Next; I'd want to check if the GPT header (at "GPT LBA 1") matches the backup GPT header (at "backup LBA"). This would help to make sure that the "GPT LBA -> BIOS LBA" conversion is being done right, would detect header corruption, and would be the beginning of basic fault tolerance (e.g. use the backup if something is wrong with the original). Let's allow another 50 bytes for this.
At this point we've gone through about 360 bytes of code, and we haven't looked at any piece of (any copy of) the partition table itself yet. Let's skip ahead...
After we find whatever we're trying to load (the boot manager's second stage?) using whatever method we use to find it (if it's in UEFI system partition or if it's in its own partition); the MBR should load it and then update TPM before executing anything. This probably costs about 40 bytes (including a "jmp whatever_got_loaded" to complete the MBR's responsibilities).
That means (likely with error messages that are worse than I'd consider acceptable, GPT header checking that's worse than I'd consider acceptable, etc) we've consumed about 400 bytes out of the 440 bytes of space available; and all of the GPT partition table loading, checking, and parsing/searching (including "fall back to backup GPT if necessary") needs to fit 40 bytes. If you're going to search for a partition with the right GUID (which is what I'd probably want to do - e.g. have a "boot manager partition" with a specific GUID that no OS uses), then you'll have to store a copy of the GUID you're looking for somewhere, and that will cost 16 of those 40 bytes all by itself.
At this point, it's just a question of how poor the quality needs to be to make everything fit, and whether or not your standards are so low that you're willing to accept the horror of a "least worst that fits" solution.
Note: An alternative would be to store a (non-standard) "BIOS LBA for second stage of boot manager" field (or maybe 2 of them, for redundant 2nd stages) in the MBR somewhere, and postpone everything to do with GPT. This would be "slightly bad" (would break if any OS moves partitions around without updating those fields in the MBR), but perhaps "slightly bad" is the least worst solution.
Cheers,
Brendan