Files
OpenCellular/cgpt/cmd_create.c
Bill Richardson 962483c1e2 This fixes the EFI BIOS boot problems introduced with cgpt.
There were two changes. First, we need to pack the GPT header to make it
match the spec (duh). Second, there's a subtle bug in how the BIOS recovers
from corrupted headers. The EFI spec says that the primary GPT header must
be at sector 1 (counting from zero) and the secondary GPT header must be at
the last sector on the drive. The BIOS correctly looks in those locations to
find the headers. However, if the secondary GPT header is invalid (as it
usually is due to our build process), the BIOS is supposed to update it from
the primary header. In this case, rather than write to the last sector on
the drive where it just looked, the BIOS trusts the alternate_lba field of
the primary header. That field is supposed to point to the secondary header
location, but the BIOS just blindly uses it no matter where it points. The
cgpt tool wasn't initializing that field, so it pointed to sector 0, which
is the PMBR. The BIOS overwrote that, resulting in an unbootable drive.

Review URL: http://codereview.chromium.org/2844006
2010-06-15 21:07:18 -07:00

108 lines
2.6 KiB
C

// 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.
#include "cgpt.h"
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <uuid/uuid.h>
#include "cgptlib_internal.h"
static void Usage(void)
{
printf("\nUsage: %s create [OPTIONS] DRIVE\n\n"
"Create or reset an empty GPT.\n\n"
"Options:\n"
" -z Zero the sectors of the GPT table and entries\n"
"\n", progname);
}
int cmd_create(int argc, char *argv[]) {
struct drive drive;
int zap = 0;
int c;
int errorcnt = 0;
opterr = 0; // quiet, you
while ((c=getopt(argc, argv, ":hz")) != -1)
{
switch (c)
{
case 'z':
zap = 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;
}
if (CGPT_OK != DriveOpen(argv[optind], &drive))
return CGPT_FAILED;
// Erase the data
memset(drive.gpt.primary_header, 0,
drive.gpt.sector_bytes * GPT_HEADER_SECTOR);
memset(drive.gpt.secondary_header, 0,
drive.gpt.sector_bytes * GPT_HEADER_SECTOR);
memset(drive.gpt.primary_entries, 0,
drive.gpt.sector_bytes * GPT_ENTRIES_SECTORS);
memset(drive.gpt.secondary_entries, 0,
drive.gpt.sector_bytes * GPT_ENTRIES_SECTORS);
drive.gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2);
// Initialize a blank set
if (!zap)
{
GptHeader *h = (GptHeader *)drive.gpt.primary_header;
memcpy(h->signature, GPT_HEADER_SIGNATURE, GPT_HEADER_SIGNATURE_SIZE);
h->revision = GPT_HEADER_REVISION;
h->size = sizeof(GptHeader);
h->my_lba = 1;
h->alternate_lba = drive.gpt.drive_sectors - 1;
h->first_usable_lba = 1 + 1 + GPT_ENTRIES_SECTORS;
h->last_usable_lba = drive.gpt.drive_sectors - 1 - GPT_ENTRIES_SECTORS - 1;
uuid_generate((uint8_t *)&h->disk_uuid);
h->entries_lba = 2;
h->number_of_entries = 128;
h->size_of_entry = sizeof(GptEntry);
// Copy to secondary
RepairHeader(&drive.gpt, MASK_PRIMARY);
UpdateCrc(&drive.gpt);
}
// Write it all out
return DriveClose(&drive, 1);
}