How to create an MBR-compatible bootloader on macOS?
Or at least on Linux?
I have a file /Users/elisey/Downloads/OS/2/Bootloader, and I want to create a hard disk for QEMU with MBR and FAT16, so that it uses my bootloader and is mountable (so that I can copy files).
How can I do this?
Creating an MBR-Compatible Bootloader for QEMU with FAT16 Filesystem on macOS or Linux
Creating an MBR-compatible bootloader for QEMU with a FAT16 filesystem on macOS or Linux can be done using the command line. The main process involves creating an empty disk image, setting up an MBR with a partition table, formatting to FAT16, copying your bootloader to the boot sector, and adding files. On macOS, the built-in tools dd and diskutil are available, while Linux offers dd, fdisk, and mkfs.vfat.
Table of Contents
- Necessary Tools for macOS
- Step-by-Step Instructions for macOS
- Alternative Method for Linux
- QEMU Configuration for Booting
- Adding Files to the Image
- Solving Common Problems
- Detailed MBR and FAT16 Structure
Necessary Tools for macOS
On macOS, you already have all the necessary tools for creating a bootable MBR image with FAT16:
dd- for creating disk images and writing MBRdiskutil- for formatting partitions to FAT16hdiutil- for mounting imagesfdisk(viafdisk_fdiskorgptfdiskfrom Homebrew)
If you need fdisk, install it via Homebrew:
brew install gptfdisk
Step-by-Step Instructions for macOS
1. Creating an Empty Disk Image
First, create an empty image of the desired size. For this example, we’ll create a 32 MB image:
dd if=/dev/zero of=mydisk.img bs=1M count=32
2. Creating MBR with Partition Table
Now, let’s create an MBR and partition table. In the MBR, we’ll define one active FAT16 partition:
# Create MBR with active FAT16 partition
(
echo "g" # Create GPT (for compatibility)
echo "n" # New partition
echo "1" # Partition number
echo "" # Starting sector (default)
echo "+31M" # Partition size
echo "t" # Change partition type
echo "1" # Select partition 1
echo "06" # FAT16 type (0x06)
echo "a" # Make partition active
echo "w" # Write changes
echo "y" # Confirm overwrite
) | fdisk mydisk.img
3. Copying Bootloader to MBR
Now, copy your bootloader to the first sector of the disk:
dd if=/Users/elisey/Downloads/OS/2/Bootloader of=mydisk.img conv=notrunc bs=512 count=1
4. Formatting Partition to FAT16
Use diskutil to format the partition to FAT16:
# Attach the image as a device
diskutil attach mydisk.img
# Get the device name (e.g., /dev/disk4)
# Format the partition to FAT16
diskutil partitiondisk /dev/disk4 1 MBR "MS-DOS FAT16" "MYDISK" 0B
# Detach the device
diskutil detach /dev/disk4
5. Mounting the Image to Add Files
Mount the image to copy files:
hdiutil attach mydisk.img
After this, the FAT16 filesystem will be accessible as a regular volume where you can copy files.
Alternative Method for Linux
If you have access to Linux, the process can be simpler:
1. Creating the Image
dd if=/dev/zero of=mydisk.img bs=1M count=32
2. Creating MBR and Partitions
# Create MBR with fdisk
(
echo "o" # Create empty MBR table
echo "n" # New partition
echo "p" # Primary partition
echo "1" # Partition number
echo "" # Starting sector
echo "" # Ending sector (to end of disk)
echo "a" # Make active
echo "w" # Write
) | fdisk mydisk.img
3. Copying the Bootloader
dd if=/Users/elisey/Downloads/OS/2/Bootloader of=mydisk.img conv=notrunc bs=512 count=1
4. Formatting to FAT16
# Determine partition offset (usually 2048 sectors of 512 bytes)
OFFSET=1048576 # 2048 * 512
# Create loop device
sudo losetup -o $OFFSET --sizelimit $((31*1024*1024)) -f mydisk.img
# Format to FAT16
sudo mkfs.vfat -F 16 /dev/loop0
# Mount
sudo mount /dev/loop0 /mnt
# Copy files
sudo cp -r /path/to/your/files /mnt/
# Unmount
sudo umount /dev/loop0
sudo losetup -d /dev/loop0
QEMU Configuration for Booting
To use your image in QEMU, use the following command:
qemu-system-x86_64 -drive file=mydisk.img,format=raw,if=ide -m 512M
Or for more precise simulation:
qemu-system-i386 -drive file=mydisk.img,format=raw,if=floppy -m 512M
Adding Files to the Image
After creating the image, you can add files in several ways:
Through macOS:
# Mount the image
hdiutil attach mydisk.img
# Copy files to the mounted volume
cp -r /path/to/files /Volumes/MYDISK/
# Unmount
hdiutil detach /Volumes/MYDISK
Through Linux:
# Create loop device
sudo losetup -o 1048576 --sizelimit $((31*1024*1024)) -f mydisk.img
# Mount
sudo mount /dev/loop0 /mnt
# Copy files
sudo cp -r /path/to/files /mnt/
# Unmount
sudo umount /dev/loop0
sudo losetup -d /dev/loop0
Solving Common Problems
Problem: QEMU doesn’t boot from the image
Solution: Check that:
- The bootloader is in the first 512 bytes of the image
- The partition is marked as active (bootable flag)
- There’s an MBR signature of 0xAA55 at the end
Check MBR:
# On macOS
diskutil info mydisk.img
# Or manually
hexdump -C mydisk.img | tail -n 1
# Should see: 0003e000 aa 55 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |.U.............|
Problem: Filesystem doesn’t mount
Solution: There might be an issue with partition alignment. Ensure the partition starts at the correct sector (usually sector 2048 for 4K alignment):
# Check partition structure
fdisk -l mydisk.img
Problem: Bootloader doesn’t work
Solution: Check that your bootloader is correctly copied and maintains the MBR structure. The bootloader should:
- Be exactly 512 bytes
- Contain the correct signature at the end
- Properly handle BIOS interrupts
Detailed MBR and FAT16 Structure
MBR Structure (512 bytes):
Bytes 0-445: Bootloader code
Bytes 446-510: Partition table (4 entries of 16 bytes each)
Bytes 510-511: MBR signature (0xAA55)
Partition Table Structure (16 bytes):
Byte 0: Active flag (0x80 for active)
Bytes 1-3: Starting CHS
Byte 4: Partition type (0x06 for FAT16)
Bytes 5-7: Ending CHS
Bytes 8-11: Starting LBA
Bytes 12-15: Partition size in sectors
FAT16 Bootable Volume Structure:
- MBR (512 bytes) with your bootloader
- VBR (Volume Boot Record) - 512 bytes, including BPB (BIOS Parameter Block)
- Reserved sectors - usually 1 sector
- FAT tables (2 copies)
- Root directory
- Data area
To create a fully compatible image, ensure your bootloader maintains the MBR structure and properly handles the transition to VBR code when necessary.
Sources
- Creating bootable FreeDOS DOS floppy diskette IMG file for V86 on OSX
- How to create SD card .img and add files to it in linux (fat16)?
- Bootable FAT16 Image - OSDev.org
- How do I create an MBR on a USB stick using DD command line tool
- Creating and using disk images mini-howto
- How To Create Disk Image on Mac OS X With dd Command
- Disk Images — QEMU documentation
- Booting from real (UEFI) disk image on QEMU
Conclusion
Creating an MBR-compatible bootloader for QEMU with a FAT16 filesystem on macOS is a feasible task using standard command-line utilities. The key steps include:
- Creating an empty image using
dd - Setting up MBR and partition table via
fdiskordiskutil - Copying the bootloader to the first 512 bytes of the image
- Formatting the partition to FAT16 using
mkfs.vfatordiskutil - Mounting the image to add files
On macOS, the process is slightly more complex due to limited built-in tools, but it’s fully achievable. For more convenient work, it’s recommended to install gptfdisk via Homebrew. If you encounter booting issues, check the correctness of the MBR signature (0xAA55) and the active partition flag.
For experimenting with booting, you might also consider using simpler formats like hybrid images or ISOs, but MBR+FAT16 remains the most universal solution for QEMU bootable images.