blob: 67ce9fe428972d78a21d3d52ac8f6801a46728bd [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));
219 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700220}
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700221
Randall Spanglere9213a72013-01-24 11:19:55 -0800222/*
223 * Test if wrong sector_bytes or drive_sectors is detected by GptInit().
224 * Currently we only support 512 bytes per sector. In the future, we may
225 * support other sizes. A too small drive_sectors should be rejected by
226 * GptInit().
227 */
228static int ParameterTests(void)
229{
230 GptData *gpt;
231 struct {
232 uint32_t sector_bytes;
233 uint64_t drive_sectors;
234 int expected_retval;
235 } cases[] = {
236 {512, DEFAULT_DRIVE_SECTORS, GPT_SUCCESS},
237 {520, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
238 {512, 0, GPT_ERROR_INVALID_SECTOR_NUMBER},
239 {512, 66, GPT_ERROR_INVALID_SECTOR_NUMBER},
240 {512, GPT_PMBR_SECTOR + GPT_HEADER_SECTOR * 2 +
241 GPT_ENTRIES_SECTORS * 2, GPT_SUCCESS},
242 {4096, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
243 };
244 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700245
Randall Spanglere9213a72013-01-24 11:19:55 -0800246 gpt = GetEmptyGptData();
247 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
248 BuildTestGptData(gpt);
249 gpt->sector_bytes = cases[i].sector_bytes;
250 gpt->drive_sectors = cases[i].drive_sectors;
251 EXPECT(cases[i].expected_retval == CheckParameters(gpt));
252 }
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700253
Randall Spanglere9213a72013-01-24 11:19:55 -0800254 return TEST_OK;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700255}
256
Randall Spanglere9213a72013-01-24 11:19:55 -0800257/* Test if header CRC in two copies are calculated. */
258static int HeaderCrcTest(void)
259{
260 GptData *gpt = GetEmptyGptData();
261 GptHeader *h1 = (GptHeader *)gpt->primary_header;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700262
Randall Spanglere9213a72013-01-24 11:19:55 -0800263 BuildTestGptData(gpt);
264 EXPECT(HeaderCrc(h1) == h1->header_crc32);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700265
Randall Spanglere9213a72013-01-24 11:19:55 -0800266 /* CRC covers first byte of header */
267 BuildTestGptData(gpt);
268 gpt->primary_header[0] ^= 0xa5;
269 EXPECT(HeaderCrc(h1) != h1->header_crc32);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700270
Randall Spanglere9213a72013-01-24 11:19:55 -0800271 /* CRC covers last byte of header */
272 BuildTestGptData(gpt);
273 gpt->primary_header[h1->size - 1] ^= 0x5a;
274 EXPECT(HeaderCrc(h1) != h1->header_crc32);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700275
Randall Spanglere9213a72013-01-24 11:19:55 -0800276 /* CRC only covers header */
277 BuildTestGptData(gpt);
278 gpt->primary_header[h1->size] ^= 0x5a;
279 EXPECT(HeaderCrc(h1) == h1->header_crc32);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700280
Randall Spanglere9213a72013-01-24 11:19:55 -0800281 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700282}
283
Randall Spanglere9213a72013-01-24 11:19:55 -0800284/* Test if signature ("EFI PART") is checked. */
285static int SignatureTest(void)
286{
287 GptData *gpt = GetEmptyGptData();
288 GptHeader *h1 = (GptHeader *)gpt->primary_header;
289 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
290 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700291
Randall Spanglere9213a72013-01-24 11:19:55 -0800292 for (i = 0; i < 8; ++i) {
293 BuildTestGptData(gpt);
294 h1->signature[i] ^= 0xff;
295 h2->signature[i] ^= 0xff;
296 RefreshCrc32(gpt);
297 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
298 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
299 }
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700300
Randall Spanglere9213a72013-01-24 11:19:55 -0800301 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700302}
303
Randall Spanglere9213a72013-01-24 11:19:55 -0800304/*
305 * The revision we currently support is GPT_HEADER_REVISION. If the revision
306 * in header is not that, we expect the header is invalid.
307 */
308static int RevisionTest(void)
309{
310 GptData *gpt = GetEmptyGptData();
311 GptHeader *h1 = (GptHeader *)gpt->primary_header;
312 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
313 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700314
Randall Spanglere9213a72013-01-24 11:19:55 -0800315 struct {
316 uint32_t value_to_test;
317 int expect_rv;
318 } cases[] = {
319 {0x01000000, 1},
320 {0x00010000, 0}, /* GPT_HEADER_REVISION */
321 {0x00000100, 1},
322 {0x00000001, 1},
323 {0x23010456, 1},
324 };
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700325
Randall Spanglere9213a72013-01-24 11:19:55 -0800326 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
327 BuildTestGptData(gpt);
328 h1->revision = cases[i].value_to_test;
329 h2->revision = cases[i].value_to_test;
330 RefreshCrc32(gpt);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700331
Randall Spanglere9213a72013-01-24 11:19:55 -0800332 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
333 cases[i].expect_rv);
334 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
335 cases[i].expect_rv);
336 }
337 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700338}
339
Randall Spanglere9213a72013-01-24 11:19:55 -0800340static int SizeTest(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 Spanglere9213a72013-01-24 11:19:55 -0800347 struct {
348 uint32_t value_to_test;
349 int expect_rv;
350 } cases[] = {
351 {91, 1},
352 {92, 0},
353 {93, 0},
354 {511, 0},
355 {512, 0},
356 {513, 1},
357 };
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700358
Randall Spanglere9213a72013-01-24 11:19:55 -0800359 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
360 BuildTestGptData(gpt);
361 h1->size = cases[i].value_to_test;
362 h2->size = cases[i].value_to_test;
363 RefreshCrc32(gpt);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700364
Randall Spanglere9213a72013-01-24 11:19:55 -0800365 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
366 cases[i].expect_rv);
367 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
368 cases[i].expect_rv);
369 }
370 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700371}
372
Randall Spanglere9213a72013-01-24 11:19:55 -0800373/* Test if CRC is checked. */
374static int CrcFieldTest(void)
375{
376 GptData *gpt = GetEmptyGptData();
377 GptHeader *h1 = (GptHeader *)gpt->primary_header;
378 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700379
Randall Spanglere9213a72013-01-24 11:19:55 -0800380 BuildTestGptData(gpt);
381 /* Modify a field that the header verification doesn't care about */
382 h1->entries_crc32++;
383 h2->entries_crc32++;
384 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
385 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
386 /* Refresh the CRC; should pass now */
387 RefreshCrc32(gpt);
388 EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
389 EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700390
Randall Spanglere9213a72013-01-24 11:19:55 -0800391 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700392}
393
Randall Spanglere9213a72013-01-24 11:19:55 -0800394/* Test if reserved fields are checked. We'll try non-zero values to test. */
395static int ReservedFieldsTest(void)
396{
397 GptData *gpt = GetEmptyGptData();
398 GptHeader *h1 = (GptHeader *)gpt->primary_header;
399 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700400
Randall Spanglere9213a72013-01-24 11:19:55 -0800401 BuildTestGptData(gpt);
402 h1->reserved_zero ^= 0x12345678; /* whatever random */
403 h2->reserved_zero ^= 0x12345678; /* whatever random */
404 RefreshCrc32(gpt);
405 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
406 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700407
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700408#ifdef PADDING_CHECKED
Randall Spanglere9213a72013-01-24 11:19:55 -0800409 /* TODO: padding check is currently disabled */
410 BuildTestGptData(gpt);
411 h1->padding[12] ^= 0x34; /* whatever random */
412 h2->padding[56] ^= 0x78; /* whatever random */
413 RefreshCrc32(gpt);
414 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
415 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700416#endif
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700417
Randall Spanglere9213a72013-01-24 11:19:55 -0800418 return TEST_OK;
419}
420
421/*
422 * Technically, any size which is 2^N where N > 6 should work, but our
423 * library only supports one size.
424 */
425static int SizeOfPartitionEntryTest(void) {
426 GptData *gpt = GetEmptyGptData();
427 GptHeader *h1 = (GptHeader *)gpt->primary_header;
428 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
429 int i;
430
431 struct {
432 uint32_t value_to_test;
433 int expect_rv;
434 } cases[] = {
435 {127, 1},
436 {128, 0},
437 {129, 1},
438 {256, 1},
439 {512, 1},
440 };
441
442 /* Check size of entryes */
443 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
444 BuildTestGptData(gpt);
445 h1->size_of_entry = cases[i].value_to_test;
446 h2->size_of_entry = cases[i].value_to_test;
447 h1->number_of_entries = TOTAL_ENTRIES_SIZE /
448 cases[i].value_to_test;
449 h2->number_of_entries = TOTAL_ENTRIES_SIZE /
450 cases[i].value_to_test;
451 RefreshCrc32(gpt);
452
453 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
454 cases[i].expect_rv);
455 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
456 cases[i].expect_rv);
457 }
458
459 return TEST_OK;
460}
461
462/*
463 * Technically, any size which is 2^N where N > 6 should work, but our library
464 * only supports one size.
465 */
466static int NumberOfPartitionEntriesTest(void)
467{
468 GptData *gpt = GetEmptyGptData();
469 GptHeader *h1 = (GptHeader *)gpt->primary_header;
470 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
471
472 BuildTestGptData(gpt);
473 h1->number_of_entries--;
474 h2->number_of_entries /= 2;
475 RefreshCrc32(gpt);
476 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
477 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
478
479 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700480}
481
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700482
Randall Spanglere9213a72013-01-24 11:19:55 -0800483/* Test if myLBA field is checked (1 for primary, last for secondary). */
484static int MyLbaTest(void)
485{
486 GptData *gpt = GetEmptyGptData();
487 GptHeader *h1 = (GptHeader *)gpt->primary_header;
488 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700489
Randall Spanglere9213a72013-01-24 11:19:55 -0800490 /* myLBA depends on primary vs secondary flag */
491 BuildTestGptData(gpt);
492 EXPECT(1 == CheckHeader(h1, 1, gpt->drive_sectors));
493 EXPECT(1 == CheckHeader(h2, 0, gpt->drive_sectors));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700494
Randall Spanglere9213a72013-01-24 11:19:55 -0800495 BuildTestGptData(gpt);
496 h1->my_lba--;
497 h2->my_lba--;
498 RefreshCrc32(gpt);
499 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
500 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700501
Randall Spanglere9213a72013-01-24 11:19:55 -0800502 BuildTestGptData(gpt);
503 h1->my_lba = 2;
504 h2->my_lba--;
505 RefreshCrc32(gpt);
506 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
507 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700508
Randall Spanglere9213a72013-01-24 11:19:55 -0800509 /* We should ignore the alternate_lba field entirely */
510 BuildTestGptData(gpt);
511 h1->alternate_lba++;
512 h2->alternate_lba++;
513 RefreshCrc32(gpt);
514 EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
515 EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
516
517 BuildTestGptData(gpt);
518 h1->alternate_lba--;
519 h2->alternate_lba--;
520 RefreshCrc32(gpt);
521 EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
522 EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
523
524 BuildTestGptData(gpt);
525 h1->entries_lba++;
526 h2->entries_lba++;
527 RefreshCrc32(gpt);
528 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
529 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
530
531 BuildTestGptData(gpt);
532 h1->entries_lba--;
533 h2->entries_lba--;
534 RefreshCrc32(gpt);
535 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
536 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
537
538 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700539}
540
Randall Spanglere9213a72013-01-24 11:19:55 -0800541/* Test if FirstUsableLBA and LastUsableLBA are checked.
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700542 * FirstUsableLBA must be after the end of the primary GPT table array.
543 * LastUsableLBA must be before the start of the secondary GPT table array.
544 * FirstUsableLBA <= LastUsableLBA. */
Randall Spanglere9213a72013-01-24 11:19:55 -0800545static int FirstUsableLbaAndLastUsableLbaTest(void)
546{
547 GptData *gpt = GetEmptyGptData();
548 GptHeader *h1 = (GptHeader *)gpt->primary_header;
549 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
550 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700551
Randall Spanglere9213a72013-01-24 11:19:55 -0800552 struct {
553 uint64_t primary_entries_lba;
554 uint64_t primary_first_usable_lba;
555 uint64_t primary_last_usable_lba;
556 uint64_t secondary_first_usable_lba;
557 uint64_t secondary_last_usable_lba;
558 uint64_t secondary_entries_lba;
559 int primary_rv;
560 int secondary_rv;
561 } cases[] = {
562 {2, 34, 433, 34, 433, 434, 0, 0},
563 {2, 34, 432, 34, 430, 434, 0, 0},
564 {2, 33, 433, 33, 433, 434, 1, 1},
565 {2, 34, 434, 34, 433, 434, 1, 0},
566 {2, 34, 433, 34, 434, 434, 0, 1},
567 {2, 35, 433, 35, 433, 434, 0, 0},
568 {2, 433, 433, 433, 433, 434, 0, 0},
569 {2, 434, 433, 434, 434, 434, 1, 1},
570 {2, 433, 34, 34, 433, 434, 1, 0},
571 {2, 34, 433, 433, 34, 434, 0, 1},
572 };
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700573
Randall Spanglere9213a72013-01-24 11:19:55 -0800574 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
575 BuildTestGptData(gpt);
576 h1->entries_lba = cases[i].primary_entries_lba;
577 h1->first_usable_lba = cases[i].primary_first_usable_lba;
578 h1->last_usable_lba = cases[i].primary_last_usable_lba;
579 h2->entries_lba = cases[i].secondary_entries_lba;
580 h2->first_usable_lba = cases[i].secondary_first_usable_lba;
581 h2->last_usable_lba = cases[i].secondary_last_usable_lba;
582 RefreshCrc32(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700583
Randall Spanglere9213a72013-01-24 11:19:55 -0800584 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
585 cases[i].primary_rv);
586 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
587 cases[i].secondary_rv);
588 }
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700589
Randall Spanglere9213a72013-01-24 11:19:55 -0800590 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700591}
592
Randall Spanglere9213a72013-01-24 11:19:55 -0800593/*
594 * Test if PartitionEntryArrayCRC32 is checked. PartitionEntryArrayCRC32 must
595 * be calculated over SizeOfPartitionEntry * NumberOfPartitionEntries bytes.
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700596 */
Randall Spanglere9213a72013-01-24 11:19:55 -0800597static int EntriesCrcTest(void)
598{
599 GptData *gpt = GetEmptyGptData();
600 GptHeader *h1 = (GptHeader *)gpt->primary_header;
601 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
602 GptEntry *e2 = (GptEntry *)(gpt->secondary_entries);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700603
Randall Spanglere9213a72013-01-24 11:19:55 -0800604 /* Modify first byte of primary entries, and expect the CRC is wrong. */
605 BuildTestGptData(gpt);
606 EXPECT(0 == CheckEntries(e1, h1));
607 EXPECT(0 == CheckEntries(e2, h1));
608 gpt->primary_entries[0] ^= 0xa5; /* just XOR a non-zero value */
609 gpt->secondary_entries[TOTAL_ENTRIES_SIZE-1] ^= 0x5a;
610 EXPECT(GPT_ERROR_CRC_CORRUPTED == CheckEntries(e1, h1));
611 EXPECT(GPT_ERROR_CRC_CORRUPTED == CheckEntries(e2, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700612
Randall Spanglere9213a72013-01-24 11:19:55 -0800613 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700614}
615
Randall Spanglere9213a72013-01-24 11:19:55 -0800616/*
617 * Test if partition geometry is checked.
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700618 * All active (non-zero PartitionTypeGUID) partition entries should have:
619 * entry.StartingLBA >= header.FirstUsableLBA
620 * entry.EndingLBA <= header.LastUsableLBA
621 * entry.StartingLBA <= entry.EndingLBA
622 */
Randall Spanglere9213a72013-01-24 11:19:55 -0800623static int ValidEntryTest(void)
624{
625 GptData *gpt = GetEmptyGptData();
626 GptHeader *h1 = (GptHeader *)gpt->primary_header;
627 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700628
Randall Spanglere9213a72013-01-24 11:19:55 -0800629 /* error case: entry.StartingLBA < header.FirstUsableLBA */
630 BuildTestGptData(gpt);
631 e1[0].starting_lba = h1->first_usable_lba - 1;
632 RefreshCrc32(gpt);
633 EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700634
Randall Spanglere9213a72013-01-24 11:19:55 -0800635 /* error case: entry.EndingLBA > header.LastUsableLBA */
636 BuildTestGptData(gpt);
637 e1[2].ending_lba = h1->last_usable_lba + 1;
638 RefreshCrc32(gpt);
639 EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700640
Randall Spanglere9213a72013-01-24 11:19:55 -0800641 /* error case: entry.StartingLBA > entry.EndingLBA */
642 BuildTestGptData(gpt);
643 e1[3].starting_lba = e1[3].ending_lba + 1;
644 RefreshCrc32(gpt);
645 EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700646
Randall Spanglere9213a72013-01-24 11:19:55 -0800647 /* case: non active entry should be ignored. */
648 BuildTestGptData(gpt);
649 Memset(&e1[1].type, 0, sizeof(e1[1].type));
650 e1[1].starting_lba = e1[1].ending_lba + 1;
651 RefreshCrc32(gpt);
652 EXPECT(0 == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700653
Randall Spanglere9213a72013-01-24 11:19:55 -0800654 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700655}
656
Randall Spanglere9213a72013-01-24 11:19:55 -0800657/* Test if overlapped partition tables can be detected. */
658static int OverlappedPartitionTest(void) {
659 GptData *gpt = GetEmptyGptData();
660 GptHeader *h = (GptHeader *)gpt->primary_header;
661 GptEntry *e = (GptEntry *)gpt->primary_entries;
662 int i, j;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700663
Randall Spanglere9213a72013-01-24 11:19:55 -0800664 struct {
665 int overlapped;
666 struct {
667 int active;
668 uint64_t starting_lba;
669 uint64_t ending_lba;
670 } entries[16]; /* enough for testing. */
671 } cases[] = {
672 {GPT_SUCCESS, {{0, 100, 199}}},
673 {GPT_SUCCESS, {{1, 100, 199}}},
674 {GPT_SUCCESS, {{1, 100, 150}, {1, 200, 250}, {1, 300, 350}}},
675 {GPT_ERROR_START_LBA_OVERLAP,
676 {{1, 200, 299}, {1, 100, 199}, {1, 100, 100}}},
677 {GPT_ERROR_END_LBA_OVERLAP,
678 {{1, 200, 299}, {1, 100, 199}, {1, 299, 299}}},
679 {GPT_SUCCESS, {{1, 300, 399}, {1, 200, 299}, {1, 100, 199}}},
680 {GPT_ERROR_END_LBA_OVERLAP,
681 {{1, 100, 199}, {1, 199, 299}, {1, 299, 399}}},
682 {GPT_ERROR_START_LBA_OVERLAP,
683 {{1, 100, 199}, {1, 200, 299}, {1, 75, 399}}},
684 {GPT_ERROR_START_LBA_OVERLAP,
685 {{1, 100, 199}, {1, 75, 250}, {1, 200, 299}}},
686 {GPT_ERROR_END_LBA_OVERLAP,
687 {{1, 75, 150}, {1, 100, 199}, {1, 200, 299}}},
688 {GPT_ERROR_START_LBA_OVERLAP,
689 {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {1, 100, 399}}},
690 {GPT_SUCCESS,
691 {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {0, 100, 399}}},
692 {GPT_ERROR_START_LBA_OVERLAP,
693 {{1, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400}}},
694 {GPT_ERROR_START_LBA_OVERLAP,
695 {{0, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400}}},
696 {GPT_SUCCESS,
697 {{1, 200, 300}, {1, 100, 199}, {0, 100, 400}, {0, 300, 400}}},
698 {GPT_ERROR_END_LBA_OVERLAP,
699 {{1, 200, 299}, {1, 100, 199}, {1, 199, 199}}},
700 {GPT_SUCCESS, {{1, 200, 299}, {0, 100, 199}, {1, 199, 199}}},
701 {GPT_SUCCESS, {{1, 200, 299}, {1, 100, 199}, {0, 199, 199}}},
702 {GPT_ERROR_START_LBA_OVERLAP,
703 {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202},
704 {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206},
705 {1, 207, 207}, {1, 208, 208}, {1, 199, 199}}},
706 {GPT_SUCCESS,
707 {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202},
708 {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206},
709 {1, 207, 207}, {1, 208, 208}, {0, 199, 199}}},
710 };
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700711
Randall Spanglere9213a72013-01-24 11:19:55 -0800712 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
713 BuildTestGptData(gpt);
714 ZeroEntries(gpt);
715 for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) {
716 if (!cases[i].entries[j].starting_lba)
717 break;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700718
Randall Spanglere9213a72013-01-24 11:19:55 -0800719 if (cases[i].entries[j].active)
720 Memcpy(&e[j].type, &guid_kernel, sizeof(Guid));
721 SetGuid(&e[j].unique, j);
722 e[j].starting_lba = cases[i].entries[j].starting_lba;
723 e[j].ending_lba = cases[i].entries[j].ending_lba;
724 }
725 RefreshCrc32(gpt);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700726
Randall Spanglere9213a72013-01-24 11:19:55 -0800727 EXPECT(cases[i].overlapped == CheckEntries(e, h));
728 }
729 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700730}
731
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700732/* Test both sanity checking and repair. */
Randall Spanglere9213a72013-01-24 11:19:55 -0800733static int SanityCheckTest(void)
734{
735 GptData *gpt = GetEmptyGptData();
736 GptHeader *h1 = (GptHeader *)gpt->primary_header;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700737
Randall Spanglere9213a72013-01-24 11:19:55 -0800738 /* Unmodified test data is completely sane */
739 BuildTestGptData(gpt);
740 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
741 EXPECT(MASK_BOTH == gpt->valid_headers);
742 EXPECT(MASK_BOTH == gpt->valid_entries);
743 /* Repair doesn't damage it */
744 GptRepair(gpt);
745 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
746 EXPECT(MASK_BOTH == gpt->valid_headers);
747 EXPECT(MASK_BOTH == gpt->valid_entries);
748 EXPECT(0 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700749
Randall Spanglere9213a72013-01-24 11:19:55 -0800750 /* Modify headers */
751 BuildTestGptData(gpt);
752 gpt->primary_header[0]++;
753 gpt->secondary_header[0]++;
754 EXPECT(GPT_ERROR_INVALID_HEADERS == GptSanityCheck(gpt));
755 EXPECT(0 == gpt->valid_headers);
756 EXPECT(0 == gpt->valid_entries);
757 /* Repair can't fix completely busted headers */
758 GptRepair(gpt);
759 EXPECT(GPT_ERROR_INVALID_HEADERS == GptSanityCheck(gpt));
760 EXPECT(0 == gpt->valid_headers);
761 EXPECT(0 == gpt->valid_entries);
762 EXPECT(0 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700763
Randall Spanglere9213a72013-01-24 11:19:55 -0800764 BuildTestGptData(gpt);
765 gpt->primary_header[0]++;
766 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
767 EXPECT(MASK_SECONDARY == gpt->valid_headers);
768 EXPECT(MASK_BOTH == gpt->valid_entries);
769 GptRepair(gpt);
770 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
771 EXPECT(MASK_BOTH == gpt->valid_headers);
772 EXPECT(MASK_BOTH == gpt->valid_entries);
773 EXPECT(GPT_MODIFIED_HEADER1 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700774
Randall Spanglere9213a72013-01-24 11:19:55 -0800775 BuildTestGptData(gpt);
776 gpt->secondary_header[0]++;
777 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
778 EXPECT(MASK_PRIMARY == gpt->valid_headers);
779 EXPECT(MASK_BOTH == gpt->valid_entries);
780 GptRepair(gpt);
781 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
782 EXPECT(MASK_BOTH == gpt->valid_headers);
783 EXPECT(MASK_BOTH == gpt->valid_entries);
784 EXPECT(GPT_MODIFIED_HEADER2 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700785
Randall Spanglere9213a72013-01-24 11:19:55 -0800786 /*
787 * Modify header1 and update its CRC. Since header2 is now different
788 * than header1, it'll be the one considered invalid.
789 */
790 BuildTestGptData(gpt);
791 h1->size++;
792 RefreshCrc32(gpt);
793 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
794 EXPECT(MASK_PRIMARY == gpt->valid_headers);
795 EXPECT(MASK_BOTH == gpt->valid_entries);
796 GptRepair(gpt);
797 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
798 EXPECT(MASK_BOTH == gpt->valid_headers);
799 EXPECT(MASK_BOTH == gpt->valid_entries);
800 EXPECT(GPT_MODIFIED_HEADER2 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700801
Randall Spanglere9213a72013-01-24 11:19:55 -0800802 /* Modify entries */
803 BuildTestGptData(gpt);
804 gpt->primary_entries[0]++;
805 gpt->secondary_entries[0]++;
806 EXPECT(GPT_ERROR_INVALID_ENTRIES == GptSanityCheck(gpt));
807 EXPECT(MASK_BOTH == gpt->valid_headers);
808 EXPECT(MASK_NONE == gpt->valid_entries);
809 /* Repair can't fix both copies of entries being bad, either. */
810 GptRepair(gpt);
811 EXPECT(GPT_ERROR_INVALID_ENTRIES == GptSanityCheck(gpt));
812 EXPECT(MASK_BOTH == gpt->valid_headers);
813 EXPECT(MASK_NONE == gpt->valid_entries);
814 EXPECT(0 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700815
Randall Spanglere9213a72013-01-24 11:19:55 -0800816 BuildTestGptData(gpt);
817 gpt->primary_entries[0]++;
818 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
819 EXPECT(MASK_BOTH == gpt->valid_headers);
820 EXPECT(MASK_SECONDARY == gpt->valid_entries);
821 GptRepair(gpt);
822 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
823 EXPECT(MASK_BOTH == gpt->valid_headers);
824 EXPECT(MASK_BOTH == gpt->valid_entries);
825 EXPECT(GPT_MODIFIED_ENTRIES1 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700826
Randall Spanglere9213a72013-01-24 11:19:55 -0800827 BuildTestGptData(gpt);
828 gpt->secondary_entries[0]++;
829 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
830 EXPECT(MASK_BOTH == gpt->valid_headers);
831 EXPECT(MASK_PRIMARY == gpt->valid_entries);
832 GptRepair(gpt);
833 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
834 EXPECT(MASK_BOTH == gpt->valid_headers);
835 EXPECT(MASK_BOTH == gpt->valid_entries);
836 EXPECT(GPT_MODIFIED_ENTRIES2 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700837
Randall Spanglere9213a72013-01-24 11:19:55 -0800838 /* Modify both header and entries */
839 BuildTestGptData(gpt);
840 gpt->primary_header[0]++;
841 gpt->primary_entries[0]++;
842 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
843 EXPECT(MASK_SECONDARY == gpt->valid_headers);
844 EXPECT(MASK_SECONDARY == gpt->valid_entries);
845 GptRepair(gpt);
846 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
847 EXPECT(MASK_BOTH == gpt->valid_headers);
848 EXPECT(MASK_BOTH == gpt->valid_entries);
849 EXPECT((GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1) == gpt->modified);
Bill Richardsonaa8eda42010-08-27 09:31:26 -0700850
Randall Spanglere9213a72013-01-24 11:19:55 -0800851 BuildTestGptData(gpt);
852 gpt->secondary_header[0]++;
853 gpt->secondary_entries[0]++;
854 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
855 EXPECT(MASK_PRIMARY == gpt->valid_headers);
856 EXPECT(MASK_PRIMARY == gpt->valid_entries);
857 GptRepair(gpt);
858 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
859 EXPECT(MASK_BOTH == gpt->valid_headers);
860 EXPECT(MASK_BOTH == gpt->valid_entries);
861 EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
Bill Richardsonaa8eda42010-08-27 09:31:26 -0700862
Randall Spanglere9213a72013-01-24 11:19:55 -0800863 /* Test cross-correction (h1+e2, h2+e1) */
864 BuildTestGptData(gpt);
865 gpt->primary_header[0]++;
866 gpt->secondary_entries[0]++;
867 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
868 EXPECT(MASK_SECONDARY == gpt->valid_headers);
869 EXPECT(MASK_PRIMARY == gpt->valid_entries);
870 GptRepair(gpt);
871 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
872 EXPECT(MASK_BOTH == gpt->valid_headers);
873 EXPECT(MASK_BOTH == gpt->valid_entries);
874 EXPECT((GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700875
Randall Spanglere9213a72013-01-24 11:19:55 -0800876 BuildTestGptData(gpt);
877 gpt->secondary_header[0]++;
878 gpt->primary_entries[0]++;
879 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
880 EXPECT(MASK_PRIMARY == gpt->valid_headers);
881 EXPECT(MASK_SECONDARY == gpt->valid_entries);
882 GptRepair(gpt);
883 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
884 EXPECT(MASK_BOTH == gpt->valid_headers);
885 EXPECT(MASK_BOTH == gpt->valid_entries);
886 EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES1) == gpt->modified);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700887
Randall Spanglere9213a72013-01-24 11:19:55 -0800888 /*
889 * Test mismatched pairs (h1+e1 valid, h2+e2 valid but different. This
890 * simulates a partial update of the drive.
891 */
892 BuildTestGptData(gpt);
893 gpt->secondary_entries[0]++;
894 RefreshCrc32(gpt);
895 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
896 EXPECT(MASK_PRIMARY == gpt->valid_headers);
897 EXPECT(MASK_PRIMARY == gpt->valid_entries);
898 GptRepair(gpt);
899 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
900 EXPECT(MASK_BOTH == gpt->valid_headers);
901 EXPECT(MASK_BOTH == gpt->valid_entries);
902 EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700903
Randall Spanglere9213a72013-01-24 11:19:55 -0800904 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700905}
906
Randall Spanglere9213a72013-01-24 11:19:55 -0800907static int EntryAttributeGetSetTest(void)
908{
909 GptData *gpt = GetEmptyGptData();
910 GptEntry *e = (GptEntry *)(gpt->primary_entries);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700911
Randall Spanglere9213a72013-01-24 11:19:55 -0800912 e->attrs.whole = 0x0000000000000000ULL;
913 SetEntrySuccessful(e, 1);
914 EXPECT(0x0100000000000000ULL == e->attrs.whole);
915 EXPECT(1 == GetEntrySuccessful(e));
916 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
917 SetEntrySuccessful(e, 0);
918 EXPECT(0xFEFFFFFFFFFFFFFFULL == e->attrs.whole);
919 EXPECT(0 == GetEntrySuccessful(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700920
Randall Spanglere9213a72013-01-24 11:19:55 -0800921 e->attrs.whole = 0x0000000000000000ULL;
922 SetEntryTries(e, 15);
923 EXPECT(15 == GetEntryTries(e));
924 EXPECT(0x00F0000000000000ULL == e->attrs.whole);
925 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
926 SetEntryTries(e, 0);
927 EXPECT(0xFF0FFFFFFFFFFFFFULL == e->attrs.whole);
928 EXPECT(0 == GetEntryTries(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700929
Randall Spanglere9213a72013-01-24 11:19:55 -0800930 e->attrs.whole = 0x0000000000000000ULL;
931 SetEntryPriority(e, 15);
932 EXPECT(0x000F000000000000ULL == e->attrs.whole);
933 EXPECT(15 == GetEntryPriority(e));
934 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
935 SetEntryPriority(e, 0);
936 EXPECT(0xFFF0FFFFFFFFFFFFULL == e->attrs.whole);
937 EXPECT(0 == GetEntryPriority(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700938
Randall Spanglere9213a72013-01-24 11:19:55 -0800939 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
940 EXPECT(1 == GetEntrySuccessful(e));
941 EXPECT(15 == GetEntryPriority(e));
942 EXPECT(15 == GetEntryTries(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700943
Randall Spanglere9213a72013-01-24 11:19:55 -0800944 e->attrs.whole = 0x0123000000000000ULL;
945 EXPECT(1 == GetEntrySuccessful(e));
946 EXPECT(2 == GetEntryTries(e));
947 EXPECT(3 == GetEntryPriority(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700948
Randall Spanglere9213a72013-01-24 11:19:55 -0800949 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700950}
951
Randall Spanglere9213a72013-01-24 11:19:55 -0800952static int EntryTypeTest(void)
953{
954 GptData *gpt = GetEmptyGptData();
955 GptEntry *e = (GptEntry *)(gpt->primary_entries);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700956
Randall Spanglere9213a72013-01-24 11:19:55 -0800957 Memcpy(&e->type, &guid_zero, sizeof(Guid));
958 EXPECT(1 == IsUnusedEntry(e));
959 EXPECT(0 == IsKernelEntry(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700960
Randall Spanglere9213a72013-01-24 11:19:55 -0800961 Memcpy(&e->type, &guid_kernel, sizeof(Guid));
962 EXPECT(0 == IsUnusedEntry(e));
963 EXPECT(1 == IsKernelEntry(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700964
Randall Spanglere9213a72013-01-24 11:19:55 -0800965 Memcpy(&e->type, &guid_rootfs, sizeof(Guid));
966 EXPECT(0 == IsUnusedEntry(e));
967 EXPECT(0 == IsKernelEntry(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700968
Randall Spanglere9213a72013-01-24 11:19:55 -0800969 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700970}
971
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700972/* Make an entry unused by clearing its type. */
Randall Spanglere9213a72013-01-24 11:19:55 -0800973static void FreeEntry(GptEntry *e)
974{
975 Memset(&e->type, 0, sizeof(Guid));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700976}
977
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700978/* Set up an entry. */
Randall Spanglere9213a72013-01-24 11:19:55 -0800979static void FillEntry(GptEntry *e, int is_kernel,
980 int priority, int successful, int tries)
981{
982 Memcpy(&e->type, (is_kernel ? &guid_kernel : &guid_zero), sizeof(Guid));
983 SetEntryPriority(e, priority);
984 SetEntrySuccessful(e, successful);
985 SetEntryTries(e, tries);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700986}
987
Randall Spanglere9213a72013-01-24 11:19:55 -0800988/*
989 * Invalidate all kernel entries and expect GptNextKernelEntry() cannot find
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700990 * any usable kernel entry.
991 */
Randall Spanglere9213a72013-01-24 11:19:55 -0800992static int NoValidKernelEntryTest(void)
993{
994 GptData *gpt = GetEmptyGptData();
995 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700996
Randall Spanglere9213a72013-01-24 11:19:55 -0800997 BuildTestGptData(gpt);
998 SetEntryPriority(e1 + KERNEL_A, 0);
999 FreeEntry(e1 + KERNEL_B);
1000 RefreshCrc32(gpt);
1001 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1002 GptNextKernelEntry(gpt, NULL, NULL));
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001003
Randall Spanglere9213a72013-01-24 11:19:55 -08001004 return TEST_OK;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001005}
1006
Randall Spanglere9213a72013-01-24 11:19:55 -08001007static int GetNextNormalTest(void)
1008{
1009 GptData *gpt = GetEmptyGptData();
1010 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
1011 uint64_t start, size;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001012
Randall Spanglere9213a72013-01-24 11:19:55 -08001013 /* Normal case - both kernels successful */
1014 BuildTestGptData(gpt);
1015 FillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
1016 FillEntry(e1 + KERNEL_B, 1, 2, 1, 0);
1017 RefreshCrc32(gpt);
1018 GptInit(gpt);
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001019
Randall Spanglere9213a72013-01-24 11:19:55 -08001020 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1021 EXPECT(KERNEL_A == gpt->current_kernel);
1022 EXPECT(34 == start);
1023 EXPECT(100 == size);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001024
Randall Spanglere9213a72013-01-24 11:19:55 -08001025 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1026 EXPECT(KERNEL_B == gpt->current_kernel);
1027 EXPECT(134 == start);
1028 EXPECT(99 == size);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001029
Randall Spanglere9213a72013-01-24 11:19:55 -08001030 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1031 GptNextKernelEntry(gpt, &start, &size));
1032 EXPECT(-1 == gpt->current_kernel);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001033
Randall Spanglere9213a72013-01-24 11:19:55 -08001034 /* Call as many times as you want; you won't get another kernel... */
1035 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1036 GptNextKernelEntry(gpt, &start, &size));
1037 EXPECT(-1 == gpt->current_kernel);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001038
Randall Spanglere9213a72013-01-24 11:19:55 -08001039 return TEST_OK;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001040}
1041
Randall Spanglere9213a72013-01-24 11:19:55 -08001042static int GetNextPrioTest(void)
1043{
1044 GptData *gpt = GetEmptyGptData();
1045 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
1046 uint64_t start, size;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001047
Randall Spanglere9213a72013-01-24 11:19:55 -08001048 /* Priority 3, 4, 0, 4 - should boot order B, Y, A */
1049 BuildTestGptData(gpt);
1050 FillEntry(e1 + KERNEL_A, 1, 3, 1, 0);
1051 FillEntry(e1 + KERNEL_B, 1, 4, 1, 0);
1052 FillEntry(e1 + KERNEL_X, 1, 0, 1, 0);
1053 FillEntry(e1 + KERNEL_Y, 1, 4, 1, 0);
1054 RefreshCrc32(gpt);
1055 GptInit(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001056
Randall Spanglere9213a72013-01-24 11:19:55 -08001057 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1058 EXPECT(KERNEL_B == gpt->current_kernel);
1059 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1060 EXPECT(KERNEL_Y == gpt->current_kernel);
1061 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1062 EXPECT(KERNEL_A == gpt->current_kernel);
1063 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1064 GptNextKernelEntry(gpt, &start, &size));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001065
Randall Spanglere9213a72013-01-24 11:19:55 -08001066 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001067}
1068
Randall Spanglere9213a72013-01-24 11:19:55 -08001069static int GetNextTriesTest(void)
1070{
1071 GptData *gpt = GetEmptyGptData();
1072 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
1073 uint64_t start, size;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001074
Randall Spanglere9213a72013-01-24 11:19:55 -08001075 /* Tries=nonzero is attempted just like success, but tries=0 isn't */
1076 BuildTestGptData(gpt);
1077 FillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
1078 FillEntry(e1 + KERNEL_B, 1, 3, 0, 0);
1079 FillEntry(e1 + KERNEL_X, 1, 4, 0, 1);
1080 FillEntry(e1 + KERNEL_Y, 1, 0, 0, 5);
1081 RefreshCrc32(gpt);
1082 GptInit(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001083
Randall Spanglere9213a72013-01-24 11:19:55 -08001084 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1085 EXPECT(KERNEL_X == gpt->current_kernel);
1086 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1087 EXPECT(KERNEL_A == gpt->current_kernel);
1088 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1089 GptNextKernelEntry(gpt, &start, &size));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001090
Randall Spanglere9213a72013-01-24 11:19:55 -08001091 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001092}
1093
Randall Spanglere9213a72013-01-24 11:19:55 -08001094static int GptUpdateTest(void)
1095{
1096 GptData *gpt = GetEmptyGptData();
1097 GptEntry *e = (GptEntry *)(gpt->primary_entries);
1098 GptEntry *e2 = (GptEntry *)(gpt->secondary_entries);
1099 uint64_t start, size;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001100
Randall Spanglere9213a72013-01-24 11:19:55 -08001101 /* Tries=nonzero is attempted just like success, but tries=0 isn't */
1102 BuildTestGptData(gpt);
1103 FillEntry(e + KERNEL_A, 1, 4, 1, 0);
1104 FillEntry(e + KERNEL_B, 1, 3, 0, 2);
1105 FillEntry(e + KERNEL_X, 1, 2, 0, 2);
1106 RefreshCrc32(gpt);
1107 GptInit(gpt);
1108 gpt->modified = 0; /* Nothing modified yet */
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001109
Randall Spanglere9213a72013-01-24 11:19:55 -08001110 /* Successful kernel */
1111 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1112 EXPECT(KERNEL_A == gpt->current_kernel);
1113 EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
1114 EXPECT(4 == GetEntryPriority(e + KERNEL_A));
1115 EXPECT(0 == GetEntryTries(e + KERNEL_A));
1116 EXPECT(1 == GetEntrySuccessful(e2 + KERNEL_A));
1117 EXPECT(4 == GetEntryPriority(e2 + KERNEL_A));
1118 EXPECT(0 == GetEntryTries(e2 + KERNEL_A));
1119 /* Trying successful kernel changes nothing */
1120 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
1121 EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
1122 EXPECT(4 == GetEntryPriority(e + KERNEL_A));
1123 EXPECT(0 == GetEntryTries(e + KERNEL_A));
1124 EXPECT(0 == gpt->modified);
1125 /* Marking it bad also does not update it. */
1126 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
1127 EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
1128 EXPECT(4 == GetEntryPriority(e + KERNEL_A));
1129 EXPECT(0 == GetEntryTries(e + KERNEL_A));
1130 EXPECT(0 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001131
Randall Spanglere9213a72013-01-24 11:19:55 -08001132 /* Kernel with tries */
1133 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1134 EXPECT(KERNEL_B == gpt->current_kernel);
1135 EXPECT(0 == GetEntrySuccessful(e + KERNEL_B));
1136 EXPECT(3 == GetEntryPriority(e + KERNEL_B));
1137 EXPECT(2 == GetEntryTries(e + KERNEL_B));
1138 /* Marking it bad clears it */
1139 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
1140 EXPECT(0 == GetEntrySuccessful(e + KERNEL_B));
1141 EXPECT(0 == GetEntryPriority(e + KERNEL_B));
1142 EXPECT(0 == GetEntryTries(e + KERNEL_B));
1143 /* Which affects both copies of the partition entries */
1144 EXPECT(0 == GetEntrySuccessful(e2 + KERNEL_B));
1145 EXPECT(0 == GetEntryPriority(e2 + KERNEL_B));
1146 EXPECT(0 == GetEntryTries(e2 + KERNEL_B));
1147 /* And that's caused the GPT to need updating */
1148 EXPECT(0x0F == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001149
Randall Spanglere9213a72013-01-24 11:19:55 -08001150 /* Another kernel with tries */
1151 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1152 EXPECT(KERNEL_X == gpt->current_kernel);
1153 EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
1154 EXPECT(2 == GetEntryPriority(e + KERNEL_X));
1155 EXPECT(2 == GetEntryTries(e + KERNEL_X));
1156 /* Trying it uses up a try */
1157 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
1158 EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
1159 EXPECT(2 == GetEntryPriority(e + KERNEL_X));
1160 EXPECT(1 == GetEntryTries(e + KERNEL_X));
1161 EXPECT(0 == GetEntrySuccessful(e2 + KERNEL_X));
1162 EXPECT(2 == GetEntryPriority(e2 + KERNEL_X));
1163 EXPECT(1 == GetEntryTries(e2 + KERNEL_X));
1164 /* Trying it again marks it inactive */
1165 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
1166 EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
1167 EXPECT(0 == GetEntryPriority(e + KERNEL_X));
1168 EXPECT(0 == GetEntryTries(e + KERNEL_X));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001169
Randall Spanglere9213a72013-01-24 11:19:55 -08001170 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001171}
1172
Randall Spanglere9213a72013-01-24 11:19:55 -08001173/*
1174 * Give an invalid kernel type, and expect GptUpdateKernelEntry() returns
1175 * GPT_ERROR_INVALID_UPDATE_TYPE.
1176 */
1177static int UpdateInvalidKernelTypeTest(void)
1178{
1179 GptData *gpt = GetEmptyGptData();
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001180
Randall Spanglere9213a72013-01-24 11:19:55 -08001181 BuildTestGptData(gpt);
1182 /* anything, but not CGPT_KERNEL_ENTRY_NOT_FOUND */
1183 gpt->current_kernel = 0;
1184 /* any invalid update_type value */
1185 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1186 GptUpdateKernelEntry(gpt, 99));
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001187
Randall Spanglere9213a72013-01-24 11:19:55 -08001188 return TEST_OK;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001189}
1190
Randall Spanglere9213a72013-01-24 11:19:55 -08001191/* Test duplicate UniqueGuids can be detected. */
1192static int DuplicateUniqueGuidTest(void)
1193{
1194 GptData *gpt = GetEmptyGptData();
1195 GptHeader *h = (GptHeader *)gpt->primary_header;
1196 GptEntry *e = (GptEntry *)gpt->primary_entries;
1197 int i, j;
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001198
Randall Spanglere9213a72013-01-24 11:19:55 -08001199 struct {
1200 int duplicate;
1201 struct {
1202 uint64_t starting_lba;
1203 uint64_t ending_lba;
1204 uint32_t type_guid;
1205 uint32_t unique_guid;
1206 } entries[16]; /* enough for testing. */
1207 } cases[] = {
1208 {GPT_SUCCESS, {{100, 109, 1, 1},
1209 {110, 119, 2, 2},
1210 {120, 129, 3, 3},
1211 {130, 139, 4, 4},
1212 }},
1213 {GPT_SUCCESS, {{100, 109, 1, 1},
1214 {110, 119, 1, 2},
1215 {120, 129, 2, 3},
1216 {130, 139, 2, 4},
1217 }},
1218 {GPT_ERROR_DUP_GUID, {{100, 109, 1, 1},
1219 {110, 119, 2, 2},
1220 {120, 129, 3, 1},
1221 {130, 139, 4, 4},
1222 }},
1223 {GPT_ERROR_DUP_GUID, {{100, 109, 1, 1},
1224 {110, 119, 1, 2},
1225 {120, 129, 2, 3},
1226 {130, 139, 2, 2},
1227 }},
1228 };
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001229
Randall Spanglere9213a72013-01-24 11:19:55 -08001230 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
1231 BuildTestGptData(gpt);
1232 ZeroEntries(gpt);
1233 for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) {
1234 if (!cases[i].entries[j].starting_lba)
1235 break;
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001236
Randall Spanglere9213a72013-01-24 11:19:55 -08001237 e[j].starting_lba = cases[i].entries[j].starting_lba;
1238 e[j].ending_lba = cases[i].entries[j].ending_lba;
1239 SetGuid(&e[j].type, cases[i].entries[j].type_guid);
1240 SetGuid(&e[j].unique, cases[i].entries[j].unique_guid);
1241 }
1242 RefreshCrc32(gpt);
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001243
Randall Spanglere9213a72013-01-24 11:19:55 -08001244 EXPECT(cases[i].duplicate == CheckEntries(e, h));
1245 }
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001246
Randall Spanglere9213a72013-01-24 11:19:55 -08001247 return TEST_OK;
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001248}
1249
vbendeb3ecaf772010-06-24 16:19:53 -07001250/* disable MSVC warnings on unused arguments */
1251__pragma(warning (disable: 4100))
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001252
Randall Spanglere9213a72013-01-24 11:19:55 -08001253int main(int argc, char *argv[])
1254{
1255 int i;
1256 int error_count = 0;
1257 struct {
1258 char *name;
1259 test_func fp;
1260 int retval;
1261 } test_cases[] = {
1262 { TEST_CASE(StructSizeTest), },
1263 { TEST_CASE(TestBuildTestGptData), },
1264 { TEST_CASE(ParameterTests), },
1265 { TEST_CASE(HeaderCrcTest), },
1266 { TEST_CASE(SignatureTest), },
1267 { TEST_CASE(RevisionTest), },
1268 { TEST_CASE(SizeTest), },
1269 { TEST_CASE(CrcFieldTest), },
1270 { TEST_CASE(ReservedFieldsTest), },
1271 { TEST_CASE(SizeOfPartitionEntryTest), },
1272 { TEST_CASE(NumberOfPartitionEntriesTest), },
1273 { TEST_CASE(MyLbaTest), },
1274 { TEST_CASE(FirstUsableLbaAndLastUsableLbaTest), },
1275 { TEST_CASE(EntriesCrcTest), },
1276 { TEST_CASE(ValidEntryTest), },
1277 { TEST_CASE(OverlappedPartitionTest), },
1278 { TEST_CASE(SanityCheckTest), },
1279 { TEST_CASE(NoValidKernelEntryTest), },
1280 { TEST_CASE(EntryAttributeGetSetTest), },
1281 { TEST_CASE(EntryTypeTest), },
1282 { TEST_CASE(GetNextNormalTest), },
1283 { TEST_CASE(GetNextPrioTest), },
1284 { TEST_CASE(GetNextTriesTest), },
1285 { TEST_CASE(GptUpdateTest), },
1286 { TEST_CASE(UpdateInvalidKernelTypeTest), },
1287 { TEST_CASE(DuplicateUniqueGuidTest), },
1288 { TEST_CASE(TestCrc32TestVectors), },
1289 };
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001290
Randall Spanglere9213a72013-01-24 11:19:55 -08001291 for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
1292 printf("Running %s() ...\n", test_cases[i].name);
1293 test_cases[i].retval = test_cases[i].fp();
1294 if (test_cases[i].retval) {
1295 printf(COL_RED "[ERROR]\n\n" COL_STOP);
1296 ++error_count;
1297 } else {
1298 printf(COL_GREEN "[PASS]\n\n" COL_STOP);
1299 }
1300 }
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001301
Randall Spanglere9213a72013-01-24 11:19:55 -08001302 if (error_count) {
1303 printf("\n------------------------------------------------\n");
1304 printf(COL_RED "The following %d test cases are failed:\n"
1305 COL_STOP, error_count);
1306 for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
1307 if (test_cases[i].retval)
1308 printf(" %s()\n", test_cases[i].name);
1309 }
1310 }
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001311
Randall Spanglere9213a72013-01-24 11:19:55 -08001312 return error_count ? 1 : 0;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001313}