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