Sunday, December 8, 2019

Memory: Master Boot Record and Partition Tables

In summary, this post describes fundamentals of persistent memory storage, that is, how to interpret the data on most memory devices including SD cards, eMMC devices, flash and thumb drives, hard disk drives, and so on.

Master Boot Record

The master boot record (MBR) describes traits of the memory, bootloader (or bootstrap) code, and most especially the partition tables. A classic MBR is formatted as follows:

AddressDescriptionSize
(bytes)
HexDec
+000hex+0Bootstrap code area446
+1BEhex+446Partition entry №1Partition table
(for primary partitions)
16
+1CEhex+462Partition entry №216
+1DEhex+478Partition entry №316
+1EEhex+494Partition entry №416
+1FEhex+51055hexBoot signature[a]2
+1FFhex+511AAhex
Total size: 446 + 4×16 + 2512

The MBR is located in the first sector of the entire storage device - sector 1. Theoretically this is the equivalent to the memory address '0x0'. There are exactly four partition table entries, no more, no less for historical and compatibility reasons. The end of the boot record is signaled by the signature "0x55AA." MBR addresses are absolute, meaning address 0x000001BE is always going to be the address for partition table entry one.

Define 'Sector': An aligned chunk of data within a memory device. Sectors are usually no less than 512 bytes each. Larger memory devices sometimes use 1024 bytes up to 4096 bytes per sector. SD cards are commonly 512 bytes per sector.

Partition Table Entries

An entry describes where in the memory space each partition is located, how big it is, the partition type, and whether or not the partition is active. Side note: an active partition can be booted from, that is, an operating system or other bootstrap can execute code contained within the partition's own boot record. The byte-code layout of a partition is formatted as follows:

AddressDescriptionSize
(bits)
HexDec
+0hex+0Active Partition (0x00 - inactive, 0x80 - active, other - invalid)8
+1hex+1Start Head8
+2hex+2*Start Sector (bits 0-5)8
+3hex+3*Start Cylinder (bits 0-7 and bits 6&7 from the previous byte)8
+4hex+4Partition Type8
+5hex+5End Head8
+6hex+6*End Sector (bits 0-5)8
+7hex+7*End Cylinder (bits 0-7 and bits 6&7 from the previous byte)8
+8hex+8†Absolute starting sector of the partition8
+Chex+12†Size of the partition in sectors8
Total size: 16x8128

* Start sector and end sector values are only 6-bits in size. The remaining two bits in the byte are the most significant bits of the 10-bit start and end cylinder values respectively. For example, if the 'Start Sector' byte is 0xFE and the 'Start Cylinder' byte is 0xFF, then their actual values are 0x3E and 0x3FF respectively.
† Multi-byte values are little-endian! So an absolute starting sector with a value of 0x00080000 for example is actually 0x800. Same goes for the sector size.

An (incomplete) list of partition types:

Value (hex)Description
00Empty partition-table entry
01FAT12
04FAT16 (<= 32 MB)
05Extended Partition
06FAT16 (> 32 MB)
07OS/2 HPFS, Windows NT NTFS, Advanced Unix
08OS/2 v1.0-1.3, AIX Bootable Partition, SplitDrive
09AIX Data Partition
0AOS/2 Boot Manager
0BFAT32
0CFAT32 (using LBA-mode INT13 extensions)
0EFAT16 (> 32 MB using INT13 extensions)
0FExtended Partition (using INT13 extensions)
17Hidden NTFS
1BHidden FAT32
1CHidden FAT32 (using LBA-mode INT13 extensions)
1EHidden LBA VFAT
42Dynamic Disk Volume
50OnTrack Disk Manager (read-only)
51OnTrack Disk Manager (read-write)
81Linux
82Linux Swap, Solaris
83Linux Native (EXT2 / XIAFS)
85Linux EXT
86FAT16 Volume/Stripe (Windows NT)
87HPFS Fault-Tolerant Mirrored, NTFS Volume/Strip
BESolaris Boot
C0DR-DOS / Novell DOS Secured
C6Corrupt FAT16 Volume/Strip
C7Corrupt NTFS Volume/Stripe
F2Secondary Partition

Cylinder-Head-Sector Geomtery & Logical Block Addressing

Cylinder-Header-Sector (CHS) is the legacy way of locating the start and end sectors of partitions. Historically these values corresponded to the physical reading head, the cylinder or track of data, and the slice or sector within the track. Many modern solid-state and flash devices don't have such features, and CHS itself is limited to a max size of about 7.8 GB. So, most devices now-a-days use the Logical-Block-Addressing (LBA) method to locating partition boundaries. The 'absolute starting sector' in a partition table entry is an example of an LBA. (LBA units are in sectors.) CHS is kept for compatibility reasons.

To convert from CHS to LBA, use the following formula:

(C x TH x TS) + (H x TS) + (S - 1) = LBA

Where,

C  = cylinder number
H  = head number
S  = sector number
TH = total heads (255 or 16)
TS = total sectors (63)

Exploration

Try it out! Find a 512 MB - 4 GB SD card or thumb drive and create an image from it using the dd Linux command. Then use a hex editor to inspect the binary values of the image. (The memory size is only for exploratory convenience.) Try searching for partitions and determining their characteristics. (You can use the gparted Linux utility to format the device and fdisk -l /dev/mmcblkX to quickly print out basic MBR info.)

If your SD card is listed under the Linux devices as /dev/mmcblk0 for example, you can create a binary image with the command:

sudo dd if=/dev/mmcblk0 of=$(pwd)/mmc.img bs=512 status=progress

You can then open the file mmc.img in a hex editor such as GHex for Linux or HxD on Windows.

Happy Hacking!