When booting from a partition, the first sector of the partition is loaded and executed. This sector is often referred to as the boot sector or as a logical boot record (LBR). Generally, it will contain information about the size of the filesystem and the location of key filesystem structures. It will also begin the process of booting the operating system, usually by searching a limited area of the filesystem for the operating system's boot files (e.g. IO.SYS, NTLDR).
Both LBRs and MBRs have a 2-byte boot marker at the end of the sector at offset 0x1FE, the hex sequence 0x55 0xAA. This indicates that the sector contains executable code. The MBR will usually check for this signature, and not execute the MBR/LBR if the signature is not there. The reason is that if the signature is not there, then the LBR code could be filled with random junk and shouldn't be executed. MBRs are pretty consistent about this, but BIOSes are not; some BIOSes will ignore whether the flag is there. Others will require that flag, plus the initial JMP at offset 0 (0xEB 0x3C).
Logical Block Addressing (LBA) simplifies addressing greatly. Since most programs that perform disk access used some sort of LBA internally anyway (even boot sector code), and just converted to CHS when the API was called, this came very naturally. LBA starts numbering sectors from 0, and can potentially address more than the older CHS style addressing. This is because the cylinders/heads/sectors actually returned by the drive is limited to full cylinders. If the last cylinder ends before reaching the last maximum head and sector numbers, then the cylinder is not reported. Although they may be addressable via the drive's CHS scheme, they're not reported. This is interesting because when Windows partitions a drive, it will use the CHS figures reported by the drive to size the partition, instead of using the LBA sector count. Consequently, there is often a small amount of empty space after the last partition. Using a figure of 255 heads and 63 sectors, there could be up to 8MB of unpartitioned space there.
Another common overlay actually reserved 63 sectors for itself, causing all addresses to be shifted by 63 sectors when comparing the disk with and without the overlay running. Partition tables and boot sectors would have to be adjusted accordingly if the overlay is removed manually.
Offset | Size (bytes) | Usage |
---|---|---|
0 | 1 | Bootable flag (partition "active") |
1 | 1 | Starting CHS head |
2 | 2 | Starting CHS sector/cylinder (more on this below) |
4 | 1 | Partition type |
5 | 1 | Ending CHS head |
6 | 2 | Ending CHS sector/cylinder (more on this below) |
8 | 4 | LBA offset of partition |
12 | 4 | Length of partition in sectors |
Bootable flag: This field is used to mark a partition is active. When the MBR code runs, it scans the partition table for non-zero entries here. The value 0x80 is expected, although some MBRs will react to other values. For example, the Windows 2000 MBR will look for values in the range 0x80-0xFF, and pass this to the BIOS int 13h functions (the upshot of this is that it can load an LBR from another hard drive if the value is greater than 0x80, although I'm not sure to what end). It will also look for values in the range 0x01-0x7F, and report an invalid partition table. Furthermore, if more than one entry is non-zero, this will also trigger the invalid partition table message.
Starting/Ending CHS head: The head part of the CHS address of the first or last sector of the partition. If the word at offset 0 containing the boot indicator and the head number is read as a little-endian word into the DX register, it can be loaded without modification to call the BIOS int 13h disk I/O functions. The boot indicator 0x80 is also the drive number of the first drive, and will go into DL, and the head number will go into DH.
Starting/Ending CHS sector and cylinder: This is a little trickier because it's in a packed format. The sector number occupies 6 bits, while the cylinder number occupies 10 bits. The pair should be read as a little-endian word. The low byte of this little-endian word contains the sector number in the lower 6 bits, and bits 8-9 of the cylinder in the upper 2 bits. The high byte of this word (offset 3 for the starting pair, offset 7 for the ending pair) contains bits 0-7 of the cylinder number. The packing comes from the BIOS int 13h call -- the word can be read directly into the CX register and used.
Byte: | Byte 0 | Byte 1 | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Bit: | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Use: | Cyl high bits 9-8 | Sector bits 5-0 | Cyl low bits 7-0 |
Partition type: A magic byte indicating what filesystem is in the partition. Sometimes the OS will ignore the value here if the partition type is different than indicated by the LBR of the partition. Some common values are:
Value | Partition type |
---|---|
0x00 | Empty entry in the table |
0x05 | Extended partition, CHS addressing |
0x06 | FAT16, CHS |
0x07 | NTFS |
0x0B | FAT32, CHS |
0x0C | FAT32, LBA |
0x0E | FAT16, LBA |
0x0F | Extended partition, LBA |
0x42 | Dynamic disk |
Side note: Although dynamic disk partitions are a placeholder for Windows to allocate filesystems however it wants, the most common scenario is just a single NTFS partition. The upshot is that converting a dynamic disk back to basic is usually just a matter of changing the partition type from 0x42 to 0x07.
Windows NT 4.0 would add 0x80 to partition types that were part of a fault-tolerant set. This is a Windows-centric list; there are more complete lists of partition types available on the internet.
LBA offset of partition: This is the starting LBA of the partition. In the most common case, a single partition the size of the disk, this value is 0x3F (63). Normally this address is absolute (or relative to the MBR at sector 0), but this is different for extended and logical partitions which will be explained in the next section. It's stored as an unsigned 32-bit value in little-endian byte order.
Length of partition in sectors: Number of sectors the partition occupies. The last sector number of the partition can be calculated as (LBAOffset + Length - 1). It's stored as an unsigned 32-bit value in little-endian byte order.
The outermost EBR, referenced by the MBR, is used to allocate all the space required for all the logical drives contained within it. We'll call it the primary extended partition. Like the MBR, an extended partition is only allowed to contain one extended partition (a chained extended partition). This limits the partitioning structure to a chain instead of a tree. The chain is made up of the MBR, EBR, and chained partitions (CBRs), and can be followed straight from start to finish. No branches are allowed on this chain, only leaves ("primary partitions" in the MBR, "logical drives" in the EBR/CBR) which contain no further partitions.
Regular partitions within EBRs/CBRs are typically called logical drives. Commonly, each EBR/CBR will allocate one logical drive, and if another one is needed, it will create a CBR slightly larger than the logical drive and then create the logical drive within the newly allocated CBR. However, EBRs and CBRs can contain multiple logical drives within themselves (multiple leaves) instead of extending the chain.
The LBA of partitions within the primary extended partition is not relative to the start of the drive. All chained extended partitions (CBRs) contained within the primary EBR are addressed relative to the start of the primary EBR. In contrast, all logical drives are addressed relative to the start of the EBR/CBR that contains them. As an example, we'll start with a 150GB drive. The first 10GB will be allocated to a primary partition, and the remaining 140GB will be allocated to the primary extended partition:
MBR at LBA 0 on disk | |||
---|---|---|---|
LBA | Length | Allocated for | Physical LBA on disk |
0GB | 10GB | Primary partition 1 | 0GB (0GB offset of MBR + 0GB offset of partition) |
10GB | 140GB | Extended partition (primary) | 10GB (0GB offset of MBR + 10GB offset of partition) |
Note:The 0GB LBA for primary partitions and logical drives is actually usually 63 sectors in, which is about 32KB.
If we wanted to partition the extended partition into three partitions of sizes 20GB, 30GB, 40GB, and 50GB it will typically be done this way: The first entry in the EBR will be the first logical drive, with an offset of 0GB and a size of 20GB. The second entry would then be another extended partition (CBR) with an offset of 20GB and a size of 30GB.
Primary EBR at LBA 10GB on disk | |||
---|---|---|---|
LBA | Length | Allocated for | Physical LBA on disk |
0GB | 20GB | Logical drive 1 | 10GB (10GB offset of EBR + 0GB offset of partition) |
20GB | 30GB | Chained extended partition (CBR 1) | 30GB (10GB offset of EBR + 20GB offset of partition) |
Note: Primary partitions and logical drives contain the same thing. The reason for the different names is that primary partitions are addressed relative to the MBR at the start of the disk, while logical drives are addressed relative to the EBR/CBR that contains them.
In the new chained partition, the first entry will be for a logical drive at offset 0GB, and a size of 30GB (minus the overhead of the CBR, usually 63 sectors). The second entry will be another CBR with an offset of 50GB, and a length of 40GB.
CBR 1 at LBA 30GB on disk | |||
---|---|---|---|
LBA | Length | Allocated for | Physical LBA on disk |
0GB | 30GB | Logical drive 2 | 30GB (30GB offset of CBR 1 + 0GB offset of partition) |
50GB | 40GB | Chained extended partition (CBR 2) | 60GB (10GB offset of EBR + 50GB offset of partition) |
CBR 2 is addressed relative to the start of the primary EBR, as opposed to logical drive 2, which is addressed relative to the start of CBR 1. In CBR 2 there will be an entry for a logical drive at offset 0GB, size 40GB, and one entry for CBR 3 at offset 100GB, size 50GB.
CBR 2 at LBA 60GB on disk | |||
---|---|---|---|
LBA | Length | Allocated for | Physical LBA on disk |
0GB | 40GB | Logical drive 3 | 60GB (60GB offset of CBR 2 + 0GB offset of partition) |
90GB | 50GB | Chained extended partition (CBR 2) | 100GB (10GB offset of EBR + 90GB offset of partition) |
Finally, CBR 3 would contain a single entry for logical drive 4 at offset 0GB, size 50GB.
CBR 3 at LBA 100GB on disk | |||
---|---|---|---|
LBA | Length | Allocated for | Physical LBA on disk |
0GB | 50GB | Logical drive 4 | 100GB (100GB offset of CBR 3 + 0GB offset of partition) |
Walking the partition tables does not need to be recursive.
Because only one extended partition is allowed in any partition table, the partition tables form a chain, not a tree. Each node in this chain can have either up to four primary partitions, or one extended partition and up to three primary/logical partitions. This makes enumerating partitions easier since you don't have to use a stack or other such structure.
The starting LBA of a partition is relative.
What it's relative to depends on the partition type. For primary/logical partitions, it's relative to the sector the partition is declared in. For primary partitions, this means the MBR at sector 0, and for logical partitions, this means the extended or chained partition they're declared in. The primary extended partition is always declared in the MBR, so it's always relative to sector 0. Chained extended partitions are always relative to the start of the primary extended partition.
That's pretty much it for partition tables. Some of this information is reflected in LBRs of various filesystems. Some LBRs will contain the offset of the partition from the start of the drive ("hidden sectors") which can be a factor when moving a partition, but I don't know if this is actually used or not. LBRs will contain their own length, which can be matched against the partition table for consistency (in the case of NTFS, it can also be used to find the backup boot sector). There's a lot more data and structures in LBRs, but they're specific to individual filesystem types (FAT, FAT32, NTFS, Linux, etc), and beyond the scope of this document.
Copyright (c) 2007 Paul Miner <$firstname.$lastname@gmail.com>, Last Updated 2007/12/03