blob: 72fb5e6c21226a5c736e07e30f884bd6fe3600c6 [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 Lo418ad3b2010-05-27 11:21:17 +0800117 gpt->valid_headers = MASK_BOTH;
118 gpt->valid_entries = MASK_BOTH;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700119
120 /* build primary */
121 header = (GptHeader*)gpt->primary_header;
122 entries = (GptEntry*)gpt->primary_entries;
123 Memcpy(header->signature, GPT_HEADER_SIGNATURE, sizeof(GPT_HEADER_SIGNATURE));
124 header->revision = GPT_HEADER_REVISION;
125 header->size = sizeof(GptHeader) - sizeof(header->padding);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700126 header->reserved = 0;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700127 header->my_lba = 1;
128 header->first_usable_lba = 34;
129 header->last_usable_lba = DEFAULT_DRIVE_SECTORS - 1 - 32 - 1; /* 433 */
130 header->entries_lba = 2;
131 header->number_of_entries = 128; /* 512B / 128B * 32sectors = 128 entries */
132 header->size_of_entry = 128; /* bytes */
133 Memcpy(&entries[0].type, &chromeos_kernel, sizeof(chromeos_kernel));
134 entries[0].starting_lba = 34;
135 entries[0].ending_lba = 133;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700136 Memcpy(&entries[1].type, &chromeos_rootfs, sizeof(chromeos_rootfs));
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700137 entries[1].starting_lba = 134;
138 entries[1].ending_lba = 233;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700139 Memcpy(&entries[2].type, &chromeos_rootfs, sizeof(chromeos_rootfs));
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700140 entries[2].starting_lba = 234;
141 entries[2].ending_lba = 333;
142 Memcpy(&entries[3].type, &chromeos_kernel, sizeof(chromeos_kernel));
143 entries[3].starting_lba = 334;
144 entries[3].ending_lba = 433;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700145 header->padding = 0;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700146
147 /* build secondary */
148 header2 = (GptHeader*)gpt->secondary_header;
149 entries2 = (GptEntry*)gpt->secondary_entries;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700150 Memcpy(header2, header, sizeof(GptHeader));
151 Memcpy(entries2, entries, PARTITION_ENTRIES_SIZE);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700152 header2->my_lba = DEFAULT_DRIVE_SECTORS - 1; /* 466 */
153 header2->entries_lba = DEFAULT_DRIVE_SECTORS - 1 - 32; /* 434 */
154
155 RefreshCrc32(gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700156}
157
158/* Dumps memory starting from [vp] with [len] bytes.
159 * Prints [memo] if not NULL. Example output:
160 *
161 * 00 01 02 03 04 05 06 07 - 08 09 0a 0b 0c 0d 0e 0f
162 * 10 11 12 13 14 15 16 17 - 18 19 1a 1b 1c 1d 1e 1f
163 * ...
164 */
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700165static void Dump(void *vp, int len, char* memo) {
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700166 uint8_t *start = vp;
167 int i;
168 if (memo) printf("--[%s]----------\n", memo);
169 for (i = 0; i < len; ++i) {
170 printf("%02x%s", start[i],
171 (!(~i & 15) ? "\n" :
172 !(~i & 7) ? " - ": " "));
173 }
174 if (i&15) printf("\n");
175}
176
177/* More formatted dump with GptData. */
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700178void DumpGptData(GptData *gpt) {
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700179 printf("DumpGptData(%p)...\n", gpt);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700180 Dump(gpt, sizeof(gpt), NULL);
181 Dump(gpt->primary_header, sizeof(GptHeader), "Primary header");
182 Dump(gpt->primary_entries, sizeof(GptEntry) * 8, "Primary entries");
183 Dump(gpt->secondary_header, sizeof(GptHeader), "Secondary header");
184 Dump(gpt->secondary_entries, sizeof(GptEntry) * 8,
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700185 "Secondary entries");
186}
187
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700188/* Tests if the default structure returned by BuildTestGptData() is good. */
189int TestBuildTestGptData() {
190 GptData *gpt;
191 gpt = GetEmptyGptData();
192 BuildTestGptData(gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700193 EXPECT(GPT_SUCCESS == GptInit(gpt));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700194 return TEST_OK;
195}
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700196
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700197/* Tests if wrong sector_bytes or drive_sectors is detected by GptInit().
198 * Currently we only support 512 bytes per sector.
199 * In the future, we may support other sizes.
200 * A too small drive_sectors should be rejected by GptInit(). */
201int ParameterTests() {
202 GptData *gpt;
203 struct {
204 uint32_t sector_bytes;
205 uint64_t drive_sectors;
206 int expected_retval;
207 } cases[] = {
208 {512, DEFAULT_DRIVE_SECTORS, GPT_SUCCESS},
209 {520, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
210 {512, 0, GPT_ERROR_INVALID_SECTOR_NUMBER},
211 {512, 66, GPT_ERROR_INVALID_SECTOR_NUMBER},
212 {512, GPT_PMBR_SECTOR + GPT_HEADER_SECTOR * 2 + GPT_ENTRIES_SECTORS * 2,
213 GPT_SUCCESS},
214 {4096, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
215 };
216 int i;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700217
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700218 gpt = GetEmptyGptData();
219 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
220 BuildTestGptData(gpt);
221 gpt->sector_bytes = cases[i].sector_bytes;
222 gpt->drive_sectors = cases[i].drive_sectors;
223 EXPECT(cases[i].expected_retval == CheckParameters(gpt));
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700224 }
225
226 return TEST_OK;
227}
228
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700229/* Tests if signature ("EFI PART") is checked. */
230int SignatureTest() {
231 int i;
232 GptData *gpt;
233 int test_mask;
234 GptHeader *headers[2];
235
236 gpt = GetEmptyGptData();
237 headers[PRIMARY] = (GptHeader*)gpt->primary_header;
238 headers[SECONDARY] = (GptHeader*)gpt->secondary_header;
239
240 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
241 for (i = 0; i < 8; ++i) {
242 BuildTestGptData(gpt);
243 if (test_mask & MASK_PRIMARY)
244 headers[PRIMARY]->signature[i] ^= 0xff;
245 if (test_mask & MASK_SECONDARY)
246 headers[SECONDARY]->signature[i] ^= 0xff;
247 EXPECT((MASK_BOTH ^ test_mask) == CheckHeaderSignature(gpt));
248 }
249 }
250
251 return TEST_OK;
252}
253
254/* The revision we currently support is GPT_HEADER_REVISION.
255 * If the revision in header is not that, we expect the header is invalid. */
256int RevisionTest() {
257 GptData *gpt;
258 struct {
259 uint32_t value_to_test;
260 int is_valid_value;
261 } cases[] = {
262 {0x01000000, 0},
263 {0x00010000, 1}, /* GPT_HEADER_REVISION */
264 {0x00000100, 0},
265 {0x00000001, 0},
266 {0x23010456, 0},
267 };
268 int i;
269 int test_mask;
270 GptHeader *headers[2];
271 uint32_t valid_headers;
272
273 gpt = GetEmptyGptData();
274 headers[PRIMARY] = (GptHeader*)gpt->primary_header;
275 headers[SECONDARY] = (GptHeader*)gpt->secondary_header;
276
277 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
278 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
279 BuildTestGptData(gpt);
280 if (test_mask & MASK_PRIMARY)
281 headers[PRIMARY]->revision = cases[i].value_to_test;
282 if (test_mask & MASK_SECONDARY)
283 headers[SECONDARY]->revision = cases[i].value_to_test;
284 valid_headers = CheckRevision(gpt);
285 if (cases[i].is_valid_value)
286 EXPECT(MASK_BOTH == valid_headers);
287 else
288 EXPECT((MASK_BOTH ^ test_mask) == valid_headers);
289 }
290 }
291 return TEST_OK;
292}
293
294int SizeTest() {
295 GptData *gpt;
296 struct {
297 uint32_t value_to_test;
298 int is_valid_value;
299 } cases[] = {
300 {91, 0},
301 {92, 1},
302 {93, 1},
303 {511, 1},
304 {512, 1},
305 {513, 0},
306 };
307 int i;
308 int test_mask;
309 GptHeader *headers[2];
310 uint32_t valid_headers;
311
312 gpt = GetEmptyGptData();
313 headers[PRIMARY] = (GptHeader*)gpt->primary_header;
314 headers[SECONDARY] = (GptHeader*)gpt->secondary_header;
315
316 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
317 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
318 BuildTestGptData(gpt);
319 if (test_mask & MASK_PRIMARY)
320 headers[PRIMARY]->size = cases[i].value_to_test;
321 if (test_mask & MASK_SECONDARY)
322 headers[SECONDARY]->size = cases[i].value_to_test;
323 valid_headers = CheckSize(gpt);
324 if (cases[i].is_valid_value)
325 EXPECT(MASK_BOTH == valid_headers);
326 else
327 EXPECT((MASK_BOTH ^ test_mask) == valid_headers);
328 }
329 }
330 return TEST_OK;
331}
332
333/* Tests if reserved fields are checked.
334 * We'll try non-zero values to test. */
335int ReservedFieldsTest() {
336 GptData *gpt;
337 GptHeader *primary_header, *secondary_header;
338
339 gpt = GetEmptyGptData();
340 primary_header = (GptHeader*)gpt->primary_header;
341 secondary_header = (GptHeader*)gpt->secondary_header;
342
343 /* expect secondary is still valid. */
344 BuildTestGptData(gpt);
345 primary_header->reserved ^= 0x12345678; /* whatever random */
346 EXPECT(MASK_SECONDARY == CheckReservedFields(gpt));
347
348 /* expect secondary is still valid. */
349 BuildTestGptData(gpt);
350 primary_header->padding ^= 0x12345678; /* whatever random */
351 EXPECT(MASK_SECONDARY == CheckReservedFields(gpt));
352
353 /* expect primary is still valid. */
354 BuildTestGptData(gpt);
355 secondary_header->reserved ^= 0x12345678; /* whatever random */
356 EXPECT(MASK_PRIMARY == CheckReservedFields(gpt));
357
358 /* expect primary is still valid. */
359 BuildTestGptData(gpt);
360 secondary_header->padding ^= 0x12345678; /* whatever random */
361 EXPECT(MASK_PRIMARY == CheckReservedFields(gpt));
362
363 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700364}
365
366/* Tests if myLBA field is checked (1 for primary, last for secondary). */
367int MyLbaTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700368 GptData *gpt;
369 int test_mask;
370 GptHeader *headers[2];
371 uint32_t valid_headers;
372
373 gpt = GetEmptyGptData();
374 headers[PRIMARY] = (GptHeader*)gpt->primary_header;
375 headers[SECONDARY] = (GptHeader*)gpt->secondary_header;
376
377 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
378 BuildTestGptData(gpt);
379 if (test_mask & MASK_PRIMARY)
380 ++headers[PRIMARY]->my_lba;
381 if (test_mask & MASK_SECONDARY)
382 --headers[SECONDARY]->my_lba;
383 valid_headers = CheckMyLba(gpt);
384 EXPECT((MASK_BOTH ^ test_mask) == valid_headers);
385 }
386 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700387}
388
389/* Tests if SizeOfPartitionEntry is checked. SizeOfPartitionEntry must be
390 * between 128 and 512, and a multiple of 8. */
391int SizeOfPartitionEntryTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700392 GptData *gpt;
393 struct {
394 uint32_t value_to_test;
395 int is_valid_value;
396 } cases[] = {
397 {127, 0},
398 {128, 1},
399 {129, 0},
400 {130, 0},
401 {131, 0},
402 {132, 0},
403 {133, 0},
404 {134, 0},
405 {135, 0},
406 {136, 1},
407 {144, 1},
408 {160, 1},
409 {192, 1},
410 {256, 1},
411 {384, 1},
412 {504, 1},
413 {512, 1},
414 {513, 0},
415 {520, 0},
416 };
417 int i;
418 int test_mask;
419 GptHeader *headers[2];
420 uint32_t valid_headers;
421
422 gpt = GetEmptyGptData();
423 headers[PRIMARY] = (GptHeader*)gpt->primary_header;
424 headers[SECONDARY] = (GptHeader*)gpt->secondary_header;
425
426 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
427 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
428 BuildTestGptData(gpt);
429 if (test_mask & MASK_PRIMARY) {
430 headers[PRIMARY]->size_of_entry = cases[i].value_to_test;
431 headers[PRIMARY]->number_of_entries =
432 TOTAL_ENTRIES_SIZE / cases[i].value_to_test;
433 }
434 if (test_mask & MASK_SECONDARY) {
435 headers[SECONDARY]->size_of_entry = cases[i].value_to_test;
436 headers[SECONDARY]->number_of_entries =
437 TOTAL_ENTRIES_SIZE / cases[i].value_to_test;
438 }
439 valid_headers = CheckSizeOfPartitionEntry(gpt);
440 if (cases[i].is_valid_value)
441 EXPECT(MASK_BOTH == valid_headers);
442 else
443 EXPECT((MASK_BOTH ^ test_mask) == valid_headers);
444 }
445 }
446 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700447}
448
449/* Tests if NumberOfPartitionEntries is checes. NumberOfPartitionEntries must
450 * be between 32 and 512, and SizeOfPartitionEntry * NumberOfPartitionEntries
451 * must be 16384. */
452int NumberOfPartitionEntriesTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700453 GptData *gpt;
454 struct {
455 uint32_t size_of_entry;
456 uint32_t number_of_entries;
457 int is_valid_value;
458 } cases[] = {
459 {111, 147, 0},
460 {111, 149, 0},
461 {128, 32, 0},
462 {128, 64, 0},
463 {128, 127, 0},
464 {128, 128, 1},
465 {128, 129, 0},
466 {128, 256, 0},
467 {256, 32, 0},
468 {256, 64, 1},
469 {256, 128, 0},
470 {256, 256, 0},
471 {512, 32, 1},
472 {512, 64, 0},
473 {512, 128, 0},
474 {512, 256, 0},
475 {1024, 128, 0},
476 };
477 int i;
478 int test_mask;
479 GptHeader *headers[2];
480 uint32_t valid_headers;
481
482 gpt = GetEmptyGptData();
483 headers[PRIMARY] = (GptHeader*)gpt->primary_header;
484 headers[SECONDARY] = (GptHeader*)gpt->secondary_header;
485
486 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
487 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
488 BuildTestGptData(gpt);
489 if (test_mask & MASK_PRIMARY) {
490 headers[PRIMARY]->size_of_entry = cases[i].size_of_entry;
491 headers[PRIMARY]->number_of_entries = cases[i].number_of_entries;
492 }
493 if (test_mask & MASK_SECONDARY) {
494 headers[SECONDARY]->size_of_entry = cases[i].size_of_entry;
495 headers[SECONDARY]->number_of_entries = cases[i].number_of_entries;
496 }
497 valid_headers = CheckNumberOfEntries(gpt);
498 if (cases[i].is_valid_value)
499 EXPECT(MASK_BOTH == valid_headers);
500 else
501 EXPECT((MASK_BOTH ^ test_mask) == valid_headers);
502 }
503 }
504 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700505}
506
507/* Tests if PartitionEntryLBA in primary/secondary headers is checked. */
508int PartitionEntryLbaTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700509 GptData *gpt;
510 int test_mask;
511 GptHeader *headers[2];
512 uint32_t valid_headers;
513
514 gpt = GetEmptyGptData();
515 headers[PRIMARY] = (GptHeader*)gpt->primary_header;
516 headers[SECONDARY] = (GptHeader*)gpt->secondary_header;
517
518 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
519 BuildTestGptData(gpt);
520 if (test_mask & MASK_PRIMARY)
521 headers[PRIMARY]->entries_lba = 0;
522 if (test_mask & MASK_SECONDARY)
523 headers[SECONDARY]->entries_lba = DEFAULT_DRIVE_SECTORS - 31 - 1;
524 valid_headers = CheckEntriesLba(gpt);
525 EXPECT((MASK_BOTH ^ test_mask) == valid_headers);
526 }
527 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700528}
529
530/* Tests if FirstUsableLBA and LastUsableLBA are checked.
531 * FirstUsableLBA must be after the end of the primary GPT table array.
532 * LastUsableLBA must be before the start of the secondary GPT table array.
533 * FirstUsableLBA <= LastUsableLBA. */
534int FirstUsableLbaAndLastUsableLbaTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700535 GptData *gpt;
536 GptHeader *primary_header, *secondary_header;
537 uint32_t valid_headers;
538 int i;
539 struct {
540 uint64_t primary_entries_lba;
541 uint64_t primary_first_usable_lba;
542 uint64_t primary_last_usable_lba;
543 uint64_t secondary_first_usable_lba;
544 uint64_t secondary_last_usable_lba;
545 uint64_t secondary_entries_lba;
546 int expected_masks;
547 } cases[] = {
548 {2, 34, 433, 34, 433, 434, MASK_BOTH},
549 {2, 34, 432, 34, 430, 434, MASK_BOTH},
550 {2, 33, 433, 33, 433, 434, MASK_NONE},
551 {3, 34, 433, 35, 433, 434, MASK_SECONDARY},
552 {3, 35, 433, 33, 433, 434, MASK_PRIMARY},
553 {2, 34, 434, 34, 433, 434, MASK_SECONDARY},
554 {2, 34, 433, 34, 434, 434, MASK_PRIMARY},
555 {2, 35, 433, 35, 433, 434, MASK_BOTH},
556 {2, 433, 433, 433, 433, 434, MASK_BOTH},
557 {2, 434, 433, 434, 434, 434, MASK_NONE},
558 {2, 433, 34, 34, 433, 434, MASK_SECONDARY},
559 {2, 34, 433, 433, 34, 434, MASK_PRIMARY},
560 };
561
562 gpt = GetEmptyGptData();
563 primary_header = (GptHeader*)gpt->primary_header;
564 secondary_header = (GptHeader*)gpt->secondary_header;
565
566 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
567 BuildTestGptData(gpt);
568 primary_header->entries_lba = cases[i].primary_entries_lba;
569 primary_header->first_usable_lba = cases[i].primary_first_usable_lba;
570 primary_header->last_usable_lba = cases[i].primary_last_usable_lba;
571 secondary_header->entries_lba = cases[i].secondary_entries_lba;
572 secondary_header->first_usable_lba = cases[i].secondary_first_usable_lba;
573 secondary_header->last_usable_lba = cases[i].secondary_last_usable_lba;
574 valid_headers = CheckValidUsableLbas(gpt);
575 EXPECT(cases[i].expected_masks == valid_headers);
576 }
577
578 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700579}
580
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700581/* Tests if header CRC in two copies are calculated. */
582int HeaderCrcTest() {
583 GptData *gpt;
584 GptHeader *primary_header, *secondary_header;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700585
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700586 gpt = GetEmptyGptData();
587 primary_header = (GptHeader*)gpt->primary_header;
588 secondary_header = (GptHeader*)gpt->secondary_header;
589
590 /* Modify the first byte of primary header, and expect the CRC is wrong. */
591 BuildTestGptData(gpt);
592 gpt->primary_header[0] ^= 0xa5; /* just XOR a non-zero value */
593 EXPECT(MASK_SECONDARY == CheckHeaderCrc(gpt));
594
595 /* Modify the last byte of secondary header, and expect the CRC is wrong. */
596 BuildTestGptData(gpt);
597 gpt->secondary_header[secondary_header->size-1] ^= 0x5a;
598 EXPECT(MASK_PRIMARY == CheckHeaderCrc(gpt));
599
600 /* Modify out of CRC range, expect CRC is still right. */
601 BuildTestGptData(gpt);
602 gpt->primary_header[primary_header->size] ^= 0x87;
603 EXPECT(MASK_BOTH == CheckHeaderCrc(gpt));
604
Louis Yung-Chieh Lo418ad3b2010-05-27 11:21:17 +0800605 /* Very long header (actually invalid header). Expect will be ignored. */
606 primary_header->size = 0x12345678;
607 secondary_header->size = 0x87654321;
608 gpt->valid_headers = MASK_NONE;
609 EXPECT(MASK_NONE == CheckHeaderCrc(gpt));
610
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700611 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700612}
613
614/* Tests if PartitionEntryArrayCRC32 is checked.
615 * PartitionEntryArrayCRC32 must be calculated over SizeOfPartitionEntry *
616 * NumberOfPartitionEntries bytes.
617 */
618int EntriesCrcTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700619 GptData *gpt;
620
621 gpt = GetEmptyGptData();
622
623 /* Modify the first byte of primary entries, and expect the CRC is wrong. */
624 BuildTestGptData(gpt);
625 gpt->primary_entries[0] ^= 0xa5; /* just XOR a non-zero value */
626 EXPECT(MASK_SECONDARY == CheckEntriesCrc(gpt));
627
628 /* Modify the last byte of secondary entries, and expect the CRC is wrong. */
629 BuildTestGptData(gpt);
630 gpt->secondary_entries[TOTAL_ENTRIES_SIZE-1] ^= 0x5a;
631 EXPECT(MASK_PRIMARY == CheckEntriesCrc(gpt));
632
633 return TEST_OK;
634}
635
636/* Tests if GptInit() handles non-identical partition entries well.
637 * Two copies of partition table entries must be identical. If not, we trust the
638 * primary table entries, and mark secondary as modified. */
639int IdenticalEntriesTest() {
640 GptData *gpt;
641
642 gpt = GetEmptyGptData();
643
644 /* Tests RepairEntries() first. */
645 BuildTestGptData(gpt);
646 EXPECT(0 == RepairEntries(gpt, MASK_BOTH));
647 gpt->secondary_entries[0] ^= 0xa5; /* XOR any number */
648 EXPECT(GPT_MODIFIED_ENTRIES2 == RepairEntries(gpt, MASK_BOTH));
649 EXPECT(GPT_MODIFIED_ENTRIES2 == RepairEntries(gpt, MASK_PRIMARY));
650 EXPECT(GPT_MODIFIED_ENTRIES1 == RepairEntries(gpt, MASK_SECONDARY));
651 EXPECT(0 == RepairEntries(gpt, MASK_NONE));
652
653 /* The first byte is different. We expect secondary entries is marked as
654 * modified. */
655 BuildTestGptData(gpt);
656 gpt->primary_entries[0] ^= 0xff;
657 RefreshCrc32(gpt);
658 EXPECT(GPT_SUCCESS == GptInit(gpt));
659 EXPECT(GPT_MODIFIED_ENTRIES2 == gpt->modified);
660 EXPECT(0 == Memcmp(gpt->primary_entries, gpt->secondary_entries,
661 TOTAL_ENTRIES_SIZE));
662
663 /* The last byte is different, but the primary entries CRC is bad.
664 * We expect primary entries is marked as modified. */
665 BuildTestGptData(gpt);
666 gpt->primary_entries[TOTAL_ENTRIES_SIZE-1] ^= 0xff;
667 EXPECT(GPT_SUCCESS == GptInit(gpt));
668 EXPECT(GPT_MODIFIED_ENTRIES1 == gpt->modified);
669 EXPECT(0 == Memcmp(gpt->primary_entries, gpt->secondary_entries,
670 TOTAL_ENTRIES_SIZE));
671
672 return TEST_OK;
673}
674
675/* Tests if GptInit() handles synonymous headers well.
676 * Note that two partition headers are NOT bit-swise identical.
677 * For exmaple, my_lba must be different (pointing to respective self).
678 * So in normal case, they are synonymous, not identical.
679 * If not synonymous, we trust the primary partition header, and
680 * overwrite secondary, then mark secondary as modified.*/
681int SynonymousHeaderTest() {
682 GptData *gpt;
683 GptHeader *primary_header, *secondary_header;
684
685 gpt = GetEmptyGptData();
686 primary_header = (GptHeader*)gpt->primary_header;
687 secondary_header = (GptHeader*)gpt->secondary_header;
688
689 /* Tests RepairHeader() for synonymous cases first. */
690 BuildTestGptData(gpt);
691 EXPECT(0 == RepairHeader(gpt, MASK_BOTH));
692 EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_PRIMARY));
693 EXPECT(GPT_MODIFIED_HEADER1 == RepairHeader(gpt, MASK_SECONDARY));
694 EXPECT(0 == RepairHeader(gpt, MASK_NONE));
695 /* Then tests non-synonymous cases. */
696 BuildTestGptData(gpt);
697 ++secondary_header->first_usable_lba; /* chnage any bit */
698 EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_BOTH));
699 EXPECT(primary_header->first_usable_lba ==
700 secondary_header->first_usable_lba);
701 /* ---- */
702 BuildTestGptData(gpt);
703 --secondary_header->last_usable_lba;
704 EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_BOTH));
705 EXPECT(primary_header->last_usable_lba == secondary_header->last_usable_lba);
706 /* ---- */
707 BuildTestGptData(gpt);
708 ++secondary_header->number_of_entries;
709 EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_BOTH));
710 EXPECT(primary_header->number_of_entries ==
711 secondary_header->number_of_entries);
712 /* ---- */
713 BuildTestGptData(gpt);
714 --secondary_header->size_of_entry;
715 EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_BOTH));
716 EXPECT(primary_header->size_of_entry ==
717 secondary_header->size_of_entry);
718 /* ---- */
719 BuildTestGptData(gpt);
720 secondary_header->disk_uuid.u.raw[0] ^= 0x56;
721 EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_BOTH));
722 EXPECT(0 == Memcmp(&primary_header->disk_uuid,
723 &secondary_header->disk_uuid, sizeof(Guid)));
724
725 /* Consider header repairing in GptInit(). */
726 BuildTestGptData(gpt);
727 ++secondary_header->first_usable_lba;
728 RefreshCrc32(gpt);
729 EXPECT(GPT_SUCCESS == GptInit(gpt));
Louis Yung-Chieh Lo418ad3b2010-05-27 11:21:17 +0800730 EXPECT((gpt->modified & (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_HEADER2)) ==
731 GPT_MODIFIED_HEADER2);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700732 EXPECT(primary_header->first_usable_lba ==
733 secondary_header->first_usable_lba);
734
735 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700736}
737
738/* Tests if partition geometry is checked.
739 * All active (non-zero PartitionTypeGUID) partition entries should have:
740 * entry.StartingLBA >= header.FirstUsableLBA
741 * entry.EndingLBA <= header.LastUsableLBA
742 * entry.StartingLBA <= entry.EndingLBA
743 */
744int ValidEntryTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700745 GptData *gpt;
746 GptHeader *primary_header, *secondary_header;
747 GptEntry *primary_entries, *secondary_entries;
748
749 gpt = GetEmptyGptData();
750 primary_header = (GptHeader*)gpt->primary_header;
751 secondary_header = (GptHeader*)gpt->secondary_header;
752 primary_entries = (GptEntry*)gpt->primary_entries;
753 secondary_entries = (GptEntry*)gpt->secondary_entries;
754
755 /* error case: entry.StartingLBA < header.FirstUsableLBA */
756 BuildTestGptData(gpt);
757 primary_entries[0].starting_lba = primary_header->first_usable_lba - 1;
758 EXPECT(MASK_SECONDARY == CheckValidEntries(gpt));
759 secondary_entries[1].starting_lba = secondary_header->first_usable_lba - 1;
760 EXPECT(MASK_NONE == CheckValidEntries(gpt));
761
762 /* error case: entry.EndingLBA > header.LastUsableLBA */
763 BuildTestGptData(gpt);
764 primary_entries[2].ending_lba = primary_header->last_usable_lba + 1;
765 EXPECT(MASK_SECONDARY == CheckValidEntries(gpt));
766 secondary_entries[3].ending_lba = secondary_header->last_usable_lba + 1;
767 EXPECT(MASK_NONE == CheckValidEntries(gpt));
768
769 /* error case: entry.StartingLBA > entry.EndingLBA */
770 BuildTestGptData(gpt);
771 primary_entries[3].starting_lba = primary_entries[3].ending_lba + 1;
772 EXPECT(MASK_SECONDARY == CheckValidEntries(gpt));
773 secondary_entries[1].starting_lba = secondary_entries[1].ending_lba + 1;
774 EXPECT(MASK_NONE == CheckValidEntries(gpt));
775
776 /* case: non active entry should be ignored. */
777 BuildTestGptData(gpt);
778 Memset(&primary_entries[1].type, 0, sizeof(primary_entries[1].type));
779 primary_entries[1].starting_lba = primary_entries[1].ending_lba + 1;
780 EXPECT(MASK_BOTH == CheckValidEntries(gpt));
781 Memset(&secondary_entries[2].type, 0, sizeof(secondary_entries[2].type));
782 secondary_entries[2].starting_lba = secondary_entries[2].ending_lba + 1;
783 EXPECT(MASK_BOTH == CheckValidEntries(gpt));
784
785 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700786}
787
788/* Tests if overlapped partition tables can be detected. */
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700789int OverlappedPartitionTest() {
790 GptData *gpt;
791 struct {
792 int overlapped;
793 struct {
794 int active;
795 uint64_t starting_lba;
796 uint64_t ending_lba;
797 } entries[16]; /* enough for testing. */
798 } cases[] = {
799 {0, {{0, 100, 199}, {0, 0, 0}}},
800 {0, {{1, 100, 199}, {0, 0, 0}}},
801 {0, {{1, 100, 150}, {1, 200, 250}, {1, 300, 350}, {0, 0, 0}}},
802 {1, {{1, 200, 299}, {1, 100, 199}, {1, 100, 100}, {0, 0, 0}}},
803 {1, {{1, 200, 299}, {1, 100, 199}, {1, 299, 299}, {0, 0, 0}}},
804 {0, {{1, 300, 399}, {1, 200, 299}, {1, 100, 199}, {0, 0, 0}}},
805 {1, {{1, 100, 199}, {1, 199, 299}, {1, 299, 399}, {0, 0, 0}}},
806 {1, {{1, 100, 199}, {1, 200, 299}, {1, 75, 399}, {0, 0, 0}}},
807 {1, {{1, 100, 199}, {1, 75, 250}, {1, 200, 299}, {0, 0, 0}}},
808 {1, {{1, 75, 150}, {1, 100, 199}, {1, 200, 299}, {0, 0, 0}}},
809 {1, {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {1, 100, 399},
810 {0, 0, 0}}},
811 {0, {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {0, 100, 399},
812 {0, 0, 0}}},
813 {1, {{1, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400},
814 {0, 0, 0}}},
815 {1, {{0, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400},
816 {0, 0, 0}}},
817 {0, {{1, 200, 300}, {1, 100, 199}, {0, 100, 400}, {0, 300, 400},
818 {0, 0, 0}}},
819 {1, {{1, 200, 299}, {1, 100, 199}, {1, 199, 199}, {0, 0, 0}}},
820 {0, {{1, 200, 299}, {0, 100, 199}, {1, 199, 199}, {0, 0, 0}}},
821 {0, {{1, 200, 299}, {1, 100, 199}, {0, 199, 199}, {0, 0, 0}}},
822 {1, {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202},
823 {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206},
824 {1, 207, 207}, {1, 208, 208}, {1, 199, 199}, {0, 0, 0}}},
825 {0, {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202},
826 {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206},
827 {1, 207, 207}, {1, 208, 208}, {0, 199, 199}, {0, 0, 0}}},
828 };
829 Guid any_type = GPT_ENT_TYPE_CHROMEOS_KERNEL;
830 int i, j;
831 int test_mask;
832 GptEntry *entries[2];
833
834 gpt = GetEmptyGptData();
835 entries[PRIMARY] = (GptEntry*)gpt->primary_entries;
836 entries[SECONDARY] = (GptEntry*)gpt->secondary_entries;
837
838 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
839 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
840 BuildTestGptData(gpt);
841 ZeroEntries(gpt);
842 for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) {
843 if (!cases[i].entries[j].starting_lba) break;
844 if (test_mask & MASK_PRIMARY) {
845 if (cases[i].entries[j].active)
846 Memcpy(&entries[PRIMARY][j].type, &any_type, sizeof(any_type));
847 entries[PRIMARY][j].starting_lba = cases[i].entries[j].starting_lba;
848 entries[PRIMARY][j].ending_lba = cases[i].entries[j].ending_lba;
849 }
850 if (test_mask & MASK_SECONDARY) {
851 if (cases[i].entries[j].active)
852 Memcpy(&entries[SECONDARY][j].type, &any_type, sizeof(any_type));
853 entries[SECONDARY][j].starting_lba = cases[i].entries[j].starting_lba;
854 entries[SECONDARY][j].ending_lba = cases[i].entries[j].ending_lba;
855 }
856 }
857 EXPECT((cases[i].overlapped * test_mask) ==
858 (OverlappedEntries(entries[PRIMARY], j) |
859 (OverlappedEntries(entries[SECONDARY], j) << SECONDARY))
860 );
861
862 EXPECT((MASK_BOTH ^ (cases[i].overlapped * test_mask)) ==
863 CheckOverlappedPartition(gpt));
864 }
865 }
866 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700867}
868
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700869/* Tests if GptInit() can survive in different corrupt header/entries
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700870 * combinations, like:
871 * primary GPT header - valid
872 * primary partition table - invalid
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700873 * secondary GPT header - invalid
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700874 * secondary partition table - valid
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700875 */
876int CorruptCombinationTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700877 GptData *gpt;
878 GptHeader *primary_header, *secondary_header;
879 GptEntry *primary_entries, *secondary_entries;
880
881 gpt = GetEmptyGptData();
882 primary_header = (GptHeader*)gpt->primary_header;
883 secondary_header = (GptHeader*)gpt->secondary_header;
884 primary_entries = (GptEntry*)gpt->primary_entries;
885 secondary_entries = (GptEntry*)gpt->secondary_entries;
886
887 /* Make primary entries and secondary header invalid, we expect GptInit()
888 * can recover them (returns GPT_SUCCESS and MODIFIED flasgs). */
889 BuildTestGptData(gpt);
890 primary_entries[0].type.u.raw[0] ^= 0x33;
891 secondary_header->header_crc32 ^= 0x55;
892 EXPECT(GPT_SUCCESS == GptInit(gpt));
893 EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES1) == gpt->modified);
894 EXPECT(0 == Memcmp(primary_entries, secondary_entries, TOTAL_ENTRIES_SIZE));
895 /* We expect the modified header/entries can pass GptInit(). */
896 EXPECT(GPT_SUCCESS == GptInit(gpt));
897 EXPECT(0 == gpt->modified);
898
899 /* Make primary header invalid (the entries is not damaged actually). */
900 BuildTestGptData(gpt);
901 primary_header->entries_crc32 ^= 0x73;
902 EXPECT(GPT_SUCCESS == GptInit(gpt));
903 /* After header is repaired, the entries are valid actually. */
Louis Yung-Chieh Lo418ad3b2010-05-27 11:21:17 +0800904 EXPECT((gpt->modified & (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_HEADER2)) ==
905 GPT_MODIFIED_HEADER1);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700906 /* We expect the modified header/entries can pass GptInit(). */
907 EXPECT(GPT_SUCCESS == GptInit(gpt));
908 EXPECT(0 == gpt->modified);
909
910 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700911}
912
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700913/* Invalidate all kernel entries and expect GptNextKernelEntry() cannot find
914 * any usable kernel entry.
915 */
916int NoValidKernelEntryTest() {
917 GptData *gpt;
918 GptEntry *entries, *entries2;
919
920 gpt = GetEmptyGptData();
921 entries = (GptEntry*)gpt->primary_entries;
922 entries2 = (GptEntry*)gpt->secondary_entries;
923
924 BuildTestGptData(gpt);
925 entries[KERNEL_A].attributes |= CGPT_ATTRIBUTE_BAD_MASK;
926 Memset(&entries[KERNEL_B].type, 0, sizeof(Guid));
927 RefreshCrc32(gpt);
928
929 EXPECT(GPT_ERROR_NO_VALID_KERNEL == GptNextKernelEntry(gpt, NULL, NULL));
930
931 return TEST_OK;
932}
933
934/* This is the combination test. Both kernel A and B could be either inactive
935 * or invalid. We expect GptNextKetnelEntry() returns good kernel or
936 * GPT_ERROR_NO_VALID_KERNEL if no kernel is available. */
937enum FAILURE_MASK {
938 MASK_INACTIVE = 1,
939 MASK_BAD_ENTRY = 2,
940 MASK_FAILURE_BOTH = 3,
941};
942void BreakAnEntry(GptEntry *entry, enum FAILURE_MASK failure) {
943 if (failure & MASK_INACTIVE)
944 Memset(&entry->type, 0, sizeof(Guid));
945 if (failure & MASK_BAD_ENTRY)
946 entry->attributes |= CGPT_ATTRIBUTE_BAD_MASK;
947}
948
949int CombinationalNextKernelEntryTest() {
950 GptData *gpt;
951 enum {
952 MASK_KERNEL_A = 1,
953 MASK_KERNEL_B = 2,
954 MASK_KERNEL_BOTH = 3,
955 } kernel;
956 enum FAILURE_MASK failure;
957 uint64_t start_sector, size;
958 int retval;
959
960 for (kernel = MASK_KERNEL_A; kernel <= MASK_KERNEL_BOTH; ++kernel) {
961 for (failure = MASK_INACTIVE; failure < MASK_FAILURE_BOTH; ++failure) {
962 gpt = GetEmptyGptData();
963 BuildTestGptData(gpt);
964
965 if (kernel & MASK_KERNEL_A)
966 BreakAnEntry(GetEntry(gpt, PRIMARY, KERNEL_A), failure);
967 if (kernel & MASK_KERNEL_B)
968 BreakAnEntry(GetEntry(gpt, PRIMARY, KERNEL_B), failure);
969
970 retval = GptNextKernelEntry(gpt, &start_sector, &size);
971
972 if (kernel == MASK_KERNEL_A) {
973 EXPECT(retval == GPT_SUCCESS);
974 EXPECT(start_sector == 334);
975 } else if (kernel == MASK_KERNEL_B) {
976 EXPECT(retval == GPT_SUCCESS);
977 EXPECT(start_sector == 34);
978 } else { /* MASK_KERNEL_BOTH */
979 EXPECT(retval == GPT_ERROR_NO_VALID_KERNEL);
980 }
981 }
982 }
983 return TEST_OK;
984}
985
986/* Increase tries value from zero, expect it won't explode/overflow after
987 * CGPT_ATTRIBUTE_TRIES_MASK.
988 */
989/* Tries would not count up after CGPT_ATTRIBUTE_MAX_TRIES. */
990#define EXPECTED_TRIES(tries) \
991 ((tries >= CGPT_ATTRIBUTE_MAX_TRIES) ? CGPT_ATTRIBUTE_MAX_TRIES \
992 : tries)
993int IncreaseTriesTest() {
994 GptData *gpt;
995 int kernel_index[] = {
996 KERNEL_B,
997 KERNEL_A,
998 };
999 int i, tries, j;
1000
1001 gpt = GetEmptyGptData();
1002 for (i = 0; i < ARRAY_SIZE(kernel_index); ++i) {
1003 GptEntry *entries[2] = {
1004 (GptEntry*)gpt->primary_entries,
1005 (GptEntry*)gpt->secondary_entries,
1006 };
1007 int current;
1008
1009 BuildTestGptData(gpt);
1010 current = gpt->current_kernel = kernel_index[i];
1011
1012 for (tries = 0; tries < 2 * CGPT_ATTRIBUTE_MAX_TRIES; ++tries) {
1013 for (j = 0; j < ARRAY_SIZE(entries); ++j) {
1014 EXPECT(EXPECTED_TRIES(tries) ==
1015 ((entries[j][current].attributes & CGPT_ATTRIBUTE_TRIES_MASK) >>
1016 CGPT_ATTRIBUTE_TRIES_OFFSET));
1017 }
1018
1019 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
1020 /* The expected tries value will be checked in next iteration. */
1021
1022 if (tries < CGPT_ATTRIBUTE_MAX_TRIES)
1023 EXPECT((GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
1024 GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
1025 gpt->modified = 0; /* reset before next test */
1026 EXPECT(0 ==
1027 Memcmp(entries[PRIMARY], entries[SECONDARY], TOTAL_ENTRIES_SIZE));
1028 }
1029 }
1030 return TEST_OK;
1031}
1032
1033/* Mark a kernel as bad. Expect:
1034 * 1. the both bad bits of kernel A in primary and secondary entries are set.
1035 * 2. headers and entries are marked as modified.
1036 * 3. primary and secondary entries are identical.
1037 */
1038int MarkBadKernelEntryTest() {
1039 GptData *gpt;
1040 GptEntry *entries, *entries2;
1041
1042 gpt = GetEmptyGptData();
1043 entries = (GptEntry*)gpt->primary_entries;
1044 entries2 = (GptEntry*)gpt->secondary_entries;
1045
1046 BuildTestGptData(gpt);
1047 gpt->current_kernel = KERNEL_A;
1048 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
1049 EXPECT((GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
1050 GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
1051 EXPECT(entries[KERNEL_A].attributes & CGPT_ATTRIBUTE_BAD_MASK);
1052 EXPECT(entries2[KERNEL_A].attributes & CGPT_ATTRIBUTE_BAD_MASK);
1053 EXPECT(0 == Memcmp(entries, entries2, TOTAL_ENTRIES_SIZE));
1054
1055 return TEST_OK;
1056}
1057
1058/* Given an invalid kernel type, and expect GptUpdateKernelEntry() returns
1059 * GPT_ERROR_INVALID_UPDATE_TYPE. */
1060int UpdateInvalidKernelTypeTest() {
1061 GptData *gpt;
1062
1063 gpt = GetEmptyGptData();
1064 BuildTestGptData(gpt);
1065 gpt->current_kernel = 0; /* anything, but not CGPT_KERNEL_ENTRY_NOT_FOUND */
1066 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1067 GptUpdateKernelEntry(gpt, 99)); /* any invalid update_type value */
1068
1069 return TEST_OK;
1070}
1071
1072/* A normal boot case:
1073 * GptInit()
1074 * GptNextKernelEntry()
1075 * GptUpdateKernelEntry()
1076 */
1077int NormalBootCase() {
1078 GptData *gpt;
1079 GptEntry *entries;
1080 uint64_t start_sector, size;
1081
1082 gpt = GetEmptyGptData();
1083 entries = (GptEntry*)gpt->primary_entries;
1084 BuildTestGptData(gpt);
1085
1086 EXPECT(GPT_SUCCESS == GptInit(gpt));
1087 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start_sector, &size));
1088 EXPECT(start_sector == 34); /* Kernel A, see top of this file. */
1089 EXPECT(size == 100);
1090
1091 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
1092 EXPECT(((entries[KERNEL_A].attributes & CGPT_ATTRIBUTE_TRIES_MASK) >>
1093 CGPT_ATTRIBUTE_TRIES_OFFSET) == 1);
1094
1095 return TEST_OK;
1096}
1097
1098/* Higher priority kernel should boot first.
1099 * KERNEL_A is low priority
1100 * KERNEL_B is high priority.
1101 * We expect KERNEL_B is selected in first run, and then KERNEL_A.
1102 * We also expect the GptNextKernelEntry() wraps back to KERNEL_B if it's called
1103 * after twice.
1104 */
1105int HigherPriorityTest() {
1106 GptData *gpt;
1107 GptEntry *entries;
1108
1109 gpt = GetEmptyGptData();
1110 entries = (GptEntry*)gpt->primary_entries;
1111 BuildTestGptData(gpt);
1112
1113 SetPriority(gpt, PRIMARY, KERNEL_A, 0);
1114 SetPriority(gpt, PRIMARY, KERNEL_B, 1);
1115 RefreshCrc32(gpt);
1116
1117 EXPECT(GPT_SUCCESS == GptInit(gpt));
1118 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, NULL, NULL));
1119 EXPECT(KERNEL_B == gpt->current_kernel);
1120
1121 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, NULL, NULL));
1122 EXPECT(KERNEL_A == gpt->current_kernel);
1123
1124 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, NULL, NULL));
1125 EXPECT(KERNEL_B == gpt->current_kernel);
1126
1127 return TEST_OK;
1128}
1129
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001130int main(int argc, char *argv[]) {
1131 int i;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001132 int error_count = 0;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001133 struct {
1134 char *name;
1135 test_func fp;
1136 int retval;
1137 } test_cases[] = {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001138 { TEST_CASE(TestBuildTestGptData), },
1139 { TEST_CASE(ParameterTests), },
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -07001140 { TEST_CASE(SignatureTest), },
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001141 { TEST_CASE(RevisionTest), },
1142 { TEST_CASE(SizeTest), },
1143 { TEST_CASE(ReservedFieldsTest), },
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001144 { TEST_CASE(MyLbaTest), },
1145 { TEST_CASE(SizeOfPartitionEntryTest), },
1146 { TEST_CASE(NumberOfPartitionEntriesTest), },
1147 { TEST_CASE(PartitionEntryLbaTest), },
1148 { TEST_CASE(FirstUsableLbaAndLastUsableLbaTest), },
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001149 { TEST_CASE(HeaderCrcTest), },
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001150 { TEST_CASE(EntriesCrcTest), },
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001151 { TEST_CASE(IdenticalEntriesTest), },
1152 { TEST_CASE(SynonymousHeaderTest), },
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001153 { TEST_CASE(ValidEntryTest), },
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001154 { TEST_CASE(OverlappedPartitionTest), },
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001155 { TEST_CASE(CorruptCombinationTest), },
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001156 { TEST_CASE(TestQuickSortFixed), },
1157 { TEST_CASE(TestQuickSortRandom), },
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001158 { TEST_CASE(NoValidKernelEntryTest), },
1159 { TEST_CASE(CombinationalNextKernelEntryTest), },
1160 { TEST_CASE(IncreaseTriesTest), },
1161 { TEST_CASE(MarkBadKernelEntryTest), },
1162 { TEST_CASE(UpdateInvalidKernelTypeTest), },
1163 { TEST_CASE(NormalBootCase), },
1164 { TEST_CASE(HigherPriorityTest), },
Louis Yung-Chieh Lob31ddce2010-05-21 16:35:44 +08001165 { TEST_CASE(TestCrc32TestVectors), },
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001166 };
1167
1168 for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
1169 printf("Running %s() ...\n", test_cases[i].name);
1170 test_cases[i].retval = test_cases[i].fp();
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001171 if (test_cases[i].retval) {
1172 printf(COL_RED "[ERROR]\n\n" COL_STOP);
1173 ++error_count;
1174 } else {
1175 printf(COL_GREEN "[PASS]\n\n" COL_STOP);
1176 }
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001177 }
1178
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001179 if (error_count) {
1180 printf("\n--------------------------------------------------\n");
1181 printf(COL_RED "The following %d test cases are failed:\n" COL_STOP,
1182 error_count);
1183 for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
1184 if (test_cases[i].retval)
1185 printf(" %s()\n", test_cases[i].name);
1186 }
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001187 }
1188
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001189 return (error_count) ? 1 : 0;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001190}