Last update : 19/06/1998

Master Boot Record

Introduction

At the early ages of the PC, the capacity of hard disks didn't exceed 10 Mb. As a result, the FAT filesystem didn't support disks with more than 32 Mb. However, the capacity of hard disks quickly increased and operating system manufacturers had to find a way to manage these disks. The idea was to divide a disk of more than 32 Mb into smaller parts. This is called partitioning and each part of a partitioned disk is called a partition.

The latest versions of the FAT filesystem can handle much larger disks, and new and more sophisticated filesystems have been created. However, in some cases partitioning is still needed. One of these cases is when several operating systems have to share one hard disks. On the other hand, some people don't like to have such large disks and prefer to divide them in smaller parts just for convenience.

This page explains how the system maintains the information about the partitions of a hard disk.

The Master Boot Record

The master boot record is the sector where all the partition information is stored. The system needs to know where this sector is so it was given a fixed location : the first sector of the hard disk (head 0, cylinder 0, sector 1). Before looking at the structure of the master boot record, I'll say a word about the booting of an operating system.

At startup, the BIOS of the PC loads the first sector of the first hard disk into memory (we suppose that no floppy disk is present). You can get details on this at Boot sequence of a PC. In our case the sector that will be loaded will thus be the master boot record. To identify the sector as bootable, the last word of the sector must be AA55h. This implies that, if the hard disk is the first one, the first bytes of the master boot record have to be instructions.
Notice that the BIOS itself has no idea of what a partition is, it only loads the first sector of the disk into memory and executes it.

Here is the structure of the master boot record.

Address Content
+000h Partition code : the code lying here is executed if the sector is identified as an executable sector, i.e. the word at offset 1FEh is AA55h.
+1BEh Partition table
+1FEh These 2 bytes are tested by the BIOS to check if the sector can be executed. If byte +1FEh is equal to 55h and byte +1FFh is equal to AAh then the BIOS assumes the sector can be executed.

The structure of the partition table will be explained in the next section. For the moment, we will focus on the partition code.

One of the partitions holds the operating system we want to launch. This partition is called the active partition. Only one active partition can be defined at any moment. It's the partition table which stores the information about the active partition. If more than one partition is active the partition table is considered invalid.

It's the job of the partition code to identify the active partition, to load the boot sector of this partition into memory and then to execute it. This sector must also be loaded at address 0000h:7C00h, so the partition code moves itself elsewhere before loading the boot sector.

The partition table

This table lies at offset +1BEh of the master boot record. It has four entries of 16 bytes each. The structure of the partition table is as follows :

+1BEh First entry of the partition table
+1CEh Second entry of the partition table
+1DEh Third entry of the partition table
+1EEh Fourth entry of the partition table
Each partition is described by a 16 byte structure. The follow table shows this structure.

Offset Content
+00h State of partition : 00h if not active, 80h if active
+01h Head where the partition starts
+02h Sector and cylinder where the partition starts
+04h Type of partition : see Appendix A.
+05h Head where the partition ends
+06h Sector and cylinder where the partition ends
+08h Distance, in sectors, from the partition sector to the first sector of the partition
+0Ch Number of sectors in the partition

Appendix A : Type of partitions

Reference number Type
0h Empty
1h DOS 12-bits FAT
2h XENIX root
3h XENIX usr
4h DOS 16-bits < 32 Mb
5h Extended partition
6h DOS 16-bits >= 32 Mb
7h OS/2 HPFS
8h AIX
9h AIX initializable
Ah OS/2 Boot Manager
40h Venix 80286
51h Novell
52h Microport
63h GNU HURD
64h Novell
75h PC/IX
80h Old MINIX
81h MINIX/Linux
82h Linux Swap
83h Linux Native
93h Amoeba
94h Amoeba BBT
A5h BSD/386
B7h BSDI fs
B8h BSDI swap
C7h Syrinx
DBh CP/M
E1h Access to DOS
E3h DOS R/O
F2h DOS secondary
FFh BBT


Example of partition tables

Partition table of a 850 Mbyte hard disk with a DOS partition

The disk we analyze here is a 850 Mbyte hard disk in LBA mode with 827 cylinders, 63 sectors and 32 heads.
This is the code found at addresses 1BEh to 1FEh of the Master Boot Record. It's the partition table.

Entry 1 80 01 01 00 06 1F FF 39 3F 00 00 00 81 68 19 00
Entry 2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Entry 3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Entry 4 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

As we see only the first entry of the table is used.

The content of address 1BEh is 80h, meaning that this is the boot partition.

The next byte (address 1BFh) is the head where the partition starts. This partition starts at head 1.

The bytes at addresses 1C0h and 1C1h are used to know the sector and the cylinder where the partition starts.
The value of the first byte is 01h but only the 6 least significant bits are used for the sector number. The sector number is thus 000001b. The 2 most significant bits are the thwo most significant bits of the cylinder number and must be appended to the value in 1C1h. This gives : 0000000000b.

From all the fields above, we know the partition starts at sector 1, head 1, cylinder 0.

The byte at address 1C2h is the type of partition. Here we have a DOS 4.0 with more than 32 Mbyte partition (value 06h).

The next byte (address 1C3h) is the head where the partitions ends : head 1Fh or 31 (remember this is a disk with 32 heads, head 31 is thus the last).

The bytes at addresses 1C4h and 1C5h are used to know the sector and the cylinder where the partition ends.
The value of the first byte is FFh but only the 6 least significant bits are used for the sector number. The sector number is thus 111111b (63). The 2 most significant bits are the thwo most significant bits of the cylinder number and must be appended to the value in 1C5h. This gives : 1100111001b (825).

From all the fields above, we know the partition ends at sector 63, head 31, cylinder 825.

The bytes at addresses 1C6h to 1C9h are the distance from the partition sector to the first sector of the partition calculated in sectors. Here we have 0000003Fh (remember that Intel architecture uses the Little-Endian format) or 63. The distance from the beginning of the partition sector to the beginning of the partition is 63 sectors since the partition begins at head 1, cylinder 0, sector 0 and there are 63 sectors per track.

The bytes at addresses 1CAh to 1CDh are the number of sectors in the partition. Here we have : 00196881h or 1665153. If we multiply this number by the number of bytes in a sector (512), we get 852,558,336 bytes. This is the result expected because the partition covers all the disk space.

Partition table of a 3.2 Gbyte hard disk with a Linux partition

The disk we analyze here is a 3.2 Gbyte hard disk in LBA mode with 63 sectors/track and 128 heads/cylinder. It has two partitions : a Linux swap partition of 100 Mb and a Linux native partition of 1.5 Gb. About half of the disk is thus unused.
This is the code found at addresses 1BEh to 1FEh of the Master Boot Record. It's the partition table.

Entry 1 00 01 01 00 82 7F 3F 19 3F 00 00 00 C1 32 03 00
Entry 2 80 00 01 1A 83 7F 7F 96 00 33 03 00 80 E1 2E 00
Entry 3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Entry 4 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

As we see only the first and second entries of the table are used.

The content of address 1BEh is 00h, so this isn't the boot partition (in fact, it's a Linux swap partition).

The next byte (address 1BFh) is the head where the partition starts. This partition starts at head 1.

The bytes at addresses 1C0h and 1C1h are used to know the sector and the cylinder where the partition starts.
The value of the first byte is 01h but only the 6 least significant bits are used for the sector number. The sector number is thus 000001b. The 2 most significant bits are the thwo most significant bits of the cylinder number and must be appended to the value in 1C1h. This gives : 0000000000b.

From all the fields above, we know the partition starts at sector 1, head 1, cylinder 0.

The byte at address 1C2h is the type of partition. Here we have a Linux swap partition (value 82h).

The next byte (address 1C3h) is the head where the partitions ends : head 7Fh or 127 (remember this is a disk with 128 heads, head 127 is thus the last).

The bytes at addresses 1C4h and 1C5h are used to know the sector and the cylinder where the partition ends.
The value of the first byte is 3Fh but only the 6 least significant bits are used for the sector number. The sector number is thus 111111b (63). The 2 most significant bits are the two most significant bits of the cylinder number and must be appended to the value in 1C5h. This gives : 0000011001b (25).

From all the fields above, we know the partition ends at sector 63, head 127, cylinder 25.

The bytes at addresses 1C6h to 1C9h are the distance from the partition sector to the first sector of the partition calculated in sectors. Here we have 0000003Fh (remember that Intel architecture uses the Little-Endian format) or 63. The distance from the beginning of the partition sector to the beginning of the partition is 63 sectors since the partition begins at head 1, cylinder 0, sector 1 and there are 63 sectors per track.

The bytes at addresses 1CAh to 1CDh are the number of sectors in the partition. Here we have : 000332C1h or 209601. If we multiply this number by the number of bytes in a sector (512), we get 107,315,712 bytes.

The content of address 1CEh is 80h, this is a boot partition.

The next byte (address 1CFh) is the head where the partition starts. This partition starts at head 0.

The bytes at addresses 1D0h and 1D1h are used to know the sector and the cylinder where the partition starts.
The value of the first byte is 01h but only the 6 least significant bits are used for the sector number. The sector number is thus 000001b. The 2 most significant bits are the thwo most significant bits of the cylinder number and must be appended to the value in 1D1h. This gives : 0000011010b.

From all the fields above, we know the partition starts at sector 1, head 0, cylinder 26.

The byte at address 1D2h is the type of partition. Here we have a Linux native partition (value 83h).

The next byte (address 1D3h) is the head where the partitions ends : head 7Fh or 127 (remember this is a disk with 128 heads, head 127 is thus the last).

The bytes at addresses 1D4h and 1D5h are used to know the sector and the cylinder where the partition ends.
The value of the first byte is 7Fh but only the 6 least significant bits are used for the sector number. The sector number is thus 111111b (63). The 2 most significant bits are the two most significant bits of the cylinder number and must be appended to the value in 1D5h. This gives : 0110010110b (406).

From all the fields above, we know the partition ends at sector 63, head 127, cylinder 406.

The bytes at addresses 1D6h to 1D9h are the distance from the partition sector to the first sector of the partition calculated in sectors. Here we have 00033300h (remember that Intel architecture uses the Little-Endian format) or 209664. This is approximately the length of the first partition (107 Mb).

The bytes at addresses 1DAh to 1DDh are the number of sectors in the partition. Here we have : 002EE180h or 3075384. If we multiply this number by the number of bytes in a sector (512), we get 1,573,060,608 bytes.

Partition table of a 2.5 Gbyte hard disk with two DOS partitions

The disk we analyze here is a 2.5 Gbyte hard disk in LBA mode with 620 cylinders, 63 sectors/track and 128 heads/cylinder. It has two partitions : a partition of 1 Gb and a partition of 1.5 Gb.
This is the code found at addresses 1BEh to 1FEh of the Master Boot Record. It's the partition table.

Entry 1 00 00 01 01 05 7F BF 6A 80 1F 00 00 00 0B 4C 00
Entry 2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Entry 3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Entry 4 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

As we see only the first entry of the table are used.

The content of address 1BEh is 00h, so this isn't a boot partition.

The next byte (address 1BFh) is the head where the partition starts. This partition starts at head 0.

The bytes at addresses 1C0h and 1C1h are used to know the sector and the cylinder where the partition starts.
The value of the first byte is 01h but only the 6 least significant bits are used for the sector number. The sector number is thus 000001b. The 2 most significant bits are the two most significant bits of the cylinder number and must be appended to the value in 1C1h. This gives : 0000000001b.

From all the fields above, we know the partition starts at sector 1, head 0, cylinder 1.

The byte at address 1C2h is the type of partition. Here we have an extended partition (05h), meaning that the first sector of this partition is a master boot record itself.

The next byte (address 1C3h) is the head where the partitions ends : head 7Fh or 127 (remember this is a disk with 128 heads, head 127 is thus the last).

The bytes at addresses 1C4h and 1C5h are used to know the sector and the cylinder where the partition ends.
The value of the first byte is BFh but only the 6 least significant bits are used for the sector number. The sector number is thus 111111b (63). The 2 most significant bits are the two most significant bits of the cylinder number and must be appended to the value in 1C5h. This gives : 1001101010b (618).

From all the fields above, we know the partition ends at sector 63, head 127, cylinder 618.

The bytes at addresses 1C6h to 1C9h are the distance from the partition sector to the first sector of the partition calculated in sectors. Here we have 00001F80h (remember that Intel architecture uses the Little-Endian format) or 8064. The distance from the beginning of the partition sector to the beginning of the partition is 8064 sectors since the partition begins at head 0, cylinder 1, sector 1. The first cylinder is unused, it holds 63*128 = 8064 sectors.

The bytes at addresses 1CAh to 1CDh are the number of sectors in the partition. Here we have : 004C0B00h or 4983552. If we multiply this number by the number of bytes in a sector (512), we get 2,551,578,624 bytes.

Since this is an extended partition, its first sector has also a partition table. Here is this table :

Entry 1 00 01 01 01 06 7F 3F FE 3F 00 00 00 C1 40 1F 00
Entry 2 00 00 01 FF 05 7F BF 6A 00 41 1F 00 00 CA 2C 00
Entry 3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Entry 4 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

As we see only the first and second entries of the table are used.

The content of address 1BEh is 00h, so this isn't a boot partition.

The next byte (address 1BFh) is the head where the partition starts. This partition starts at head 1.

The bytes at addresses 1C0h and 1C1h are used to know the sector and the cylinder where the partition starts.
The value of the first byte is 01h but only the 6 least significant bits are used for the sector number. The sector number is thus 000001b. The 2 most significant bits are the two most significant bits of the cylinder number and must be appended to the value in 1C1h. This gives : 0000000001b.

From all the fields above, we know the partition starts at sector 1, head 1, cylinder 1.

The byte at address 1C2h is the type of partition. Here we have a DOS 4.0 partition (06h).

The next byte (address 1C3h) is the head where the partitions ends : head 7Fh or 127 (remember this is a disk with 128 heads, head 127 is thus the last).

The bytes at addresses 1C4h and 1C5h are used to know the sector and the cylinder where the partition ends.
The value of the first byte is 3Fh but only the 6 least significant bits are used for the sector number. The sector number is thus 111111b (63). The 2 most significant bits are the two most significant bits of the cylinder number and must be appended to the value in 1C5h. This gives : 0011111110b (254).

From all the fields above, we know the partition ends at sector 63, head 127, cylinder 254.

The bytes at addresses 1C6h to 1C9h are the distance from the partition sector to the first sector of the partition calculated in sectors. Here we have 0000003Fh (remember that Intel architecture uses the Little-Endian format) or 63.

The bytes at addresses 1CAh to 1CDh are the number of sectors in the partition. Here we have : 001F40C1h or 2048193. If we multiply this number by the number of bytes in a sector (512), we get 1,048,674,816 bytes.

The content of address 1CEh is 00h, this isn't a boot partition either.

The next byte (address 1CFh) is the head where the partition starts. This partition starts at head 0.

The bytes at addresses 1D0h and 1D1h are used to know the sector and the cylinder where the partition starts.
The value of the first byte is 01h but only the 6 least significant bits are used for the sector number. The sector number is thus 000001b. The 2 most significant bits are the two most significant bits of the cylinder number and must be appended to the value in 1D1h. This gives : 0011111111b (255).

From all the fields above, we know the partition starts at sector 1, head 0, cylinder 255.

The byte at address 1D2h is the type of partition. Here we have an extended partition (05h).

The next byte (address 1D3h) is the head where the partitions ends : head 7Fh or 127 (remember this is a disk with 128 heads, head 127 is thus the last).

The bytes at addresses 1D4h and 1D5h are used to know the sector and the cylinder where the partition ends.
The value of the first byte is BFh but only the 6 least significant bits are used for the sector number. The sector number is thus 111111b (63). The 2 most significant bits are the two most significant bits of the cylinder number and must be appended to the value in 1D5h. This gives : 1001101010b (618).

From all the fields above, we know the partition ends at sector 63, head 127, cylinder 618.

The bytes at addresses 1D6h to 1D9h are the distance from the partition sector to the first sector of the partition calculated in sectors. Here we have 001F4100h (remember that Intel architecture uses the Little-Endian format) or 2048256. This is approximately the length of the first partition (1 Gb).

The bytes at addresses 1DAh to 1DDh are the number of sectors in the partition. Here we have : 002CCA00h or 2935296. If we multiply this number by the number of bytes in a sector (512), we get 1,502,871,552 bytes.

Since this is an extended partition, we look at its first sector to find the partition table :

Entry 1 00 01 01 FF 06 7F BF 6A 3F 00 00 00 C1 C9 2C 00
Entry 2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Entry 3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Entry 4 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

We have here a DOS 4.0 partition of 1.5 Gb.


Example of a Master Boot Record

Here's a copy of the code found a the first sector of 850 Mbyte hard drive with one DOS 4.0 partition.

Offset Hexadecimal code Instruction or data
00 FA cli
01 33C0 xor ax,ax
03 8ED0 mov ss,ax
05 BC007C mov sp,7C00h
08 8BF4 mov si,sp
0A 50 push ax
0B 07 pop es
0C 50 push ax
0D 1F pop ds
0E FB sti
0F FC cld
10 BF0006 mov di,0600h
13 B90001 mov cx,0100h
16 F2A5 repnz movsw
18 EA1D060000 jmp 0000h:061Dh
1D BEBE07 mov si,07BEh
20 B304 mov bl,04h
22 803C80 cmp byte ptr [si],80h
25 740E je 35h
27 803C00 cmp byte ptr [si],00h
2A 751C jne 48h
2C 83C610 add si,0010h
2F FECB dec bl
31 75EF jne 22h
33 CD18 int 18h
35 8B14 mov dx,[si]
37 8B4C02 mov cx,[si+02h]
3A 8BEE mov bp,si
3C 83C610 add si,0010h
3F FECB dec bl
41 741A je 5Dh
43 803C00 cmp byte ptr [si],00h
46 74F4 je 3Ch
48 BE8B06 mov si,068Bh
4B AC lodsb
4C 3C00 cmp al,00h
4E 740B je 5Bh
50 56 push si
51 BB0700 mov bx,7h
54 B40E mov ah,0Eh
56 CD10 int 10h
58 5E pop si
59 EBF0 jmp 4Bh
5B EBFE jmp 5Bh
5D BF0500 mov di,5h
60 BB007C mov bx,7C00h
63 B80102 mov ax,0201h
66 57 push di
67 CD13 int 13h
69 5F pop di
6A 730C jnb 78h
6C 33C0 xor ax,ax
6E CD13 int 13h
70 4F dec di
71 75ED jne 60h
73 BEA306 mov si,06A3h
76 EBD3 jmp 4Bh
78 BEC206 mov si,06C2h
7B BFFE7D mov di,7DFE
7E 813D55AA cmp word ptr [di],AA55h
82 75C7 jne 4Bh
84 8BF5 mov si,bp
86 EA007C0000 jmp 0000h:7C00h
8B Invalid partition table
A2 00
A3 Error loading operating system
C1 00
C2 Missing operating system
DA 00
DB-1BE 00 Unused space
1BE-1CD See description of this entry in Partition Table of a 850 Mb hard disk
1CE-1DD 00 Unused entry of partition table
1DE-1ED 00 Unused entry of partition table
1EE-1FD 00 Unused entry of partition table
1FE 55AA The sector can be executed
Note : when a jump is made in this table, the value that follows the instruction refers to the offset in the table, you don't have to add this value to the offset of the instruction (i.e. je 48h sends you to offset 48h).

00-0E :
The first thing the code does, is to disable interrupts while it is initializing the segment and stack registers. After that, it reenables them. Please note that the si register is also initialized. Its initial value is 7C00h, so that it points to the boot code.

0F-18 :
The boot code is copied to 0000h:0600h. The program then jumps to the next instruction but in the copy of the code.

1D :
si is loaded with 07BEh. This is the location of the first entry of the partition table. Remember that this entry is at offset 1BEh of the boot sector and that this sector is now at 600h (600h + 1BEh = 7BEh).

20-33 :
This code goes through the partition table and looks for a bootable partition.
If it has found a boot partition, it goes to offset 35h.
If it has found a partition whose first byte isn't 80h nor 00h, it goes to offset 48h.
If it hasn't found a bootable partition in any of the 4 entries of the table, it triggers interrupt 18h.

35-46 :
This code is executed when a bootable partition has been found. It checks if the entries that haven't been examined yet start with a null byte (indicating a non bootable partition). If anything else is found, the partition table is considered invalid and the execution continues with the code located at offset 48h.
cx is loaded with the cylinder and head information.
If all the other entries of the table are start with 0, the code at offset 5Dh is executed.

48 : si is loaded with 68B. This is the offset of the string "Invalid partition table". Then execution is continued with the code at 4Bh.

4B-5B :
This code is used to print an error message on the screen. si has been previously loaded by the offset of the string to print. It uses interrupt 10h to do so. The last byte of the string must be equal to 0 to indicate the end of the string. When the procedure detects the end of the string it jumps to offset 5Bh, which is an infinite loop.

5D-76 :
This code loads the boot sector of the active partition at address 0000h:7C00h. It tries to do so with interrupt 13h, function 2h. cx has already been loaded with the appropriate value by the procedure at offset 35h.
If an error is detected, the procedure resets the drive with interrupt 13h, function 0h and retries to read the disk. It retries 5 times. After that, si is loaded with 06A3h, the offset of the "Error loading operating system" string, and the printing procedure at offset 4Bh is called.
If the procedure managed to load the boot sector, the code at offset 78h is executed.

78-86 :
The si register is loaded with the value 06C2h, which is the offset of string "Missing operating system". This is done in prevision of an error.
The procedure checks if the newly loaded boot sector is executable. If it is, it should find a word with value AA55h at offset 7DFEh (7C00h+1FEh). If it doesn't find it, it calls the printing procedure at offset 4Bh.
If everything is allright, the procedure jumps to the boot code.


[ Return to General Information Index ] [ Return to main index ]

Copyright(c) 1998 - Xavier Leclercq <xavierleclercq@iname.com>