Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Side by Side Diff: src/platform/vboot_reference/vboot_firmware/lib/cgptlib/cgptlib_internal.c

Issue 2438005: Much rearranging of cgptlib. Passes all its (new) unit tests. (Closed) Base URL: ssh://gitrw.chromium.org/chromiumos
Patch Set: Pre commit Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /* Copyright (c) 2010 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 "cgptlib.h"
7 #include "cgptlib_internal.h"
8 #include "crc32.h"
9 #include "gpt.h"
10 #include "utility.h"
11
12
13 int CheckParameters(GptData *gpt) {
14 /* Currently, we only support 512-byte sector. In the future, we may support
15 * larger sector. */
16 if (gpt->sector_bytes != 512)
17 return GPT_ERROR_INVALID_SECTOR_SIZE;
18
19 /* The sector number of a drive should be reasonable. If the given value is
20 * too small to contain basic GPT structure (PMBR + Headers + Entries),
21 * the value is wrong. */
22 if (gpt->drive_sectors < (1 + 2 * (1 + GPT_ENTRIES_SECTORS)))
23 return GPT_ERROR_INVALID_SECTOR_NUMBER;
24
25 return GPT_SUCCESS;
26 }
27
28
29 uint32_t HeaderCrc(GptHeader* h) {
30 uint32_t crc32, original_crc32;
31
32 /* Original CRC is calculated with the CRC field 0. */
33 original_crc32 = h->header_crc32;
34 h->header_crc32 = 0;
35 crc32 = Crc32((const uint8_t *)h, h->size);
36 h->header_crc32 = original_crc32;
37
38 return crc32;
39 }
40
41
42 int CheckHeader(GptHeader *h, int is_secondary, uint64_t drive_sectors) {
43 if (!h)
44 return 1;
45
46 /* Make sure we're looking at a header of reasonable size before
47 * attempting to calculate CRC. */
48 if (Memcmp(h->signature, GPT_HEADER_SIGNATURE, GPT_HEADER_SIGNATURE_SIZE))
49 return 1;
50 if (h->revision != GPT_HEADER_REVISION)
51 return 1;
52 if (h->size < MIN_SIZE_OF_HEADER || h->size > MAX_SIZE_OF_HEADER)
53 return 1;
54
55 /* Check CRC before looking at remaining fields */
56 if (HeaderCrc(h) != h->header_crc32)
57 return 1;
58
59 /* Reserved fields must be zero. */
60 if (h->reserved)
61 return 1;
62
63 /* TODO: Padding must be set to zero. */
64
65 /* If entry size is different than our struct, we won't be able to
66 * parse it. Technically, any size 2^N where N>=7 is valid. */
67 if (h->size_of_entry != sizeof(GptEntry))
68 return 1;
69 if ((h->number_of_entries < MIN_NUMBER_OF_ENTRIES) ||
70 (h->number_of_entries > MAX_NUMBER_OF_ENTRIES) ||
71 (h->number_of_entries * h->size_of_entry != TOTAL_ENTRIES_SIZE))
72 return 1;
73
74 /* Check locations for the header and its entries. The primary
75 * immediately follows the PMBR, and is followed by its entries.
76 * The secondary is at the end of the drive, preceded by its
77 * entries. */
78 if (is_secondary) {
79 if ((h->my_lba != drive_sectors - 1) || (h->alternate_lba != 1))
80 return 1;
81 if (h->entries_lba != h->my_lba - GPT_ENTRIES_SECTORS)
82 return 1;
83 } else {
84 if ((h->my_lba != 1) || (h->alternate_lba != drive_sectors - 1))
85 return 1;
86 if (h->entries_lba != h->my_lba + 1)
87 return 1;
88 }
89
90 /* FirstUsableLBA must be after the end of the primary GPT table
91 * array. LastUsableLBA must be before the start of the secondary
92 * GPT table array. FirstUsableLBA <= LastUsableLBA. */
93 if (h->first_usable_lba < 2 + GPT_ENTRIES_SECTORS)
94 return 1;
95 if (h->last_usable_lba >= drive_sectors - 1 - GPT_ENTRIES_SECTORS)
96 return 1;
97 if (h->first_usable_lba > h->last_usable_lba)
98 return 1;
99
100 /* Success */
101 return 0;
102 }
103
104
105 /* Return 1 if the entry is unused, 0 if it is used. */
106 int IsUnusedEntry(const GptEntry* e) {
107 static Guid zero = {{{0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0}}}};
108 return (Memcmp(&zero, (const uint8_t*)(&e->type), sizeof(zero)) ? 0 : 1);
109 }
110
111 /* Returns 1 if the entry is a Chrome OS kernel partition, else 0. */
112 int IsKernelEntry(const GptEntry* e) {
113 static Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
114 return (Memcmp(&e->type, &chromeos_kernel, sizeof(Guid)) ? 0 : 1);
115 }
116
117
118 int CheckEntries(GptEntry* entries, GptHeader* h, uint64_t drive_sectors) {
119
120 GptEntry* entry;
121 uint32_t crc32;
122 int i;
123
124 /* Check CRC before examining entries. */
125 crc32 = Crc32((const uint8_t *)entries,
126 h->size_of_entry * h->number_of_entries);
127 if (crc32 != h->entries_crc32)
128 return 1;
129
130 /* Check all entries. */
131 for (i = 0, entry = entries; i < h->number_of_entries; i++, entry++) {
132 GptEntry* e2;
133 int i2;
134
135 if (IsUnusedEntry(entry))
136 continue;
137
138 /* Entry must be in valid region. */
139 if ((entry->starting_lba < h->first_usable_lba) ||
140 (entry->ending_lba > h->last_usable_lba) ||
141 (entry->ending_lba < entry->starting_lba))
142 return 1;
143
144 /* Entry must not overlap other entries. */
145 for (i2 = 0, e2 = entries; i2 < h->number_of_entries; i2++, e2++) {
146 if (i2 == i || IsUnusedEntry(e2))
147 continue;
148
149 if ((entry->starting_lba >= e2->starting_lba) &&
150 (entry->starting_lba <= e2->ending_lba))
151 return 1;
152 if ((entry->ending_lba >= e2->starting_lba) &&
153 (entry->ending_lba <= e2->ending_lba))
154 return 1;
155 }
156 }
157
158 /* Success */
159 return 0;
160 }
161
162
163 /* Returns 0 if the GptHeaders are the same for all fields which don't
164 * differ between the primary and secondary headers - that is, all
165 * fields other than:
166 *
167 * my_lba
168 * alternate_lba
169 * entries_lba */
170 int HeaderFieldsSame(GptHeader *h1, GptHeader *h2) {
171 if (Memcmp(h1->signature, h2->signature, sizeof(h1->signature)))
172 return 1;
173 if (h1->revision != h2->revision)
174 return 1;
175 if (h1->size != h2->size)
176 return 1;
177 if (h1->reserved != h2->reserved)
178 return 1;
179 if (h1->first_usable_lba != h2->first_usable_lba)
180 return 1;
181 if (h1->last_usable_lba != h2->last_usable_lba)
182 return 1;
183 if (Memcmp(&h1->disk_uuid, &h2->disk_uuid, sizeof(Guid)))
184 return 1;
185 if (h1->number_of_entries != h2->number_of_entries)
186 return 1;
187 if (h1->size_of_entry != h2->size_of_entry)
188 return 1;
189 if (h1->entries_crc32 != h2->entries_crc32)
190 return 1;
191
192 return 0;
193 }
194
195
196 int GptSanityCheck(GptData *gpt) {
197 int retval;
198 GptHeader* header1 = (GptHeader*)(gpt->primary_header);
199 GptHeader* header2 = (GptHeader*)(gpt->secondary_header);
200 GptEntry* entries1 = (GptEntry*)(gpt->primary_entries);
201 GptEntry* entries2 = (GptEntry*)(gpt->secondary_entries);
202 GptHeader* goodhdr = NULL;
203
204 gpt->valid_headers = 0;
205 gpt->valid_entries = 0;
206
207 retval = CheckParameters(gpt);
208 if (retval != GPT_SUCCESS)
209 return retval;
210
211 /* Check both headers; we need at least one valid header. */
212 if (0 == CheckHeader(header1, 0, gpt->drive_sectors)) {
213 gpt->valid_headers |= MASK_PRIMARY;
214 goodhdr = header1;
215 }
216 if (0 == CheckHeader(header2, 1, gpt->drive_sectors)) {
217 gpt->valid_headers |= MASK_SECONDARY;
218 if (!goodhdr)
219 goodhdr = header2;
220 }
221
222 if (!gpt->valid_headers)
223 return GPT_ERROR_INVALID_HEADERS;
224
225 /* Checks if entries are valid.
226 *
227 * Note that we use the same header in both checks. This way we'll
228 * catch the case where (header1,entries1) and (header2,entries2)
229 * are both valid, but (entries1 != entries2). */
230 if (0 == CheckEntries(entries1, goodhdr, gpt->drive_sectors))
231 gpt->valid_entries |= MASK_PRIMARY;
232 if (0 == CheckEntries(entries2, goodhdr, gpt->drive_sectors))
233 gpt->valid_entries |= MASK_SECONDARY;
234
235 /* If both headers are good but neither entries were good, check the
236 * entries with the secondary header. */
237 if (MASK_BOTH == gpt->valid_headers && !gpt->valid_entries) {
238 if (0 == CheckEntries(entries1, header2, gpt->drive_sectors))
239 gpt->valid_entries |= MASK_PRIMARY;
240 if (0 == CheckEntries(entries2, header2, gpt->drive_sectors))
241 gpt->valid_entries |= MASK_SECONDARY;
242 if (gpt->valid_entries) {
243 /* Sure enough, header2 had a good CRC for one of the entries. Mark
244 * header1 invalid, so we'll update its entries CRC. */
245 gpt->valid_headers &= ~MASK_PRIMARY;
246 goodhdr = header2;
247 }
248 }
249
250 if (!gpt->valid_entries)
251 return GPT_ERROR_INVALID_ENTRIES;
252
253 /* Now that we've determined which header contains a good CRC for
254 * the entries, make sure the headers are otherwise identical. */
255 if (MASK_BOTH == gpt->valid_headers &&
256 0 != HeaderFieldsSame(header1, header2))
257 gpt->valid_headers &= ~MASK_SECONDARY;
258
259 return GPT_SUCCESS;
260 }
261
262
263 void GptRepair(GptData *gpt) {
264 GptHeader* header1 = (GptHeader*)(gpt->primary_header);
265 GptHeader* header2 = (GptHeader*)(gpt->secondary_header);
266 GptEntry* entries1 = (GptEntry*)(gpt->primary_entries);
267 GptEntry* entries2 = (GptEntry*)(gpt->secondary_entries);
268 int entries_size;
269
270 /* Need at least one good header and one good set of entries. */
271 if (MASK_NONE == gpt->valid_headers || MASK_NONE == gpt->valid_entries)
272 return;
273
274 /* Repair headers if necessary */
275 if (MASK_PRIMARY == gpt->valid_headers) {
276 /* Primary is good, secondary is bad */
277 Memcpy(header2, header1, sizeof(GptHeader));
278 header2->my_lba = gpt->drive_sectors - 1;
279 header2->alternate_lba = 1;
280 header2->entries_lba = header2->my_lba - GPT_ENTRIES_SECTORS;
281 header2->header_crc32 = HeaderCrc(header2);
282 gpt->modified |= GPT_MODIFIED_HEADER2;
283 }
284 else if (MASK_SECONDARY == gpt->valid_headers) {
285 /* Secondary is good, primary is bad */
286 Memcpy(header1, header2, sizeof(GptHeader));
287 header1->my_lba = 1;
288 header1->alternate_lba = gpt->drive_sectors - 1;
289 header1->entries_lba = header1->my_lba + 1;
290 header1->header_crc32 = HeaderCrc(header1);
291 gpt->modified |= GPT_MODIFIED_HEADER1;
292 }
293 gpt->valid_headers = MASK_BOTH;
294
295 /* Repair entries if necessary */
296 entries_size = header1->size_of_entry * header1->number_of_entries;
297 if (MASK_PRIMARY == gpt->valid_entries) {
298 /* Primary is good, secondary is bad */
299 Memcpy(entries2, entries1, entries_size);
300 gpt->modified |= GPT_MODIFIED_ENTRIES2;
301 }
302 else if (MASK_SECONDARY == gpt->valid_entries) {
303 /* Secondary is good, primary is bad */
304 Memcpy(entries1, entries2, entries_size);
305 gpt->modified |= GPT_MODIFIED_ENTRIES1;
306 }
307 gpt->valid_entries = MASK_BOTH;
308 }
309
310
311 int GetEntrySuccessful(const GptEntry* e) {
312 return (e->attributes & CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >>
313 CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET;
314 }
315
316
317 int GetEntryPriority(const GptEntry* e) {
318 return (e->attributes & CGPT_ATTRIBUTE_PRIORITY_MASK) >>
319 CGPT_ATTRIBUTE_PRIORITY_OFFSET;
320 }
321
322
323 int GetEntryTries(const GptEntry* e) {
324 return (e->attributes & CGPT_ATTRIBUTE_TRIES_MASK) >>
325 CGPT_ATTRIBUTE_TRIES_OFFSET;
326 }
327
328
329 void SetEntrySuccessful(GptEntry* e, int successful) {
330 if (successful)
331 e->attributes |= CGPT_ATTRIBUTE_SUCCESSFUL_MASK;
332 else
333 e->attributes &= ~CGPT_ATTRIBUTE_SUCCESSFUL_MASK;
334 }
335
336
337 void SetEntryPriority(GptEntry* e, int priority) {
338 e->attributes &= ~CGPT_ATTRIBUTE_PRIORITY_MASK;
339 e->attributes |= ((uint64_t)priority << CGPT_ATTRIBUTE_PRIORITY_OFFSET) &
340 CGPT_ATTRIBUTE_PRIORITY_MASK;
341 }
342
343
344 void SetEntryTries(GptEntry* e, int tries) {
345 e->attributes &= ~CGPT_ATTRIBUTE_TRIES_MASK;
346 e->attributes |= ((uint64_t)tries << CGPT_ATTRIBUTE_TRIES_OFFSET) &
347 CGPT_ATTRIBUTE_TRIES_MASK;
348 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698