xref: /aosp_15_r20/external/vboot_reference/firmware/lib/gpt_misc.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1*8617a60dSAndroid Build Coastguard Worker /* Copyright 2013 The ChromiumOS Authors
2*8617a60dSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
3*8617a60dSAndroid Build Coastguard Worker  * found in the LICENSE file.
4*8617a60dSAndroid Build Coastguard Worker  */
5*8617a60dSAndroid Build Coastguard Worker 
6*8617a60dSAndroid Build Coastguard Worker #include "2common.h"
7*8617a60dSAndroid Build Coastguard Worker #include "2sysincludes.h"
8*8617a60dSAndroid Build Coastguard Worker #include "cgptlib.h"
9*8617a60dSAndroid Build Coastguard Worker #include "cgptlib_internal.h"
10*8617a60dSAndroid Build Coastguard Worker #include "crc32.h"
11*8617a60dSAndroid Build Coastguard Worker #include "gpt.h"
12*8617a60dSAndroid Build Coastguard Worker #include "vboot_api.h"
13*8617a60dSAndroid Build Coastguard Worker 
14*8617a60dSAndroid Build Coastguard Worker /**
15*8617a60dSAndroid Build Coastguard Worker  * Allocate and read GPT data from the drive.
16*8617a60dSAndroid Build Coastguard Worker  *
17*8617a60dSAndroid Build Coastguard Worker  * The sector_bytes and gpt_drive_sectors fields should be filled on input.  The
18*8617a60dSAndroid Build Coastguard Worker  * primary and secondary header and entries are filled on output.
19*8617a60dSAndroid Build Coastguard Worker  *
20*8617a60dSAndroid Build Coastguard Worker  * Returns 0 if successful, 1 if error.
21*8617a60dSAndroid Build Coastguard Worker  */
AllocAndReadGptData(vb2ex_disk_handle_t disk_handle,GptData * gptdata)22*8617a60dSAndroid Build Coastguard Worker int AllocAndReadGptData(vb2ex_disk_handle_t disk_handle, GptData *gptdata)
23*8617a60dSAndroid Build Coastguard Worker {
24*8617a60dSAndroid Build Coastguard Worker 	int primary_valid = 0, secondary_valid = 0;
25*8617a60dSAndroid Build Coastguard Worker 
26*8617a60dSAndroid Build Coastguard Worker 	/* No data to be written yet */
27*8617a60dSAndroid Build Coastguard Worker 	gptdata->modified = 0;
28*8617a60dSAndroid Build Coastguard Worker 	/* This should get overwritten by GptInit() */
29*8617a60dSAndroid Build Coastguard Worker 	gptdata->ignored = 0;
30*8617a60dSAndroid Build Coastguard Worker 
31*8617a60dSAndroid Build Coastguard Worker 	/* Allocate all buffers */
32*8617a60dSAndroid Build Coastguard Worker 	gptdata->primary_header = (uint8_t *)malloc(gptdata->sector_bytes);
33*8617a60dSAndroid Build Coastguard Worker 	gptdata->secondary_header =
34*8617a60dSAndroid Build Coastguard Worker 		(uint8_t *)malloc(gptdata->sector_bytes);
35*8617a60dSAndroid Build Coastguard Worker 	gptdata->primary_entries = (uint8_t *)malloc(GPT_ENTRIES_ALLOC_SIZE);
36*8617a60dSAndroid Build Coastguard Worker 	gptdata->secondary_entries = (uint8_t *)malloc(GPT_ENTRIES_ALLOC_SIZE);
37*8617a60dSAndroid Build Coastguard Worker 
38*8617a60dSAndroid Build Coastguard Worker 	/* In some cases we try to validate header1 with entries2 or vice versa,
39*8617a60dSAndroid Build Coastguard Worker 	   so make sure the entries buffers always got fully initialized. */
40*8617a60dSAndroid Build Coastguard Worker 	memset(gptdata->primary_entries, 0, GPT_ENTRIES_ALLOC_SIZE);
41*8617a60dSAndroid Build Coastguard Worker 	memset(gptdata->secondary_entries, 0, GPT_ENTRIES_ALLOC_SIZE);
42*8617a60dSAndroid Build Coastguard Worker 
43*8617a60dSAndroid Build Coastguard Worker 	if (gptdata->primary_header == NULL ||
44*8617a60dSAndroid Build Coastguard Worker 	    gptdata->secondary_header == NULL ||
45*8617a60dSAndroid Build Coastguard Worker 	    gptdata->primary_entries == NULL ||
46*8617a60dSAndroid Build Coastguard Worker 	    gptdata->secondary_entries == NULL)
47*8617a60dSAndroid Build Coastguard Worker 		return 1;
48*8617a60dSAndroid Build Coastguard Worker 
49*8617a60dSAndroid Build Coastguard Worker 	/* Read primary header from the drive, skipping the protective MBR */
50*8617a60dSAndroid Build Coastguard Worker 	if (0 != VbExDiskRead(disk_handle, 1, 1, gptdata->primary_header)) {
51*8617a60dSAndroid Build Coastguard Worker 		VB2_DEBUG("Read error in primary GPT header\n");
52*8617a60dSAndroid Build Coastguard Worker 		memset(gptdata->primary_header, 0, gptdata->sector_bytes);
53*8617a60dSAndroid Build Coastguard Worker 	}
54*8617a60dSAndroid Build Coastguard Worker 
55*8617a60dSAndroid Build Coastguard Worker 	/* Only read primary GPT if the primary header is valid */
56*8617a60dSAndroid Build Coastguard Worker 	GptHeader* primary_header = (GptHeader*)gptdata->primary_header;
57*8617a60dSAndroid Build Coastguard Worker 	if (0 == CheckHeader(primary_header, 0,
58*8617a60dSAndroid Build Coastguard Worker 			gptdata->streaming_drive_sectors,
59*8617a60dSAndroid Build Coastguard Worker 			gptdata->gpt_drive_sectors,
60*8617a60dSAndroid Build Coastguard Worker 			gptdata->flags,
61*8617a60dSAndroid Build Coastguard Worker 			gptdata->sector_bytes)) {
62*8617a60dSAndroid Build Coastguard Worker 		primary_valid = 1;
63*8617a60dSAndroid Build Coastguard Worker 		uint64_t entries_bytes =
64*8617a60dSAndroid Build Coastguard Worker 				(uint64_t)primary_header->number_of_entries
65*8617a60dSAndroid Build Coastguard Worker 				* primary_header->size_of_entry;
66*8617a60dSAndroid Build Coastguard Worker 		uint64_t entries_sectors =
67*8617a60dSAndroid Build Coastguard Worker 				(entries_bytes + gptdata->sector_bytes - 1)
68*8617a60dSAndroid Build Coastguard Worker 				/ gptdata->sector_bytes;
69*8617a60dSAndroid Build Coastguard Worker 		if (0 != VbExDiskRead(disk_handle,
70*8617a60dSAndroid Build Coastguard Worker 				      primary_header->entries_lba,
71*8617a60dSAndroid Build Coastguard Worker 				      entries_sectors,
72*8617a60dSAndroid Build Coastguard Worker 				      gptdata->primary_entries)) {
73*8617a60dSAndroid Build Coastguard Worker 			VB2_DEBUG("Read error in primary GPT entries\n");
74*8617a60dSAndroid Build Coastguard Worker 			primary_valid = 0;
75*8617a60dSAndroid Build Coastguard Worker 		}
76*8617a60dSAndroid Build Coastguard Worker 	} else {
77*8617a60dSAndroid Build Coastguard Worker 		VB2_DEBUG("Primary GPT header is %s\n",
78*8617a60dSAndroid Build Coastguard Worker 			  memcmp(primary_header->signature,
79*8617a60dSAndroid Build Coastguard Worker 				 GPT_HEADER_SIGNATURE_IGNORED,
80*8617a60dSAndroid Build Coastguard Worker 				 GPT_HEADER_SIGNATURE_SIZE)
81*8617a60dSAndroid Build Coastguard Worker 			  ? "invalid" : "being ignored");
82*8617a60dSAndroid Build Coastguard Worker 	}
83*8617a60dSAndroid Build Coastguard Worker 
84*8617a60dSAndroid Build Coastguard Worker 	/* Read secondary header from the end of the drive */
85*8617a60dSAndroid Build Coastguard Worker 	if (0 != VbExDiskRead(disk_handle, gptdata->gpt_drive_sectors - 1, 1,
86*8617a60dSAndroid Build Coastguard Worker 			      gptdata->secondary_header)) {
87*8617a60dSAndroid Build Coastguard Worker 		VB2_DEBUG("Read error in secondary GPT header\n");
88*8617a60dSAndroid Build Coastguard Worker 		memset(gptdata->secondary_header, 0, gptdata->sector_bytes);
89*8617a60dSAndroid Build Coastguard Worker 	}
90*8617a60dSAndroid Build Coastguard Worker 
91*8617a60dSAndroid Build Coastguard Worker 	/* Only read secondary GPT if the secondary header is valid */
92*8617a60dSAndroid Build Coastguard Worker 	GptHeader* secondary_header = (GptHeader*)gptdata->secondary_header;
93*8617a60dSAndroid Build Coastguard Worker 	if (0 == CheckHeader(secondary_header, 1,
94*8617a60dSAndroid Build Coastguard Worker 			gptdata->streaming_drive_sectors,
95*8617a60dSAndroid Build Coastguard Worker 			gptdata->gpt_drive_sectors,
96*8617a60dSAndroid Build Coastguard Worker 			gptdata->flags,
97*8617a60dSAndroid Build Coastguard Worker 			gptdata->sector_bytes)) {
98*8617a60dSAndroid Build Coastguard Worker 		secondary_valid = 1;
99*8617a60dSAndroid Build Coastguard Worker 		uint64_t entries_bytes =
100*8617a60dSAndroid Build Coastguard Worker 				(uint64_t)secondary_header->number_of_entries
101*8617a60dSAndroid Build Coastguard Worker 				* secondary_header->size_of_entry;
102*8617a60dSAndroid Build Coastguard Worker 		uint64_t entries_sectors =
103*8617a60dSAndroid Build Coastguard Worker 				(entries_bytes + gptdata->sector_bytes - 1)
104*8617a60dSAndroid Build Coastguard Worker 				/ gptdata->sector_bytes;
105*8617a60dSAndroid Build Coastguard Worker 		if (0 != VbExDiskRead(disk_handle,
106*8617a60dSAndroid Build Coastguard Worker 				      secondary_header->entries_lba,
107*8617a60dSAndroid Build Coastguard Worker 				      entries_sectors,
108*8617a60dSAndroid Build Coastguard Worker 				      gptdata->secondary_entries)) {
109*8617a60dSAndroid Build Coastguard Worker 			VB2_DEBUG("Read error in secondary GPT entries\n");
110*8617a60dSAndroid Build Coastguard Worker 			secondary_valid = 0;
111*8617a60dSAndroid Build Coastguard Worker 		}
112*8617a60dSAndroid Build Coastguard Worker 	} else {
113*8617a60dSAndroid Build Coastguard Worker 		VB2_DEBUG("Secondary GPT header is %s\n",
114*8617a60dSAndroid Build Coastguard Worker 			  memcmp(secondary_header->signature,
115*8617a60dSAndroid Build Coastguard Worker 				 GPT_HEADER_SIGNATURE_IGNORED,
116*8617a60dSAndroid Build Coastguard Worker 				 GPT_HEADER_SIGNATURE_SIZE)
117*8617a60dSAndroid Build Coastguard Worker 			  ? "invalid" : "being ignored");
118*8617a60dSAndroid Build Coastguard Worker 	}
119*8617a60dSAndroid Build Coastguard Worker 
120*8617a60dSAndroid Build Coastguard Worker 	/* Return 0 if least one GPT header was valid */
121*8617a60dSAndroid Build Coastguard Worker 	return (primary_valid || secondary_valid) ? 0 : 1;
122*8617a60dSAndroid Build Coastguard Worker }
123*8617a60dSAndroid Build Coastguard Worker 
124*8617a60dSAndroid Build Coastguard Worker /**
125*8617a60dSAndroid Build Coastguard Worker  * Write any changes for the GPT data back to the drive, then free the buffers.
126*8617a60dSAndroid Build Coastguard Worker  *
127*8617a60dSAndroid Build Coastguard Worker  * Returns 0 if successful, 1 if error.
128*8617a60dSAndroid Build Coastguard Worker  */
WriteAndFreeGptData(vb2ex_disk_handle_t disk_handle,GptData * gptdata)129*8617a60dSAndroid Build Coastguard Worker int WriteAndFreeGptData(vb2ex_disk_handle_t disk_handle, GptData *gptdata)
130*8617a60dSAndroid Build Coastguard Worker {
131*8617a60dSAndroid Build Coastguard Worker 	int skip_primary = 0;
132*8617a60dSAndroid Build Coastguard Worker 	GptHeader *header;
133*8617a60dSAndroid Build Coastguard Worker 	uint64_t entries_bytes, entries_sectors;
134*8617a60dSAndroid Build Coastguard Worker 	int ret = 1;
135*8617a60dSAndroid Build Coastguard Worker 
136*8617a60dSAndroid Build Coastguard Worker 	header = (GptHeader *)gptdata->primary_header;
137*8617a60dSAndroid Build Coastguard Worker 	if (!header)
138*8617a60dSAndroid Build Coastguard Worker 		header = (GptHeader *)gptdata->secondary_header;
139*8617a60dSAndroid Build Coastguard Worker 	if (!header)
140*8617a60dSAndroid Build Coastguard Worker 		return 1;  /* No headers at all, so nothing to write */
141*8617a60dSAndroid Build Coastguard Worker 
142*8617a60dSAndroid Build Coastguard Worker 	entries_bytes = (uint64_t)header->number_of_entries
143*8617a60dSAndroid Build Coastguard Worker 			* header->size_of_entry;
144*8617a60dSAndroid Build Coastguard Worker 	entries_sectors = entries_bytes / gptdata->sector_bytes;
145*8617a60dSAndroid Build Coastguard Worker 
146*8617a60dSAndroid Build Coastguard Worker 	/*
147*8617a60dSAndroid Build Coastguard Worker 	 * TODO(namnguyen): Preserve padding between primary GPT header and
148*8617a60dSAndroid Build Coastguard Worker 	 * its entries.
149*8617a60dSAndroid Build Coastguard Worker 	 */
150*8617a60dSAndroid Build Coastguard Worker 	uint64_t entries_lba = GPT_PMBR_SECTORS + GPT_HEADER_SECTORS;
151*8617a60dSAndroid Build Coastguard Worker 	if (gptdata->primary_header) {
152*8617a60dSAndroid Build Coastguard Worker 		GptHeader *h = (GptHeader *)(gptdata->primary_header);
153*8617a60dSAndroid Build Coastguard Worker 		entries_lba = h->entries_lba;
154*8617a60dSAndroid Build Coastguard Worker 
155*8617a60dSAndroid Build Coastguard Worker 		if (gptdata->ignored & MASK_PRIMARY) {
156*8617a60dSAndroid Build Coastguard Worker 			VB2_DEBUG("Not updating primary GPT: "
157*8617a60dSAndroid Build Coastguard Worker 				  "marked to be ignored.\n");
158*8617a60dSAndroid Build Coastguard Worker 			skip_primary = 1;
159*8617a60dSAndroid Build Coastguard Worker 		} else if (gptdata->modified & GPT_MODIFIED_HEADER1) {
160*8617a60dSAndroid Build Coastguard Worker 			if (!memcmp(h->signature, GPT_HEADER_SIGNATURE2,
161*8617a60dSAndroid Build Coastguard Worker 				    GPT_HEADER_SIGNATURE_SIZE)) {
162*8617a60dSAndroid Build Coastguard Worker 				VB2_DEBUG("Not updating primary GPT: "
163*8617a60dSAndroid Build Coastguard Worker 					  "legacy mode is enabled.\n");
164*8617a60dSAndroid Build Coastguard Worker 				skip_primary = 1;
165*8617a60dSAndroid Build Coastguard Worker 			} else {
166*8617a60dSAndroid Build Coastguard Worker 				VB2_DEBUG("Updating GPT header 1\n");
167*8617a60dSAndroid Build Coastguard Worker 				if (0 != VbExDiskWrite(disk_handle, 1, 1,
168*8617a60dSAndroid Build Coastguard Worker 						       gptdata->primary_header))
169*8617a60dSAndroid Build Coastguard Worker 					goto fail;
170*8617a60dSAndroid Build Coastguard Worker 			}
171*8617a60dSAndroid Build Coastguard Worker 		}
172*8617a60dSAndroid Build Coastguard Worker 	}
173*8617a60dSAndroid Build Coastguard Worker 
174*8617a60dSAndroid Build Coastguard Worker 	if (gptdata->primary_entries && !skip_primary) {
175*8617a60dSAndroid Build Coastguard Worker 		if (gptdata->modified & GPT_MODIFIED_ENTRIES1) {
176*8617a60dSAndroid Build Coastguard Worker 			VB2_DEBUG("Updating GPT entries 1\n");
177*8617a60dSAndroid Build Coastguard Worker 			if (0 != VbExDiskWrite(disk_handle, entries_lba,
178*8617a60dSAndroid Build Coastguard Worker 					       entries_sectors,
179*8617a60dSAndroid Build Coastguard Worker 					       gptdata->primary_entries))
180*8617a60dSAndroid Build Coastguard Worker 				goto fail;
181*8617a60dSAndroid Build Coastguard Worker 		}
182*8617a60dSAndroid Build Coastguard Worker 	}
183*8617a60dSAndroid Build Coastguard Worker 
184*8617a60dSAndroid Build Coastguard Worker 	entries_lba = (gptdata->gpt_drive_sectors - entries_sectors -
185*8617a60dSAndroid Build Coastguard Worker 		GPT_HEADER_SECTORS);
186*8617a60dSAndroid Build Coastguard Worker 	if (gptdata->secondary_header && !(gptdata->ignored & MASK_SECONDARY)) {
187*8617a60dSAndroid Build Coastguard Worker 		GptHeader *h = (GptHeader *)(gptdata->secondary_header);
188*8617a60dSAndroid Build Coastguard Worker 		entries_lba = h->entries_lba;
189*8617a60dSAndroid Build Coastguard Worker 		if (gptdata->modified & GPT_MODIFIED_HEADER2) {
190*8617a60dSAndroid Build Coastguard Worker 			VB2_DEBUG("Updating GPT header 2\n");
191*8617a60dSAndroid Build Coastguard Worker 			if (0 != VbExDiskWrite(disk_handle,
192*8617a60dSAndroid Build Coastguard Worker 					       gptdata->gpt_drive_sectors - 1, 1,
193*8617a60dSAndroid Build Coastguard Worker 					       gptdata->secondary_header))
194*8617a60dSAndroid Build Coastguard Worker 				goto fail;
195*8617a60dSAndroid Build Coastguard Worker 		}
196*8617a60dSAndroid Build Coastguard Worker 	}
197*8617a60dSAndroid Build Coastguard Worker 
198*8617a60dSAndroid Build Coastguard Worker 	if (gptdata->secondary_entries && !(gptdata->ignored & MASK_SECONDARY)){
199*8617a60dSAndroid Build Coastguard Worker 		if (gptdata->modified & GPT_MODIFIED_ENTRIES2) {
200*8617a60dSAndroid Build Coastguard Worker 			VB2_DEBUG("Updating GPT entries 2\n");
201*8617a60dSAndroid Build Coastguard Worker 			if (0 != VbExDiskWrite(disk_handle,
202*8617a60dSAndroid Build Coastguard Worker 					       entries_lba, entries_sectors,
203*8617a60dSAndroid Build Coastguard Worker 					       gptdata->secondary_entries))
204*8617a60dSAndroid Build Coastguard Worker 				goto fail;
205*8617a60dSAndroid Build Coastguard Worker 		}
206*8617a60dSAndroid Build Coastguard Worker 	}
207*8617a60dSAndroid Build Coastguard Worker 
208*8617a60dSAndroid Build Coastguard Worker 	ret = 0;
209*8617a60dSAndroid Build Coastguard Worker 
210*8617a60dSAndroid Build Coastguard Worker  fail:
211*8617a60dSAndroid Build Coastguard Worker 	/* Avoid leaking memory on disk write failure */
212*8617a60dSAndroid Build Coastguard Worker 	if (gptdata->primary_header)
213*8617a60dSAndroid Build Coastguard Worker 		free(gptdata->primary_header);
214*8617a60dSAndroid Build Coastguard Worker 	if (gptdata->primary_entries)
215*8617a60dSAndroid Build Coastguard Worker 		free(gptdata->primary_entries);
216*8617a60dSAndroid Build Coastguard Worker 	if (gptdata->secondary_entries)
217*8617a60dSAndroid Build Coastguard Worker 		free(gptdata->secondary_entries);
218*8617a60dSAndroid Build Coastguard Worker 	if (gptdata->secondary_header)
219*8617a60dSAndroid Build Coastguard Worker 		free(gptdata->secondary_header);
220*8617a60dSAndroid Build Coastguard Worker 
221*8617a60dSAndroid Build Coastguard Worker 	/* Success */
222*8617a60dSAndroid Build Coastguard Worker 	return ret;
223*8617a60dSAndroid Build Coastguard Worker }
224*8617a60dSAndroid Build Coastguard Worker 
IsUnusedEntry(const GptEntry * e)225*8617a60dSAndroid Build Coastguard Worker int IsUnusedEntry(const GptEntry *e)
226*8617a60dSAndroid Build Coastguard Worker {
227*8617a60dSAndroid Build Coastguard Worker 	static Guid zero = {{{0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0}}}};
228*8617a60dSAndroid Build Coastguard Worker 	return !memcmp(&zero, (const uint8_t*)(&e->type), sizeof(zero));
229*8617a60dSAndroid Build Coastguard Worker }
230*8617a60dSAndroid Build Coastguard Worker 
231*8617a60dSAndroid Build Coastguard Worker /*
232*8617a60dSAndroid Build Coastguard Worker  * Func: GptGetEntrySize
233*8617a60dSAndroid Build Coastguard Worker  * Desc: This function returns size(in lba) of a partition represented by
234*8617a60dSAndroid Build Coastguard Worker  * given GPT entry.
235*8617a60dSAndroid Build Coastguard Worker  */
GptGetEntrySizeLba(const GptEntry * e)236*8617a60dSAndroid Build Coastguard Worker uint64_t GptGetEntrySizeLba(const GptEntry *e)
237*8617a60dSAndroid Build Coastguard Worker {
238*8617a60dSAndroid Build Coastguard Worker 	return (e->ending_lba - e->starting_lba + 1);
239*8617a60dSAndroid Build Coastguard Worker }
240*8617a60dSAndroid Build Coastguard Worker 
241*8617a60dSAndroid Build Coastguard Worker /*
242*8617a60dSAndroid Build Coastguard Worker  * Func: GptGetEntrySize
243*8617a60dSAndroid Build Coastguard Worker  * Desc: This function returns size(in bytes) of a partition represented by
244*8617a60dSAndroid Build Coastguard Worker  * given GPT entry.
245*8617a60dSAndroid Build Coastguard Worker  */
GptGetEntrySizeBytes(const GptData * gpt,const GptEntry * e)246*8617a60dSAndroid Build Coastguard Worker uint64_t GptGetEntrySizeBytes(const GptData *gpt, const GptEntry *e)
247*8617a60dSAndroid Build Coastguard Worker {
248*8617a60dSAndroid Build Coastguard Worker 	return GptGetEntrySizeLba(e) * gpt->sector_bytes;
249*8617a60dSAndroid Build Coastguard Worker }
250