blob: 964232d6e6c3f7f7f82b37a710541f31d5b76c01 [file] [log] [blame]
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001/* 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
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07006#include "cgpt_test.h"
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -07007#include <string.h>
8#include "cgpt.h"
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07009#include "cgpt_internal.h"
10#include "crc32.h"
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070011#include "gpt.h"
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070012#include "quick_sort_test.h"
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070013#include "utility.h"
14
15/* Testing partition layout (sector_bytes=512)
16 *
17 * LBA Size Usage
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -070018 * ---------------------------------------------------------
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070019 * 0 1 PMBR
20 * 1 1 primary partition header
21 * 2 32 primary partition entries (128B * 128)
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -070022 * 34 100 kernel A (index: 0)
23 * 134 100 root A (index: 1)
24 * 234 100 root B (index: 2)
25 * 334 100 kernel B (index: 3)
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070026 * 434 32 secondary partition entries
27 * 466 1 secondary partition header
28 * 467
29 */
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -070030#define KERNEL_A 0
31#define ROOTFS_A 1
32#define ROOTFS_B 2
33#define KERNEL_B 3
34
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070035#define DEFAULT_SECTOR_SIZE 512
36#define MAX_SECTOR_SIZE 4096
37#define DEFAULT_DRIVE_SECTORS 467
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070038#define PARTITION_ENTRIES_SIZE TOTAL_ENTRIES_SIZE /* 16384 */
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070039
40/* Given a GptData pointer, first re-calculate entries CRC32 value,
41 * then reset header CRC32 value to 0, and calculate header CRC32 value.
42 * Both primary and secondary are updated. */
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070043void RefreshCrc32(GptData *gpt) {
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070044 GptHeader *header, *header2;
45 GptEntry *entries, *entries2;
46
47 header = (GptHeader*)gpt->primary_header;
48 entries = (GptEntry*)gpt->primary_entries;
49 header2 = (GptHeader*)gpt->secondary_header;
50 entries2 = (GptEntry*)gpt->secondary_entries;
51
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070052 header->entries_crc32 =
53 Crc32((uint8_t*)entries,
54 header->number_of_entries * header->size_of_entry);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070055 header->header_crc32 = 0;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070056 header->header_crc32 = Crc32((uint8_t*)header, header->size);
57 header2->entries_crc32 =
58 Crc32((uint8_t*)entries2,
59 header2->number_of_entries * header2->size_of_entry);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070060 header2->header_crc32 = 0;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070061 header2->header_crc32 = Crc32((uint8_t*)header2, header2->size);
62}
63
64void ZeroHeaders(GptData* gpt) {
65 Memset(gpt->primary_header, 0, MAX_SECTOR_SIZE);
66 Memset(gpt->secondary_header, 0, MAX_SECTOR_SIZE);
67}
68
69void ZeroEntries(GptData* gpt) {
70 Memset(gpt->primary_entries, 0, PARTITION_ENTRIES_SIZE);
71 Memset(gpt->secondary_entries, 0, PARTITION_ENTRIES_SIZE);
72}
73
74void ZeroHeadersEntries(GptData* gpt) {
75 ZeroHeaders(gpt);
76 ZeroEntries(gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070077}
78
79/* Returns a pointer to a static GptData instance (no free is required).
80 * All fields are zero except 4 pointers linking to header and entries.
81 * All content of headers and entries are zero. */
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070082GptData* GetEmptyGptData() {
83 static GptData gpt;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070084 static uint8_t primary_header[MAX_SECTOR_SIZE];
85 static uint8_t primary_entries[PARTITION_ENTRIES_SIZE];
86 static uint8_t secondary_header[MAX_SECTOR_SIZE];
87 static uint8_t secondary_entries[PARTITION_ENTRIES_SIZE];
88
89 Memset(&gpt, 0, sizeof(gpt));
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070090 gpt.primary_header = primary_header;
91 gpt.primary_entries = primary_entries;
92 gpt.secondary_header = secondary_header;
93 gpt.secondary_entries = secondary_entries;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070094 ZeroHeadersEntries(&gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070095
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -070096 /* Initialize GptData internal states. */
97 gpt.current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
98
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070099 return &gpt;
100}
101
102/* Fills in most of fields and creates the layout described in the top of this
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700103 * file. Before calling this function, primary/secondary header/entries must
104 * have been pointed to the buffer, say, a gpt returned from GetEmptyGptData().
105 * This function returns a good (valid) copy of GPT layout described in top of
106 * this file. */
107void BuildTestGptData(GptData *gpt) {
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700108 GptHeader *header, *header2;
109 GptEntry *entries, *entries2;
110 Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700111 Guid chromeos_rootfs = GPT_ENT_TYPE_CHROMEOS_ROOTFS;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700112
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700113 gpt->sector_bytes = DEFAULT_SECTOR_SIZE;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700114 gpt->drive_sectors = DEFAULT_DRIVE_SECTORS;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700115 gpt->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700116
117 /* build primary */
118 header = (GptHeader*)gpt->primary_header;
119 entries = (GptEntry*)gpt->primary_entries;
120 Memcpy(header->signature, GPT_HEADER_SIGNATURE, sizeof(GPT_HEADER_SIGNATURE));
121 header->revision = GPT_HEADER_REVISION;
122 header->size = sizeof(GptHeader) - sizeof(header->padding);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700123 header->reserved = 0;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700124 header->my_lba = 1;
125 header->first_usable_lba = 34;
126 header->last_usable_lba = DEFAULT_DRIVE_SECTORS - 1 - 32 - 1; /* 433 */
127 header->entries_lba = 2;
128 header->number_of_entries = 128; /* 512B / 128B * 32sectors = 128 entries */
129 header->size_of_entry = 128; /* bytes */
130 Memcpy(&entries[0].type, &chromeos_kernel, sizeof(chromeos_kernel));
131 entries[0].starting_lba = 34;
132 entries[0].ending_lba = 133;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700133 Memcpy(&entries[1].type, &chromeos_rootfs, sizeof(chromeos_rootfs));
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700134 entries[1].starting_lba = 134;
135 entries[1].ending_lba = 233;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700136 Memcpy(&entries[2].type, &chromeos_rootfs, sizeof(chromeos_rootfs));
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700137 entries[2].starting_lba = 234;
138 entries[2].ending_lba = 333;
139 Memcpy(&entries[3].type, &chromeos_kernel, sizeof(chromeos_kernel));
140 entries[3].starting_lba = 334;
141 entries[3].ending_lba = 433;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700142 header->padding = 0;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700143
144 /* build secondary */
145 header2 = (GptHeader*)gpt->secondary_header;
146 entries2 = (GptEntry*)gpt->secondary_entries;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700147 Memcpy(header2, header, sizeof(GptHeader));
148 Memcpy(entries2, entries, PARTITION_ENTRIES_SIZE);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700149 header2->my_lba = DEFAULT_DRIVE_SECTORS - 1; /* 466 */
150 header2->entries_lba = DEFAULT_DRIVE_SECTORS - 1 - 32; /* 434 */
151
152 RefreshCrc32(gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700153}
154
155/* Dumps memory starting from [vp] with [len] bytes.
156 * Prints [memo] if not NULL. Example output:
157 *
158 * 00 01 02 03 04 05 06 07 - 08 09 0a 0b 0c 0d 0e 0f
159 * 10 11 12 13 14 15 16 17 - 18 19 1a 1b 1c 1d 1e 1f
160 * ...
161 */
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700162static void Dump(void *vp, int len, char* memo) {
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700163 uint8_t *start = vp;
164 int i;
165 if (memo) printf("--[%s]----------\n", memo);
166 for (i = 0; i < len; ++i) {
167 printf("%02x%s", start[i],
168 (!(~i & 15) ? "\n" :
169 !(~i & 7) ? " - ": " "));
170 }
171 if (i&15) printf("\n");
172}
173
174/* More formatted dump with GptData. */
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700175void DumpGptData(GptData *gpt) {
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700176 printf("DumpGptData(%p)...\n", gpt);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700177 Dump(gpt, sizeof(gpt), NULL);
178 Dump(gpt->primary_header, sizeof(GptHeader), "Primary header");
179 Dump(gpt->primary_entries, sizeof(GptEntry) * 8, "Primary entries");
180 Dump(gpt->secondary_header, sizeof(GptHeader), "Secondary header");
181 Dump(gpt->secondary_entries, sizeof(GptEntry) * 8,
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700182 "Secondary entries");
183}
184
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700185/* Tests if the default structure returned by BuildTestGptData() is good. */
186int TestBuildTestGptData() {
187 GptData *gpt;
188 gpt = GetEmptyGptData();
189 BuildTestGptData(gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700190 EXPECT(GPT_SUCCESS == GptInit(gpt));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700191 return TEST_OK;
192}
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700193
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700194/* Tests if wrong sector_bytes or drive_sectors is detected by GptInit().
195 * Currently we only support 512 bytes per sector.
196 * In the future, we may support other sizes.
197 * A too small drive_sectors should be rejected by GptInit(). */
198int ParameterTests() {
199 GptData *gpt;
200 struct {
201 uint32_t sector_bytes;
202 uint64_t drive_sectors;
203 int expected_retval;
204 } cases[] = {
205 {512, DEFAULT_DRIVE_SECTORS, GPT_SUCCESS},
206 {520, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
207 {512, 0, GPT_ERROR_INVALID_SECTOR_NUMBER},
208 {512, 66, GPT_ERROR_INVALID_SECTOR_NUMBER},
209 {512, GPT_PMBR_SECTOR + GPT_HEADER_SECTOR * 2 + GPT_ENTRIES_SECTORS * 2,
210 GPT_SUCCESS},
211 {4096, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
212 };
213 int i;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700214
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700215 gpt = GetEmptyGptData();
216 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
217 BuildTestGptData(gpt);
218 gpt->sector_bytes = cases[i].sector_bytes;
219 gpt->drive_sectors = cases[i].drive_sectors;
220 EXPECT(cases[i].expected_retval == CheckParameters(gpt));
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700221 }
222
223 return TEST_OK;
224}
225
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700226/* Tests if signature ("EFI PART") is checked. */
227int SignatureTest() {
228 int i;
229 GptData *gpt;
230 int test_mask;
231 GptHeader *headers[2];
232
233 gpt = GetEmptyGptData();
234 headers[PRIMARY] = (GptHeader*)gpt->primary_header;
235 headers[SECONDARY] = (GptHeader*)gpt->secondary_header;
236
237 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
238 for (i = 0; i < 8; ++i) {
239 BuildTestGptData(gpt);
240 if (test_mask & MASK_PRIMARY)
241 headers[PRIMARY]->signature[i] ^= 0xff;
242 if (test_mask & MASK_SECONDARY)
243 headers[SECONDARY]->signature[i] ^= 0xff;
244 EXPECT((MASK_BOTH ^ test_mask) == CheckHeaderSignature(gpt));
245 }
246 }
247
248 return TEST_OK;
249}
250
251/* The revision we currently support is GPT_HEADER_REVISION.
252 * If the revision in header is not that, we expect the header is invalid. */
253int RevisionTest() {
254 GptData *gpt;
255 struct {
256 uint32_t value_to_test;
257 int is_valid_value;
258 } cases[] = {
259 {0x01000000, 0},
260 {0x00010000, 1}, /* GPT_HEADER_REVISION */
261 {0x00000100, 0},
262 {0x00000001, 0},
263 {0x23010456, 0},
264 };
265 int i;
266 int test_mask;
267 GptHeader *headers[2];
268 uint32_t valid_headers;
269
270 gpt = GetEmptyGptData();
271 headers[PRIMARY] = (GptHeader*)gpt->primary_header;
272 headers[SECONDARY] = (GptHeader*)gpt->secondary_header;
273
274 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
275 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
276 BuildTestGptData(gpt);
277 if (test_mask & MASK_PRIMARY)
278 headers[PRIMARY]->revision = cases[i].value_to_test;
279 if (test_mask & MASK_SECONDARY)
280 headers[SECONDARY]->revision = cases[i].value_to_test;
281 valid_headers = CheckRevision(gpt);
282 if (cases[i].is_valid_value)
283 EXPECT(MASK_BOTH == valid_headers);
284 else
285 EXPECT((MASK_BOTH ^ test_mask) == valid_headers);
286 }
287 }
288 return TEST_OK;
289}
290
291int SizeTest() {
292 GptData *gpt;
293 struct {
294 uint32_t value_to_test;
295 int is_valid_value;
296 } cases[] = {
297 {91, 0},
298 {92, 1},
299 {93, 1},
300 {511, 1},
301 {512, 1},
302 {513, 0},
303 };
304 int i;
305 int test_mask;
306 GptHeader *headers[2];
307 uint32_t valid_headers;
308
309 gpt = GetEmptyGptData();
310 headers[PRIMARY] = (GptHeader*)gpt->primary_header;
311 headers[SECONDARY] = (GptHeader*)gpt->secondary_header;
312
313 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
314 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
315 BuildTestGptData(gpt);
316 if (test_mask & MASK_PRIMARY)
317 headers[PRIMARY]->size = cases[i].value_to_test;
318 if (test_mask & MASK_SECONDARY)
319 headers[SECONDARY]->size = cases[i].value_to_test;
320 valid_headers = CheckSize(gpt);
321 if (cases[i].is_valid_value)
322 EXPECT(MASK_BOTH == valid_headers);
323 else
324 EXPECT((MASK_BOTH ^ test_mask) == valid_headers);
325 }
326 }
327 return TEST_OK;
328}
329
330/* Tests if reserved fields are checked.
331 * We'll try non-zero values to test. */
332int ReservedFieldsTest() {
333 GptData *gpt;
334 GptHeader *primary_header, *secondary_header;
335
336 gpt = GetEmptyGptData();
337 primary_header = (GptHeader*)gpt->primary_header;
338 secondary_header = (GptHeader*)gpt->secondary_header;
339
340 /* expect secondary is still valid. */
341 BuildTestGptData(gpt);
342 primary_header->reserved ^= 0x12345678; /* whatever random */
343 EXPECT(MASK_SECONDARY == CheckReservedFields(gpt));
344
345 /* expect secondary is still valid. */
346 BuildTestGptData(gpt);
347 primary_header->padding ^= 0x12345678; /* whatever random */
348 EXPECT(MASK_SECONDARY == CheckReservedFields(gpt));
349
350 /* expect primary is still valid. */
351 BuildTestGptData(gpt);
352 secondary_header->reserved ^= 0x12345678; /* whatever random */
353 EXPECT(MASK_PRIMARY == CheckReservedFields(gpt));
354
355 /* expect primary is still valid. */
356 BuildTestGptData(gpt);
357 secondary_header->padding ^= 0x12345678; /* whatever random */
358 EXPECT(MASK_PRIMARY == CheckReservedFields(gpt));
359
360 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700361}
362
363/* Tests if myLBA field is checked (1 for primary, last for secondary). */
364int MyLbaTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700365 GptData *gpt;
366 int test_mask;
367 GptHeader *headers[2];
368 uint32_t valid_headers;
369
370 gpt = GetEmptyGptData();
371 headers[PRIMARY] = (GptHeader*)gpt->primary_header;
372 headers[SECONDARY] = (GptHeader*)gpt->secondary_header;
373
374 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
375 BuildTestGptData(gpt);
376 if (test_mask & MASK_PRIMARY)
377 ++headers[PRIMARY]->my_lba;
378 if (test_mask & MASK_SECONDARY)
379 --headers[SECONDARY]->my_lba;
380 valid_headers = CheckMyLba(gpt);
381 EXPECT((MASK_BOTH ^ test_mask) == valid_headers);
382 }
383 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700384}
385
386/* Tests if SizeOfPartitionEntry is checked. SizeOfPartitionEntry must be
387 * between 128 and 512, and a multiple of 8. */
388int SizeOfPartitionEntryTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700389 GptData *gpt;
390 struct {
391 uint32_t value_to_test;
392 int is_valid_value;
393 } cases[] = {
394 {127, 0},
395 {128, 1},
396 {129, 0},
397 {130, 0},
398 {131, 0},
399 {132, 0},
400 {133, 0},
401 {134, 0},
402 {135, 0},
403 {136, 1},
404 {144, 1},
405 {160, 1},
406 {192, 1},
407 {256, 1},
408 {384, 1},
409 {504, 1},
410 {512, 1},
411 {513, 0},
412 {520, 0},
413 };
414 int i;
415 int test_mask;
416 GptHeader *headers[2];
417 uint32_t valid_headers;
418
419 gpt = GetEmptyGptData();
420 headers[PRIMARY] = (GptHeader*)gpt->primary_header;
421 headers[SECONDARY] = (GptHeader*)gpt->secondary_header;
422
423 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
424 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
425 BuildTestGptData(gpt);
426 if (test_mask & MASK_PRIMARY) {
427 headers[PRIMARY]->size_of_entry = cases[i].value_to_test;
428 headers[PRIMARY]->number_of_entries =
429 TOTAL_ENTRIES_SIZE / cases[i].value_to_test;
430 }
431 if (test_mask & MASK_SECONDARY) {
432 headers[SECONDARY]->size_of_entry = cases[i].value_to_test;
433 headers[SECONDARY]->number_of_entries =
434 TOTAL_ENTRIES_SIZE / cases[i].value_to_test;
435 }
436 valid_headers = CheckSizeOfPartitionEntry(gpt);
437 if (cases[i].is_valid_value)
438 EXPECT(MASK_BOTH == valid_headers);
439 else
440 EXPECT((MASK_BOTH ^ test_mask) == valid_headers);
441 }
442 }
443 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700444}
445
446/* Tests if NumberOfPartitionEntries is checes. NumberOfPartitionEntries must
447 * be between 32 and 512, and SizeOfPartitionEntry * NumberOfPartitionEntries
448 * must be 16384. */
449int NumberOfPartitionEntriesTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700450 GptData *gpt;
451 struct {
452 uint32_t size_of_entry;
453 uint32_t number_of_entries;
454 int is_valid_value;
455 } cases[] = {
456 {111, 147, 0},
457 {111, 149, 0},
458 {128, 32, 0},
459 {128, 64, 0},
460 {128, 127, 0},
461 {128, 128, 1},
462 {128, 129, 0},
463 {128, 256, 0},
464 {256, 32, 0},
465 {256, 64, 1},
466 {256, 128, 0},
467 {256, 256, 0},
468 {512, 32, 1},
469 {512, 64, 0},
470 {512, 128, 0},
471 {512, 256, 0},
472 {1024, 128, 0},
473 };
474 int i;
475 int test_mask;
476 GptHeader *headers[2];
477 uint32_t valid_headers;
478
479 gpt = GetEmptyGptData();
480 headers[PRIMARY] = (GptHeader*)gpt->primary_header;
481 headers[SECONDARY] = (GptHeader*)gpt->secondary_header;
482
483 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
484 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
485 BuildTestGptData(gpt);
486 if (test_mask & MASK_PRIMARY) {
487 headers[PRIMARY]->size_of_entry = cases[i].size_of_entry;
488 headers[PRIMARY]->number_of_entries = cases[i].number_of_entries;
489 }
490 if (test_mask & MASK_SECONDARY) {
491 headers[SECONDARY]->size_of_entry = cases[i].size_of_entry;
492 headers[SECONDARY]->number_of_entries = cases[i].number_of_entries;
493 }
494 valid_headers = CheckNumberOfEntries(gpt);
495 if (cases[i].is_valid_value)
496 EXPECT(MASK_BOTH == valid_headers);
497 else
498 EXPECT((MASK_BOTH ^ test_mask) == valid_headers);
499 }
500 }
501 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700502}
503
504/* Tests if PartitionEntryLBA in primary/secondary headers is checked. */
505int PartitionEntryLbaTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700506 GptData *gpt;
507 int test_mask;
508 GptHeader *headers[2];
509 uint32_t valid_headers;
510
511 gpt = GetEmptyGptData();
512 headers[PRIMARY] = (GptHeader*)gpt->primary_header;
513 headers[SECONDARY] = (GptHeader*)gpt->secondary_header;
514
515 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
516 BuildTestGptData(gpt);
517 if (test_mask & MASK_PRIMARY)
518 headers[PRIMARY]->entries_lba = 0;
519 if (test_mask & MASK_SECONDARY)
520 headers[SECONDARY]->entries_lba = DEFAULT_DRIVE_SECTORS - 31 - 1;
521 valid_headers = CheckEntriesLba(gpt);
522 EXPECT((MASK_BOTH ^ test_mask) == valid_headers);
523 }
524 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700525}
526
527/* Tests if FirstUsableLBA and LastUsableLBA are checked.
528 * FirstUsableLBA must be after the end of the primary GPT table array.
529 * LastUsableLBA must be before the start of the secondary GPT table array.
530 * FirstUsableLBA <= LastUsableLBA. */
531int FirstUsableLbaAndLastUsableLbaTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700532 GptData *gpt;
533 GptHeader *primary_header, *secondary_header;
534 uint32_t valid_headers;
535 int i;
536 struct {
537 uint64_t primary_entries_lba;
538 uint64_t primary_first_usable_lba;
539 uint64_t primary_last_usable_lba;
540 uint64_t secondary_first_usable_lba;
541 uint64_t secondary_last_usable_lba;
542 uint64_t secondary_entries_lba;
543 int expected_masks;
544 } cases[] = {
545 {2, 34, 433, 34, 433, 434, MASK_BOTH},
546 {2, 34, 432, 34, 430, 434, MASK_BOTH},
547 {2, 33, 433, 33, 433, 434, MASK_NONE},
548 {3, 34, 433, 35, 433, 434, MASK_SECONDARY},
549 {3, 35, 433, 33, 433, 434, MASK_PRIMARY},
550 {2, 34, 434, 34, 433, 434, MASK_SECONDARY},
551 {2, 34, 433, 34, 434, 434, MASK_PRIMARY},
552 {2, 35, 433, 35, 433, 434, MASK_BOTH},
553 {2, 433, 433, 433, 433, 434, MASK_BOTH},
554 {2, 434, 433, 434, 434, 434, MASK_NONE},
555 {2, 433, 34, 34, 433, 434, MASK_SECONDARY},
556 {2, 34, 433, 433, 34, 434, MASK_PRIMARY},
557 };
558
559 gpt = GetEmptyGptData();
560 primary_header = (GptHeader*)gpt->primary_header;
561 secondary_header = (GptHeader*)gpt->secondary_header;
562
563 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
564 BuildTestGptData(gpt);
565 primary_header->entries_lba = cases[i].primary_entries_lba;
566 primary_header->first_usable_lba = cases[i].primary_first_usable_lba;
567 primary_header->last_usable_lba = cases[i].primary_last_usable_lba;
568 secondary_header->entries_lba = cases[i].secondary_entries_lba;
569 secondary_header->first_usable_lba = cases[i].secondary_first_usable_lba;
570 secondary_header->last_usable_lba = cases[i].secondary_last_usable_lba;
571 valid_headers = CheckValidUsableLbas(gpt);
572 EXPECT(cases[i].expected_masks == valid_headers);
573 }
574
575 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700576}
577
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700578/* Tests if header CRC in two copies are calculated. */
579int HeaderCrcTest() {
580 GptData *gpt;
581 GptHeader *primary_header, *secondary_header;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700582
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700583 gpt = GetEmptyGptData();
584 primary_header = (GptHeader*)gpt->primary_header;
585 secondary_header = (GptHeader*)gpt->secondary_header;
586
587 /* Modify the first byte of primary header, and expect the CRC is wrong. */
588 BuildTestGptData(gpt);
589 gpt->primary_header[0] ^= 0xa5; /* just XOR a non-zero value */
590 EXPECT(MASK_SECONDARY == CheckHeaderCrc(gpt));
591
592 /* Modify the last byte of secondary header, and expect the CRC is wrong. */
593 BuildTestGptData(gpt);
594 gpt->secondary_header[secondary_header->size-1] ^= 0x5a;
595 EXPECT(MASK_PRIMARY == CheckHeaderCrc(gpt));
596
597 /* Modify out of CRC range, expect CRC is still right. */
598 BuildTestGptData(gpt);
599 gpt->primary_header[primary_header->size] ^= 0x87;
600 EXPECT(MASK_BOTH == CheckHeaderCrc(gpt));
601
602 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700603}
604
605/* Tests if PartitionEntryArrayCRC32 is checked.
606 * PartitionEntryArrayCRC32 must be calculated over SizeOfPartitionEntry *
607 * NumberOfPartitionEntries bytes.
608 */
609int EntriesCrcTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700610 GptData *gpt;
611
612 gpt = GetEmptyGptData();
613
614 /* Modify the first byte of primary entries, and expect the CRC is wrong. */
615 BuildTestGptData(gpt);
616 gpt->primary_entries[0] ^= 0xa5; /* just XOR a non-zero value */
617 EXPECT(MASK_SECONDARY == CheckEntriesCrc(gpt));
618
619 /* Modify the last byte of secondary entries, and expect the CRC is wrong. */
620 BuildTestGptData(gpt);
621 gpt->secondary_entries[TOTAL_ENTRIES_SIZE-1] ^= 0x5a;
622 EXPECT(MASK_PRIMARY == CheckEntriesCrc(gpt));
623
624 return TEST_OK;
625}
626
627/* Tests if GptInit() handles non-identical partition entries well.
628 * Two copies of partition table entries must be identical. If not, we trust the
629 * primary table entries, and mark secondary as modified. */
630int IdenticalEntriesTest() {
631 GptData *gpt;
632
633 gpt = GetEmptyGptData();
634
635 /* Tests RepairEntries() first. */
636 BuildTestGptData(gpt);
637 EXPECT(0 == RepairEntries(gpt, MASK_BOTH));
638 gpt->secondary_entries[0] ^= 0xa5; /* XOR any number */
639 EXPECT(GPT_MODIFIED_ENTRIES2 == RepairEntries(gpt, MASK_BOTH));
640 EXPECT(GPT_MODIFIED_ENTRIES2 == RepairEntries(gpt, MASK_PRIMARY));
641 EXPECT(GPT_MODIFIED_ENTRIES1 == RepairEntries(gpt, MASK_SECONDARY));
642 EXPECT(0 == RepairEntries(gpt, MASK_NONE));
643
644 /* The first byte is different. We expect secondary entries is marked as
645 * modified. */
646 BuildTestGptData(gpt);
647 gpt->primary_entries[0] ^= 0xff;
648 RefreshCrc32(gpt);
649 EXPECT(GPT_SUCCESS == GptInit(gpt));
650 EXPECT(GPT_MODIFIED_ENTRIES2 == gpt->modified);
651 EXPECT(0 == Memcmp(gpt->primary_entries, gpt->secondary_entries,
652 TOTAL_ENTRIES_SIZE));
653
654 /* The last byte is different, but the primary entries CRC is bad.
655 * We expect primary entries is marked as modified. */
656 BuildTestGptData(gpt);
657 gpt->primary_entries[TOTAL_ENTRIES_SIZE-1] ^= 0xff;
658 EXPECT(GPT_SUCCESS == GptInit(gpt));
659 EXPECT(GPT_MODIFIED_ENTRIES1 == gpt->modified);
660 EXPECT(0 == Memcmp(gpt->primary_entries, gpt->secondary_entries,
661 TOTAL_ENTRIES_SIZE));
662
663 return TEST_OK;
664}
665
666/* Tests if GptInit() handles synonymous headers well.
667 * Note that two partition headers are NOT bit-swise identical.
668 * For exmaple, my_lba must be different (pointing to respective self).
669 * So in normal case, they are synonymous, not identical.
670 * If not synonymous, we trust the primary partition header, and
671 * overwrite secondary, then mark secondary as modified.*/
672int SynonymousHeaderTest() {
673 GptData *gpt;
674 GptHeader *primary_header, *secondary_header;
675
676 gpt = GetEmptyGptData();
677 primary_header = (GptHeader*)gpt->primary_header;
678 secondary_header = (GptHeader*)gpt->secondary_header;
679
680 /* Tests RepairHeader() for synonymous cases first. */
681 BuildTestGptData(gpt);
682 EXPECT(0 == RepairHeader(gpt, MASK_BOTH));
683 EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_PRIMARY));
684 EXPECT(GPT_MODIFIED_HEADER1 == RepairHeader(gpt, MASK_SECONDARY));
685 EXPECT(0 == RepairHeader(gpt, MASK_NONE));
686 /* Then tests non-synonymous cases. */
687 BuildTestGptData(gpt);
688 ++secondary_header->first_usable_lba; /* chnage any bit */
689 EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_BOTH));
690 EXPECT(primary_header->first_usable_lba ==
691 secondary_header->first_usable_lba);
692 /* ---- */
693 BuildTestGptData(gpt);
694 --secondary_header->last_usable_lba;
695 EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_BOTH));
696 EXPECT(primary_header->last_usable_lba == secondary_header->last_usable_lba);
697 /* ---- */
698 BuildTestGptData(gpt);
699 ++secondary_header->number_of_entries;
700 EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_BOTH));
701 EXPECT(primary_header->number_of_entries ==
702 secondary_header->number_of_entries);
703 /* ---- */
704 BuildTestGptData(gpt);
705 --secondary_header->size_of_entry;
706 EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_BOTH));
707 EXPECT(primary_header->size_of_entry ==
708 secondary_header->size_of_entry);
709 /* ---- */
710 BuildTestGptData(gpt);
711 secondary_header->disk_uuid.u.raw[0] ^= 0x56;
712 EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_BOTH));
713 EXPECT(0 == Memcmp(&primary_header->disk_uuid,
714 &secondary_header->disk_uuid, sizeof(Guid)));
715
716 /* Consider header repairing in GptInit(). */
717 BuildTestGptData(gpt);
718 ++secondary_header->first_usable_lba;
719 RefreshCrc32(gpt);
720 EXPECT(GPT_SUCCESS == GptInit(gpt));
721 EXPECT(GPT_MODIFIED_HEADER2 == gpt->modified);
722 EXPECT(primary_header->first_usable_lba ==
723 secondary_header->first_usable_lba);
724
725 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700726}
727
728/* Tests if partition geometry is checked.
729 * All active (non-zero PartitionTypeGUID) partition entries should have:
730 * entry.StartingLBA >= header.FirstUsableLBA
731 * entry.EndingLBA <= header.LastUsableLBA
732 * entry.StartingLBA <= entry.EndingLBA
733 */
734int ValidEntryTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700735 GptData *gpt;
736 GptHeader *primary_header, *secondary_header;
737 GptEntry *primary_entries, *secondary_entries;
738
739 gpt = GetEmptyGptData();
740 primary_header = (GptHeader*)gpt->primary_header;
741 secondary_header = (GptHeader*)gpt->secondary_header;
742 primary_entries = (GptEntry*)gpt->primary_entries;
743 secondary_entries = (GptEntry*)gpt->secondary_entries;
744
745 /* error case: entry.StartingLBA < header.FirstUsableLBA */
746 BuildTestGptData(gpt);
747 primary_entries[0].starting_lba = primary_header->first_usable_lba - 1;
748 EXPECT(MASK_SECONDARY == CheckValidEntries(gpt));
749 secondary_entries[1].starting_lba = secondary_header->first_usable_lba - 1;
750 EXPECT(MASK_NONE == CheckValidEntries(gpt));
751
752 /* error case: entry.EndingLBA > header.LastUsableLBA */
753 BuildTestGptData(gpt);
754 primary_entries[2].ending_lba = primary_header->last_usable_lba + 1;
755 EXPECT(MASK_SECONDARY == CheckValidEntries(gpt));
756 secondary_entries[3].ending_lba = secondary_header->last_usable_lba + 1;
757 EXPECT(MASK_NONE == CheckValidEntries(gpt));
758
759 /* error case: entry.StartingLBA > entry.EndingLBA */
760 BuildTestGptData(gpt);
761 primary_entries[3].starting_lba = primary_entries[3].ending_lba + 1;
762 EXPECT(MASK_SECONDARY == CheckValidEntries(gpt));
763 secondary_entries[1].starting_lba = secondary_entries[1].ending_lba + 1;
764 EXPECT(MASK_NONE == CheckValidEntries(gpt));
765
766 /* case: non active entry should be ignored. */
767 BuildTestGptData(gpt);
768 Memset(&primary_entries[1].type, 0, sizeof(primary_entries[1].type));
769 primary_entries[1].starting_lba = primary_entries[1].ending_lba + 1;
770 EXPECT(MASK_BOTH == CheckValidEntries(gpt));
771 Memset(&secondary_entries[2].type, 0, sizeof(secondary_entries[2].type));
772 secondary_entries[2].starting_lba = secondary_entries[2].ending_lba + 1;
773 EXPECT(MASK_BOTH == CheckValidEntries(gpt));
774
775 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700776}
777
778/* Tests if overlapped partition tables can be detected. */
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700779int OverlappedPartitionTest() {
780 GptData *gpt;
781 struct {
782 int overlapped;
783 struct {
784 int active;
785 uint64_t starting_lba;
786 uint64_t ending_lba;
787 } entries[16]; /* enough for testing. */
788 } cases[] = {
789 {0, {{0, 100, 199}, {0, 0, 0}}},
790 {0, {{1, 100, 199}, {0, 0, 0}}},
791 {0, {{1, 100, 150}, {1, 200, 250}, {1, 300, 350}, {0, 0, 0}}},
792 {1, {{1, 200, 299}, {1, 100, 199}, {1, 100, 100}, {0, 0, 0}}},
793 {1, {{1, 200, 299}, {1, 100, 199}, {1, 299, 299}, {0, 0, 0}}},
794 {0, {{1, 300, 399}, {1, 200, 299}, {1, 100, 199}, {0, 0, 0}}},
795 {1, {{1, 100, 199}, {1, 199, 299}, {1, 299, 399}, {0, 0, 0}}},
796 {1, {{1, 100, 199}, {1, 200, 299}, {1, 75, 399}, {0, 0, 0}}},
797 {1, {{1, 100, 199}, {1, 75, 250}, {1, 200, 299}, {0, 0, 0}}},
798 {1, {{1, 75, 150}, {1, 100, 199}, {1, 200, 299}, {0, 0, 0}}},
799 {1, {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {1, 100, 399},
800 {0, 0, 0}}},
801 {0, {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {0, 100, 399},
802 {0, 0, 0}}},
803 {1, {{1, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400},
804 {0, 0, 0}}},
805 {1, {{0, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400},
806 {0, 0, 0}}},
807 {0, {{1, 200, 300}, {1, 100, 199}, {0, 100, 400}, {0, 300, 400},
808 {0, 0, 0}}},
809 {1, {{1, 200, 299}, {1, 100, 199}, {1, 199, 199}, {0, 0, 0}}},
810 {0, {{1, 200, 299}, {0, 100, 199}, {1, 199, 199}, {0, 0, 0}}},
811 {0, {{1, 200, 299}, {1, 100, 199}, {0, 199, 199}, {0, 0, 0}}},
812 {1, {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202},
813 {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206},
814 {1, 207, 207}, {1, 208, 208}, {1, 199, 199}, {0, 0, 0}}},
815 {0, {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202},
816 {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206},
817 {1, 207, 207}, {1, 208, 208}, {0, 199, 199}, {0, 0, 0}}},
818 };
819 Guid any_type = GPT_ENT_TYPE_CHROMEOS_KERNEL;
820 int i, j;
821 int test_mask;
822 GptEntry *entries[2];
823
824 gpt = GetEmptyGptData();
825 entries[PRIMARY] = (GptEntry*)gpt->primary_entries;
826 entries[SECONDARY] = (GptEntry*)gpt->secondary_entries;
827
828 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
829 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
830 BuildTestGptData(gpt);
831 ZeroEntries(gpt);
832 for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) {
833 if (!cases[i].entries[j].starting_lba) break;
834 if (test_mask & MASK_PRIMARY) {
835 if (cases[i].entries[j].active)
836 Memcpy(&entries[PRIMARY][j].type, &any_type, sizeof(any_type));
837 entries[PRIMARY][j].starting_lba = cases[i].entries[j].starting_lba;
838 entries[PRIMARY][j].ending_lba = cases[i].entries[j].ending_lba;
839 }
840 if (test_mask & MASK_SECONDARY) {
841 if (cases[i].entries[j].active)
842 Memcpy(&entries[SECONDARY][j].type, &any_type, sizeof(any_type));
843 entries[SECONDARY][j].starting_lba = cases[i].entries[j].starting_lba;
844 entries[SECONDARY][j].ending_lba = cases[i].entries[j].ending_lba;
845 }
846 }
847 EXPECT((cases[i].overlapped * test_mask) ==
848 (OverlappedEntries(entries[PRIMARY], j) |
849 (OverlappedEntries(entries[SECONDARY], j) << SECONDARY))
850 );
851
852 EXPECT((MASK_BOTH ^ (cases[i].overlapped * test_mask)) ==
853 CheckOverlappedPartition(gpt));
854 }
855 }
856 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700857}
858
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700859/* Tests if GptInit() can survive in different corrupt header/entries
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700860 * combinations, like:
861 * primary GPT header - valid
862 * primary partition table - invalid
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700863 * secondary GPT header - invalid
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700864 * secondary partition table - valid
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700865 */
866int CorruptCombinationTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700867 GptData *gpt;
868 GptHeader *primary_header, *secondary_header;
869 GptEntry *primary_entries, *secondary_entries;
870
871 gpt = GetEmptyGptData();
872 primary_header = (GptHeader*)gpt->primary_header;
873 secondary_header = (GptHeader*)gpt->secondary_header;
874 primary_entries = (GptEntry*)gpt->primary_entries;
875 secondary_entries = (GptEntry*)gpt->secondary_entries;
876
877 /* Make primary entries and secondary header invalid, we expect GptInit()
878 * can recover them (returns GPT_SUCCESS and MODIFIED flasgs). */
879 BuildTestGptData(gpt);
880 primary_entries[0].type.u.raw[0] ^= 0x33;
881 secondary_header->header_crc32 ^= 0x55;
882 EXPECT(GPT_SUCCESS == GptInit(gpt));
883 EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES1) == gpt->modified);
884 EXPECT(0 == Memcmp(primary_entries, secondary_entries, TOTAL_ENTRIES_SIZE));
885 /* We expect the modified header/entries can pass GptInit(). */
886 EXPECT(GPT_SUCCESS == GptInit(gpt));
887 EXPECT(0 == gpt->modified);
888
889 /* Make primary header invalid (the entries is not damaged actually). */
890 BuildTestGptData(gpt);
891 primary_header->entries_crc32 ^= 0x73;
892 EXPECT(GPT_SUCCESS == GptInit(gpt));
893 /* After header is repaired, the entries are valid actually. */
894 EXPECT((GPT_MODIFIED_HEADER1) == gpt->modified);
895 /* We expect the modified header/entries can pass GptInit(). */
896 EXPECT(GPT_SUCCESS == GptInit(gpt));
897 EXPECT(0 == gpt->modified);
898
899 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700900}
901
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700902/* Invalidate all kernel entries and expect GptNextKernelEntry() cannot find
903 * any usable kernel entry.
904 */
905int NoValidKernelEntryTest() {
906 GptData *gpt;
907 GptEntry *entries, *entries2;
908
909 gpt = GetEmptyGptData();
910 entries = (GptEntry*)gpt->primary_entries;
911 entries2 = (GptEntry*)gpt->secondary_entries;
912
913 BuildTestGptData(gpt);
914 entries[KERNEL_A].attributes |= CGPT_ATTRIBUTE_BAD_MASK;
915 Memset(&entries[KERNEL_B].type, 0, sizeof(Guid));
916 RefreshCrc32(gpt);
917
918 EXPECT(GPT_ERROR_NO_VALID_KERNEL == GptNextKernelEntry(gpt, NULL, NULL));
919
920 return TEST_OK;
921}
922
923/* This is the combination test. Both kernel A and B could be either inactive
924 * or invalid. We expect GptNextKetnelEntry() returns good kernel or
925 * GPT_ERROR_NO_VALID_KERNEL if no kernel is available. */
926enum FAILURE_MASK {
927 MASK_INACTIVE = 1,
928 MASK_BAD_ENTRY = 2,
929 MASK_FAILURE_BOTH = 3,
930};
931void BreakAnEntry(GptEntry *entry, enum FAILURE_MASK failure) {
932 if (failure & MASK_INACTIVE)
933 Memset(&entry->type, 0, sizeof(Guid));
934 if (failure & MASK_BAD_ENTRY)
935 entry->attributes |= CGPT_ATTRIBUTE_BAD_MASK;
936}
937
938int CombinationalNextKernelEntryTest() {
939 GptData *gpt;
940 enum {
941 MASK_KERNEL_A = 1,
942 MASK_KERNEL_B = 2,
943 MASK_KERNEL_BOTH = 3,
944 } kernel;
945 enum FAILURE_MASK failure;
946 uint64_t start_sector, size;
947 int retval;
948
949 for (kernel = MASK_KERNEL_A; kernel <= MASK_KERNEL_BOTH; ++kernel) {
950 for (failure = MASK_INACTIVE; failure < MASK_FAILURE_BOTH; ++failure) {
951 gpt = GetEmptyGptData();
952 BuildTestGptData(gpt);
953
954 if (kernel & MASK_KERNEL_A)
955 BreakAnEntry(GetEntry(gpt, PRIMARY, KERNEL_A), failure);
956 if (kernel & MASK_KERNEL_B)
957 BreakAnEntry(GetEntry(gpt, PRIMARY, KERNEL_B), failure);
958
959 retval = GptNextKernelEntry(gpt, &start_sector, &size);
960
961 if (kernel == MASK_KERNEL_A) {
962 EXPECT(retval == GPT_SUCCESS);
963 EXPECT(start_sector == 334);
964 } else if (kernel == MASK_KERNEL_B) {
965 EXPECT(retval == GPT_SUCCESS);
966 EXPECT(start_sector == 34);
967 } else { /* MASK_KERNEL_BOTH */
968 EXPECT(retval == GPT_ERROR_NO_VALID_KERNEL);
969 }
970 }
971 }
972 return TEST_OK;
973}
974
975/* Increase tries value from zero, expect it won't explode/overflow after
976 * CGPT_ATTRIBUTE_TRIES_MASK.
977 */
978/* Tries would not count up after CGPT_ATTRIBUTE_MAX_TRIES. */
979#define EXPECTED_TRIES(tries) \
980 ((tries >= CGPT_ATTRIBUTE_MAX_TRIES) ? CGPT_ATTRIBUTE_MAX_TRIES \
981 : tries)
982int IncreaseTriesTest() {
983 GptData *gpt;
984 int kernel_index[] = {
985 KERNEL_B,
986 KERNEL_A,
987 };
988 int i, tries, j;
989
990 gpt = GetEmptyGptData();
991 for (i = 0; i < ARRAY_SIZE(kernel_index); ++i) {
992 GptEntry *entries[2] = {
993 (GptEntry*)gpt->primary_entries,
994 (GptEntry*)gpt->secondary_entries,
995 };
996 int current;
997
998 BuildTestGptData(gpt);
999 current = gpt->current_kernel = kernel_index[i];
1000
1001 for (tries = 0; tries < 2 * CGPT_ATTRIBUTE_MAX_TRIES; ++tries) {
1002 for (j = 0; j < ARRAY_SIZE(entries); ++j) {
1003 EXPECT(EXPECTED_TRIES(tries) ==
1004 ((entries[j][current].attributes & CGPT_ATTRIBUTE_TRIES_MASK) >>
1005 CGPT_ATTRIBUTE_TRIES_OFFSET));
1006 }
1007
1008 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
1009 /* The expected tries value will be checked in next iteration. */
1010
1011 if (tries < CGPT_ATTRIBUTE_MAX_TRIES)
1012 EXPECT((GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
1013 GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
1014 gpt->modified = 0; /* reset before next test */
1015 EXPECT(0 ==
1016 Memcmp(entries[PRIMARY], entries[SECONDARY], TOTAL_ENTRIES_SIZE));
1017 }
1018 }
1019 return TEST_OK;
1020}
1021
1022/* Mark a kernel as bad. Expect:
1023 * 1. the both bad bits of kernel A in primary and secondary entries are set.
1024 * 2. headers and entries are marked as modified.
1025 * 3. primary and secondary entries are identical.
1026 */
1027int MarkBadKernelEntryTest() {
1028 GptData *gpt;
1029 GptEntry *entries, *entries2;
1030
1031 gpt = GetEmptyGptData();
1032 entries = (GptEntry*)gpt->primary_entries;
1033 entries2 = (GptEntry*)gpt->secondary_entries;
1034
1035 BuildTestGptData(gpt);
1036 gpt->current_kernel = KERNEL_A;
1037 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
1038 EXPECT((GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
1039 GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
1040 EXPECT(entries[KERNEL_A].attributes & CGPT_ATTRIBUTE_BAD_MASK);
1041 EXPECT(entries2[KERNEL_A].attributes & CGPT_ATTRIBUTE_BAD_MASK);
1042 EXPECT(0 == Memcmp(entries, entries2, TOTAL_ENTRIES_SIZE));
1043
1044 return TEST_OK;
1045}
1046
1047/* Given an invalid kernel type, and expect GptUpdateKernelEntry() returns
1048 * GPT_ERROR_INVALID_UPDATE_TYPE. */
1049int UpdateInvalidKernelTypeTest() {
1050 GptData *gpt;
1051
1052 gpt = GetEmptyGptData();
1053 BuildTestGptData(gpt);
1054 gpt->current_kernel = 0; /* anything, but not CGPT_KERNEL_ENTRY_NOT_FOUND */
1055 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1056 GptUpdateKernelEntry(gpt, 99)); /* any invalid update_type value */
1057
1058 return TEST_OK;
1059}
1060
1061/* A normal boot case:
1062 * GptInit()
1063 * GptNextKernelEntry()
1064 * GptUpdateKernelEntry()
1065 */
1066int NormalBootCase() {
1067 GptData *gpt;
1068 GptEntry *entries;
1069 uint64_t start_sector, size;
1070
1071 gpt = GetEmptyGptData();
1072 entries = (GptEntry*)gpt->primary_entries;
1073 BuildTestGptData(gpt);
1074
1075 EXPECT(GPT_SUCCESS == GptInit(gpt));
1076 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start_sector, &size));
1077 EXPECT(start_sector == 34); /* Kernel A, see top of this file. */
1078 EXPECT(size == 100);
1079
1080 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
1081 EXPECT(((entries[KERNEL_A].attributes & CGPT_ATTRIBUTE_TRIES_MASK) >>
1082 CGPT_ATTRIBUTE_TRIES_OFFSET) == 1);
1083
1084 return TEST_OK;
1085}
1086
1087/* Higher priority kernel should boot first.
1088 * KERNEL_A is low priority
1089 * KERNEL_B is high priority.
1090 * We expect KERNEL_B is selected in first run, and then KERNEL_A.
1091 * We also expect the GptNextKernelEntry() wraps back to KERNEL_B if it's called
1092 * after twice.
1093 */
1094int HigherPriorityTest() {
1095 GptData *gpt;
1096 GptEntry *entries;
1097
1098 gpt = GetEmptyGptData();
1099 entries = (GptEntry*)gpt->primary_entries;
1100 BuildTestGptData(gpt);
1101
1102 SetPriority(gpt, PRIMARY, KERNEL_A, 0);
1103 SetPriority(gpt, PRIMARY, KERNEL_B, 1);
1104 RefreshCrc32(gpt);
1105
1106 EXPECT(GPT_SUCCESS == GptInit(gpt));
1107 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, NULL, NULL));
1108 EXPECT(KERNEL_B == gpt->current_kernel);
1109
1110 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, NULL, NULL));
1111 EXPECT(KERNEL_A == gpt->current_kernel);
1112
1113 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, NULL, NULL));
1114 EXPECT(KERNEL_B == gpt->current_kernel);
1115
1116 return TEST_OK;
1117}
1118
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001119int main(int argc, char *argv[]) {
1120 int i;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001121 int error_count = 0;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001122 struct {
1123 char *name;
1124 test_func fp;
1125 int retval;
1126 } test_cases[] = {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001127 { TEST_CASE(TestBuildTestGptData), },
1128 { TEST_CASE(ParameterTests), },
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -07001129 { TEST_CASE(SignatureTest), },
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001130 { TEST_CASE(RevisionTest), },
1131 { TEST_CASE(SizeTest), },
1132 { TEST_CASE(ReservedFieldsTest), },
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001133 { TEST_CASE(MyLbaTest), },
1134 { TEST_CASE(SizeOfPartitionEntryTest), },
1135 { TEST_CASE(NumberOfPartitionEntriesTest), },
1136 { TEST_CASE(PartitionEntryLbaTest), },
1137 { TEST_CASE(FirstUsableLbaAndLastUsableLbaTest), },
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001138 { TEST_CASE(HeaderCrcTest), },
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001139 { TEST_CASE(EntriesCrcTest), },
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001140 { TEST_CASE(IdenticalEntriesTest), },
1141 { TEST_CASE(SynonymousHeaderTest), },
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001142 { TEST_CASE(ValidEntryTest), },
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001143 { TEST_CASE(OverlappedPartitionTest), },
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001144 { TEST_CASE(CorruptCombinationTest), },
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001145 { TEST_CASE(TestQuickSortFixed), },
1146 { TEST_CASE(TestQuickSortRandom), },
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001147 { TEST_CASE(NoValidKernelEntryTest), },
1148 { TEST_CASE(CombinationalNextKernelEntryTest), },
1149 { TEST_CASE(IncreaseTriesTest), },
1150 { TEST_CASE(MarkBadKernelEntryTest), },
1151 { TEST_CASE(UpdateInvalidKernelTypeTest), },
1152 { TEST_CASE(NormalBootCase), },
1153 { TEST_CASE(HigherPriorityTest), },
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001154 };
1155
1156 for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
1157 printf("Running %s() ...\n", test_cases[i].name);
1158 test_cases[i].retval = test_cases[i].fp();
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001159 if (test_cases[i].retval) {
1160 printf(COL_RED "[ERROR]\n\n" COL_STOP);
1161 ++error_count;
1162 } else {
1163 printf(COL_GREEN "[PASS]\n\n" COL_STOP);
1164 }
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001165 }
1166
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001167 if (error_count) {
1168 printf("\n--------------------------------------------------\n");
1169 printf(COL_RED "The following %d test cases are failed:\n" COL_STOP,
1170 error_count);
1171 for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
1172 if (test_cases[i].retval)
1173 printf(" %s()\n", test_cases[i].name);
1174 }
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001175 }
1176
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001177 return (error_count) ? 1 : 0;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001178}