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