summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNam T. Nguyen <namnguyen@chromium.org>2014-12-12 09:38:35 -0800
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-12-12 23:15:08 +0000
commit3200401242aec1521e7c4a8b1906366fcabfb1a2 (patch)
tree9e26df71f99eb92a09871ad64d66236d133cbe4d
parent32a999d2c0e5bf8a1c0f6141d3db77a1dcc6f5af (diff)
downloadvboot-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.c41
-rw-r--r--cgpt/cgpt_create.c35
-rw-r--r--cgpt/cgpt_show.c7
-rw-r--r--firmware/lib/cgptlib/cgptlib_internal.c23
-rw-r--r--firmware/lib/cgptlib/include/cgptlib_internal.h12
-rw-r--r--tests/cgptlib_test.c7
-rwxr-xr-xtests/run_cgpt_tests.sh6
-rw-r--r--tests/vboot_kernel_tests.c6
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);
}