diff options
author | Nam T. Nguyen <namnguyen@chromium.org> | 2014-12-12 09:38:35 -0800 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-12-12 23:15:08 +0000 |
commit | 3200401242aec1521e7c4a8b1906366fcabfb1a2 (patch) | |
tree | 9e26df71f99eb92a09871ad64d66236d133cbe4d | |
parent | 32a999d2c0e5bf8a1c0f6141d3db77a1dcc6f5af (diff) | |
download | vboot-3200401242aec1521e7c4a8b1906366fcabfb1a2.tar.gz |
cgpt: Support non-standard (smaller) entries table
The standard says that entries table must be at least 16384 bytes. On
some of our devices, the NOR section is only 8 KiB and used to store
both primary and secondary tables. On this device, we can only store 24
entries.
Therefore, this CL adds support for non-standard entry table. It adjusts
the MIN_NUMBER_OF_ENTRIES to 16, and replaces GPT_ENTRIES_SECTORS with
CalculateEntriesSectors.
BUG=chromium:441812
BRANCH=none
TEST=unittest
Change-Id: I6b85b35ce5612c7abb22142f8252bd0d45b676c5
Reviewed-on: https://chromium-review.googlesource.com/234996
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
Commit-Queue: Nam Nguyen <namnguyen@chromium.org>
Tested-by: Nam Nguyen <namnguyen@chromium.org>
-rw-r--r-- | cgpt/cgpt_common.c | 41 | ||||
-rw-r--r-- | cgpt/cgpt_create.c | 35 | ||||
-rw-r--r-- | cgpt/cgpt_show.c | 7 | ||||
-rw-r--r-- | firmware/lib/cgptlib/cgptlib_internal.c | 23 | ||||
-rw-r--r-- | firmware/lib/cgptlib/include/cgptlib_internal.h | 12 | ||||
-rw-r--r-- | tests/cgptlib_test.c | 7 | ||||
-rwxr-xr-x | tests/run_cgpt_tests.sh | 6 | ||||
-rw-r--r-- | tests/vboot_kernel_tests.c | 6 |
8 files changed, 89 insertions, 48 deletions
diff --git a/cgpt/cgpt_common.c b/cgpt/cgpt_common.c index b580e33a..ffaa3090 100644 --- a/cgpt/cgpt_common.c +++ b/cgpt/cgpt_common.c @@ -176,7 +176,8 @@ static int GptLoad(struct drive *drive, uint32_t sector_bytes) { drive->gpt.flags) == 0) { if (CGPT_OK != Load(drive, &drive->gpt.primary_entries, primary_header->entries_lba, - drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) { + drive->gpt.sector_bytes, + CalculateEntriesSectors(primary_header))) { Error("Cannot read primary partition entry array\n"); return -1; } @@ -189,7 +190,8 @@ static int GptLoad(struct drive *drive, uint32_t sector_bytes) { drive->gpt.flags) == 0) { if (CGPT_OK != Load(drive, &drive->gpt.secondary_entries, secondary_header->entries_lba, - drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) { + drive->gpt.sector_bytes, + CalculateEntriesSectors(secondary_header))) { Error("Cannot read secondary partition entry array\n"); return -1; } @@ -222,7 +224,8 @@ static int GptSave(struct drive *drive) { if (drive->gpt.modified & GPT_MODIFIED_ENTRIES1) { if (CGPT_OK != Save(drive, drive->gpt.primary_entries, primary_header->entries_lba, - drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) { + drive->gpt.sector_bytes, + CalculateEntriesSectors(primary_header))) { errors++; Error("Cannot write primary entries: %s\n", strerror(errno)); } @@ -231,7 +234,8 @@ static int GptSave(struct drive *drive) { if (drive->gpt.modified & GPT_MODIFIED_ENTRIES2) { if (CGPT_OK != Save(drive, drive->gpt.secondary_entries, secondary_header->entries_lba, - drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) { + drive->gpt.sector_bytes, + CalculateEntriesSectors(secondary_header))) { errors++; Error("Cannot write secondary entries: %s\n", strerror(errno)); } @@ -808,12 +812,16 @@ void UpdateCrc(GptData *gpt) { if (gpt->modified & GPT_MODIFIED_ENTRIES1 && memcmp(primary_header, GPT_HEADER_SIGNATURE2, GPT_HEADER_SIGNATURE_SIZE)) { + size_t entries_size = primary_header->size_of_entry * + primary_header->number_of_entries; primary_header->entries_crc32 = - Crc32(gpt->primary_entries, TOTAL_ENTRIES_SIZE); + Crc32(gpt->primary_entries, entries_size); } if (gpt->modified & GPT_MODIFIED_ENTRIES2) { + size_t entries_size = secondary_header->size_of_entry * + secondary_header->number_of_entries; secondary_header->entries_crc32 = - Crc32(gpt->secondary_entries, TOTAL_ENTRIES_SIZE); + Crc32(gpt->secondary_entries, entries_size); } if (gpt->modified & GPT_MODIFIED_HEADER1) { primary_header->header_crc32 = 0; @@ -867,17 +875,26 @@ uint8_t RepairEntries(GptData *gpt, const uint32_t valid_entries) { if (!memcmp(h->signature, GPT_HEADER_SIGNATURE2, GPT_HEADER_SIGNATURE_SIZE)) return 0; + if (gpt->valid_headers & MASK_PRIMARY) { + h = (GptHeader*)gpt->primary_header; + } else if (gpt->valid_headers & MASK_SECONDARY) { + h = (GptHeader*)gpt->secondary_header; + } else { + /* We cannot trust any header, don't update entries. */ + return 0; + } + + size_t entries_size = h->number_of_entries * h->size_of_entry; if (valid_entries == MASK_BOTH) { - if (memcmp(gpt->primary_entries, gpt->secondary_entries, - TOTAL_ENTRIES_SIZE)) { - memcpy(gpt->secondary_entries, gpt->primary_entries, TOTAL_ENTRIES_SIZE); + if (memcmp(gpt->primary_entries, gpt->secondary_entries, entries_size)) { + memcpy(gpt->secondary_entries, gpt->primary_entries, entries_size); return GPT_MODIFIED_ENTRIES2; } } else if (valid_entries == MASK_PRIMARY) { - memcpy(gpt->secondary_entries, gpt->primary_entries, TOTAL_ENTRIES_SIZE); + memcpy(gpt->secondary_entries, gpt->primary_entries, entries_size); return GPT_MODIFIED_ENTRIES2; } else if (valid_entries == MASK_SECONDARY) { - memcpy(gpt->primary_entries, gpt->secondary_entries, TOTAL_ENTRIES_SIZE); + memcpy(gpt->primary_entries, gpt->secondary_entries, entries_size); return GPT_MODIFIED_ENTRIES1; } @@ -922,7 +939,7 @@ uint8_t RepairHeader(GptData *gpt, const uint32_t valid_headers) { secondary_header->my_lba = gpt->gpt_drive_sectors - 1; /* the last sector */ secondary_header->alternate_lba = primary_header->my_lba; secondary_header->entries_lba = secondary_header->my_lba - - GPT_ENTRIES_SECTORS; + CalculateEntriesSectors(primary_header); return GPT_MODIFIED_HEADER2; } else if (valid_headers == MASK_SECONDARY) { memcpy(primary_header, secondary_header, sizeof(GptHeader)); diff --git a/cgpt/cgpt_create.c b/cgpt/cgpt_create.c index 2265c8f9..64f3f4d2 100644 --- a/cgpt/cgpt_create.c +++ b/cgpt/cgpt_create.c @@ -29,10 +29,6 @@ static int GptCreate(struct drive *drive, CgptCreateParams *params) { drive->gpt.sector_bytes * GPT_HEADER_SECTORS); AllocAndClear(&drive->gpt.secondary_header, drive->gpt.sector_bytes * GPT_HEADER_SECTORS); - AllocAndClear(&drive->gpt.primary_entries, - drive->gpt.sector_bytes * GPT_ENTRIES_SECTORS); - AllocAndClear(&drive->gpt.secondary_entries, - drive->gpt.sector_bytes * GPT_ENTRIES_SECTORS); drive->gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 | GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2); @@ -45,21 +41,12 @@ static int GptCreate(struct drive *drive, CgptCreateParams *params) { h->size = sizeof(GptHeader); h->my_lba = GPT_PMBR_SECTORS; /* The second sector on drive. */ h->alternate_lba = drive->gpt.gpt_drive_sectors - GPT_HEADER_SECTORS; - h->entries_lba = h->my_lba + GPT_HEADER_SECTORS; - if (!(drive->gpt.flags & GPT_FLAG_EXTERNAL)) { - h->entries_lba += params->padding; - h->first_usable_lba = h->entries_lba + GPT_ENTRIES_SECTORS; - h->last_usable_lba = (drive->gpt.streaming_drive_sectors - - GPT_HEADER_SECTORS - - GPT_ENTRIES_SECTORS - 1); - } else { - h->first_usable_lba = params->padding; - h->last_usable_lba = (drive->gpt.streaming_drive_sectors - 1); - } if (CGPT_OK != GenerateGuid(&h->disk_uuid)) { Error("Unable to generate new GUID.\n"); return -1; } + + /* Calculate number of entries */ h->size_of_entry = sizeof(GptEntry); h->number_of_entries = TOTAL_ENTRIES_SIZE / h->size_of_entry; if (drive->gpt.flags & GPT_FLAG_EXTERNAL) { @@ -69,7 +56,7 @@ static int GptCreate(struct drive *drive, CgptCreateParams *params) { Error("Not enough space for a GPT header.\n"); return -1; } - half_size_sectors -= GPT_HEADER_SECTORS; + half_size_sectors -= (GPT_HEADER_SECTORS + GPT_PMBR_SECTORS); size_t half_size = half_size_sectors * drive->gpt.sector_bytes; if (half_size < (MIN_NUMBER_OF_ENTRIES * h->size_of_entry)) { Error("Not enough space for minimum number of entries.\n"); @@ -80,6 +67,22 @@ static int GptCreate(struct drive *drive, CgptCreateParams *params) { } } + /* Then use number of entries to calculate entries_lba. */ + h->entries_lba = h->my_lba + GPT_HEADER_SECTORS; + if (!(drive->gpt.flags & GPT_FLAG_EXTERNAL)) { + h->entries_lba += params->padding; + h->first_usable_lba = h->entries_lba + CalculateEntriesSectors(h); + h->last_usable_lba = (drive->gpt.streaming_drive_sectors - GPT_HEADER_SECTORS - + CalculateEntriesSectors(h) - 1); + } else { + h->first_usable_lba = params->padding; + h->last_usable_lba = (drive->gpt.streaming_drive_sectors - 1); + } + + size_t entries_size = h->number_of_entries * h->size_of_entry; + AllocAndClear(&drive->gpt.primary_entries, entries_size); + AllocAndClear(&drive->gpt.secondary_entries, entries_size); + // Copy to secondary RepairHeader(&drive->gpt, MASK_PRIMARY); diff --git a/cgpt/cgpt_show.c b/cgpt/cgpt_show.c index 68a185cb..143b5fa1 100644 --- a/cgpt/cgpt_show.c +++ b/cgpt/cgpt_show.c @@ -271,7 +271,7 @@ static int GptShow(struct drive *drive, CgptShowParams *params) { GptHeader* primary_header = (GptHeader*)drive->gpt.primary_header; printf(GPT_FMT, (int)primary_header->entries_lba, - (int)GPT_ENTRIES_SECTORS, + (int)CalculateEntriesSectors(primary_header), drive->gpt.valid_entries & MASK_PRIMARY ? "" : "INVALID", "Pri GPT table"); @@ -282,7 +282,7 @@ static int GptShow(struct drive *drive, CgptShowParams *params) { /****************************** Secondary *************************/ GptHeader* secondary_header = (GptHeader*)drive->gpt.secondary_header; printf(GPT_FMT, (int)secondary_header->entries_lba, - (int)GPT_ENTRIES_SECTORS, + (int)CalculateEntriesSectors(secondary_header), drive->gpt.valid_entries & MASK_SECONDARY ? "" : "INVALID", "Sec GPT table"); /* We show secondary table details if any of following is true. @@ -294,7 +294,8 @@ static int GptShow(struct drive *drive, CgptShowParams *params) { ((drive->gpt.valid_entries & MASK_SECONDARY) && (!(drive->gpt.valid_entries & MASK_PRIMARY) || memcmp(drive->gpt.primary_entries, drive->gpt.secondary_entries, - TOTAL_ENTRIES_SIZE)))) { + secondary_header->number_of_entries * + secondary_header->size_of_entry)))) { EntriesDetails(drive, SECONDARY, params->numeric); } diff --git a/firmware/lib/cgptlib/cgptlib_internal.c b/firmware/lib/cgptlib/cgptlib_internal.c index 5e2889c6..6a89d841 100644 --- a/firmware/lib/cgptlib/cgptlib_internal.c +++ b/firmware/lib/cgptlib/cgptlib_internal.c @@ -12,11 +12,18 @@ #include "gpt_misc.h" #include "utility.h" +const static int SECTOR_SIZE = 512; + +size_t CalculateEntriesSectors(GptHeader* h) { + size_t bytes = h->number_of_entries * h->size_of_entry; + size_t ret = (bytes + SECTOR_SIZE - 1) / SECTOR_SIZE; + return ret; +} int CheckParameters(GptData *gpt) { /* Currently, we only support 512-byte sectors. */ - if (gpt->sector_bytes != 512) + if (gpt->sector_bytes != SECTOR_SIZE) return GPT_ERROR_INVALID_SECTOR_SIZE; /* @@ -33,9 +40,11 @@ int CheckParameters(GptData *gpt) /* * Sector count of a drive should be reasonable. If the given value is * too small to contain basic GPT structure (PMBR + Headers + Entries), - * the value is wrong. + * the value is wrong. Entries size is hard coded to TOTAL_ENTRIES_SIZE (see + * cgpt_create.c). This check is only applicable when GPT is stored on device. */ - if (gpt->gpt_drive_sectors < (1 + 2 * (1 + GPT_ENTRIES_SECTORS))) + if (!(gpt->flags & GPT_FLAG_EXTERNAL) && + gpt->gpt_drive_sectors < (1 + 2 * (1 + TOTAL_ENTRIES_SIZE / SECTOR_SIZE))) return GPT_ERROR_INVALID_SECTOR_NUMBER; return GPT_SUCCESS; @@ -105,7 +114,7 @@ int CheckHeader(GptHeader *h, int is_secondary, if (is_secondary) { if (h->my_lba != gpt_drive_sectors - GPT_HEADER_SECTORS) return 1; - if (h->entries_lba != h->my_lba - GPT_ENTRIES_SECTORS) + if (h->entries_lba != h->my_lba - CalculateEntriesSectors(h)) return 1; } else { if (h->my_lba != GPT_PMBR_SECTORS) @@ -131,10 +140,10 @@ int CheckHeader(GptHeader *h, int is_secondary, * array. */ /* TODO(namnguyen): Also check for padding between header & entries. */ - if (h->first_usable_lba < 2 + GPT_ENTRIES_SECTORS) + if (h->first_usable_lba < 2 + CalculateEntriesSectors(h)) return 1; if (h->last_usable_lba >= - streaming_drive_sectors - 1 - GPT_ENTRIES_SECTORS) + streaming_drive_sectors - 1 - CalculateEntriesSectors(h)) return 1; /* Success */ @@ -321,7 +330,7 @@ void GptRepair(GptData *gpt) Memcpy(header2, header1, sizeof(GptHeader)); header2->my_lba = gpt->gpt_drive_sectors - GPT_HEADER_SECTORS; header2->alternate_lba = GPT_PMBR_SECTORS; /* Second sector. */ - header2->entries_lba = header2->my_lba - GPT_ENTRIES_SECTORS; + header2->entries_lba = header2->my_lba - CalculateEntriesSectors(header1); header2->header_crc32 = HeaderCrc(header2); gpt->modified |= GPT_MODIFIED_HEADER2; } diff --git a/firmware/lib/cgptlib/include/cgptlib_internal.h b/firmware/lib/cgptlib/include/cgptlib_internal.h index f88bc567..b4e2f5f9 100644 --- a/firmware/lib/cgptlib/include/cgptlib_internal.h +++ b/firmware/lib/cgptlib/include/cgptlib_internal.h @@ -51,17 +51,12 @@ #define MIN_SIZE_OF_ENTRY 128 #define MAX_SIZE_OF_ENTRY 512 #define SIZE_OF_ENTRY_MULTIPLE 8 -#define MIN_NUMBER_OF_ENTRIES 32 +#define MIN_NUMBER_OF_ENTRIES 16 #define MAX_NUMBER_OF_ENTRIES 512 /* Defines GPT sizes */ #define GPT_PMBR_SECTORS 1 /* size (in sectors) of PMBR */ #define GPT_HEADER_SECTORS 1 -/* - * Entries sectors assumes sector size if 512 bytes; then (TOTAL_ENTRIES_SIZE / - * 512) = 32 - */ -#define GPT_ENTRIES_SECTORS 32 /* * Alias name of index in internal array for primary and secondary header and @@ -163,4 +158,9 @@ void GetCurrentKernelUniqueGuid(GptData *gpt, void *dest); */ const char *GptErrorText(int error_code); +/** + * Return number of 512-byte sectors required to store the entries table. + */ +size_t CalculateEntriesSectors(GptHeader* h); + #endif /* VBOOT_REFERENCE_CGPTLIB_INTERNAL_H_ */ diff --git a/tests/cgptlib_test.c b/tests/cgptlib_test.c index e81f50e7..759fa500 100644 --- a/tests/cgptlib_test.c +++ b/tests/cgptlib_test.c @@ -247,7 +247,7 @@ static int ParameterTests(void) {512, 0, GPT_ERROR_INVALID_SECTOR_NUMBER}, {512, 66, GPT_ERROR_INVALID_SECTOR_NUMBER}, {512, GPT_PMBR_SECTORS + GPT_HEADER_SECTORS * 2 + - GPT_ENTRIES_SECTORS * 2, GPT_SUCCESS}, + TOTAL_ENTRIES_SIZE / DEFAULT_SECTOR_SIZE * 2, GPT_SUCCESS}, {4096, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE}, }; int i; @@ -537,6 +537,8 @@ static int NumberOfPartitionEntriesTest(void) BuildTestGptData(gpt); h1->number_of_entries--; h2->number_of_entries /= 2; + /* Because we halved h2 entries, its entries_lba is going to change. */ + h2->entries_lba = h2->my_lba - CalculateEntriesSectors(h2); RefreshCrc32(gpt); EXPECT(1 == CheckHeader(h1, 0, gpt->streaming_drive_sectors, gpt->gpt_drive_sectors, 0)); EXPECT(1 == CheckHeader(h2, 1, gpt->streaming_drive_sectors, gpt->gpt_drive_sectors, 0)); @@ -1460,6 +1462,9 @@ static int CheckHeaderOffDevice() BuildTestGptData(gpt); secondary_header->number_of_entries = 100; + /* Because we change number of entries, we need to also update entrie_lba. */ + secondary_header->entries_lba = secondary_header->my_lba - + CalculateEntriesSectors(secondary_header); RefreshCrc32(gpt); EXPECT(1 == CheckHeader(secondary_header, 1, gpt->streaming_drive_sectors, gpt->gpt_drive_sectors, 0)); diff --git a/tests/run_cgpt_tests.sh b/tests/run_cgpt_tests.sh index 6619a6b8..7170eef8 100755 --- a/tests/run_cgpt_tests.sh +++ b/tests/run_cgpt_tests.sh @@ -291,12 +291,17 @@ $CGPT find $MTD -t kernel ${DEV} >/dev/null # Enable write access again to test boundary in off device storage chmod 600 ${DEV} +# Create a small 8K file to simulate Flash NOR section +dd if=/dev/zero of=${DEV} bs=8K count=1 # Drive size is not multiple of 512 assert_fail $CGPT create -D 511 ${DEV} assert_fail $CGPT create -D 513 ${DEV} MTD="-D 1024" # Create a GPT table for a device of 1024 bytes (2 sectors) $CGPT create $MTD ${DEV} +# Make sure number of entries is reasonable for 8KiB GPT +X=$($CGPT show -D 1024 -d ${DEV} | grep -c "Number of entries: 24") +[ "$X" = "2" ] || error # This fails because header verification is off due to different drive size assert_fail $CGPT show ${DEV} # But this passes because we pass in correct drive size @@ -306,6 +311,7 @@ assert_fail $CGPT add $MTD -b 2 -s 1 -t data ${DEV} # This fails because partition size is over the size of the device assert_fail $CGPT add $MTD -b 0 -s 3 -t data ${DEV} + echo "Done." happy "All tests passed." diff --git a/tests/vboot_kernel_tests.c b/tests/vboot_kernel_tests.c index 6f47ae35..41ac7add 100644 --- a/tests/vboot_kernel_tests.c +++ b/tests/vboot_kernel_tests.c @@ -87,14 +87,14 @@ static void SetupGptHeader(GptHeader *h, int is_secondary) /* Set LBA pointers for primary or secondary header */ if (is_secondary) { h->my_lba = MOCK_SECTOR_COUNT - GPT_HEADER_SECTORS; - h->entries_lba = h->my_lba - GPT_ENTRIES_SECTORS; + h->entries_lba = h->my_lba - CalculateEntriesSectors(h); } else { h->my_lba = GPT_PMBR_SECTORS; h->entries_lba = h->my_lba + 1; } - h->first_usable_lba = 2 + GPT_ENTRIES_SECTORS; - h->last_usable_lba = MOCK_SECTOR_COUNT - 2 - GPT_ENTRIES_SECTORS; + h->first_usable_lba = 2 + CalculateEntriesSectors(h); + h->last_usable_lba = MOCK_SECTOR_COUNT - 2 - CalculateEntriesSectors(h); h->header_crc32 = HeaderCrc(h); } |