O O Ø O O O O
i386 Boot Mysteries
Originally posted to openbsd-tech on Fri, 25 Jul 1997
Ok, I said I'd write this darn thing, and I finally got around to it. This is meant to help clear up some of the confusion surrounding the booting issues on i386 OpenBSD boxes. Most of this info has been compiled in a painstaking process of nuking a machine to virgin (all zero's on the disk), and then installing the following operating systems from scratch: DOS 3 & 4, OS/2, Win95, NT 3.51, NT 4.0, and SCO.
Walking through the code for all those was not pretty, and if anyone wants to, feel free to take a walk on the wild side, and see what you think of it.
Anyways, here goes. First here are a couple of abbreviations that I will use.
- MBR – Master Boot Record
- PBS – Partition Boot Sector
- BPB – BIOS Parameter Block
- EBPB – Extented BPB
First, the PC is a very dumb animal. I'm surprised that the 256 bytes we have for the boot sectors are enough to do what they need to do. Enough rambling, here is the nitty gritty.
The PBS exists in each bootable partition (including a floppy, which is to be looked at as a partition by itself). It contains the following info:
Offset | Length | Sample Value | Meaning |
0x0000 | 0x0003 | EB 3C 90 | Jump Instruction |
0x0003 | 0x0008 | MS-DOS 5.0 | OEM Name in text |
0x000B | 0x0019 | (See later) | BPB |
0x0024 | 0x001A | (See later) | EBPB |
0x003E | 0x01C0 | See later) | Bootstrap code |
0x01FE | 0x0002 | 55 AA | End of sector marker |
Which on an NT 4.0 system extends to a slightly different set:
Offset | Length | Sample Value | Meaning |
0x0000 | 0x0003 | EB 5B 00 | Jump Instruction |
0x0003 | 0x0008 | NTFS | OEM Name in text |
0x000B | 0x0019 | (See later) | BPB |
0x0024 | 0x0030 | (See later) | EBPB |
0x003E | 0x01aa | (See later) | Bootstrap code |
0x01FE | 0x0002 | 55 AA | End of sector marker |
NOTE: the 426 bytes used for the bootstrap code on NT 4.0 is longer than 426 bytes, the system allocates the first 16 sectors for the PBS and bootstrap code. The common denominator is the MS-DOS 5.0 PBS.
Here is the information that is stored in the BPB for MS-DOS 5.0, and NT 4.0:
Offset | Length | MS-DOS 5.0 | NT 4.0 | Meaning |
0x000B | 0x0002 | 0x0002 | 0x0002 | Bytes per sector |
0x000D | 0x0001 | 0x08 | 0x01 | Sectors per Cluster |
0x000E | 0x0002 | 0x0100 | 0x0000 | Reserved Sectors |
0x0010 | 0x0001 | 0x02 | 0x00 | Number of FATs |
0x0011 | 0x0002 | 0x0002 | 0x0000 | Root entries |
0x0013 | 0x0002 | 0x0000 | 0x0000 | Small Sectors (rarely used) |
0x0015 | 0x0001 | 0xF8 | 0xF8 | Media Type (F8 == HD) |
0x0016 | 0x0002 | 0xC900 | 0x0000 | Sectors per FAT |
0x0018 | 0x0002 | 0x3F00 | 0x3F00 | Sectors per Track |
0x001A | 0x0002 | 0x1000 | 0x1000 | Number of Heads |
The EBPB for NT 4.0 is much the same as the one for MS-DOS 5.0, basically using the same values in the fields below, not using some fields, and adding a couple new fields. The relevant fields that should be filled in are below:
Offset | Length | Sample Value | Meaning |
0x001C | 0x0004 | 3F 00 00 00 | Hidden Sectors |
0x0020 | 0x0004 | 51 42 06 00 | Large Sectors |
0x0024 | 0x0002 | 80 00 | Physical Disk |
0x0026 | 0x0001 | 29 | Sig. (Needed by NT) |
0x0027 | 0x0004 | CE 13 46 30 | Vol. Serial Number |
0x002B | 0x000B | NO NAME | Volume Label |
0x0036 | 0x0008 | FAT16 | System ID |
The MBR on a hard disk is a hack that someone came up with to actually partition (hence the name) a hard disk (which was huge at one time) into different usable "partition" or sections. Of course, this being a tradition, they used values in the partition table which soon (all too soon) were too small to accurately represent the geometry and layout of the disk and its various partitions. The following is the layout of an MBR on an NT 4.0 system, as explained from the NT 4.0 resource guide:
Offset | Length | Sample Value | Meaning |
0x0000 | 0x01BA | 00 33 C0 ... | MBR Code (see later) |
0x01B8 | 0x0004 | FD 4E F2 14 | Disk Signature |
0x01BC | 0x0002 | 00 00 | Junk? |
0x01BE | 0x0010 | 80 01 01 ... | Partition 1 |
0x01CE | 0x0010 | 00 00 41 ... | Partition 2 |
0x01DE | 0x0010 | 00 00 C1 ... | Partition 3 |
0x01EE | 0x0010 | 00 00 C1 ... | Partition 4 |
0x01FE | 0x0002 | 55 AA | BIOS Signature |
The partition table entries are laid out as follows:
Offset | Length | Sample Value | Meaning |
0x0000 | 0x0001 | 0x80 | Boot Indicator |
0x0001 | 0x0001 | 0x01 | Starting Head |
0x0002 | 6 bits | 0x01 | Starting Sector |
0x0003 | 10 bits | 0x00 | Starting Cylinder |
0x0004 | 0x0001 | 0x06 | System ID |
0x0005 | 0x0001 | 0x0F | Ending Head |
0x0006 | 6 bits | 0x3F | Ending Sector |
0x0007 | 10 bits | 0x196 | Ending Cylinder |
0x0008 | 0x0004 | 3F 00 00 00 | Relative Sector |
0x000C | 0x0004 | 51 42 06 00 | Total Sectors |
Now comes the fun stuff, the actual boot code. The code in the MBR is definitely different from the code in the PBS. They serve two totally different purposes. First of all, the PBS.
The PBS is there to load the rest of the OS or whatever off the partition or floppy disk. The PBS gets passed the following information that could be termed "useful". On most systems %dl is the drive number where the PBS was loaded from. This is actually an accident rather than design, that was later revised to a specification. In other words, %dl just happened to be 0x00 when PCs first were booted from the floppy, and 0x80 (the active flag) when it was booted from the hard disk. As you remember (at least my if my memory serves), the original PCs did not permit booting from anything other than the first hard disk.
All of a sudden, additional HDs started appearing in PCs, and people wanted a way to boot off those disks as well. So in their infinite wisdom, phoenix made up a spec that the BIOS and the boot blocks are supposed to follow. However, not every PC follows this. Our current boot blocks follow this "standard" fairly closely. This is the reason for the "read error" that some people have been encountering on booting with our boot blocks from a HD. The HD boot image (our boot blocks) get passed a 0x00 in %dl, which means that we try to read the rest of the stuff off the floppy, and since there is no floppy in the drive, we get a "read error".
So this covers the PBS, basically, this guys job is to load the rest of the boot program or OS into ram from the device the PBS was loaded from, and start it.
The MBR is a little bit of code, which basically relocates itself out of the way, loads all the values from the appropriate partition table entry into the right registers (they map almost 1-1, IE: active flag -> %dl), calls BIOS int 0x13 read block, and reads the PBS the MBR points to. It then jumps to this PBS so it can do its thing, passing in %dl for it to use. Nothing more fancy.
So in conclusion, here is the way that things will have to work (IMHO) for the boot process to work on most (if not all) i386 boxes. First of all, if we mess with the MBR on a disk, we do so carefully. Creating, deleting, and changing partitions should *not* affect the rest of the MBR. The equivalent of the DOS "fdisk /mbr" should be available, and should do the following:
- Read MBR, save partition table.
- Read /usr/mdec/mbr, restore partition table.
- Write MBR.
/usr/mdec/mbr is nothing fancy, just looks for the 0x80 flag, and boots that partition. If you want boot time selection, use os-bs, or some other boot selector.
The MBR will check %dl on boot-up, and if %dl == 0x00, load it with the active flag from its own image. If booting a second HD, the %dl should have been set to 0x81 by the BIOS. Maybe we can make the active flag of the active partition of the second HD be 0x81 just in case. This flag will get passed to the PBS which the MBR loads and executes.
The PBS will trust %dl (if anybody knows a better way, tell me!), and load the rest of /boot or whatever OS it was designed to load. In our case, the blocks are hard-coded into the PBS, and the drive is in %dl, so further loading of the /boot image should not be a problem.
First of all, only the MBR has a partition table in it. There used to be a mode where 386BSD was installed as the only OS on a drive. This can be accomplished in two ways. One should work with almost any BIOS out there, the other will only work with phoenix standard compatible BIOSs. Basically, you can have an MBR on the HD, which will load the PBS (from a different location), and things go on as outlined above. This is the way NT, DOS, and SCO do their thing. You might loose a cylinder due to alignment issues.
The other way is to put the PBS as the MBR on a drive. This will only work on machines that pass the drive number to the MBR in %dl. Not all of them do! Again, if anyone knows of a way to determine the boot drive via the BIOS (reliably), please let me know...
So, there is one more small problem. How do we find the disklabel on a drive. This poses a problem, because we don't really want to "scan" the disk to try and find the label. If we read the first sector of a disk, we have one of three possibilities.
- MBR (Signature 55 AA, plus valid looking partition table entries) In this scenario we check the MBR for an OpenBSD partition, where the disk label should be found. If such a partition is not present, the disk label does not exist.
- PBR (OEM name "OpenBSD") In this scenario we have a OpenBSD "partition" which spans the whole physical device. The disk label is found in the "standard" place. If the OEM name tag is not correct, this is not an OpenBSD disk partition, and the disk label does not exist.
- None of the above In this scenario, we must assume that it is an unknown disk/partition, and there exists no OpenBSD disk label.
This has been a long message, and if you stuck it out this far, please give me some feedback, and tell me what I missed, or where I messed up. Thanks,
Copyright Clearance
On Friday, December 14, [kjell] wrote:
I found an old tech posting of yours that I'm finding quite handy. Rather than lose it again, I did some quick markup on it. So - do you mind if I post it (publicly) on my web site?
Nope, don't mind at all. As a matter of fact, that should be put into documentation within the system, extended somewhat to include the LBA things. Not sure where it would go though...
Anyways, feel free to do with it what you wish. I actually forgot I wrote that... :-)
—Toby.