diff options
author | Stefan Reinauer <reinauer@chromium.org> | 2012-08-23 15:06:25 -0700 |
---|---|---|
committer | Stefan Reinauer <reinauer@chromium.org> | 2012-10-05 10:29:44 -0700 |
commit | 7f0ed64577ee6c4e2088bc566868d35745211dc2 (patch) | |
tree | 29c21f83a20f088320d422ac82a55bb7256d685c | |
parent | 7aef73eff644e774ba74b9ed7677cbdccf3829f1 (diff) | |
download | vboot-7f0ed64577ee6c4e2088bc566868d35745211dc2.tar.gz |
Support alternative GPT header signature
In order to dual boot Windows and ChromeOS, Windows must
not find a GPT partition table on the disk. So change
ChromeOS to cope with an alternative signature "CHROMEOS"
instead of the standard "EFI PART"
BUG=chrome-os-partner:6108
TEST=rebuild chromeos, install it,
run cgpt legacy /dev/sda
dd if=/dev/sda of=/tmp/x bs=1k
hexdump -C /tmp/X
see the string CHROMEOS
BRANCH=link
Signed-off-by: Stefan Reinauer <reinauer@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/31264
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Commit-Ready: Stefan Reinauer <reinauer@chromium.org>
Tested-by: Stefan Reinauer <reinauer@chromium.org>
(cherry picked from commit b7b865cfee68190babd971ab9a897bdabbab075f)
Change-Id: I7388ba8c8621ba05b8bcec6d008e5b250feaa683
Reviewed-on: https://gerrit.chromium.org/gerrit/34787
Reviewed-by: Stefan Reinauer <reinauer@chromium.org>
Tested-by: Stefan Reinauer <reinauer@chromium.org>
-rw-r--r-- | cgpt/Makefile | 2 | ||||
-rw-r--r-- | cgpt/cgpt.c | 1 | ||||
-rw-r--r-- | cgpt/cgpt.h | 1 | ||||
-rw-r--r-- | cgpt/cgpt_common.c | 12 | ||||
-rw-r--r-- | cgpt/cgpt_legacy.c | 42 | ||||
-rw-r--r-- | cgpt/cgpt_params.h | 9 | ||||
-rw-r--r-- | cgpt/cmd_legacy.c | 67 | ||||
-rw-r--r-- | firmware/lib/cgptlib/cgptlib_internal.c | 3 | ||||
-rw-r--r-- | firmware/lib/cgptlib/include/gpt.h | 3 | ||||
-rw-r--r-- | firmware/lib/vboot_kernel.c | 26 |
10 files changed, 156 insertions, 10 deletions
diff --git a/cgpt/Makefile b/cgpt/Makefile index 8e810d42..c22a680c 100644 --- a/cgpt/Makefile +++ b/cgpt/Makefile @@ -24,6 +24,7 @@ ALL_SRCS = \ cgpt_repair.c \ cgpt_prioritize.c \ cgpt_find.c \ + cgpt_legacy.c \ cmd_show.c \ cmd_repair.c \ cmd_create.c \ @@ -31,6 +32,7 @@ ALL_SRCS = \ cmd_boot.c \ cmd_find.c \ cmd_prioritize.c \ + cmd_legacy.c \ cgpt_common.c LIB_CGPT_CC_SRCS = \ diff --git a/cgpt/cgpt.c b/cgpt/cgpt.c index e963142a..ac7aecdd 100644 --- a/cgpt/cgpt.c +++ b/cgpt/cgpt.c @@ -30,6 +30,7 @@ struct { {"find", cmd_find, "Locate a partition by its GUID"}, {"prioritize", cmd_prioritize, "Reorder the priority of all kernel partitions"}, + {"legacy", cmd_legacy, "Switch between GPT and Legacy GPT"}, }; void Usage(void) { diff --git a/cgpt/cgpt.h b/cgpt/cgpt.h index 6851ded7..b3f7ff3b 100644 --- a/cgpt/cgpt.h +++ b/cgpt/cgpt.h @@ -154,6 +154,7 @@ int cmd_add(int argc, char *argv[]); int cmd_boot(int argc, char *argv[]); int cmd_find(int argc, char *argv[]); int cmd_prioritize(int argc, char *argv[]); +int cmd_legacy(int argc, char *argv[]); #define ARRAY_COUNT(array) (sizeof(array)/sizeof((array)[0])) const char *GptError(int errnum); diff --git a/cgpt/cgpt_common.c b/cgpt/cgpt_common.c index d69eb670..193f2e1e 100644 --- a/cgpt/cgpt_common.c +++ b/cgpt/cgpt_common.c @@ -733,7 +733,9 @@ void UpdateCrc(GptData *gpt) { primary_header = (GptHeader*)gpt->primary_header; secondary_header = (GptHeader*)gpt->secondary_header; - if (gpt->modified & GPT_MODIFIED_ENTRIES1) { + if (gpt->modified & GPT_MODIFIED_ENTRIES1 && + memcmp(primary_header, GPT_HEADER_SIGNATURE2, + GPT_HEADER_SIGNATURE_SIZE)) { primary_header->entries_crc32 = Crc32(gpt->primary_entries, TOTAL_ENTRIES_SIZE); } @@ -785,6 +787,14 @@ int IsSynonymous(const GptHeader* a, const GptHeader* b) { * Note that CRC is NOT re-computed in this function. */ uint8_t RepairEntries(GptData *gpt, const uint32_t valid_entries) { + /* If we have an alternate GPT header signature, don't overwrite + * the secondary GPT with the primary one as that might wipe the + * partition table. Also don't overwrite the primary one with the + * secondary one as that will stop Windows from booting. */ + GptHeader* h = (GptHeader*)(gpt->primary_header); + if (!memcmp(h->signature, GPT_HEADER_SIGNATURE2, GPT_HEADER_SIGNATURE_SIZE)) + return 0; + if (valid_entries == MASK_BOTH) { if (memcmp(gpt->primary_entries, gpt->secondary_entries, TOTAL_ENTRIES_SIZE)) { diff --git a/cgpt/cgpt_legacy.c b/cgpt/cgpt_legacy.c new file mode 100644 index 00000000..7d1eeeac --- /dev/null +++ b/cgpt/cgpt_legacy.c @@ -0,0 +1,42 @@ +// Copyright (c) 2012 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. + +#include "cgpt.h" + +#include <string.h> + +#include "cgptlib_internal.h" +#include "cgpt_params.h" + +int cgpt_legacy(CgptLegacyParams *params) { + struct drive drive; + GptHeader *h1, *h2; + + if (params == NULL) + return CGPT_FAILED; + + if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDWR)) + return CGPT_FAILED; + + h1 = (GptHeader *)drive.gpt.primary_header; + h2 = (GptHeader *)drive.gpt.secondary_header; + if (params->efipart) { + memcpy(h1->signature, GPT_HEADER_SIGNATURE, GPT_HEADER_SIGNATURE_SIZE); + memcpy(h2->signature, GPT_HEADER_SIGNATURE, GPT_HEADER_SIGNATURE_SIZE); + RepairEntries(&drive.gpt, MASK_SECONDARY); + drive.gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 | + GPT_MODIFIED_HEADER2); + } else { + memcpy(h1->signature, GPT_HEADER_SIGNATURE2, GPT_HEADER_SIGNATURE_SIZE); + memcpy(h2->signature, GPT_HEADER_SIGNATURE2, GPT_HEADER_SIGNATURE_SIZE); + memset(drive.gpt.primary_entries, 0, drive.gpt.sector_bytes); + drive.gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 | + GPT_MODIFIED_HEADER2); + } + + UpdateCrc(&drive.gpt); + + // Write it all out + return DriveClose(&drive, 1); +} diff --git a/cgpt/cgpt_params.h b/cgpt/cgpt_params.h index 22af9626..fcee03c4 100644 --- a/cgpt/cgpt_params.h +++ b/cgpt/cgpt_params.h @@ -92,6 +92,11 @@ typedef struct CgptFindParams { int match_partnum; // 0 for no match, 1-N for match } CgptFindParams; +typedef struct CgptLegacyParams { + char *drive_name; + int efipart; +} CgptLegacyParams; + // create related methods. int cgpt_create(CgptCreateParams *params); @@ -116,4 +121,8 @@ int cgpt_prioritize(CgptPrioritizeParams *params); // find related methods. void cgpt_find(CgptFindParams *params); + +// legacy related methods. +int cgpt_legacy(CgptLegacyParams *params); + #endif // VBOOT_REFERENCE_CGPT_CGPT_PARAMS_H_ diff --git a/cgpt/cmd_legacy.c b/cgpt/cmd_legacy.c new file mode 100644 index 00000000..5dad01e3 --- /dev/null +++ b/cgpt/cmd_legacy.c @@ -0,0 +1,67 @@ +// Copyright (c) 2012 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. + +#include "cgpt.h" + +#include <getopt.h> +#include <string.h> + +#include "cgpt_params.h" + +static void Usage(void) +{ + printf("\nUsage: %s legacy [OPTIONS] DRIVE\n\n" + "Switch GPT header signature to \"CHROMEOS\".\n\n" + "Options:\n" + " -e Switch GPT header signature back to \"EFI PART\"\n" + "\n", progname); +} + +int cmd_legacy(int argc, char *argv[]) { + CgptLegacyParams params; + memset(¶ms, 0, sizeof(params)); + + int c; + int errorcnt = 0; + + opterr = 0; // quiet, you + while ((c=getopt(argc, argv, ":he")) != -1) + { + switch (c) + { + case 'e': + params.efipart = 1; + break; + + case 'h': + Usage(); + return CGPT_OK; + case '?': + Error("unrecognized option: -%c\n", optopt); + errorcnt++; + break; + case ':': + Error("missing argument to -%c\n", optopt); + errorcnt++; + break; + default: + errorcnt++; + break; + } + } + if (errorcnt) + { + Usage(); + return CGPT_FAILED; + } + + if (optind >= argc) { + Usage(); + return CGPT_FAILED; + } + + params.drive_name = argv[optind]; + + return cgpt_legacy(¶ms); +} diff --git a/firmware/lib/cgptlib/cgptlib_internal.c b/firmware/lib/cgptlib/cgptlib_internal.c index ee3c87f1..a942b1b3 100644 --- a/firmware/lib/cgptlib/cgptlib_internal.c +++ b/firmware/lib/cgptlib/cgptlib_internal.c @@ -45,7 +45,8 @@ int CheckHeader(GptHeader *h, int is_secondary, uint64_t drive_sectors) { /* Make sure we're looking at a header of reasonable size before * attempting to calculate CRC. */ - if (Memcmp(h->signature, GPT_HEADER_SIGNATURE, GPT_HEADER_SIGNATURE_SIZE)) + if (Memcmp(h->signature, GPT_HEADER_SIGNATURE, GPT_HEADER_SIGNATURE_SIZE) && + Memcmp(h->signature, GPT_HEADER_SIGNATURE2, GPT_HEADER_SIGNATURE_SIZE)) return 1; if (h->revision != GPT_HEADER_REVISION) return 1; diff --git a/firmware/lib/cgptlib/include/gpt.h b/firmware/lib/cgptlib/include/gpt.h index 69d89d94..95b77145 100644 --- a/firmware/lib/cgptlib/include/gpt.h +++ b/firmware/lib/cgptlib/include/gpt.h @@ -14,7 +14,8 @@ __pragma(pack(push,1)) /* Support packing for MSVC. */ -#define GPT_HEADER_SIGNATURE "EFI PART" +#define GPT_HEADER_SIGNATURE "EFI PART" +#define GPT_HEADER_SIGNATURE2 "CHROMEOS" #define GPT_HEADER_SIGNATURE_SIZE sizeof(GPT_HEADER_SIGNATURE) #define GPT_HEADER_REVISION 0x00010000 diff --git a/firmware/lib/vboot_kernel.c b/firmware/lib/vboot_kernel.c index 1dffc7b3..190dc1bf 100644 --- a/firmware/lib/vboot_kernel.c +++ b/firmware/lib/vboot_kernel.c @@ -72,23 +72,35 @@ int AllocAndReadGptData(VbExDiskHandle_t disk_handle, GptData* gptdata) { * Returns 0 if successful, 1 if error. */ int WriteAndFreeGptData(VbExDiskHandle_t disk_handle, GptData* gptdata) { + int legacy = 0; uint64_t entries_sectors = TOTAL_ENTRIES_SIZE / gptdata->sector_bytes; if (gptdata->primary_header) { + GptHeader* h = (GptHeader*)(gptdata->primary_header); + legacy = !Memcmp(h->signature, GPT_HEADER_SIGNATURE2, + GPT_HEADER_SIGNATURE_SIZE); if (gptdata->modified & GPT_MODIFIED_HEADER1) { - VBDEBUG(("Updating GPT header 1\n")); - if (0 != VbExDiskWrite(disk_handle, 1, 1, gptdata->primary_header)) - return 1; + if (legacy) { + VBDEBUG(("Not updating GPT header 1: legacy mode is enabled.\n")); + } else { + VBDEBUG(("Updating GPT header 1\n")); + if (0 != VbExDiskWrite(disk_handle, 1, 1, gptdata->primary_header)) + return 1; + } } VbExFree(gptdata->primary_header); } if (gptdata->primary_entries) { if (gptdata->modified & GPT_MODIFIED_ENTRIES1) { - VBDEBUG(("Updating GPT entries 1\n")); - if (0 != VbExDiskWrite(disk_handle, 2, entries_sectors, - gptdata->primary_entries)) - return 1; + if (legacy) { + VBDEBUG(("Not updating GPT entries 1: legacy mode is enabled.\n")); + } else { + VBDEBUG(("Updating GPT entries 1\n")); + if (0 != VbExDiskWrite(disk_handle, 2, entries_sectors, + gptdata->primary_entries)) + return 1; + } } VbExFree(gptdata->primary_entries); } |