mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-24 10:14:55 +00:00
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>
This commit is contained in:
committed by
chrome-internal-fetch
parent
32a999d2c0
commit
3200401242
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user