summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Reinauer <reinauer@chromium.org>2012-08-23 15:06:25 -0700
committerGerrit <chrome-bot@google.com>2012-09-19 15:33:30 -0700
commitb7b865cfee68190babd971ab9a897bdabbab075f (patch)
tree8ad900ddff6a69f9a65cd0507857a6da2677592f
parent40d8651bb36048c9b5f07be97ff17b2cf503015e (diff)
downloadvboot-b7b865cfee68190babd971ab9a897bdabbab075f.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> Change-Id: Ia88eff33b9880bd73a78c1b8e026c1f8298c4557 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>
-rw-r--r--cgpt/Makefile2
-rw-r--r--cgpt/cgpt.c1
-rw-r--r--cgpt/cgpt.h1
-rw-r--r--cgpt/cgpt_common.c12
-rw-r--r--cgpt/cgpt_legacy.c42
-rw-r--r--cgpt/cgpt_params.h9
-rw-r--r--cgpt/cmd_legacy.c67
-rw-r--r--firmware/lib/cgptlib/cgptlib_internal.c3
-rw-r--r--firmware/lib/cgptlib/include/gpt.h3
-rw-r--r--firmware/lib/vboot_kernel.c26
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(&params, 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(&params);
+}
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 d1f261d7..d189e43e 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);
}