How to create master boot record (MBR) file on Linux

Usually when working with USB thumb drives, memory cards and hard drives, the partitioning can be easily done just by plugging them to a Linux (or Windows) PC and using a partitioning application such as fdisk. However, with embedded devices it is sometimes more practical to write the partition table to a file instead of directly writing it to the memory device. This can be the case with embedded MMC (eMMC) memories which are soldered directly to the device and cannot be connected to a PC for partitioning.

The partitioning information is stored in a special sector in the very beginning (address zero) of the mass storage device. This special sector is called master boot record (MBR). The details and internal structure of the MBR will not be covered here since there already is a comprehensive Wikipedia article available. Instead this post focuses on how to create one to a file.

First, a file needs to be created to represent the mass memory. The file size needs to match the mass storage device size so the fdisk utility can create correct partition sizes. As an example, lets assume an eMMC chip with 7553024 sectors and 512 byte sector size. These values may be different between manufacturers so refer to the memory datasheet.

There is a simple trick to create large files practically instantaneously. Instead of actually writing gigabytes of zeros to a file, it is possible to seek to large address and only  write a little.

# Size of the eMMC/SD in sectors
SECTORS=7553024
SECTOR_SIZE=512

# Create zero-file to represent the eMMC (needed for fdisk)
dd if=/dev/zero of=mem_file seek=$((SECTORS - 1)) bs=$SECTOR_SIZE count=1

The script above creates a file that is 7553024b * 512b = 3,6 GiB in size. Note that the script first seeks to SECTORS-1 and then writes one sector worth of data, making the file size match SECTORS.

Next, fdisk can be invoked on the file.

# -u give sizes in sectors instead of cylinders
fdisk -u mem_file

Now normal fdisk commands can be issued. The following commands show  how to create one bootable 10 megabyte FAT partition and second partition for data (e.g. root filesystem). The user commands are shown in bold and enter is used to show where the default value was accepted by pressing enter key.

Welcome to fdisk (util-linux 2.27.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0x55ecee0c.

Command (m for help): o
Created a new DOS disklabel with disk identifier 0xe648bbde.

Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-7553023, default 2048): enter
Last sector, +sectors or +size{K,M,G,T,P} (2048-7553023, default 7553023): +10M

Created a new partition 1 of type 'Linux' and of size 10 MiB.

Command (m for help): n
Partition type
   p   primary (1 primary, 0 extended, 3 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (2-4, default 2): 2
First sector (22528-7553023, default 22528): 
Last sector, +sectors or +size{K,M,G,T,P} (22528-7553023, default 7553023): enter

Created a new partition 2 of type 'Linux' and of size 3,6 GiB.

Command (m for help): t
Partition number (1,2, default 2): 1
Partition type (type L to list all types): e

Changed type of partition 'Linux' to 'W95 FAT16 (LBA)'.

Command (m for help): t
Partition number (1,2, default 2): 2
Partition type (type L to list all types): 83

Changed type of partition 'Linux' to 'Linux'.

Command (m for help): a
Partition number (1,2, default 2): 1

The bootable flag on partition 1 is enabled now.

Command (m for help): w
The partition table has been altered.
Syncing disks.

The partition table has now been written to the file. The result can be verified by running fdisk list command.

~$ fdisk -u -l mem_file
Disk mem_file: 3,6 GiB, 3867148288 bytes, 7553024 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xe648bbde

Device     Boot Start     End Sectors  Size Id Type
mem_file1  *     2048   22527   20480   10M  e W95 FAT16 (LBA)
mem_file2       22528 7553023 7530496  3,6G 83 Linux

Finally the MBR needs to be picked up from the beginning of the file.

# Collect MBR from the beginning of "disk" and write it to file
dd if=mem_file of=mbr.bin bs=512 count=1

The MBR binary is now ready to be flashed to the actual memory device, to sector 0. The fdisk also prints the sector addresses for the created partitions (sector 2048 = address 0x100000 and sector 22528 = address 0xB00000). The filesystem binaries can be flashed to these addresses.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s