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>
This commit is contained in:
Stefan Reinauer
2012-08-23 15:06:25 -07:00
committed by Gerrit
parent 40d8651bb3
commit b7b865cfee
10 changed files with 156 additions and 10 deletions

View File

@@ -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 = \

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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)) {

42
cgpt/cgpt_legacy.c Normal file
View File

@@ -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);
}

View File

@@ -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_

67
cgpt/cmd_legacy.c Normal file
View File

@@ -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);
}

View File

@@ -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;

View File

@@ -15,6 +15,7 @@
__pragma(pack(push,1)) /* Support packing for MSVC. */
#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

View File

@@ -72,24 +72,36 @@ 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) {
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) {
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);
}