From 962483c1e27627aad843a2c394f11b830dd1ce02 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Tue, 15 Jun 2010 21:07:18 -0700 Subject: [PATCH] This fixes the EFI BIOS boot problems introduced with cgpt. There were two changes. First, we need to pack the GPT header to make it match the spec (duh). Second, there's a subtle bug in how the BIOS recovers from corrupted headers. The EFI spec says that the primary GPT header must be at sector 1 (counting from zero) and the secondary GPT header must be at the last sector on the drive. The BIOS correctly looks in those locations to find the headers. However, if the secondary GPT header is invalid (as it usually is due to our build process), the BIOS is supposed to update it from the primary header. In this case, rather than write to the last sector on the drive where it just looked, the BIOS trusts the alternate_lba field of the primary header. That field is supposed to point to the secondary header location, but the BIOS just blindly uses it no matter where it points. The cgpt tool wasn't initializing that field, so it pointed to sector 0, which is the PMBR. The BIOS overwrote that, resulting in an unbootable drive. Review URL: http://codereview.chromium.org/2844006 --- cgpt/cmd_create.c | 1 + cgpt/cmd_show.c | 1 + vboot_firmware/lib/cgptlib/include/gpt.h | 5 ++--- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cgpt/cmd_create.c b/cgpt/cmd_create.c index 4e6eb65361..1680370949 100644 --- a/cgpt/cmd_create.c +++ b/cgpt/cmd_create.c @@ -88,6 +88,7 @@ int cmd_create(int argc, char *argv[]) { h->revision = GPT_HEADER_REVISION; h->size = sizeof(GptHeader); h->my_lba = 1; + h->alternate_lba = drive.gpt.drive_sectors - 1; h->first_usable_lba = 1 + 1 + GPT_ENTRIES_SECTORS; h->last_usable_lba = drive.gpt.drive_sectors - 1 - GPT_ENTRIES_SECTORS - 1; uuid_generate((uint8_t *)&h->disk_uuid); diff --git a/cgpt/cmd_show.c b/cgpt/cmd_show.c index 9f52cb1d4b..91461490cf 100644 --- a/cgpt/cmd_show.c +++ b/cgpt/cmd_show.c @@ -95,6 +95,7 @@ static void HeaderDetails(GptHeader *header, const char *indent, int raw) { printf("%sSize: %d\n", indent, header->size); printf("%sHeader CRC: 0x%08x\n", indent, header->header_crc32); printf("%sMy LBA: %lld\n", indent, (long long)header->my_lba); + printf("%sAlternate LBA: %lld\n", indent, (long long)header->alternate_lba); printf("%sFirst LBA: %lld\n", indent, (long long)header->first_usable_lba); printf("%sLast LBA: %lld\n", indent, (long long)header->last_usable_lba); diff --git a/vboot_firmware/lib/cgptlib/include/gpt.h b/vboot_firmware/lib/cgptlib/include/gpt.h index 7a1d576849..4ba016c38c 100644 --- a/vboot_firmware/lib/cgptlib/include/gpt.h +++ b/vboot_firmware/lib/cgptlib/include/gpt.h @@ -79,13 +79,12 @@ typedef struct { uint64_t first_usable_lba; uint64_t last_usable_lba; Guid disk_uuid; - uint64_t entries_lba; uint32_t number_of_entries; uint32_t size_of_entry; uint32_t entries_crc32; uint8_t reserved_padding[]; /* entire sector reserved for header */ -} GptHeader; +} __attribute__((packed)) GptHeader; /* GPT partition entry defines the starting and ending LBAs of a partition. * It also contains the unique GUID, type, and attribute bits. @@ -100,6 +99,6 @@ typedef struct { uint64_t attributes; uint16_t name[36]; /* UTF-16 encoded partition name */ uint8_t reserved[]; /* nothing, really */ -} GptEntry; +} __attribute__((packed)) GptEntry; #endif /* VBOOT_REFERENCE_CGPTLIB_GPT_H_ */