1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
/* Copyright 2012 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <string.h>
#include "cgpt.h"
#include "cgptlib_internal.h"
#include "vboot_host.h"
static void AllocAndClear(uint8_t **buf, uint64_t size) {
if (*buf) {
memset(*buf, 0, size);
} else {
*buf = calloc(1, size);
if (!*buf) {
Error("Cannot allocate %" PRIu64 " bytes.\n", size);
abort();
}
}
}
static int GptCreate(struct drive *drive, CgptCreateParams *params) {
// Do not replace any existing IGNOREME GPT headers.
if (!memcmp(((GptHeader*)drive->gpt.primary_header)->signature,
GPT_HEADER_SIGNATURE_IGNORED, GPT_HEADER_SIGNATURE_SIZE)) {
drive->gpt.ignored |= MASK_PRIMARY;
Warning("Primary GPT was marked ignored, will not overwrite.\n");
}
if (!memcmp(((GptHeader*)drive->gpt.secondary_header)->signature,
GPT_HEADER_SIGNATURE_IGNORED, GPT_HEADER_SIGNATURE_SIZE)) {
drive->gpt.ignored |= MASK_SECONDARY;
Warning("Secondary GPT was marked ignored, will not overwrite.\n");
}
// Allocate and/or erase the data.
// We cannot assume the GPT headers or entry arrays have been allocated
// by GptLoad() because those fields might have failed validation checks.
AllocAndClear(&drive->gpt.primary_header,
drive->gpt.sector_bytes * GPT_HEADER_SECTORS);
AllocAndClear(&drive->gpt.secondary_header,
drive->gpt.sector_bytes * GPT_HEADER_SECTORS);
drive->gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2);
// Initialize a blank set
if (!params->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 = GPT_PMBR_SECTORS; /* The second sector on drive. */
h->alternate_lba = drive->gpt.gpt_drive_sectors - GPT_HEADER_SECTORS;
if (CGPT_OK != GenerateGuid(&h->disk_uuid)) {
Error("Unable to generate new GUID.\n");
return -1;
}
/* Calculate number of entries */
h->size_of_entry = sizeof(GptEntry);
h->number_of_entries = MAX_NUMBER_OF_ENTRIES;
if (drive->gpt.flags & GPT_FLAG_EXTERNAL) {
// We might have smaller space for the GPT table. Scale accordingly.
//
// +------+------------+---------------+-----+--------------+-----------+
// | PMBR | Prim. Head | Prim. Entries | ... | Sec. Entries | Sec. Head |
// +------+------------+---------------+-----+--------------+-----------+
//
// Half the size of gpt_drive_sectors must be big enough to hold PMBR +
// GPT Header + Entries Table, though the secondary structures do not
// contain PMBR.
size_t required_headers_size =
(GPT_PMBR_SECTORS + GPT_HEADER_SECTORS) * drive->gpt.sector_bytes;
size_t min_entries_size = MIN_NUMBER_OF_ENTRIES * h->size_of_entry;
size_t required_min_size = required_headers_size + min_entries_size;
size_t half_size =
(drive->gpt.gpt_drive_sectors / 2) * drive->gpt.sector_bytes;
if (half_size < required_min_size) {
Error("Not enough space to store GPT structures. Required %zu bytes.\n",
required_min_size * 2);
return -1;
}
size_t max_entries =
(half_size - required_headers_size) / h->size_of_entry;
if (h->number_of_entries > max_entries) {
h->number_of_entries = max_entries;
}
}
/* Then use number of entries to calculate entries_lba. */
h->entries_lba = h->my_lba + GPT_HEADER_SECTORS;
if (!(drive->gpt.flags & GPT_FLAG_EXTERNAL)) {
h->entries_lba += params->padding;
h->first_usable_lba = h->entries_lba + CalculateEntriesSectors(h,
drive->gpt.sector_bytes);
h->last_usable_lba =
(drive->gpt.streaming_drive_sectors - GPT_HEADER_SECTORS -
CalculateEntriesSectors(h, drive->gpt.sector_bytes) - 1);
} else {
h->first_usable_lba = params->padding;
h->last_usable_lba = (drive->gpt.streaming_drive_sectors - 1);
}
size_t entries_size = h->number_of_entries * h->size_of_entry;
AllocAndClear(&drive->gpt.primary_entries, entries_size);
AllocAndClear(&drive->gpt.secondary_entries, entries_size);
// Copy to secondary
RepairHeader(&drive->gpt, MASK_PRIMARY);
UpdateCrc(&drive->gpt);
}
return 0;
}
int CgptCreate(CgptCreateParams *params) {
struct drive drive;
if (params == NULL)
return CGPT_FAILED;
if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDWR,
params->drive_size))
return CGPT_FAILED;
if (GptCreate(&drive, params))
goto bad;
// Write it all out
return DriveClose(&drive, 1);
bad:
DriveClose(&drive, 0);
return CGPT_FAILED;
}
|