commit 9ff35b028aa13ebe40ab84158d22faa85a5bf20d Author: Leonid Krivoshein Date: Fri Mar 23 00:58:26 2018 +0300 Add description for MBR/GPT and boot flag detection diff --git a/rpm/extlinux-config b/rpm/extlinux-config index db90250..3562736 100755 --- a/rpm/extlinux-config +++ b/rpm/extlinux-config @@ -39,12 +39,18 @@ print_version() { exit } +# Read 32-bit little-endian from GPT header and output its as decimal number. +# GPT header begins in the second sector of the disk. $1 is offset. +# read_gpt() { local offset=$(($sector_size + $1)) dd if="$dev" bs=1 skip=$offset count=4 2>/dev/null | hexdump '-e"%u"' } +# Read single byte from partition table element and output its as decimal number. +# GPT partition table begins in the third sector of the disk. $1 is offset. +# read_entry() { local offset=$(($sector_size * 2 + $1)) local x="$(dd if="$dev" bs=1 skip=$offset count=1 2>/dev/null)" @@ -106,13 +112,24 @@ verbose "Device name: $dev" verbose "Partition number: $partition" verbose "Sector size: $sector_size" +# +# First, 2-bytes MBR-signature at address 510 (end of the first sector) is read. +# It should be read as 0x55, 0xAA. +# https://en.wikipedia.org/wiki/Master_boot_record#Sector_layout +# magic="$(dd if="$dev" bs=2 skip=255 count=1 2>/dev/null | base64)" [ "$magic" = "Vao=" ] || fatal "Unknown partition table" -magic="$(dd if="$dev" bs=8 skip=64 count=1 2>/dev/null)" +# +# Then 8-bytes GPT-signature "EFI PART" is checked at the beginning of the second +# sector of the disk. +# https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_table_header_(LBA_1) +# +magic="$(dd if="$dev" bs=1 skip=$sector_size count=8 2>/dev/null)" if [ "$magic" = "EFI PART" ]; then partition_table='gpt' + # Number of partition entries, 4 bytes little-endian. magic=$(read_gpt 80) else partition_table='msdos' @@ -125,16 +142,26 @@ verbose "Partition table: $partition_table" fatal "invalid partition number: $partition" if [ "$partition_table" = "msdos" ]; then + # MBR partition table starts at offset 446. + # Each element of the table occupying 16 bytes. magic=$((16 * ($partition - 1) + 446)) magic="$(dd if="$dev" bs=1 skip=$magic count=1 2>/dev/null | base64)" + # First byte of the element is 0x80 for the boot partition. + # https://en.wikipedia.org/wiki/Master_boot_record#PTE [ "$magic" = "gA==" ] || fatal "partition not bootable" mbr_bin='mbr.bin' else + # Size of a single partition entry, 4 bytes little-endian. magic=$(read_gpt 84) + # Attribute flags (8 bytes little-endian) starts at offset 48 of the entry. + # https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_entries_(LBA_2-33) magic=$(($magic * ($partition - 1) + 48)) + # We interested only low byte of the attribute flags and only bit "2" (mask 0x04). magic=$(read_entry $magic) magic=$(($magic & 4)) + # If the bit "2" of the attribute flags is set, + # partition is marked as bootable in the Legacy BIOS. [ "$magic" = "4" ] || fatal "partition not bootable" mbr_bin='gptmbr.bin'