xref: /aosp_15_r20/external/vboot_reference/firmware/lib/cgptlib/cgptlib.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 
GptInit(GptData * gpt)14*8617a60dSAndroid Build Coastguard Worker int GptInit(GptData *gpt)
15*8617a60dSAndroid Build Coastguard Worker {
16*8617a60dSAndroid Build Coastguard Worker 	int retval;
17*8617a60dSAndroid Build Coastguard Worker 
18*8617a60dSAndroid Build Coastguard Worker 	gpt->modified = 0;
19*8617a60dSAndroid Build Coastguard Worker 	gpt->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
20*8617a60dSAndroid Build Coastguard Worker 	gpt->current_priority = 999;
21*8617a60dSAndroid Build Coastguard Worker 
22*8617a60dSAndroid Build Coastguard Worker 	retval = GptValidityCheck(gpt);
23*8617a60dSAndroid Build Coastguard Worker 	if (GPT_SUCCESS != retval) {
24*8617a60dSAndroid Build Coastguard Worker 		VB2_DEBUG("GptInit() failed validity check\n");
25*8617a60dSAndroid Build Coastguard Worker 		return retval;
26*8617a60dSAndroid Build Coastguard Worker 	}
27*8617a60dSAndroid Build Coastguard Worker 
28*8617a60dSAndroid Build Coastguard Worker 	GptRepair(gpt);
29*8617a60dSAndroid Build Coastguard Worker 	return GPT_SUCCESS;
30*8617a60dSAndroid Build Coastguard Worker }
31*8617a60dSAndroid Build Coastguard Worker 
GptNextKernelEntry(GptData * gpt,uint64_t * start_sector,uint64_t * size)32*8617a60dSAndroid Build Coastguard Worker int GptNextKernelEntry(GptData *gpt, uint64_t *start_sector, uint64_t *size)
33*8617a60dSAndroid Build Coastguard Worker {
34*8617a60dSAndroid Build Coastguard Worker 	GptHeader *header = (GptHeader *)gpt->primary_header;
35*8617a60dSAndroid Build Coastguard Worker 	GptEntry *entries = (GptEntry *)gpt->primary_entries;
36*8617a60dSAndroid Build Coastguard Worker 	GptEntry *e;
37*8617a60dSAndroid Build Coastguard Worker 	int new_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
38*8617a60dSAndroid Build Coastguard Worker 	int new_prio = 0;
39*8617a60dSAndroid Build Coastguard Worker 	uint32_t i;
40*8617a60dSAndroid Build Coastguard Worker 
41*8617a60dSAndroid Build Coastguard Worker 	/*
42*8617a60dSAndroid Build Coastguard Worker 	 * If we already found a kernel, continue the scan at the current
43*8617a60dSAndroid Build Coastguard Worker 	 * kernel's priority, in case there is another kernel with the same
44*8617a60dSAndroid Build Coastguard Worker 	 * priority.
45*8617a60dSAndroid Build Coastguard Worker 	 */
46*8617a60dSAndroid Build Coastguard Worker 	if (gpt->current_kernel != CGPT_KERNEL_ENTRY_NOT_FOUND) {
47*8617a60dSAndroid Build Coastguard Worker 		for (i = gpt->current_kernel + 1;
48*8617a60dSAndroid Build Coastguard Worker 		     i < header->number_of_entries; i++) {
49*8617a60dSAndroid Build Coastguard Worker 			e = entries + i;
50*8617a60dSAndroid Build Coastguard Worker 			if (!IsKernelEntry(e))
51*8617a60dSAndroid Build Coastguard Worker 				continue;
52*8617a60dSAndroid Build Coastguard Worker 			VB2_DEBUG("GptNextKernelEntry looking at same prio "
53*8617a60dSAndroid Build Coastguard Worker 				  "partition %d\n", i+1);
54*8617a60dSAndroid Build Coastguard Worker 			VB2_DEBUG("GptNextKernelEntry s%d t%d p%d\n",
55*8617a60dSAndroid Build Coastguard Worker 				  GetEntrySuccessful(e), GetEntryTries(e),
56*8617a60dSAndroid Build Coastguard Worker 				  GetEntryPriority(e));
57*8617a60dSAndroid Build Coastguard Worker 			if (!(GetEntrySuccessful(e) || GetEntryTries(e)))
58*8617a60dSAndroid Build Coastguard Worker 				continue;
59*8617a60dSAndroid Build Coastguard Worker 			if (GetEntryPriority(e) == gpt->current_priority) {
60*8617a60dSAndroid Build Coastguard Worker 				gpt->current_kernel = i;
61*8617a60dSAndroid Build Coastguard Worker 				*start_sector = e->starting_lba;
62*8617a60dSAndroid Build Coastguard Worker 				*size = e->ending_lba - e->starting_lba + 1;
63*8617a60dSAndroid Build Coastguard Worker 				VB2_DEBUG("GptNextKernelEntry likes it\n");
64*8617a60dSAndroid Build Coastguard Worker 				return GPT_SUCCESS;
65*8617a60dSAndroid Build Coastguard Worker 			}
66*8617a60dSAndroid Build Coastguard Worker 		}
67*8617a60dSAndroid Build Coastguard Worker 	}
68*8617a60dSAndroid Build Coastguard Worker 
69*8617a60dSAndroid Build Coastguard Worker 	/*
70*8617a60dSAndroid Build Coastguard Worker 	 * We're still here, so scan for the remaining kernel with the highest
71*8617a60dSAndroid Build Coastguard Worker 	 * priority less than the previous attempt.
72*8617a60dSAndroid Build Coastguard Worker 	 */
73*8617a60dSAndroid Build Coastguard Worker 	for (i = 0, e = entries; i < header->number_of_entries; i++, e++) {
74*8617a60dSAndroid Build Coastguard Worker 		int current_prio = GetEntryPriority(e);
75*8617a60dSAndroid Build Coastguard Worker 		if (!IsKernelEntry(e))
76*8617a60dSAndroid Build Coastguard Worker 			continue;
77*8617a60dSAndroid Build Coastguard Worker 		VB2_DEBUG("GptNextKernelEntry looking at new prio "
78*8617a60dSAndroid Build Coastguard Worker 			  "partition %d\n", i+1);
79*8617a60dSAndroid Build Coastguard Worker 		VB2_DEBUG("GptNextKernelEntry s%d t%d p%d\n",
80*8617a60dSAndroid Build Coastguard Worker 			  GetEntrySuccessful(e), GetEntryTries(e),
81*8617a60dSAndroid Build Coastguard Worker 			  GetEntryPriority(e));
82*8617a60dSAndroid Build Coastguard Worker 		if (!(GetEntrySuccessful(e) || GetEntryTries(e)))
83*8617a60dSAndroid Build Coastguard Worker 			continue;
84*8617a60dSAndroid Build Coastguard Worker 		if (current_prio >= gpt->current_priority) {
85*8617a60dSAndroid Build Coastguard Worker 			/* Already returned this kernel in a previous call */
86*8617a60dSAndroid Build Coastguard Worker 			continue;
87*8617a60dSAndroid Build Coastguard Worker 		}
88*8617a60dSAndroid Build Coastguard Worker 		if (current_prio > new_prio) {
89*8617a60dSAndroid Build Coastguard Worker 			new_kernel = i;
90*8617a60dSAndroid Build Coastguard Worker 			new_prio = current_prio;
91*8617a60dSAndroid Build Coastguard Worker 		}
92*8617a60dSAndroid Build Coastguard Worker 	}
93*8617a60dSAndroid Build Coastguard Worker 
94*8617a60dSAndroid Build Coastguard Worker 	/*
95*8617a60dSAndroid Build Coastguard Worker 	 * Save what we found.  Note that if we didn't find a new kernel,
96*8617a60dSAndroid Build Coastguard Worker 	 * new_prio will still be -1, so future calls to this function will
97*8617a60dSAndroid Build Coastguard Worker 	 * also fail.
98*8617a60dSAndroid Build Coastguard Worker 	 */
99*8617a60dSAndroid Build Coastguard Worker 	gpt->current_kernel = new_kernel;
100*8617a60dSAndroid Build Coastguard Worker 	gpt->current_priority = new_prio;
101*8617a60dSAndroid Build Coastguard Worker 
102*8617a60dSAndroid Build Coastguard Worker 	if (CGPT_KERNEL_ENTRY_NOT_FOUND == new_kernel) {
103*8617a60dSAndroid Build Coastguard Worker 		VB2_DEBUG("GptNextKernelEntry no more kernels\n");
104*8617a60dSAndroid Build Coastguard Worker 		return GPT_ERROR_NO_VALID_KERNEL;
105*8617a60dSAndroid Build Coastguard Worker 	}
106*8617a60dSAndroid Build Coastguard Worker 
107*8617a60dSAndroid Build Coastguard Worker 	VB2_DEBUG("GptNextKernelEntry likes partition %d\n", new_kernel + 1);
108*8617a60dSAndroid Build Coastguard Worker 	e = entries + new_kernel;
109*8617a60dSAndroid Build Coastguard Worker 	*start_sector = e->starting_lba;
110*8617a60dSAndroid Build Coastguard Worker 	*size = e->ending_lba - e->starting_lba + 1;
111*8617a60dSAndroid Build Coastguard Worker 	return GPT_SUCCESS;
112*8617a60dSAndroid Build Coastguard Worker }
113*8617a60dSAndroid Build Coastguard Worker 
114*8617a60dSAndroid Build Coastguard Worker /*
115*8617a60dSAndroid Build Coastguard Worker  * Func: GptUpdateKernelWithEntry
116*8617a60dSAndroid Build Coastguard Worker  * Desc: This function updates the given kernel entry according to the provided
117*8617a60dSAndroid Build Coastguard Worker  * update_type.
118*8617a60dSAndroid Build Coastguard Worker  */
GptUpdateKernelWithEntry(GptData * gpt,GptEntry * e,uint32_t update_type)119*8617a60dSAndroid Build Coastguard Worker int GptUpdateKernelWithEntry(GptData *gpt, GptEntry *e, uint32_t update_type)
120*8617a60dSAndroid Build Coastguard Worker {
121*8617a60dSAndroid Build Coastguard Worker 	int modified = 0;
122*8617a60dSAndroid Build Coastguard Worker 
123*8617a60dSAndroid Build Coastguard Worker 	if (!IsKernelEntry(e))
124*8617a60dSAndroid Build Coastguard Worker 		return GPT_ERROR_INVALID_UPDATE_TYPE;
125*8617a60dSAndroid Build Coastguard Worker 
126*8617a60dSAndroid Build Coastguard Worker 	switch (update_type) {
127*8617a60dSAndroid Build Coastguard Worker 	case GPT_UPDATE_ENTRY_TRY: {
128*8617a60dSAndroid Build Coastguard Worker 		/* Used up a try */
129*8617a60dSAndroid Build Coastguard Worker 		int tries;
130*8617a60dSAndroid Build Coastguard Worker 		if (GetEntrySuccessful(e)) {
131*8617a60dSAndroid Build Coastguard Worker 			/*
132*8617a60dSAndroid Build Coastguard Worker 			 * Successfully booted this partition, so tries field
133*8617a60dSAndroid Build Coastguard Worker 			 * is ignored.
134*8617a60dSAndroid Build Coastguard Worker 			 */
135*8617a60dSAndroid Build Coastguard Worker 			return GPT_SUCCESS;
136*8617a60dSAndroid Build Coastguard Worker 		}
137*8617a60dSAndroid Build Coastguard Worker 		tries = GetEntryTries(e);
138*8617a60dSAndroid Build Coastguard Worker 		if (tries > 1) {
139*8617a60dSAndroid Build Coastguard Worker 			/* Still have tries left */
140*8617a60dSAndroid Build Coastguard Worker 			modified = 1;
141*8617a60dSAndroid Build Coastguard Worker 			SetEntryTries(e, tries - 1);
142*8617a60dSAndroid Build Coastguard Worker 			break;
143*8617a60dSAndroid Build Coastguard Worker 		}
144*8617a60dSAndroid Build Coastguard Worker 		/* Out of tries, so drop through and mark partition bad. */
145*8617a60dSAndroid Build Coastguard Worker 		VBOOT_FALLTHROUGH;
146*8617a60dSAndroid Build Coastguard Worker 	}
147*8617a60dSAndroid Build Coastguard Worker 	case GPT_UPDATE_ENTRY_BAD: {
148*8617a60dSAndroid Build Coastguard Worker 		/* Giving up on this partition entirely. */
149*8617a60dSAndroid Build Coastguard Worker 		if (!GetEntrySuccessful(e)) {
150*8617a60dSAndroid Build Coastguard Worker 			/*
151*8617a60dSAndroid Build Coastguard Worker 			 * Only clear tries and priority if the successful bit
152*8617a60dSAndroid Build Coastguard Worker 			 * is not set.
153*8617a60dSAndroid Build Coastguard Worker 			 */
154*8617a60dSAndroid Build Coastguard Worker 			modified = 1;
155*8617a60dSAndroid Build Coastguard Worker 			SetEntryTries(e, 0);
156*8617a60dSAndroid Build Coastguard Worker 			SetEntryPriority(e, 0);
157*8617a60dSAndroid Build Coastguard Worker 		}
158*8617a60dSAndroid Build Coastguard Worker 		break;
159*8617a60dSAndroid Build Coastguard Worker 	}
160*8617a60dSAndroid Build Coastguard Worker 	case GPT_UPDATE_ENTRY_ACTIVE: {
161*8617a60dSAndroid Build Coastguard Worker 		/*
162*8617a60dSAndroid Build Coastguard Worker 		 * Used for fastboot mode. If kernel partition slot is marked
163*8617a60dSAndroid Build Coastguard Worker 		 * active, its GPT entry is marked with S1,P2,T0.
164*8617a60dSAndroid Build Coastguard Worker 		 */
165*8617a60dSAndroid Build Coastguard Worker 		modified = 1;
166*8617a60dSAndroid Build Coastguard Worker 		SetEntryTries(e, 0);
167*8617a60dSAndroid Build Coastguard Worker 		SetEntryPriority(e, 2);
168*8617a60dSAndroid Build Coastguard Worker 		SetEntrySuccessful(e, 1);
169*8617a60dSAndroid Build Coastguard Worker 		break;
170*8617a60dSAndroid Build Coastguard Worker 	}
171*8617a60dSAndroid Build Coastguard Worker 	case GPT_UPDATE_ENTRY_INVALID: {
172*8617a60dSAndroid Build Coastguard Worker 		/*
173*8617a60dSAndroid Build Coastguard Worker 		 * Used for fastboot mode. If kernel partition slot is marked
174*8617a60dSAndroid Build Coastguard Worker 		 * invalid, its GPT entry is marked with S0,P0,T0
175*8617a60dSAndroid Build Coastguard Worker 		 */
176*8617a60dSAndroid Build Coastguard Worker 		modified = 1;
177*8617a60dSAndroid Build Coastguard Worker 		SetEntryTries(e, 0);
178*8617a60dSAndroid Build Coastguard Worker 		SetEntryPriority(e, 0);
179*8617a60dSAndroid Build Coastguard Worker 		SetEntrySuccessful(e, 0);
180*8617a60dSAndroid Build Coastguard Worker 		break;
181*8617a60dSAndroid Build Coastguard Worker 	}
182*8617a60dSAndroid Build Coastguard Worker 	default:
183*8617a60dSAndroid Build Coastguard Worker 		return GPT_ERROR_INVALID_UPDATE_TYPE;
184*8617a60dSAndroid Build Coastguard Worker 	}
185*8617a60dSAndroid Build Coastguard Worker 
186*8617a60dSAndroid Build Coastguard Worker 	if (modified) {
187*8617a60dSAndroid Build Coastguard Worker 		GptModified(gpt);
188*8617a60dSAndroid Build Coastguard Worker 	}
189*8617a60dSAndroid Build Coastguard Worker 
190*8617a60dSAndroid Build Coastguard Worker 	return GPT_SUCCESS;
191*8617a60dSAndroid Build Coastguard Worker }
192*8617a60dSAndroid Build Coastguard Worker 
193*8617a60dSAndroid Build Coastguard Worker /*
194*8617a60dSAndroid Build Coastguard Worker  * Func: GptUpdateKernelEntry
195*8617a60dSAndroid Build Coastguard Worker  * Desc: This function updates current_kernel entry with provided
196*8617a60dSAndroid Build Coastguard Worker  * update_type. If current_kernel is not set, then it returns error.
197*8617a60dSAndroid Build Coastguard Worker  */
GptUpdateKernelEntry(GptData * gpt,uint32_t update_type)198*8617a60dSAndroid Build Coastguard Worker int GptUpdateKernelEntry(GptData *gpt, uint32_t update_type)
199*8617a60dSAndroid Build Coastguard Worker {
200*8617a60dSAndroid Build Coastguard Worker 	GptEntry *entries = (GptEntry *)gpt->primary_entries;
201*8617a60dSAndroid Build Coastguard Worker 	GptEntry *e = entries + gpt->current_kernel;
202*8617a60dSAndroid Build Coastguard Worker 
203*8617a60dSAndroid Build Coastguard Worker 	if (gpt->current_kernel == CGPT_KERNEL_ENTRY_NOT_FOUND)
204*8617a60dSAndroid Build Coastguard Worker 		return GPT_ERROR_INVALID_UPDATE_TYPE;
205*8617a60dSAndroid Build Coastguard Worker 
206*8617a60dSAndroid Build Coastguard Worker 	return GptUpdateKernelWithEntry(gpt, e, update_type);
207*8617a60dSAndroid Build Coastguard Worker }
208*8617a60dSAndroid Build Coastguard Worker 
209*8617a60dSAndroid Build Coastguard Worker /*
210*8617a60dSAndroid Build Coastguard Worker  * Func: GptFindNthEntry
211*8617a60dSAndroid Build Coastguard Worker  * Desc: This function returns the nth instance of parition entry matching the
212*8617a60dSAndroid Build Coastguard Worker  * partition type guid from the gpt table. Instance value starts from 0. If the
213*8617a60dSAndroid Build Coastguard Worker  * entry is not found it returns NULL.
214*8617a60dSAndroid Build Coastguard Worker  */
GptFindNthEntry(GptData * gpt,const Guid * guid,unsigned int n)215*8617a60dSAndroid Build Coastguard Worker GptEntry *GptFindNthEntry(GptData *gpt, const Guid *guid, unsigned int n)
216*8617a60dSAndroid Build Coastguard Worker {
217*8617a60dSAndroid Build Coastguard Worker 	GptHeader *header = (GptHeader *)gpt->primary_header;
218*8617a60dSAndroid Build Coastguard Worker 	GptEntry *entries = (GptEntry *)gpt->primary_entries;
219*8617a60dSAndroid Build Coastguard Worker 	GptEntry *e;
220*8617a60dSAndroid Build Coastguard Worker 	int i;
221*8617a60dSAndroid Build Coastguard Worker 
222*8617a60dSAndroid Build Coastguard Worker 	for (i = 0, e = entries; i < header->number_of_entries; i++, e++) {
223*8617a60dSAndroid Build Coastguard Worker 		if (!memcmp(&e->type, guid, sizeof(*guid))) {
224*8617a60dSAndroid Build Coastguard Worker 			if (n == 0)
225*8617a60dSAndroid Build Coastguard Worker 				return e;
226*8617a60dSAndroid Build Coastguard Worker 			n--;
227*8617a60dSAndroid Build Coastguard Worker 		}
228*8617a60dSAndroid Build Coastguard Worker 	}
229*8617a60dSAndroid Build Coastguard Worker 
230*8617a60dSAndroid Build Coastguard Worker 	return NULL;
231*8617a60dSAndroid Build Coastguard Worker }
232