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