blob: b48543f32f33bae69a146bb5b87747007bbf4bdc [file] [log] [blame]
Randall Spanglere9213a72013-01-24 11:19:55 -08001/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07002 * 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 Lo37f6b552010-04-22 21:22:22 -07006#include <string.h>
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07007
Louis Yung-Chieh Lo0dce41c2010-05-17 22:45:30 -07008#include "cgptlib_internal.h"
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07009#include "cgptlib_test.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"
vbendeb3ecaf772010-06-24 16:19:53 -070013#include "test_common.h"
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070014#include "utility.h"
15
Randall Spanglere9213a72013-01-24 11:19:55 -080016/*
17 * Testing partition layout (sector_bytes=512)
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070018 *
19 * LBA Size Usage
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -070020 * ---------------------------------------------------------
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070021 * 0 1 PMBR
22 * 1 1 primary partition header
23 * 2 32 primary partition entries (128B * 128)
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -070024 * 34 100 kernel A (index: 0)
25 * 134 100 root A (index: 1)
26 * 234 100 root B (index: 2)
27 * 334 100 kernel B (index: 3)
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070028 * 434 32 secondary partition entries
29 * 466 1 secondary partition header
30 * 467
31 */
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -070032#define KERNEL_A 0
Randall Spangler3dcf9dc2010-06-02 12:46:17 -070033#define KERNEL_B 1
34#define ROOTFS_A 2
35#define ROOTFS_B 3
36#define KERNEL_X 2 /* Overload ROOTFS_A, for some GetNext tests */
37#define KERNEL_Y 3 /* Overload ROOTFS_B, for some GetNext tests */
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -070038
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070039#define DEFAULT_SECTOR_SIZE 512
40#define MAX_SECTOR_SIZE 4096
41#define DEFAULT_DRIVE_SECTORS 467
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070042#define PARTITION_ENTRIES_SIZE TOTAL_ENTRIES_SIZE /* 16384 */
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070043
Randall Spangler3dcf9dc2010-06-02 12:46:17 -070044static const Guid guid_zero = {{{0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0}}}};
45static const Guid guid_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
46static const Guid guid_rootfs = GPT_ENT_TYPE_CHROMEOS_ROOTFS;
47
Randall Spanglere9213a72013-01-24 11:19:55 -080048/*
49 * Copy a random-for-this-program-only Guid into the dest. The num parameter
Bill Richardsonaa8eda42010-08-27 09:31:26 -070050 * completely determines the Guid.
51 */
Randall Spanglere9213a72013-01-24 11:19:55 -080052static void SetGuid(void *dest, uint32_t num)
53{
54 Guid g = {{{num,0xd450,0x44bc,0xa6,0x93,
55 {0xb8,0xac,0x75,0x5f,0xcd,0x48}}}};
56 Memcpy(dest, &g, sizeof(Guid));
Bill Richardsonaa8eda42010-08-27 09:31:26 -070057}
Randall Spangler3dcf9dc2010-06-02 12:46:17 -070058
Randall Spanglere9213a72013-01-24 11:19:55 -080059/*
60 * Given a GptData pointer, first re-calculate entries CRC32 value, then reset
61 * header CRC32 value to 0, and calculate header CRC32 value. Both primary and
62 * secondary are updated.
63 */
64static void RefreshCrc32(GptData *gpt)
65{
66 GptHeader *header, *header2;
67 GptEntry *entries, *entries2;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070068
Randall Spanglere9213a72013-01-24 11:19:55 -080069 header = (GptHeader *)gpt->primary_header;
70 entries = (GptEntry *)gpt->primary_entries;
71 header2 = (GptHeader *)gpt->secondary_header;
72 entries2 = (GptEntry *)gpt->secondary_entries;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070073
Randall Spanglere9213a72013-01-24 11:19:55 -080074 header->entries_crc32 =
75 Crc32((uint8_t *)entries,
76 header->number_of_entries * header->size_of_entry);
77 header->header_crc32 = 0;
78 header->header_crc32 = Crc32((uint8_t *)header, header->size);
79 header2->entries_crc32 =
80 Crc32((uint8_t *)entries2,
81 header2->number_of_entries * header2->size_of_entry);
82 header2->header_crc32 = 0;
83 header2->header_crc32 = Crc32((uint8_t *)header2, header2->size);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070084}
85
Randall Spanglere9213a72013-01-24 11:19:55 -080086static void ZeroHeaders(GptData *gpt)
87{
88 Memset(gpt->primary_header, 0, MAX_SECTOR_SIZE);
89 Memset(gpt->secondary_header, 0, MAX_SECTOR_SIZE);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070090}
91
Randall Spanglere9213a72013-01-24 11:19:55 -080092static void ZeroEntries(GptData *gpt)
93{
94 Memset(gpt->primary_entries, 0, PARTITION_ENTRIES_SIZE);
95 Memset(gpt->secondary_entries, 0, PARTITION_ENTRIES_SIZE);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070096}
97
Randall Spanglere9213a72013-01-24 11:19:55 -080098static void ZeroHeadersEntries(GptData *gpt)
99{
100 ZeroHeaders(gpt);
101 ZeroEntries(gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700102}
103
Randall Spanglere9213a72013-01-24 11:19:55 -0800104/*
105 * Return a pointer to a static GptData instance (no free is required).
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700106 * All fields are zero except 4 pointers linking to header and entries.
Randall Spanglere9213a72013-01-24 11:19:55 -0800107 * All content of headers and entries are zero.
108 */
109static GptData *GetEmptyGptData(void)
110{
111 static GptData gpt;
112 static uint8_t primary_header[MAX_SECTOR_SIZE];
113 static uint8_t primary_entries[PARTITION_ENTRIES_SIZE];
114 static uint8_t secondary_header[MAX_SECTOR_SIZE];
115 static uint8_t secondary_entries[PARTITION_ENTRIES_SIZE];
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700116
Randall Spanglere9213a72013-01-24 11:19:55 -0800117 Memset(&gpt, 0, sizeof(gpt));
118 gpt.primary_header = primary_header;
119 gpt.primary_entries = primary_entries;
120 gpt.secondary_header = secondary_header;
121 gpt.secondary_entries = secondary_entries;
122 ZeroHeadersEntries(&gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700123
Randall Spanglere9213a72013-01-24 11:19:55 -0800124 /* Initialize GptData internal states. */
125 gpt.current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700126
Randall Spanglere9213a72013-01-24 11:19:55 -0800127 return &gpt;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700128}
129
Randall Spanglere9213a72013-01-24 11:19:55 -0800130/*
131 * Fill in most of fields and creates the layout described in the top of this
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700132 * file. Before calling this function, primary/secondary header/entries must
133 * have been pointed to the buffer, say, a gpt returned from GetEmptyGptData().
134 * This function returns a good (valid) copy of GPT layout described in top of
Randall Spanglere9213a72013-01-24 11:19:55 -0800135 * this file.
136 */
137static void BuildTestGptData(GptData *gpt)
138{
139 GptHeader *header, *header2;
140 GptEntry *entries, *entries2;
141 Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
142 Guid chromeos_rootfs = GPT_ENT_TYPE_CHROMEOS_ROOTFS;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700143
Randall Spanglere9213a72013-01-24 11:19:55 -0800144 gpt->sector_bytes = DEFAULT_SECTOR_SIZE;
145 gpt->drive_sectors = DEFAULT_DRIVE_SECTORS;
146 gpt->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
147 gpt->valid_headers = MASK_BOTH;
148 gpt->valid_entries = MASK_BOTH;
149 gpt->modified = 0;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700150
Randall Spanglere9213a72013-01-24 11:19:55 -0800151 /* Build primary */
152 header = (GptHeader *)gpt->primary_header;
153 entries = (GptEntry *)gpt->primary_entries;
154 Memcpy(header->signature, GPT_HEADER_SIGNATURE,
155 sizeof(GPT_HEADER_SIGNATURE));
156 header->revision = GPT_HEADER_REVISION;
157 header->size = sizeof(GptHeader);
158 header->reserved_zero = 0;
159 header->my_lba = 1;
160 header->alternate_lba = DEFAULT_DRIVE_SECTORS - 1;
161 header->first_usable_lba = 34;
162 header->last_usable_lba = DEFAULT_DRIVE_SECTORS - 1 - 32 - 1; /* 433 */
163 header->entries_lba = 2;
164 /* 512B / 128B * 32sectors = 128 entries */
165 header->number_of_entries = 128;
166 header->size_of_entry = 128; /* bytes */
167 Memcpy(&entries[0].type, &chromeos_kernel, sizeof(chromeos_kernel));
168 SetGuid(&entries[0].unique, 0);
169 entries[0].starting_lba = 34;
170 entries[0].ending_lba = 133;
171 Memcpy(&entries[1].type, &chromeos_rootfs, sizeof(chromeos_rootfs));
172 SetGuid(&entries[1].unique, 1);
173 entries[1].starting_lba = 134;
174 entries[1].ending_lba = 232;
175 Memcpy(&entries[2].type, &chromeos_rootfs, sizeof(chromeos_rootfs));
176 SetGuid(&entries[2].unique, 2);
177 entries[2].starting_lba = 234;
178 entries[2].ending_lba = 331;
179 Memcpy(&entries[3].type, &chromeos_kernel, sizeof(chromeos_kernel));
180 SetGuid(&entries[3].unique, 3);
181 entries[3].starting_lba = 334;
182 entries[3].ending_lba = 430;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700183
Randall Spanglere9213a72013-01-24 11:19:55 -0800184 /* Build secondary */
185 header2 = (GptHeader *)gpt->secondary_header;
186 entries2 = (GptEntry *)gpt->secondary_entries;
187 Memcpy(header2, header, sizeof(GptHeader));
188 Memcpy(entries2, entries, PARTITION_ENTRIES_SIZE);
189 header2->my_lba = DEFAULT_DRIVE_SECTORS - 1; /* 466 */
190 header2->alternate_lba = 1;
191 header2->entries_lba = DEFAULT_DRIVE_SECTORS - 1 - 32; /* 434 */
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700192
Randall Spanglere9213a72013-01-24 11:19:55 -0800193 RefreshCrc32(gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700194}
195
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700196
Randall Spanglere9213a72013-01-24 11:19:55 -0800197/*
198 * Test if the structures are the expected size; if this fails, struct packing
199 * is not working properly.
200 */
201static int StructSizeTest(void)
202{
Randall Spangler81d09962010-06-23 10:15:38 -0700203
Randall Spanglere9213a72013-01-24 11:19:55 -0800204 EXPECT(GUID_EXPECTED_SIZE == sizeof(Guid));
205 EXPECT(GPTHEADER_EXPECTED_SIZE == sizeof(GptHeader));
206 EXPECT(GPTENTRY_EXPECTED_SIZE == sizeof(GptEntry));
207 return TEST_OK;
Randall Spangler81d09962010-06-23 10:15:38 -0700208}
209
210
Randall Spanglere9213a72013-01-24 11:19:55 -0800211/* Test if the default structure returned by BuildTestGptData() is good. */
212static int TestBuildTestGptData(void)
213{
214 GptData *gpt;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700215
Randall Spanglere9213a72013-01-24 11:19:55 -0800216 gpt = GetEmptyGptData();
217 BuildTestGptData(gpt);
218 EXPECT(GPT_SUCCESS == GptInit(gpt));
Randall Spangler0bda13f2013-01-24 12:25:26 -0800219 gpt->sector_bytes = 0;
220 EXPECT(GPT_ERROR_INVALID_SECTOR_SIZE == GptInit(gpt));
Randall Spanglere9213a72013-01-24 11:19:55 -0800221 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700222}
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700223
Randall Spanglere9213a72013-01-24 11:19:55 -0800224/*
225 * Test if wrong sector_bytes or drive_sectors is detected by GptInit().
226 * Currently we only support 512 bytes per sector. In the future, we may
227 * support other sizes. A too small drive_sectors should be rejected by
228 * GptInit().
229 */
230static int ParameterTests(void)
231{
232 GptData *gpt;
233 struct {
234 uint32_t sector_bytes;
235 uint64_t drive_sectors;
236 int expected_retval;
237 } cases[] = {
238 {512, DEFAULT_DRIVE_SECTORS, GPT_SUCCESS},
239 {520, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
240 {512, 0, GPT_ERROR_INVALID_SECTOR_NUMBER},
241 {512, 66, GPT_ERROR_INVALID_SECTOR_NUMBER},
242 {512, GPT_PMBR_SECTOR + GPT_HEADER_SECTOR * 2 +
243 GPT_ENTRIES_SECTORS * 2, GPT_SUCCESS},
244 {4096, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
245 };
246 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700247
Randall Spanglere9213a72013-01-24 11:19:55 -0800248 gpt = GetEmptyGptData();
249 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
250 BuildTestGptData(gpt);
251 gpt->sector_bytes = cases[i].sector_bytes;
252 gpt->drive_sectors = cases[i].drive_sectors;
253 EXPECT(cases[i].expected_retval == CheckParameters(gpt));
254 }
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700255
Randall Spanglere9213a72013-01-24 11:19:55 -0800256 return TEST_OK;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700257}
258
Randall Spanglere9213a72013-01-24 11:19:55 -0800259/* Test if header CRC in two copies are calculated. */
260static int HeaderCrcTest(void)
261{
262 GptData *gpt = GetEmptyGptData();
263 GptHeader *h1 = (GptHeader *)gpt->primary_header;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700264
Randall Spanglere9213a72013-01-24 11:19:55 -0800265 BuildTestGptData(gpt);
266 EXPECT(HeaderCrc(h1) == h1->header_crc32);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700267
Randall Spanglere9213a72013-01-24 11:19:55 -0800268 /* CRC covers first byte of header */
269 BuildTestGptData(gpt);
270 gpt->primary_header[0] ^= 0xa5;
271 EXPECT(HeaderCrc(h1) != h1->header_crc32);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700272
Randall Spanglere9213a72013-01-24 11:19:55 -0800273 /* CRC covers last byte of header */
274 BuildTestGptData(gpt);
275 gpt->primary_header[h1->size - 1] ^= 0x5a;
276 EXPECT(HeaderCrc(h1) != h1->header_crc32);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700277
Randall Spanglere9213a72013-01-24 11:19:55 -0800278 /* CRC only covers header */
279 BuildTestGptData(gpt);
280 gpt->primary_header[h1->size] ^= 0x5a;
281 EXPECT(HeaderCrc(h1) == h1->header_crc32);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700282
Randall Spanglere9213a72013-01-24 11:19:55 -0800283 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700284}
285
Randall Spangler0bda13f2013-01-24 12:25:26 -0800286/* Test if header-same comparison works. */
287static int HeaderSameTest(void)
288{
289 GptData *gpt = GetEmptyGptData();
290 GptHeader *h1 = (GptHeader *)gpt->primary_header;
291 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
292 GptHeader h3;
293
294 EXPECT(0 == HeaderFieldsSame(h1, h2));
295
296 Memcpy(&h3, h2, sizeof(h3));
297 h3.signature[0] ^= 0xba;
298 EXPECT(1 == HeaderFieldsSame(h1, &h3));
299
300 Memcpy(&h3, h2, sizeof(h3));
301 h3.revision++;
302 EXPECT(1 == HeaderFieldsSame(h1, &h3));
303
304 Memcpy(&h3, h2, sizeof(h3));
305 h3.size++;
306 EXPECT(1 == HeaderFieldsSame(h1, &h3));
307
308 Memcpy(&h3, h2, sizeof(h3));
309 h3.reserved_zero++;
310 EXPECT(1 == HeaderFieldsSame(h1, &h3));
311
312 Memcpy(&h3, h2, sizeof(h3));
313 h3.first_usable_lba++;
314 EXPECT(1 == HeaderFieldsSame(h1, &h3));
315
316 Memcpy(&h3, h2, sizeof(h3));
317 h3.last_usable_lba++;
318 EXPECT(1 == HeaderFieldsSame(h1, &h3));
319
320 Memcpy(&h3, h2, sizeof(h3));
321 h3.disk_uuid.u.raw[0] ^= 0xba;
322 EXPECT(1 == HeaderFieldsSame(h1, &h3));
323
324 Memcpy(&h3, h2, sizeof(h3));
325 h3.number_of_entries++;
326 EXPECT(1 == HeaderFieldsSame(h1, &h3));
327
328 Memcpy(&h3, h2, sizeof(h3));
329 h3.size_of_entry++;
330 EXPECT(1 == HeaderFieldsSame(h1, &h3));
331
332 Memcpy(&h3, h2, sizeof(h3));
333 h3.entries_crc32++;
334 EXPECT(1 == HeaderFieldsSame(h1, &h3));
335
336 return TEST_OK;
337}
338
Randall Spanglere9213a72013-01-24 11:19:55 -0800339/* Test if signature ("EFI PART") is checked. */
340static int SignatureTest(void)
341{
342 GptData *gpt = GetEmptyGptData();
343 GptHeader *h1 = (GptHeader *)gpt->primary_header;
344 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
345 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700346
Randall Spangler0bda13f2013-01-24 12:25:26 -0800347 EXPECT(1 == CheckHeader(NULL, 0, gpt->drive_sectors));
348
Randall Spanglere9213a72013-01-24 11:19:55 -0800349 for (i = 0; i < 8; ++i) {
350 BuildTestGptData(gpt);
351 h1->signature[i] ^= 0xff;
352 h2->signature[i] ^= 0xff;
353 RefreshCrc32(gpt);
354 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
355 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
356 }
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700357
Randall Spanglere9213a72013-01-24 11:19:55 -0800358 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700359}
360
Randall Spanglere9213a72013-01-24 11:19:55 -0800361/*
362 * The revision we currently support is GPT_HEADER_REVISION. If the revision
363 * in header is not that, we expect the header is invalid.
364 */
365static int RevisionTest(void)
366{
367 GptData *gpt = GetEmptyGptData();
368 GptHeader *h1 = (GptHeader *)gpt->primary_header;
369 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
370 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700371
Randall Spanglere9213a72013-01-24 11:19:55 -0800372 struct {
373 uint32_t value_to_test;
374 int expect_rv;
375 } cases[] = {
376 {0x01000000, 1},
377 {0x00010000, 0}, /* GPT_HEADER_REVISION */
378 {0x00000100, 1},
379 {0x00000001, 1},
380 {0x23010456, 1},
381 };
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700382
Randall Spanglere9213a72013-01-24 11:19:55 -0800383 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
384 BuildTestGptData(gpt);
385 h1->revision = cases[i].value_to_test;
386 h2->revision = cases[i].value_to_test;
387 RefreshCrc32(gpt);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700388
Randall Spanglere9213a72013-01-24 11:19:55 -0800389 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
390 cases[i].expect_rv);
391 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
392 cases[i].expect_rv);
393 }
394 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700395}
396
Randall Spanglere9213a72013-01-24 11:19:55 -0800397static int SizeTest(void)
398{
399 GptData *gpt = GetEmptyGptData();
400 GptHeader *h1 = (GptHeader *)gpt->primary_header;
401 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
402 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700403
Randall Spanglere9213a72013-01-24 11:19:55 -0800404 struct {
405 uint32_t value_to_test;
406 int expect_rv;
407 } cases[] = {
408 {91, 1},
409 {92, 0},
410 {93, 0},
411 {511, 0},
412 {512, 0},
413 {513, 1},
414 };
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700415
Randall Spanglere9213a72013-01-24 11:19:55 -0800416 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
417 BuildTestGptData(gpt);
418 h1->size = cases[i].value_to_test;
419 h2->size = cases[i].value_to_test;
420 RefreshCrc32(gpt);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700421
Randall Spanglere9213a72013-01-24 11:19:55 -0800422 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
423 cases[i].expect_rv);
424 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
425 cases[i].expect_rv);
426 }
427 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700428}
429
Randall Spanglere9213a72013-01-24 11:19:55 -0800430/* Test if CRC is checked. */
431static int CrcFieldTest(void)
432{
433 GptData *gpt = GetEmptyGptData();
434 GptHeader *h1 = (GptHeader *)gpt->primary_header;
435 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700436
Randall Spanglere9213a72013-01-24 11:19:55 -0800437 BuildTestGptData(gpt);
438 /* Modify a field that the header verification doesn't care about */
439 h1->entries_crc32++;
440 h2->entries_crc32++;
441 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
442 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
443 /* Refresh the CRC; should pass now */
444 RefreshCrc32(gpt);
445 EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
446 EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700447
Randall Spanglere9213a72013-01-24 11:19:55 -0800448 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700449}
450
Randall Spanglere9213a72013-01-24 11:19:55 -0800451/* Test if reserved fields are checked. We'll try non-zero values to test. */
452static int ReservedFieldsTest(void)
453{
454 GptData *gpt = GetEmptyGptData();
455 GptHeader *h1 = (GptHeader *)gpt->primary_header;
456 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700457
Randall Spanglere9213a72013-01-24 11:19:55 -0800458 BuildTestGptData(gpt);
459 h1->reserved_zero ^= 0x12345678; /* whatever random */
460 h2->reserved_zero ^= 0x12345678; /* whatever random */
461 RefreshCrc32(gpt);
462 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
463 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700464
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700465#ifdef PADDING_CHECKED
Randall Spanglere9213a72013-01-24 11:19:55 -0800466 /* TODO: padding check is currently disabled */
467 BuildTestGptData(gpt);
468 h1->padding[12] ^= 0x34; /* whatever random */
469 h2->padding[56] ^= 0x78; /* whatever random */
470 RefreshCrc32(gpt);
471 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
472 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700473#endif
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700474
Randall Spanglere9213a72013-01-24 11:19:55 -0800475 return TEST_OK;
476}
477
478/*
479 * Technically, any size which is 2^N where N > 6 should work, but our
480 * library only supports one size.
481 */
482static int SizeOfPartitionEntryTest(void) {
483 GptData *gpt = GetEmptyGptData();
484 GptHeader *h1 = (GptHeader *)gpt->primary_header;
485 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
486 int i;
487
488 struct {
489 uint32_t value_to_test;
490 int expect_rv;
491 } cases[] = {
492 {127, 1},
493 {128, 0},
494 {129, 1},
495 {256, 1},
496 {512, 1},
497 };
498
499 /* Check size of entryes */
500 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
501 BuildTestGptData(gpt);
502 h1->size_of_entry = cases[i].value_to_test;
503 h2->size_of_entry = cases[i].value_to_test;
504 h1->number_of_entries = TOTAL_ENTRIES_SIZE /
505 cases[i].value_to_test;
506 h2->number_of_entries = TOTAL_ENTRIES_SIZE /
507 cases[i].value_to_test;
508 RefreshCrc32(gpt);
509
510 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
511 cases[i].expect_rv);
512 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
513 cases[i].expect_rv);
514 }
515
516 return TEST_OK;
517}
518
519/*
520 * Technically, any size which is 2^N where N > 6 should work, but our library
521 * only supports one size.
522 */
523static int NumberOfPartitionEntriesTest(void)
524{
525 GptData *gpt = GetEmptyGptData();
526 GptHeader *h1 = (GptHeader *)gpt->primary_header;
527 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
528
529 BuildTestGptData(gpt);
530 h1->number_of_entries--;
531 h2->number_of_entries /= 2;
532 RefreshCrc32(gpt);
533 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
534 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
535
536 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700537}
538
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700539
Randall Spanglere9213a72013-01-24 11:19:55 -0800540/* Test if myLBA field is checked (1 for primary, last for secondary). */
541static int MyLbaTest(void)
542{
543 GptData *gpt = GetEmptyGptData();
544 GptHeader *h1 = (GptHeader *)gpt->primary_header;
545 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700546
Randall Spanglere9213a72013-01-24 11:19:55 -0800547 /* myLBA depends on primary vs secondary flag */
548 BuildTestGptData(gpt);
549 EXPECT(1 == CheckHeader(h1, 1, gpt->drive_sectors));
550 EXPECT(1 == CheckHeader(h2, 0, gpt->drive_sectors));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700551
Randall Spanglere9213a72013-01-24 11:19:55 -0800552 BuildTestGptData(gpt);
553 h1->my_lba--;
554 h2->my_lba--;
555 RefreshCrc32(gpt);
556 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
557 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700558
Randall Spanglere9213a72013-01-24 11:19:55 -0800559 BuildTestGptData(gpt);
560 h1->my_lba = 2;
561 h2->my_lba--;
562 RefreshCrc32(gpt);
563 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
564 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700565
Randall Spanglere9213a72013-01-24 11:19:55 -0800566 /* We should ignore the alternate_lba field entirely */
567 BuildTestGptData(gpt);
568 h1->alternate_lba++;
569 h2->alternate_lba++;
570 RefreshCrc32(gpt);
571 EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
572 EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
573
574 BuildTestGptData(gpt);
575 h1->alternate_lba--;
576 h2->alternate_lba--;
577 RefreshCrc32(gpt);
578 EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
579 EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
580
581 BuildTestGptData(gpt);
582 h1->entries_lba++;
583 h2->entries_lba++;
584 RefreshCrc32(gpt);
585 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
586 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
587
588 BuildTestGptData(gpt);
589 h1->entries_lba--;
590 h2->entries_lba--;
591 RefreshCrc32(gpt);
592 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
593 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
594
595 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700596}
597
Randall Spanglere9213a72013-01-24 11:19:55 -0800598/* Test if FirstUsableLBA and LastUsableLBA are checked.
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700599 * FirstUsableLBA must be after the end of the primary GPT table array.
600 * LastUsableLBA must be before the start of the secondary GPT table array.
601 * FirstUsableLBA <= LastUsableLBA. */
Randall Spanglere9213a72013-01-24 11:19:55 -0800602static int FirstUsableLbaAndLastUsableLbaTest(void)
603{
604 GptData *gpt = GetEmptyGptData();
605 GptHeader *h1 = (GptHeader *)gpt->primary_header;
606 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
607 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700608
Randall Spanglere9213a72013-01-24 11:19:55 -0800609 struct {
610 uint64_t primary_entries_lba;
611 uint64_t primary_first_usable_lba;
612 uint64_t primary_last_usable_lba;
613 uint64_t secondary_first_usable_lba;
614 uint64_t secondary_last_usable_lba;
615 uint64_t secondary_entries_lba;
616 int primary_rv;
617 int secondary_rv;
618 } cases[] = {
619 {2, 34, 433, 34, 433, 434, 0, 0},
620 {2, 34, 432, 34, 430, 434, 0, 0},
621 {2, 33, 433, 33, 433, 434, 1, 1},
622 {2, 34, 434, 34, 433, 434, 1, 0},
623 {2, 34, 433, 34, 434, 434, 0, 1},
624 {2, 35, 433, 35, 433, 434, 0, 0},
625 {2, 433, 433, 433, 433, 434, 0, 0},
626 {2, 434, 433, 434, 434, 434, 1, 1},
627 {2, 433, 34, 34, 433, 434, 1, 0},
628 {2, 34, 433, 433, 34, 434, 0, 1},
629 };
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700630
Randall Spanglere9213a72013-01-24 11:19:55 -0800631 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
632 BuildTestGptData(gpt);
633 h1->entries_lba = cases[i].primary_entries_lba;
634 h1->first_usable_lba = cases[i].primary_first_usable_lba;
635 h1->last_usable_lba = cases[i].primary_last_usable_lba;
636 h2->entries_lba = cases[i].secondary_entries_lba;
637 h2->first_usable_lba = cases[i].secondary_first_usable_lba;
638 h2->last_usable_lba = cases[i].secondary_last_usable_lba;
639 RefreshCrc32(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700640
Randall Spanglere9213a72013-01-24 11:19:55 -0800641 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
642 cases[i].primary_rv);
643 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
644 cases[i].secondary_rv);
645 }
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700646
Randall Spanglere9213a72013-01-24 11:19:55 -0800647 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700648}
649
Randall Spanglere9213a72013-01-24 11:19:55 -0800650/*
651 * Test if PartitionEntryArrayCRC32 is checked. PartitionEntryArrayCRC32 must
652 * be calculated over SizeOfPartitionEntry * NumberOfPartitionEntries bytes.
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700653 */
Randall Spanglere9213a72013-01-24 11:19:55 -0800654static int EntriesCrcTest(void)
655{
656 GptData *gpt = GetEmptyGptData();
657 GptHeader *h1 = (GptHeader *)gpt->primary_header;
658 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
659 GptEntry *e2 = (GptEntry *)(gpt->secondary_entries);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700660
Randall Spanglere9213a72013-01-24 11:19:55 -0800661 /* Modify first byte of primary entries, and expect the CRC is wrong. */
662 BuildTestGptData(gpt);
663 EXPECT(0 == CheckEntries(e1, h1));
664 EXPECT(0 == CheckEntries(e2, h1));
665 gpt->primary_entries[0] ^= 0xa5; /* just XOR a non-zero value */
666 gpt->secondary_entries[TOTAL_ENTRIES_SIZE-1] ^= 0x5a;
667 EXPECT(GPT_ERROR_CRC_CORRUPTED == CheckEntries(e1, h1));
668 EXPECT(GPT_ERROR_CRC_CORRUPTED == CheckEntries(e2, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700669
Randall Spanglere9213a72013-01-24 11:19:55 -0800670 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700671}
672
Randall Spanglere9213a72013-01-24 11:19:55 -0800673/*
674 * Test if partition geometry is checked.
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700675 * All active (non-zero PartitionTypeGUID) partition entries should have:
676 * entry.StartingLBA >= header.FirstUsableLBA
677 * entry.EndingLBA <= header.LastUsableLBA
678 * entry.StartingLBA <= entry.EndingLBA
679 */
Randall Spanglere9213a72013-01-24 11:19:55 -0800680static int ValidEntryTest(void)
681{
682 GptData *gpt = GetEmptyGptData();
683 GptHeader *h1 = (GptHeader *)gpt->primary_header;
684 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700685
Randall Spanglere9213a72013-01-24 11:19:55 -0800686 /* error case: entry.StartingLBA < header.FirstUsableLBA */
687 BuildTestGptData(gpt);
688 e1[0].starting_lba = h1->first_usable_lba - 1;
689 RefreshCrc32(gpt);
690 EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700691
Randall Spanglere9213a72013-01-24 11:19:55 -0800692 /* error case: entry.EndingLBA > header.LastUsableLBA */
693 BuildTestGptData(gpt);
694 e1[2].ending_lba = h1->last_usable_lba + 1;
695 RefreshCrc32(gpt);
696 EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700697
Randall Spanglere9213a72013-01-24 11:19:55 -0800698 /* error case: entry.StartingLBA > entry.EndingLBA */
699 BuildTestGptData(gpt);
700 e1[3].starting_lba = e1[3].ending_lba + 1;
701 RefreshCrc32(gpt);
702 EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700703
Randall Spanglere9213a72013-01-24 11:19:55 -0800704 /* case: non active entry should be ignored. */
705 BuildTestGptData(gpt);
706 Memset(&e1[1].type, 0, sizeof(e1[1].type));
707 e1[1].starting_lba = e1[1].ending_lba + 1;
708 RefreshCrc32(gpt);
709 EXPECT(0 == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700710
Randall Spanglere9213a72013-01-24 11:19:55 -0800711 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700712}
713
Randall Spanglere9213a72013-01-24 11:19:55 -0800714/* Test if overlapped partition tables can be detected. */
715static int OverlappedPartitionTest(void) {
716 GptData *gpt = GetEmptyGptData();
717 GptHeader *h = (GptHeader *)gpt->primary_header;
718 GptEntry *e = (GptEntry *)gpt->primary_entries;
719 int i, j;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700720
Randall Spanglere9213a72013-01-24 11:19:55 -0800721 struct {
722 int overlapped;
723 struct {
724 int active;
725 uint64_t starting_lba;
726 uint64_t ending_lba;
727 } entries[16]; /* enough for testing. */
728 } cases[] = {
729 {GPT_SUCCESS, {{0, 100, 199}}},
730 {GPT_SUCCESS, {{1, 100, 199}}},
731 {GPT_SUCCESS, {{1, 100, 150}, {1, 200, 250}, {1, 300, 350}}},
732 {GPT_ERROR_START_LBA_OVERLAP,
733 {{1, 200, 299}, {1, 100, 199}, {1, 100, 100}}},
734 {GPT_ERROR_END_LBA_OVERLAP,
735 {{1, 200, 299}, {1, 100, 199}, {1, 299, 299}}},
736 {GPT_SUCCESS, {{1, 300, 399}, {1, 200, 299}, {1, 100, 199}}},
737 {GPT_ERROR_END_LBA_OVERLAP,
738 {{1, 100, 199}, {1, 199, 299}, {1, 299, 399}}},
739 {GPT_ERROR_START_LBA_OVERLAP,
740 {{1, 100, 199}, {1, 200, 299}, {1, 75, 399}}},
741 {GPT_ERROR_START_LBA_OVERLAP,
742 {{1, 100, 199}, {1, 75, 250}, {1, 200, 299}}},
743 {GPT_ERROR_END_LBA_OVERLAP,
744 {{1, 75, 150}, {1, 100, 199}, {1, 200, 299}}},
745 {GPT_ERROR_START_LBA_OVERLAP,
746 {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {1, 100, 399}}},
747 {GPT_SUCCESS,
748 {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {0, 100, 399}}},
749 {GPT_ERROR_START_LBA_OVERLAP,
750 {{1, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400}}},
751 {GPT_ERROR_START_LBA_OVERLAP,
752 {{0, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400}}},
753 {GPT_SUCCESS,
754 {{1, 200, 300}, {1, 100, 199}, {0, 100, 400}, {0, 300, 400}}},
755 {GPT_ERROR_END_LBA_OVERLAP,
756 {{1, 200, 299}, {1, 100, 199}, {1, 199, 199}}},
757 {GPT_SUCCESS, {{1, 200, 299}, {0, 100, 199}, {1, 199, 199}}},
758 {GPT_SUCCESS, {{1, 200, 299}, {1, 100, 199}, {0, 199, 199}}},
759 {GPT_ERROR_START_LBA_OVERLAP,
760 {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202},
761 {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206},
762 {1, 207, 207}, {1, 208, 208}, {1, 199, 199}}},
763 {GPT_SUCCESS,
764 {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202},
765 {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206},
766 {1, 207, 207}, {1, 208, 208}, {0, 199, 199}}},
767 };
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700768
Randall Spanglere9213a72013-01-24 11:19:55 -0800769 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
770 BuildTestGptData(gpt);
771 ZeroEntries(gpt);
772 for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) {
773 if (!cases[i].entries[j].starting_lba)
774 break;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700775
Randall Spanglere9213a72013-01-24 11:19:55 -0800776 if (cases[i].entries[j].active)
777 Memcpy(&e[j].type, &guid_kernel, sizeof(Guid));
778 SetGuid(&e[j].unique, j);
779 e[j].starting_lba = cases[i].entries[j].starting_lba;
780 e[j].ending_lba = cases[i].entries[j].ending_lba;
781 }
782 RefreshCrc32(gpt);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700783
Randall Spanglere9213a72013-01-24 11:19:55 -0800784 EXPECT(cases[i].overlapped == CheckEntries(e, h));
785 }
786 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700787}
788
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700789/* Test both sanity checking and repair. */
Randall Spanglere9213a72013-01-24 11:19:55 -0800790static int SanityCheckTest(void)
791{
792 GptData *gpt = GetEmptyGptData();
793 GptHeader *h1 = (GptHeader *)gpt->primary_header;
Randall Spangler0bda13f2013-01-24 12:25:26 -0800794 GptEntry *e1 = (GptEntry *)gpt->primary_entries;
795 uint8_t *tempptr;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700796
Randall Spanglere9213a72013-01-24 11:19:55 -0800797 /* Unmodified test data is completely sane */
798 BuildTestGptData(gpt);
799 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
800 EXPECT(MASK_BOTH == gpt->valid_headers);
801 EXPECT(MASK_BOTH == gpt->valid_entries);
802 /* Repair doesn't damage it */
803 GptRepair(gpt);
804 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
805 EXPECT(MASK_BOTH == gpt->valid_headers);
806 EXPECT(MASK_BOTH == gpt->valid_entries);
807 EXPECT(0 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700808
Randall Spangler0bda13f2013-01-24 12:25:26 -0800809 /* Invalid sector size should fail */
810 BuildTestGptData(gpt);
811 gpt->sector_bytes = 1024;
812 EXPECT(GPT_ERROR_INVALID_SECTOR_SIZE == GptSanityCheck(gpt));
813
Randall Spanglere9213a72013-01-24 11:19:55 -0800814 /* Modify headers */
815 BuildTestGptData(gpt);
816 gpt->primary_header[0]++;
817 gpt->secondary_header[0]++;
818 EXPECT(GPT_ERROR_INVALID_HEADERS == GptSanityCheck(gpt));
819 EXPECT(0 == gpt->valid_headers);
820 EXPECT(0 == gpt->valid_entries);
821 /* Repair can't fix completely busted headers */
822 GptRepair(gpt);
823 EXPECT(GPT_ERROR_INVALID_HEADERS == GptSanityCheck(gpt));
824 EXPECT(0 == gpt->valid_headers);
825 EXPECT(0 == gpt->valid_entries);
826 EXPECT(0 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700827
Randall Spanglere9213a72013-01-24 11:19:55 -0800828 BuildTestGptData(gpt);
829 gpt->primary_header[0]++;
830 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
831 EXPECT(MASK_SECONDARY == gpt->valid_headers);
832 EXPECT(MASK_BOTH == gpt->valid_entries);
833 GptRepair(gpt);
834 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
835 EXPECT(MASK_BOTH == gpt->valid_headers);
836 EXPECT(MASK_BOTH == gpt->valid_entries);
837 EXPECT(GPT_MODIFIED_HEADER1 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700838
Randall Spanglere9213a72013-01-24 11:19:55 -0800839 BuildTestGptData(gpt);
840 gpt->secondary_header[0]++;
841 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
842 EXPECT(MASK_PRIMARY == gpt->valid_headers);
843 EXPECT(MASK_BOTH == gpt->valid_entries);
844 GptRepair(gpt);
845 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
846 EXPECT(MASK_BOTH == gpt->valid_headers);
847 EXPECT(MASK_BOTH == gpt->valid_entries);
848 EXPECT(GPT_MODIFIED_HEADER2 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700849
Randall Spanglere9213a72013-01-24 11:19:55 -0800850 /*
851 * Modify header1 and update its CRC. Since header2 is now different
852 * than header1, it'll be the one considered invalid.
853 */
854 BuildTestGptData(gpt);
855 h1->size++;
856 RefreshCrc32(gpt);
857 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
858 EXPECT(MASK_PRIMARY == gpt->valid_headers);
859 EXPECT(MASK_BOTH == gpt->valid_entries);
860 GptRepair(gpt);
861 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
862 EXPECT(MASK_BOTH == gpt->valid_headers);
863 EXPECT(MASK_BOTH == gpt->valid_entries);
864 EXPECT(GPT_MODIFIED_HEADER2 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700865
Randall Spanglere9213a72013-01-24 11:19:55 -0800866 /* Modify entries */
867 BuildTestGptData(gpt);
868 gpt->primary_entries[0]++;
869 gpt->secondary_entries[0]++;
870 EXPECT(GPT_ERROR_INVALID_ENTRIES == GptSanityCheck(gpt));
871 EXPECT(MASK_BOTH == gpt->valid_headers);
872 EXPECT(MASK_NONE == gpt->valid_entries);
873 /* Repair can't fix both copies of entries being bad, either. */
874 GptRepair(gpt);
875 EXPECT(GPT_ERROR_INVALID_ENTRIES == GptSanityCheck(gpt));
876 EXPECT(MASK_BOTH == gpt->valid_headers);
877 EXPECT(MASK_NONE == gpt->valid_entries);
878 EXPECT(0 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700879
Randall Spanglere9213a72013-01-24 11:19:55 -0800880 BuildTestGptData(gpt);
881 gpt->primary_entries[0]++;
882 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
883 EXPECT(MASK_BOTH == gpt->valid_headers);
884 EXPECT(MASK_SECONDARY == gpt->valid_entries);
885 GptRepair(gpt);
886 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
887 EXPECT(MASK_BOTH == gpt->valid_headers);
888 EXPECT(MASK_BOTH == gpt->valid_entries);
889 EXPECT(GPT_MODIFIED_ENTRIES1 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700890
Randall Spanglere9213a72013-01-24 11:19:55 -0800891 BuildTestGptData(gpt);
892 gpt->secondary_entries[0]++;
893 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
894 EXPECT(MASK_BOTH == gpt->valid_headers);
895 EXPECT(MASK_PRIMARY == gpt->valid_entries);
896 GptRepair(gpt);
897 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
898 EXPECT(MASK_BOTH == gpt->valid_headers);
899 EXPECT(MASK_BOTH == gpt->valid_entries);
900 EXPECT(GPT_MODIFIED_ENTRIES2 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700901
Randall Spangler0bda13f2013-01-24 12:25:26 -0800902 /*
903 * Modify entries and recompute CRCs, then make both primary and
904 * secondary entry pointers use the secondary data. The primary
905 * header will have the wrong entries CRC, so we should fall back
906 * to the secondary header.
907 */
908 BuildTestGptData(gpt);
909 e1->starting_lba++;
910 RefreshCrc32(gpt);
911 tempptr = gpt->primary_entries;
912 gpt->primary_entries = gpt->secondary_entries;
913 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
914 EXPECT(MASK_SECONDARY == gpt->valid_headers);
915 EXPECT(MASK_BOTH == gpt->valid_entries);
916 gpt->primary_entries = tempptr;
917
Randall Spanglere9213a72013-01-24 11:19:55 -0800918 /* Modify both header and entries */
919 BuildTestGptData(gpt);
920 gpt->primary_header[0]++;
921 gpt->primary_entries[0]++;
922 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
923 EXPECT(MASK_SECONDARY == gpt->valid_headers);
924 EXPECT(MASK_SECONDARY == gpt->valid_entries);
925 GptRepair(gpt);
926 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
927 EXPECT(MASK_BOTH == gpt->valid_headers);
928 EXPECT(MASK_BOTH == gpt->valid_entries);
929 EXPECT((GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1) == gpt->modified);
Bill Richardsonaa8eda42010-08-27 09:31:26 -0700930
Randall Spanglere9213a72013-01-24 11:19:55 -0800931 BuildTestGptData(gpt);
932 gpt->secondary_header[0]++;
933 gpt->secondary_entries[0]++;
934 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
935 EXPECT(MASK_PRIMARY == gpt->valid_headers);
936 EXPECT(MASK_PRIMARY == gpt->valid_entries);
937 GptRepair(gpt);
938 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
939 EXPECT(MASK_BOTH == gpt->valid_headers);
940 EXPECT(MASK_BOTH == gpt->valid_entries);
941 EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
Bill Richardsonaa8eda42010-08-27 09:31:26 -0700942
Randall Spanglere9213a72013-01-24 11:19:55 -0800943 /* Test cross-correction (h1+e2, h2+e1) */
944 BuildTestGptData(gpt);
945 gpt->primary_header[0]++;
946 gpt->secondary_entries[0]++;
947 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
948 EXPECT(MASK_SECONDARY == gpt->valid_headers);
949 EXPECT(MASK_PRIMARY == gpt->valid_entries);
950 GptRepair(gpt);
951 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
952 EXPECT(MASK_BOTH == gpt->valid_headers);
953 EXPECT(MASK_BOTH == gpt->valid_entries);
954 EXPECT((GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700955
Randall Spanglere9213a72013-01-24 11:19:55 -0800956 BuildTestGptData(gpt);
957 gpt->secondary_header[0]++;
958 gpt->primary_entries[0]++;
959 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
960 EXPECT(MASK_PRIMARY == gpt->valid_headers);
961 EXPECT(MASK_SECONDARY == gpt->valid_entries);
962 GptRepair(gpt);
963 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
964 EXPECT(MASK_BOTH == gpt->valid_headers);
965 EXPECT(MASK_BOTH == gpt->valid_entries);
966 EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES1) == gpt->modified);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700967
Randall Spanglere9213a72013-01-24 11:19:55 -0800968 /*
969 * Test mismatched pairs (h1+e1 valid, h2+e2 valid but different. This
970 * simulates a partial update of the drive.
971 */
972 BuildTestGptData(gpt);
973 gpt->secondary_entries[0]++;
974 RefreshCrc32(gpt);
975 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
976 EXPECT(MASK_PRIMARY == gpt->valid_headers);
977 EXPECT(MASK_PRIMARY == gpt->valid_entries);
978 GptRepair(gpt);
979 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
980 EXPECT(MASK_BOTH == gpt->valid_headers);
981 EXPECT(MASK_BOTH == gpt->valid_entries);
982 EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700983
Randall Spanglere9213a72013-01-24 11:19:55 -0800984 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700985}
986
Randall Spanglere9213a72013-01-24 11:19:55 -0800987static int EntryAttributeGetSetTest(void)
988{
989 GptData *gpt = GetEmptyGptData();
990 GptEntry *e = (GptEntry *)(gpt->primary_entries);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700991
Randall Spanglere9213a72013-01-24 11:19:55 -0800992 e->attrs.whole = 0x0000000000000000ULL;
993 SetEntrySuccessful(e, 1);
994 EXPECT(0x0100000000000000ULL == e->attrs.whole);
995 EXPECT(1 == GetEntrySuccessful(e));
996 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
997 SetEntrySuccessful(e, 0);
998 EXPECT(0xFEFFFFFFFFFFFFFFULL == e->attrs.whole);
999 EXPECT(0 == GetEntrySuccessful(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001000
Randall Spanglere9213a72013-01-24 11:19:55 -08001001 e->attrs.whole = 0x0000000000000000ULL;
1002 SetEntryTries(e, 15);
1003 EXPECT(15 == GetEntryTries(e));
1004 EXPECT(0x00F0000000000000ULL == e->attrs.whole);
1005 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
1006 SetEntryTries(e, 0);
1007 EXPECT(0xFF0FFFFFFFFFFFFFULL == e->attrs.whole);
1008 EXPECT(0 == GetEntryTries(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001009
Randall Spanglere9213a72013-01-24 11:19:55 -08001010 e->attrs.whole = 0x0000000000000000ULL;
1011 SetEntryPriority(e, 15);
1012 EXPECT(0x000F000000000000ULL == e->attrs.whole);
1013 EXPECT(15 == GetEntryPriority(e));
1014 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
1015 SetEntryPriority(e, 0);
1016 EXPECT(0xFFF0FFFFFFFFFFFFULL == e->attrs.whole);
1017 EXPECT(0 == GetEntryPriority(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001018
Randall Spanglere9213a72013-01-24 11:19:55 -08001019 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
1020 EXPECT(1 == GetEntrySuccessful(e));
1021 EXPECT(15 == GetEntryPriority(e));
1022 EXPECT(15 == GetEntryTries(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001023
Randall Spanglere9213a72013-01-24 11:19:55 -08001024 e->attrs.whole = 0x0123000000000000ULL;
1025 EXPECT(1 == GetEntrySuccessful(e));
1026 EXPECT(2 == GetEntryTries(e));
1027 EXPECT(3 == GetEntryPriority(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001028
Randall Spanglere9213a72013-01-24 11:19:55 -08001029 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001030}
1031
Randall Spanglere9213a72013-01-24 11:19:55 -08001032static int EntryTypeTest(void)
1033{
1034 GptData *gpt = GetEmptyGptData();
1035 GptEntry *e = (GptEntry *)(gpt->primary_entries);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001036
Randall Spanglere9213a72013-01-24 11:19:55 -08001037 Memcpy(&e->type, &guid_zero, sizeof(Guid));
1038 EXPECT(1 == IsUnusedEntry(e));
1039 EXPECT(0 == IsKernelEntry(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001040
Randall Spanglere9213a72013-01-24 11:19:55 -08001041 Memcpy(&e->type, &guid_kernel, sizeof(Guid));
1042 EXPECT(0 == IsUnusedEntry(e));
1043 EXPECT(1 == IsKernelEntry(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001044
Randall Spanglere9213a72013-01-24 11:19:55 -08001045 Memcpy(&e->type, &guid_rootfs, sizeof(Guid));
1046 EXPECT(0 == IsUnusedEntry(e));
1047 EXPECT(0 == IsKernelEntry(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001048
Randall Spanglere9213a72013-01-24 11:19:55 -08001049 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001050}
1051
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001052/* Make an entry unused by clearing its type. */
Randall Spanglere9213a72013-01-24 11:19:55 -08001053static void FreeEntry(GptEntry *e)
1054{
1055 Memset(&e->type, 0, sizeof(Guid));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001056}
1057
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001058/* Set up an entry. */
Randall Spanglere9213a72013-01-24 11:19:55 -08001059static void FillEntry(GptEntry *e, int is_kernel,
1060 int priority, int successful, int tries)
1061{
1062 Memcpy(&e->type, (is_kernel ? &guid_kernel : &guid_zero), sizeof(Guid));
1063 SetEntryPriority(e, priority);
1064 SetEntrySuccessful(e, successful);
1065 SetEntryTries(e, tries);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001066}
1067
Randall Spanglere9213a72013-01-24 11:19:55 -08001068/*
1069 * Invalidate all kernel entries and expect GptNextKernelEntry() cannot find
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001070 * any usable kernel entry.
1071 */
Randall Spanglere9213a72013-01-24 11:19:55 -08001072static int NoValidKernelEntryTest(void)
1073{
1074 GptData *gpt = GetEmptyGptData();
1075 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001076
Randall Spanglere9213a72013-01-24 11:19:55 -08001077 BuildTestGptData(gpt);
1078 SetEntryPriority(e1 + KERNEL_A, 0);
1079 FreeEntry(e1 + KERNEL_B);
1080 RefreshCrc32(gpt);
1081 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1082 GptNextKernelEntry(gpt, NULL, NULL));
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001083
Randall Spanglere9213a72013-01-24 11:19:55 -08001084 return TEST_OK;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001085}
1086
Randall Spanglere9213a72013-01-24 11:19:55 -08001087static int GetNextNormalTest(void)
1088{
1089 GptData *gpt = GetEmptyGptData();
1090 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
1091 uint64_t start, size;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001092
Randall Spanglere9213a72013-01-24 11:19:55 -08001093 /* Normal case - both kernels successful */
1094 BuildTestGptData(gpt);
1095 FillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
1096 FillEntry(e1 + KERNEL_B, 1, 2, 1, 0);
1097 RefreshCrc32(gpt);
1098 GptInit(gpt);
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001099
Randall Spanglere9213a72013-01-24 11:19:55 -08001100 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1101 EXPECT(KERNEL_A == gpt->current_kernel);
1102 EXPECT(34 == start);
1103 EXPECT(100 == size);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001104
Randall Spanglere9213a72013-01-24 11:19:55 -08001105 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1106 EXPECT(KERNEL_B == gpt->current_kernel);
1107 EXPECT(134 == start);
1108 EXPECT(99 == size);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001109
Randall Spanglere9213a72013-01-24 11:19:55 -08001110 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1111 GptNextKernelEntry(gpt, &start, &size));
1112 EXPECT(-1 == gpt->current_kernel);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001113
Randall Spanglere9213a72013-01-24 11:19:55 -08001114 /* Call as many times as you want; you won't get another kernel... */
1115 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1116 GptNextKernelEntry(gpt, &start, &size));
1117 EXPECT(-1 == gpt->current_kernel);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001118
Randall Spanglere9213a72013-01-24 11:19:55 -08001119 return TEST_OK;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001120}
1121
Randall Spanglere9213a72013-01-24 11:19:55 -08001122static int GetNextPrioTest(void)
1123{
1124 GptData *gpt = GetEmptyGptData();
1125 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
1126 uint64_t start, size;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001127
Randall Spanglere9213a72013-01-24 11:19:55 -08001128 /* Priority 3, 4, 0, 4 - should boot order B, Y, A */
1129 BuildTestGptData(gpt);
1130 FillEntry(e1 + KERNEL_A, 1, 3, 1, 0);
1131 FillEntry(e1 + KERNEL_B, 1, 4, 1, 0);
1132 FillEntry(e1 + KERNEL_X, 1, 0, 1, 0);
1133 FillEntry(e1 + KERNEL_Y, 1, 4, 1, 0);
1134 RefreshCrc32(gpt);
1135 GptInit(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001136
Randall Spanglere9213a72013-01-24 11:19:55 -08001137 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1138 EXPECT(KERNEL_B == gpt->current_kernel);
1139 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1140 EXPECT(KERNEL_Y == gpt->current_kernel);
1141 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1142 EXPECT(KERNEL_A == gpt->current_kernel);
1143 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1144 GptNextKernelEntry(gpt, &start, &size));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001145
Randall Spanglere9213a72013-01-24 11:19:55 -08001146 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001147}
1148
Randall Spanglere9213a72013-01-24 11:19:55 -08001149static int GetNextTriesTest(void)
1150{
1151 GptData *gpt = GetEmptyGptData();
1152 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
1153 uint64_t start, size;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001154
Randall Spanglere9213a72013-01-24 11:19:55 -08001155 /* Tries=nonzero is attempted just like success, but tries=0 isn't */
1156 BuildTestGptData(gpt);
1157 FillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
1158 FillEntry(e1 + KERNEL_B, 1, 3, 0, 0);
1159 FillEntry(e1 + KERNEL_X, 1, 4, 0, 1);
1160 FillEntry(e1 + KERNEL_Y, 1, 0, 0, 5);
1161 RefreshCrc32(gpt);
1162 GptInit(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001163
Randall Spanglere9213a72013-01-24 11:19:55 -08001164 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1165 EXPECT(KERNEL_X == gpt->current_kernel);
1166 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1167 EXPECT(KERNEL_A == gpt->current_kernel);
1168 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1169 GptNextKernelEntry(gpt, &start, &size));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001170
Randall Spanglere9213a72013-01-24 11:19:55 -08001171 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001172}
1173
Randall Spanglere9213a72013-01-24 11:19:55 -08001174static int GptUpdateTest(void)
1175{
1176 GptData *gpt = GetEmptyGptData();
1177 GptEntry *e = (GptEntry *)(gpt->primary_entries);
1178 GptEntry *e2 = (GptEntry *)(gpt->secondary_entries);
1179 uint64_t start, size;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001180
Randall Spanglere9213a72013-01-24 11:19:55 -08001181 /* Tries=nonzero is attempted just like success, but tries=0 isn't */
1182 BuildTestGptData(gpt);
1183 FillEntry(e + KERNEL_A, 1, 4, 1, 0);
1184 FillEntry(e + KERNEL_B, 1, 3, 0, 2);
1185 FillEntry(e + KERNEL_X, 1, 2, 0, 2);
1186 RefreshCrc32(gpt);
1187 GptInit(gpt);
1188 gpt->modified = 0; /* Nothing modified yet */
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001189
Randall Spanglere9213a72013-01-24 11:19:55 -08001190 /* Successful kernel */
1191 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1192 EXPECT(KERNEL_A == gpt->current_kernel);
1193 EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
1194 EXPECT(4 == GetEntryPriority(e + KERNEL_A));
1195 EXPECT(0 == GetEntryTries(e + KERNEL_A));
1196 EXPECT(1 == GetEntrySuccessful(e2 + KERNEL_A));
1197 EXPECT(4 == GetEntryPriority(e2 + KERNEL_A));
1198 EXPECT(0 == GetEntryTries(e2 + KERNEL_A));
1199 /* Trying successful kernel changes nothing */
1200 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
1201 EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
1202 EXPECT(4 == GetEntryPriority(e + KERNEL_A));
1203 EXPECT(0 == GetEntryTries(e + KERNEL_A));
1204 EXPECT(0 == gpt->modified);
1205 /* Marking it bad also does not update it. */
1206 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
1207 EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
1208 EXPECT(4 == GetEntryPriority(e + KERNEL_A));
1209 EXPECT(0 == GetEntryTries(e + KERNEL_A));
1210 EXPECT(0 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001211
Randall Spanglere9213a72013-01-24 11:19:55 -08001212 /* Kernel with tries */
1213 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1214 EXPECT(KERNEL_B == gpt->current_kernel);
1215 EXPECT(0 == GetEntrySuccessful(e + KERNEL_B));
1216 EXPECT(3 == GetEntryPriority(e + KERNEL_B));
1217 EXPECT(2 == GetEntryTries(e + KERNEL_B));
1218 /* Marking it bad clears it */
1219 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
1220 EXPECT(0 == GetEntrySuccessful(e + KERNEL_B));
1221 EXPECT(0 == GetEntryPriority(e + KERNEL_B));
1222 EXPECT(0 == GetEntryTries(e + KERNEL_B));
1223 /* Which affects both copies of the partition entries */
1224 EXPECT(0 == GetEntrySuccessful(e2 + KERNEL_B));
1225 EXPECT(0 == GetEntryPriority(e2 + KERNEL_B));
1226 EXPECT(0 == GetEntryTries(e2 + KERNEL_B));
1227 /* And that's caused the GPT to need updating */
1228 EXPECT(0x0F == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001229
Randall Spanglere9213a72013-01-24 11:19:55 -08001230 /* Another kernel with tries */
1231 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1232 EXPECT(KERNEL_X == gpt->current_kernel);
1233 EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
1234 EXPECT(2 == GetEntryPriority(e + KERNEL_X));
1235 EXPECT(2 == GetEntryTries(e + KERNEL_X));
1236 /* Trying it uses up a try */
1237 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
1238 EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
1239 EXPECT(2 == GetEntryPriority(e + KERNEL_X));
1240 EXPECT(1 == GetEntryTries(e + KERNEL_X));
1241 EXPECT(0 == GetEntrySuccessful(e2 + KERNEL_X));
1242 EXPECT(2 == GetEntryPriority(e2 + KERNEL_X));
1243 EXPECT(1 == GetEntryTries(e2 + KERNEL_X));
1244 /* Trying it again marks it inactive */
1245 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
1246 EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
1247 EXPECT(0 == GetEntryPriority(e + KERNEL_X));
1248 EXPECT(0 == GetEntryTries(e + KERNEL_X));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001249
Randall Spangler0bda13f2013-01-24 12:25:26 -08001250 /* Can't update if entry isn't a kernel, or there isn't an entry */
1251 Memcpy(&e[KERNEL_X].type, &guid_rootfs, sizeof(guid_rootfs));
1252 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1253 GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
1254 gpt->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
1255 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1256 GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
1257
1258
Randall Spanglere9213a72013-01-24 11:19:55 -08001259 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001260}
1261
Randall Spanglere9213a72013-01-24 11:19:55 -08001262/*
1263 * Give an invalid kernel type, and expect GptUpdateKernelEntry() returns
1264 * GPT_ERROR_INVALID_UPDATE_TYPE.
1265 */
1266static int UpdateInvalidKernelTypeTest(void)
1267{
1268 GptData *gpt = GetEmptyGptData();
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001269
Randall Spanglere9213a72013-01-24 11:19:55 -08001270 BuildTestGptData(gpt);
1271 /* anything, but not CGPT_KERNEL_ENTRY_NOT_FOUND */
1272 gpt->current_kernel = 0;
1273 /* any invalid update_type value */
1274 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1275 GptUpdateKernelEntry(gpt, 99));
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001276
Randall Spanglere9213a72013-01-24 11:19:55 -08001277 return TEST_OK;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001278}
1279
Randall Spanglere9213a72013-01-24 11:19:55 -08001280/* Test duplicate UniqueGuids can be detected. */
1281static int DuplicateUniqueGuidTest(void)
1282{
1283 GptData *gpt = GetEmptyGptData();
1284 GptHeader *h = (GptHeader *)gpt->primary_header;
1285 GptEntry *e = (GptEntry *)gpt->primary_entries;
1286 int i, j;
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001287
Randall Spanglere9213a72013-01-24 11:19:55 -08001288 struct {
1289 int duplicate;
1290 struct {
1291 uint64_t starting_lba;
1292 uint64_t ending_lba;
1293 uint32_t type_guid;
1294 uint32_t unique_guid;
1295 } entries[16]; /* enough for testing. */
1296 } cases[] = {
1297 {GPT_SUCCESS, {{100, 109, 1, 1},
1298 {110, 119, 2, 2},
1299 {120, 129, 3, 3},
1300 {130, 139, 4, 4},
1301 }},
1302 {GPT_SUCCESS, {{100, 109, 1, 1},
1303 {110, 119, 1, 2},
1304 {120, 129, 2, 3},
1305 {130, 139, 2, 4},
1306 }},
1307 {GPT_ERROR_DUP_GUID, {{100, 109, 1, 1},
1308 {110, 119, 2, 2},
1309 {120, 129, 3, 1},
1310 {130, 139, 4, 4},
1311 }},
1312 {GPT_ERROR_DUP_GUID, {{100, 109, 1, 1},
1313 {110, 119, 1, 2},
1314 {120, 129, 2, 3},
1315 {130, 139, 2, 2},
1316 }},
1317 };
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001318
Randall Spanglere9213a72013-01-24 11:19:55 -08001319 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
1320 BuildTestGptData(gpt);
1321 ZeroEntries(gpt);
1322 for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) {
1323 if (!cases[i].entries[j].starting_lba)
1324 break;
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001325
Randall Spanglere9213a72013-01-24 11:19:55 -08001326 e[j].starting_lba = cases[i].entries[j].starting_lba;
1327 e[j].ending_lba = cases[i].entries[j].ending_lba;
1328 SetGuid(&e[j].type, cases[i].entries[j].type_guid);
1329 SetGuid(&e[j].unique, cases[i].entries[j].unique_guid);
1330 }
1331 RefreshCrc32(gpt);
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001332
Randall Spanglere9213a72013-01-24 11:19:55 -08001333 EXPECT(cases[i].duplicate == CheckEntries(e, h));
1334 }
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001335
Randall Spanglere9213a72013-01-24 11:19:55 -08001336 return TEST_OK;
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001337}
1338
Randall Spangler0bda13f2013-01-24 12:25:26 -08001339/* Test getting the current kernel GUID */
1340static int GetKernelGuidTest(void)
1341{
1342 GptData *gpt = GetEmptyGptData();
1343 GptEntry *e = (GptEntry *)gpt->primary_entries;
1344 Guid g;
1345
1346 BuildTestGptData(gpt);
1347 gpt->current_kernel = 0;
1348 GetCurrentKernelUniqueGuid(gpt, &g);
1349 EXPECT(!Memcmp(&g, &e[0].unique, sizeof(Guid)));
1350 gpt->current_kernel = 1;
1351 GetCurrentKernelUniqueGuid(gpt, &g);
1352 EXPECT(!Memcmp(&g, &e[1].unique, sizeof(Guid)));
1353
1354 return TEST_OK;
1355}
1356
1357/* Test getting GPT error text strings */
1358static int ErrorTextTest(void)
1359{
1360 int i;
1361
1362 /* Known errors are not unknown */
1363 for (i = 0; i < GPT_ERROR_COUNT; i++) {
1364 EXPECT(GptErrorText(i));
1365 EXPECT(strcmp(GptErrorText(i), "Unknown"));
1366 }
1367
1368 /* But other error values are */
1369 EXPECT(!strcmp(GptErrorText(GPT_ERROR_COUNT), "Unknown"));
1370
1371 return TEST_OK;
1372}
1373
vbendeb3ecaf772010-06-24 16:19:53 -07001374/* disable MSVC warnings on unused arguments */
1375__pragma(warning (disable: 4100))
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001376
Randall Spanglere9213a72013-01-24 11:19:55 -08001377int main(int argc, char *argv[])
1378{
1379 int i;
1380 int error_count = 0;
1381 struct {
1382 char *name;
1383 test_func fp;
1384 int retval;
1385 } test_cases[] = {
1386 { TEST_CASE(StructSizeTest), },
1387 { TEST_CASE(TestBuildTestGptData), },
1388 { TEST_CASE(ParameterTests), },
1389 { TEST_CASE(HeaderCrcTest), },
Randall Spangler0bda13f2013-01-24 12:25:26 -08001390 { TEST_CASE(HeaderSameTest), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001391 { TEST_CASE(SignatureTest), },
1392 { TEST_CASE(RevisionTest), },
1393 { TEST_CASE(SizeTest), },
1394 { TEST_CASE(CrcFieldTest), },
1395 { TEST_CASE(ReservedFieldsTest), },
1396 { TEST_CASE(SizeOfPartitionEntryTest), },
1397 { TEST_CASE(NumberOfPartitionEntriesTest), },
1398 { TEST_CASE(MyLbaTest), },
1399 { TEST_CASE(FirstUsableLbaAndLastUsableLbaTest), },
1400 { TEST_CASE(EntriesCrcTest), },
1401 { TEST_CASE(ValidEntryTest), },
1402 { TEST_CASE(OverlappedPartitionTest), },
1403 { TEST_CASE(SanityCheckTest), },
1404 { TEST_CASE(NoValidKernelEntryTest), },
1405 { TEST_CASE(EntryAttributeGetSetTest), },
1406 { TEST_CASE(EntryTypeTest), },
1407 { TEST_CASE(GetNextNormalTest), },
1408 { TEST_CASE(GetNextPrioTest), },
1409 { TEST_CASE(GetNextTriesTest), },
1410 { TEST_CASE(GptUpdateTest), },
1411 { TEST_CASE(UpdateInvalidKernelTypeTest), },
1412 { TEST_CASE(DuplicateUniqueGuidTest), },
1413 { TEST_CASE(TestCrc32TestVectors), },
Randall Spangler0bda13f2013-01-24 12:25:26 -08001414 { TEST_CASE(GetKernelGuidTest), },
1415 { TEST_CASE(ErrorTextTest), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001416 };
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001417
Randall Spanglere9213a72013-01-24 11:19:55 -08001418 for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
1419 printf("Running %s() ...\n", test_cases[i].name);
1420 test_cases[i].retval = test_cases[i].fp();
1421 if (test_cases[i].retval) {
1422 printf(COL_RED "[ERROR]\n\n" COL_STOP);
1423 ++error_count;
1424 } else {
1425 printf(COL_GREEN "[PASS]\n\n" COL_STOP);
1426 }
1427 }
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001428
Randall Spanglere9213a72013-01-24 11:19:55 -08001429 if (error_count) {
1430 printf("\n------------------------------------------------\n");
1431 printf(COL_RED "The following %d test cases are failed:\n"
1432 COL_STOP, error_count);
1433 for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
1434 if (test_cases[i].retval)
1435 printf(" %s()\n", test_cases[i].name);
1436 }
1437 }
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001438
Randall Spanglere9213a72013-01-24 11:19:55 -08001439 return error_count ? 1 : 0;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001440}