Index: src/platform/vboot_reference/utility/cgpt/cgpt_tofix.c |
diff --git a/src/platform/vboot_reference/utility/cgpt/cgpt_tofix.c b/src/platform/vboot_reference/utility/cgpt/cgpt_tofix.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..50aed529d99995ee4eb44432deab5f8d8fbd2a02 |
--- /dev/null |
+++ b/src/platform/vboot_reference/utility/cgpt/cgpt_tofix.c |
@@ -0,0 +1,269 @@ |
+/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ * |
+ * Functions to fix, after cgptlib cleanup. |
+ */ |
+#include <getopt.h> |
+#include <stdio.h> |
+#include <stdlib.h> |
+#include "cgpt.h" |
+#include "cgptlib_internal.h" |
+#include "cgpt_tofix.h" |
+#include "crc32.h" |
+#include "utility.h" |
+ |
+const char *GptError(int errno) { |
+ const char *error_string[] = { |
+ /* GPT_SUCCESS */ "Success", |
+ /* GPT_ERROR_NO_VALID_KERNEL */ "No valid kernel entry", |
+ /* GPT_ERROR_INVALID_HEADERS */ "Both primary and secondary headers are " |
+ "invalid.", |
+ /* GPT_ERROR_INVALID_ENTRIES */ "Both primary and secondary entries are " |
+ "invalid.", |
+ /* GPT_ERROR_INVALID_SECTOR_SIZE */ "Invalid sector size", |
+ /* GPT_ERROR_INVALID_SECTOR_NUMBER */ "Invalid sector number", |
+ /* GPT_ERROR_INVALID_UPDATE_TYPE */ "Invalid update type", |
+ }; |
+ return error_string[errno]; |
+} |
+ |
+ |
+/* Update CRC value if necessary. */ |
+void UpdateCrc(GptData *gpt) { |
+ GptHeader *primary_header, *secondary_header; |
+ |
+ primary_header = (GptHeader*)gpt->primary_header; |
+ secondary_header = (GptHeader*)gpt->secondary_header; |
+ |
+ if (gpt->modified & GPT_MODIFIED_ENTRIES1) { |
+ primary_header->entries_crc32 = |
+ Crc32(gpt->primary_entries, TOTAL_ENTRIES_SIZE); |
+ } |
+ if (gpt->modified & GPT_MODIFIED_ENTRIES2) { |
+ secondary_header->entries_crc32 = |
+ Crc32(gpt->secondary_entries, TOTAL_ENTRIES_SIZE); |
+ } |
+ if (gpt->modified & GPT_MODIFIED_HEADER1) { |
+ primary_header->header_crc32 = 0; |
+ primary_header->header_crc32 = Crc32( |
+ (const uint8_t *)primary_header, primary_header->size); |
+ } |
+ if (gpt->modified & GPT_MODIFIED_HEADER2) { |
+ secondary_header->header_crc32 = 0; |
+ secondary_header->header_crc32 = Crc32( |
+ (const uint8_t *)secondary_header, secondary_header->size); |
+ } |
+} |
+ |
+/* Helper function to get a pointer to the partition entry. |
+ * 'secondary' is either PRIMARY or SECONDARY. |
+ * 'entry_index' is the partition index: [0, number_of_entries). |
+ */ |
+GptEntry *GetEntry(GptData *gpt, int secondary, int entry_index) { |
+ uint8_t *entries; |
+ |
+ if (secondary == PRIMARY) { |
+ entries = gpt->primary_entries; |
+ } else { |
+ entries = gpt->secondary_entries; |
+ } |
+ |
+ return (GptEntry*)(&entries[GetNumberOfEntries(gpt) * entry_index]); |
+} |
+ |
+/* The following functions are helpers to access attributes bit more easily. |
+ * 'secondary' is either PRIMARY or SECONDARY. |
+ * 'entry_index' is the partition index: [0, number_of_entries). |
+ * |
+ * Get*() return the exact value (shifted and masked). |
+ */ |
+void SetPriority(GptData *gpt, int secondary, int entry_index, int priority) { |
+ GptEntry *entry; |
+ entry = GetEntry(gpt, secondary, entry_index); |
+ |
+ assert(priority >= 0 && priority <= CGPT_ATTRIBUTE_MAX_PRIORITY); |
+ entry->attributes &= ~CGPT_ATTRIBUTE_PRIORITY_MASK; |
+ entry->attributes |= (uint64_t)priority << CGPT_ATTRIBUTE_PRIORITY_OFFSET; |
+} |
+ |
+int GetPriority(GptData *gpt, int secondary, int entry_index) { |
+ GptEntry *entry; |
+ entry = GetEntry(gpt, secondary, entry_index); |
+ return (entry->attributes & CGPT_ATTRIBUTE_PRIORITY_MASK) >> |
+ CGPT_ATTRIBUTE_PRIORITY_OFFSET; |
+} |
+ |
+void SetBad(GptData *gpt, int secondary, int entry_index, int bad) { |
+ GptEntry *entry; |
+ entry = GetEntry(gpt, secondary, entry_index); |
+ |
+ // There is no bad attribute |
+ assert(0); |
+} |
+ |
+int GetBad(GptData *gpt, int secondary, int entry_index) { |
+ GptEntry *entry; |
+ entry = GetEntry(gpt, secondary, entry_index); |
+ |
+ // There is no bad attribute |
+ assert(0); |
+ return 0; |
+} |
+ |
+void SetTries(GptData *gpt, int secondary, int entry_index, int tries) { |
+ GptEntry *entry; |
+ entry = GetEntry(gpt, secondary, entry_index); |
+ |
+ assert(tries >= 0 && tries <= CGPT_ATTRIBUTE_MAX_TRIES); |
+ entry->attributes &= ~CGPT_ATTRIBUTE_TRIES_MASK; |
+ entry->attributes |= (uint64_t)tries << CGPT_ATTRIBUTE_TRIES_OFFSET; |
+} |
+ |
+int GetTries(GptData *gpt, int secondary, int entry_index) { |
+ GptEntry *entry; |
+ entry = GetEntry(gpt, secondary, entry_index); |
+ return (entry->attributes & CGPT_ATTRIBUTE_TRIES_MASK) >> |
+ CGPT_ATTRIBUTE_TRIES_OFFSET; |
+} |
+ |
+void SetSuccessful(GptData *gpt, int secondary, int entry_index, int success) { |
+ GptEntry *entry; |
+ entry = GetEntry(gpt, secondary, entry_index); |
+ |
+ assert(success >= 0 && success <= CGPT_ATTRIBUTE_MAX_SUCCESSFUL); |
+ entry->attributes &= ~CGPT_ATTRIBUTE_SUCCESSFUL_MASK; |
+ entry->attributes |= (uint64_t)success << CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET; |
+} |
+ |
+int GetSuccessful(GptData *gpt, int secondary, int entry_index) { |
+ GptEntry *entry; |
+ entry = GetEntry(gpt, secondary, entry_index); |
+ return (entry->attributes & CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >> |
+ CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET; |
+} |
+ |
+uint32_t GetNumberOfEntries(const GptData *gpt) { |
+ GptHeader *header = 0; |
+ if (gpt->valid_headers & MASK_PRIMARY) |
+ header = (GptHeader*)gpt->primary_header; |
+ else if (gpt->valid_headers & MASK_SECONDARY) |
+ header = (GptHeader*)gpt->secondary_header; |
+ else |
+ assert(0); |
+ return header->number_of_entries; |
+} |
+ |
+/* Two headers are NOT bitwise identical. For example, my_lba pointers to header |
+ * itself so that my_lba in primary and secondary is definitely different. |
+ * Only the following fields should be identical. |
+ * |
+ * first_usable_lba |
+ * last_usable_lba |
+ * number_of_entries |
+ * size_of_entry |
+ * disk_uuid |
+ * |
+ * If any of above field are not matched, overwrite secondary with primary since |
+ * we always trust primary. |
+ * If any one of header is invalid, copy from another. */ |
+int IsSynonymous(const GptHeader* a, const GptHeader* b) { |
+ if ((a->first_usable_lba == b->first_usable_lba) && |
+ (a->last_usable_lba == b->last_usable_lba) && |
+ (a->number_of_entries == b->number_of_entries) && |
+ (a->size_of_entry == b->size_of_entry) && |
+ (!Memcmp(&a->disk_uuid, &b->disk_uuid, sizeof(Guid)))) |
+ return 1; |
+ return 0; |
+} |
+ |
+/* Primary entries and secondary entries should be bitwise identical. |
+ * If two entries tables are valid, compare them. If not the same, |
+ * overwrites secondary with primary (primary always has higher priority), |
+ * and marks secondary as modified. |
+ * If only one is valid, overwrites invalid one. |
+ * If all are invalid, does nothing. |
+ * This function returns bit masks for GptData.modified field. |
+ * Note that CRC is NOT re-computed in this function. |
+ */ |
+uint8_t RepairEntries(GptData *gpt, const uint32_t valid_entries) { |
+ 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); |
+ return GPT_MODIFIED_ENTRIES2; |
+ } |
+ } else if (valid_entries == MASK_PRIMARY) { |
+ Memcpy(gpt->secondary_entries, gpt->primary_entries, TOTAL_ENTRIES_SIZE); |
+ return GPT_MODIFIED_ENTRIES2; |
+ } else if (valid_entries == MASK_SECONDARY) { |
+ Memcpy(gpt->primary_entries, gpt->secondary_entries, TOTAL_ENTRIES_SIZE); |
+ return GPT_MODIFIED_ENTRIES1; |
+ } |
+ |
+ return 0; |
+} |
+ |
+/* The above five fields are shared between primary and secondary headers. |
+ * We can recover one header from another through copying those fields. */ |
+void CopySynonymousParts(GptHeader* target, const GptHeader* source) { |
+ target->first_usable_lba = source->first_usable_lba; |
+ target->last_usable_lba = source->last_usable_lba; |
+ target->number_of_entries = source->number_of_entries; |
+ target->size_of_entry = source->size_of_entry; |
+ Memcpy(&target->disk_uuid, &source->disk_uuid, sizeof(Guid)); |
+} |
+ |
+/* This function repairs primary and secondary headers if possible. |
+ * If both headers are valid (CRC32 is correct) but |
+ * a) indicate inconsistent usable LBA ranges, |
+ * b) inconsistent partition entry size and number, |
+ * c) inconsistent disk_uuid, |
+ * we will use the primary header to overwrite secondary header. |
+ * If primary is invalid (CRC32 is wrong), then we repair it from secondary. |
+ * If secondary is invalid (CRC32 is wrong), then we repair it from primary. |
+ * This function returns the bitmasks for modified header. |
+ * Note that CRC value is NOT re-computed in this function. UpdateCrc() will |
+ * do it later. |
+ */ |
+uint8_t RepairHeader(GptData *gpt, const uint32_t valid_headers) { |
+ GptHeader *primary_header, *secondary_header; |
+ |
+ primary_header = (GptHeader*)gpt->primary_header; |
+ secondary_header = (GptHeader*)gpt->secondary_header; |
+ |
+ if (valid_headers == MASK_BOTH) { |
+ if (!IsSynonymous(primary_header, secondary_header)) { |
+ CopySynonymousParts(secondary_header, primary_header); |
+ return GPT_MODIFIED_HEADER2; |
+ } |
+ } else if (valid_headers == MASK_PRIMARY) { |
+ Memcpy(secondary_header, primary_header, primary_header->size); |
+ secondary_header->my_lba = gpt->drive_sectors - 1; /* the last sector */ |
+ secondary_header->entries_lba = secondary_header->my_lba - |
+ GPT_ENTRIES_SECTORS; |
+ return GPT_MODIFIED_HEADER2; |
+ } else if (valid_headers == MASK_SECONDARY) { |
+ Memcpy(primary_header, secondary_header, secondary_header->size); |
+ primary_header->my_lba = GPT_PMBR_SECTOR; /* the second sector on drive */ |
+ primary_header->entries_lba = primary_header->my_lba + GPT_HEADER_SECTOR; |
+ return GPT_MODIFIED_HEADER1; |
+ } |
+ |
+ return 0; |
+} |
+ |
+/* TODO: HORRIBLY broken non-implemented functions. These will be |
+ * fixed as part of a second stage of refactoring to use the new |
+ * cgptlib_internal functions. */ |
+uint32_t CheckOverlappedPartition(GptData *gpt) { |
+ return 1; |
+} |
+ |
+uint32_t CheckValidEntries(GptData *gpt) { |
+ return 1; |
+} |
+ |
+int NonZeroGuid(const Guid *guid) { |
+ return 1; |
+} |