blob: 891d53b72a93dcf2bf013e3dc217ff47c1082a68 [file] [log] [blame]
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
Louis Yung-Chieh 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.h"
9#include "cgptlib_internal.h"
Randall Spangler3dcf9dc2010-06-02 12:46:17 -070010#include "cgptlib_test.h"
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070011#include "crc32.h"
Louis Yung-Chieh Lob31ddce2010-05-21 16:35:44 +080012#include "crc32_test.h"
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070013#include "gpt.h"
vbendeb3ecaf772010-06-24 16:19:53 -070014#include "test_common.h"
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070015#include "utility.h"
16
17/* Testing partition layout (sector_bytes=512)
18 *
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
Bill Richardsonaa8eda42010-08-27 09:31:26 -070048/* Copy a random-for-this-program-only Guid into the dest. The num parameter
49 * completely determines the Guid.
50 */
51static void SetGuid(void *dest, uint32_t num) {
52 Guid g = {{{num,0xd450,0x44bc,0xa6,0x93,{0xb8,0xac,0x75,0x5f,0xcd,0x48}}}};
53 Memcpy(dest, &g, sizeof(Guid));
54}
Randall Spangler3dcf9dc2010-06-02 12:46:17 -070055
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070056/* Given a GptData pointer, first re-calculate entries CRC32 value,
57 * then reset header CRC32 value to 0, and calculate header CRC32 value.
58 * Both primary and secondary are updated. */
Randall Spangler3dcf9dc2010-06-02 12:46:17 -070059static void RefreshCrc32(GptData* gpt) {
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070060 GptHeader *header, *header2;
61 GptEntry *entries, *entries2;
62
63 header = (GptHeader*)gpt->primary_header;
64 entries = (GptEntry*)gpt->primary_entries;
65 header2 = (GptHeader*)gpt->secondary_header;
66 entries2 = (GptEntry*)gpt->secondary_entries;
67
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070068 header->entries_crc32 =
69 Crc32((uint8_t*)entries,
70 header->number_of_entries * header->size_of_entry);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070071 header->header_crc32 = 0;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070072 header->header_crc32 = Crc32((uint8_t*)header, header->size);
73 header2->entries_crc32 =
74 Crc32((uint8_t*)entries2,
75 header2->number_of_entries * header2->size_of_entry);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070076 header2->header_crc32 = 0;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070077 header2->header_crc32 = Crc32((uint8_t*)header2, header2->size);
78}
79
Randall Spangler3dcf9dc2010-06-02 12:46:17 -070080
81static void ZeroHeaders(GptData* gpt) {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070082 Memset(gpt->primary_header, 0, MAX_SECTOR_SIZE);
83 Memset(gpt->secondary_header, 0, MAX_SECTOR_SIZE);
84}
85
Randall Spangler3dcf9dc2010-06-02 12:46:17 -070086
87static void ZeroEntries(GptData* gpt) {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070088 Memset(gpt->primary_entries, 0, PARTITION_ENTRIES_SIZE);
89 Memset(gpt->secondary_entries, 0, PARTITION_ENTRIES_SIZE);
90}
91
Randall Spangler3dcf9dc2010-06-02 12:46:17 -070092
93static void ZeroHeadersEntries(GptData* gpt) {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070094 ZeroHeaders(gpt);
95 ZeroEntries(gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070096}
97
Randall Spangler3dcf9dc2010-06-02 12:46:17 -070098
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070099/* Returns a pointer to a static GptData instance (no free is required).
100 * All fields are zero except 4 pointers linking to header and entries.
101 * All content of headers and entries are zero. */
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700102static GptData* GetEmptyGptData() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700103 static GptData gpt;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700104 static uint8_t primary_header[MAX_SECTOR_SIZE];
105 static uint8_t primary_entries[PARTITION_ENTRIES_SIZE];
106 static uint8_t secondary_header[MAX_SECTOR_SIZE];
107 static uint8_t secondary_entries[PARTITION_ENTRIES_SIZE];
108
109 Memset(&gpt, 0, sizeof(gpt));
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700110 gpt.primary_header = primary_header;
111 gpt.primary_entries = primary_entries;
112 gpt.secondary_header = secondary_header;
113 gpt.secondary_entries = secondary_entries;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700114 ZeroHeadersEntries(&gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700115
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700116 /* Initialize GptData internal states. */
117 gpt.current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
118
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700119 return &gpt;
120}
121
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700122
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700123/* Fills in most of fields and creates the layout described in the top of this
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700124 * file. Before calling this function, primary/secondary header/entries must
125 * have been pointed to the buffer, say, a gpt returned from GetEmptyGptData().
126 * This function returns a good (valid) copy of GPT layout described in top of
127 * this file. */
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700128static void BuildTestGptData(GptData* gpt) {
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700129 GptHeader *header, *header2;
130 GptEntry *entries, *entries2;
131 Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700132 Guid chromeos_rootfs = GPT_ENT_TYPE_CHROMEOS_ROOTFS;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700133
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700134 gpt->sector_bytes = DEFAULT_SECTOR_SIZE;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700135 gpt->drive_sectors = DEFAULT_DRIVE_SECTORS;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700136 gpt->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
Louis Yung-Chieh Lo418ad3b2010-05-27 11:21:17 +0800137 gpt->valid_headers = MASK_BOTH;
138 gpt->valid_entries = MASK_BOTH;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700139 gpt->modified = 0;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700140
141 /* build primary */
142 header = (GptHeader*)gpt->primary_header;
143 entries = (GptEntry*)gpt->primary_entries;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700144 Memcpy(header->signature, GPT_HEADER_SIGNATURE,
145 sizeof(GPT_HEADER_SIGNATURE));
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700146 header->revision = GPT_HEADER_REVISION;
Bill Richardsonf1372d92010-06-11 09:15:55 -0700147 header->size = sizeof(GptHeader);
148 header->reserved_zero = 0;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700149 header->my_lba = 1;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700150 header->alternate_lba = DEFAULT_DRIVE_SECTORS - 1;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700151 header->first_usable_lba = 34;
152 header->last_usable_lba = DEFAULT_DRIVE_SECTORS - 1 - 32 - 1; /* 433 */
153 header->entries_lba = 2;
154 header->number_of_entries = 128; /* 512B / 128B * 32sectors = 128 entries */
155 header->size_of_entry = 128; /* bytes */
156 Memcpy(&entries[0].type, &chromeos_kernel, sizeof(chromeos_kernel));
Bill Richardsonaa8eda42010-08-27 09:31:26 -0700157 SetGuid(&entries[0].unique, 0);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700158 entries[0].starting_lba = 34;
159 entries[0].ending_lba = 133;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700160 Memcpy(&entries[1].type, &chromeos_rootfs, sizeof(chromeos_rootfs));
Bill Richardsonaa8eda42010-08-27 09:31:26 -0700161 SetGuid(&entries[1].unique, 1);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700162 entries[1].starting_lba = 134;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700163 entries[1].ending_lba = 232;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700164 Memcpy(&entries[2].type, &chromeos_rootfs, sizeof(chromeos_rootfs));
Bill Richardsonaa8eda42010-08-27 09:31:26 -0700165 SetGuid(&entries[2].unique, 2);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700166 entries[2].starting_lba = 234;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700167 entries[2].ending_lba = 331;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700168 Memcpy(&entries[3].type, &chromeos_kernel, sizeof(chromeos_kernel));
Bill Richardsonaa8eda42010-08-27 09:31:26 -0700169 SetGuid(&entries[3].unique, 3);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700170 entries[3].starting_lba = 334;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700171 entries[3].ending_lba = 430;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700172
173 /* build secondary */
174 header2 = (GptHeader*)gpt->secondary_header;
175 entries2 = (GptEntry*)gpt->secondary_entries;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700176 Memcpy(header2, header, sizeof(GptHeader));
177 Memcpy(entries2, entries, PARTITION_ENTRIES_SIZE);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700178 header2->my_lba = DEFAULT_DRIVE_SECTORS - 1; /* 466 */
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700179 header2->alternate_lba = 1;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700180 header2->entries_lba = DEFAULT_DRIVE_SECTORS - 1 - 32; /* 434 */
181
182 RefreshCrc32(gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700183}
184
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700185
Randall Spangler81d09962010-06-23 10:15:38 -0700186/* Tests if the structures are the expected size; if this fails,
187 * struct packing is not working properly. */
188static int StructSizeTest() {
189
190 EXPECT(GUID_EXPECTED_SIZE == sizeof(Guid));
191 EXPECT(GPTHEADER_EXPECTED_SIZE == sizeof(GptHeader));
192 EXPECT(GPTENTRY_EXPECTED_SIZE == sizeof(GptEntry));
193
194 return TEST_OK;
195}
196
197
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700198/* Tests if the default structure returned by BuildTestGptData() is good. */
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700199static int TestBuildTestGptData() {
200 GptData* gpt;
201
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700202 gpt = GetEmptyGptData();
203 BuildTestGptData(gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700204 EXPECT(GPT_SUCCESS == GptInit(gpt));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700205 return TEST_OK;
206}
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700207
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700208
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700209/* Tests if wrong sector_bytes or drive_sectors is detected by GptInit().
210 * Currently we only support 512 bytes per sector.
211 * In the future, we may support other sizes.
212 * A too small drive_sectors should be rejected by GptInit(). */
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700213static int ParameterTests() {
214 GptData* gpt;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700215 struct {
216 uint32_t sector_bytes;
217 uint64_t drive_sectors;
218 int expected_retval;
219 } cases[] = {
220 {512, DEFAULT_DRIVE_SECTORS, GPT_SUCCESS},
221 {520, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
222 {512, 0, GPT_ERROR_INVALID_SECTOR_NUMBER},
223 {512, 66, GPT_ERROR_INVALID_SECTOR_NUMBER},
224 {512, GPT_PMBR_SECTOR + GPT_HEADER_SECTOR * 2 + GPT_ENTRIES_SECTORS * 2,
225 GPT_SUCCESS},
226 {4096, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
227 };
228 int i;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700229
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700230 gpt = GetEmptyGptData();
231 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
232 BuildTestGptData(gpt);
233 gpt->sector_bytes = cases[i].sector_bytes;
234 gpt->drive_sectors = cases[i].drive_sectors;
235 EXPECT(cases[i].expected_retval == CheckParameters(gpt));
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700236 }
237
238 return TEST_OK;
239}
240
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700241
242/* Tests if header CRC in two copies are calculated. */
243static int HeaderCrcTest() {
244 GptData* gpt = GetEmptyGptData();
245 GptHeader* h1 = (GptHeader*)gpt->primary_header;
246
247 BuildTestGptData(gpt);
248 EXPECT(HeaderCrc(h1) == h1->header_crc32);
249
250 /* CRC covers first byte of header */
251 BuildTestGptData(gpt);
252 gpt->primary_header[0] ^= 0xa5;
253 EXPECT(HeaderCrc(h1) != h1->header_crc32);
254
255 /* CRC covers last byte of header */
256 BuildTestGptData(gpt);
257 gpt->primary_header[h1->size - 1] ^= 0x5a;
258 EXPECT(HeaderCrc(h1) != h1->header_crc32);
259
260 /* CRC only covers header */
261 BuildTestGptData(gpt);
262 gpt->primary_header[h1->size] ^= 0x5a;
263 EXPECT(HeaderCrc(h1) == h1->header_crc32);
264
265 return TEST_OK;
266}
267
268
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700269/* Tests if signature ("EFI PART") is checked. */
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700270static int SignatureTest() {
271 GptData* gpt = GetEmptyGptData();
272 GptHeader* h1 = (GptHeader*)gpt->primary_header;
273 GptHeader* h2 = (GptHeader*)gpt->secondary_header;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700274 int i;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700275
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700276 for (i = 0; i < 8; ++i) {
277 BuildTestGptData(gpt);
278 h1->signature[i] ^= 0xff;
279 h2->signature[i] ^= 0xff;
280 RefreshCrc32(gpt);
281 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
282 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700283 }
284
285 return TEST_OK;
286}
287
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700288
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700289/* The revision we currently support is GPT_HEADER_REVISION.
290 * If the revision in header is not that, we expect the header is invalid. */
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700291static int RevisionTest() {
292 GptData* gpt = GetEmptyGptData();
293 GptHeader* h1 = (GptHeader*)gpt->primary_header;
294 GptHeader* h2 = (GptHeader*)gpt->secondary_header;
295 int i;
296
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700297 struct {
298 uint32_t value_to_test;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700299 int expect_rv;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700300 } cases[] = {
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700301 {0x01000000, 1},
302 {0x00010000, 0}, /* GPT_HEADER_REVISION */
303 {0x00000100, 1},
304 {0x00000001, 1},
305 {0x23010456, 1},
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700306 };
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700307
308 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700309 BuildTestGptData(gpt);
310 h1->revision = cases[i].value_to_test;
311 h2->revision = cases[i].value_to_test;
312 RefreshCrc32(gpt);
313
314 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) == cases[i].expect_rv);
315 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) == cases[i].expect_rv);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700316 }
317 return TEST_OK;
318}
319
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700320
321static int SizeTest() {
322 GptData* gpt = GetEmptyGptData();
323 GptHeader* h1 = (GptHeader*)gpt->primary_header;
324 GptHeader* h2 = (GptHeader*)gpt->secondary_header;
325 int i;
326
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700327 struct {
328 uint32_t value_to_test;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700329 int expect_rv;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700330 } cases[] = {
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700331 {91, 1},
332 {92, 0},
333 {93, 0},
334 {511, 0},
335 {512, 0},
336 {513, 1},
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700337 };
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700338
339 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700340 BuildTestGptData(gpt);
341 h1->size = cases[i].value_to_test;
342 h2->size = cases[i].value_to_test;
343 RefreshCrc32(gpt);
344
345 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) == cases[i].expect_rv);
346 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) == cases[i].expect_rv);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700347 }
348 return TEST_OK;
349}
350
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700351
352/* Tests if CRC is checked. */
353static int CrcFieldTest() {
354 GptData* gpt = GetEmptyGptData();
355 GptHeader* h1 = (GptHeader*)gpt->primary_header;
356 GptHeader* h2 = (GptHeader*)gpt->secondary_header;
357
358 BuildTestGptData(gpt);
359 /* Modify a field that the header verification doesn't care about */
360 h1->entries_crc32++;
361 h2->entries_crc32++;
362 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
363 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
364 /* Refresh the CRC; should pass now */
365 RefreshCrc32(gpt);
366 EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
367 EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
368
369 return TEST_OK;
370}
371
372
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700373/* Tests if reserved fields are checked.
374 * We'll try non-zero values to test. */
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700375static int ReservedFieldsTest() {
376 GptData* gpt = GetEmptyGptData();
377 GptHeader* h1 = (GptHeader*)gpt->primary_header;
378 GptHeader* h2 = (GptHeader*)gpt->secondary_header;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700379
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700380 BuildTestGptData(gpt);
Bill Richardsonf1372d92010-06-11 09:15:55 -0700381 h1->reserved_zero ^= 0x12345678; /* whatever random */
382 h2->reserved_zero ^= 0x12345678; /* whatever random */
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700383 RefreshCrc32(gpt);
384 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
385 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700386
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700387#ifdef PADDING_CHECKED
388 /* TODO: padding check is currently disabled */
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700389 BuildTestGptData(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700390 h1->padding[12] ^= 0x34; /* whatever random */
391 h2->padding[56] ^= 0x78; /* whatever random */
392 RefreshCrc32(gpt);
393 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
394 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
395#endif
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700396
397 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700398}
399
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700400
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700401/* Technically, any size which is 2^N where N > 6 should work, but our
402 * library only supports one size. */
403static int SizeOfPartitionEntryTest() {
404 GptData* gpt = GetEmptyGptData();
405 GptHeader* h1 = (GptHeader*)gpt->primary_header;
406 GptHeader* h2 = (GptHeader*)gpt->secondary_header;
407 int i;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700408
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700409 struct {
410 uint32_t value_to_test;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700411 int expect_rv;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700412 } cases[] = {
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700413 {127, 1},
414 {128, 0},
415 {129, 1},
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700416 {256, 1},
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700417 {512, 1},
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700418 };
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700419
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700420 /* Check size of entryes */
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700421 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700422 BuildTestGptData(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700423 h1->size_of_entry = cases[i].value_to_test;
424 h2->size_of_entry = cases[i].value_to_test;
425 h1->number_of_entries = TOTAL_ENTRIES_SIZE / cases[i].value_to_test;
426 h2->number_of_entries = TOTAL_ENTRIES_SIZE / cases[i].value_to_test;
427 RefreshCrc32(gpt);
428
429 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) == cases[i].expect_rv);
430 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) == cases[i].expect_rv);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700431 }
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700432
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700433 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700434}
435
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700436
437/* Technically, any size which is 2^N where N > 6 should work, but our
438 * library only supports one size. */
439static int NumberOfPartitionEntriesTest() {
440 GptData* gpt = GetEmptyGptData();
441 GptHeader* h1 = (GptHeader*)gpt->primary_header;
442 GptHeader* h2 = (GptHeader*)gpt->secondary_header;
443
444 BuildTestGptData(gpt);
445 h1->number_of_entries--;
446 h2->number_of_entries /= 2;
447 RefreshCrc32(gpt);
448 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
449 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
450
451 return TEST_OK;
452}
453
454
455/* Tests if myLBA field is checked (1 for primary, last for secondary). */
456static int MyLbaTest() {
457 GptData* gpt = GetEmptyGptData();
458 GptHeader* h1 = (GptHeader*)gpt->primary_header;
459 GptHeader* h2 = (GptHeader*)gpt->secondary_header;
460
461 /* myLBA depends on primary vs secondary flag */
462 BuildTestGptData(gpt);
463 EXPECT(1 == CheckHeader(h1, 1, gpt->drive_sectors));
464 EXPECT(1 == CheckHeader(h2, 0, gpt->drive_sectors));
465
466 BuildTestGptData(gpt);
467 h1->my_lba--;
468 h2->my_lba--;
469 RefreshCrc32(gpt);
470 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
471 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
472
473 BuildTestGptData(gpt);
474 h1->my_lba = 2;
475 h2->my_lba--;
476 RefreshCrc32(gpt);
477 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
478 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
479
Bill Richardson31066a42010-06-03 15:20:19 -0700480 /* We should ignore the alternate_lba field entirely */
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700481 BuildTestGptData(gpt);
482 h1->alternate_lba++;
483 h2->alternate_lba++;
484 RefreshCrc32(gpt);
Bill Richardson31066a42010-06-03 15:20:19 -0700485 EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
486 EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700487
488 BuildTestGptData(gpt);
489 h1->alternate_lba--;
490 h2->alternate_lba--;
491 RefreshCrc32(gpt);
Bill Richardson31066a42010-06-03 15:20:19 -0700492 EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
493 EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700494
495 BuildTestGptData(gpt);
496 h1->entries_lba++;
497 h2->entries_lba++;
498 RefreshCrc32(gpt);
499 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
500 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
501
502 BuildTestGptData(gpt);
503 h1->entries_lba--;
504 h2->entries_lba--;
505 RefreshCrc32(gpt);
506 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
507 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
508
509 return TEST_OK;
510}
511
512
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700513/* Tests if FirstUsableLBA and LastUsableLBA are checked.
514 * FirstUsableLBA must be after the end of the primary GPT table array.
515 * LastUsableLBA must be before the start of the secondary GPT table array.
516 * FirstUsableLBA <= LastUsableLBA. */
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700517static int FirstUsableLbaAndLastUsableLbaTest() {
518 GptData* gpt = GetEmptyGptData();
519 GptHeader* h1 = (GptHeader*)gpt->primary_header;
520 GptHeader* h2 = (GptHeader*)gpt->secondary_header;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700521 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700522
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700523 struct {
524 uint64_t primary_entries_lba;
525 uint64_t primary_first_usable_lba;
526 uint64_t primary_last_usable_lba;
527 uint64_t secondary_first_usable_lba;
528 uint64_t secondary_last_usable_lba;
529 uint64_t secondary_entries_lba;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700530 int primary_rv;
531 int secondary_rv;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700532 } cases[] = {
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700533 {2, 34, 433, 34, 433, 434, 0, 0},
534 {2, 34, 432, 34, 430, 434, 0, 0},
535 {2, 33, 433, 33, 433, 434, 1, 1},
536 {2, 34, 434, 34, 433, 434, 1, 0},
537 {2, 34, 433, 34, 434, 434, 0, 1},
538 {2, 35, 433, 35, 433, 434, 0, 0},
539 {2, 433, 433, 433, 433, 434, 0, 0},
540 {2, 434, 433, 434, 434, 434, 1, 1},
541 {2, 433, 34, 34, 433, 434, 1, 0},
542 {2, 34, 433, 433, 34, 434, 0, 1},
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700543 };
544
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700545 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
546 BuildTestGptData(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700547 h1->entries_lba = cases[i].primary_entries_lba;
548 h1->first_usable_lba = cases[i].primary_first_usable_lba;
549 h1->last_usable_lba = cases[i].primary_last_usable_lba;
550 h2->entries_lba = cases[i].secondary_entries_lba;
551 h2->first_usable_lba = cases[i].secondary_first_usable_lba;
552 h2->last_usable_lba = cases[i].secondary_last_usable_lba;
553 RefreshCrc32(gpt);
554
555 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) == cases[i].primary_rv);
556 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) == cases[i].secondary_rv);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700557 }
558
559 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700560}
561
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700562
563/* Tests if PartitionEntryArrayCRC32 is checked.
564 * PartitionEntryArrayCRC32 must be calculated over SizeOfPartitionEntry *
565 * NumberOfPartitionEntries bytes.
566 */
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700567static int EntriesCrcTest() {
568 GptData* gpt = GetEmptyGptData();
569 GptHeader* h1 = (GptHeader*)gpt->primary_header;
570 GptEntry* e1 = (GptEntry*)(gpt->primary_entries);
571 GptEntry* e2 = (GptEntry*)(gpt->secondary_entries);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700572
573 /* Modify the first byte of primary entries, and expect the CRC is wrong. */
574 BuildTestGptData(gpt);
vbendeb3ecaf772010-06-24 16:19:53 -0700575 EXPECT(0 == CheckEntries(e1, h1));
576 EXPECT(0 == CheckEntries(e2, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700577 gpt->primary_entries[0] ^= 0xa5; /* just XOR a non-zero value */
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700578 gpt->secondary_entries[TOTAL_ENTRIES_SIZE-1] ^= 0x5a;
vbendeb3ecaf772010-06-24 16:19:53 -0700579 EXPECT(1 == CheckEntries(e1, h1));
580 EXPECT(1 == CheckEntries(e2, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700581
582 return TEST_OK;
583}
584
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700585
586/* Tests if partition geometry is checked.
587 * All active (non-zero PartitionTypeGUID) partition entries should have:
588 * entry.StartingLBA >= header.FirstUsableLBA
589 * entry.EndingLBA <= header.LastUsableLBA
590 * entry.StartingLBA <= entry.EndingLBA
591 */
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700592static int ValidEntryTest() {
593 GptData* gpt = GetEmptyGptData();
594 GptHeader* h1 = (GptHeader*)gpt->primary_header;
595 GptEntry* e1 = (GptEntry*)(gpt->primary_entries);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700596
597 /* error case: entry.StartingLBA < header.FirstUsableLBA */
598 BuildTestGptData(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700599 e1[0].starting_lba = h1->first_usable_lba - 1;
600 RefreshCrc32(gpt);
vbendeb3ecaf772010-06-24 16:19:53 -0700601 EXPECT(1 == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700602
603 /* error case: entry.EndingLBA > header.LastUsableLBA */
604 BuildTestGptData(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700605 e1[2].ending_lba = h1->last_usable_lba + 1;
606 RefreshCrc32(gpt);
vbendeb3ecaf772010-06-24 16:19:53 -0700607 EXPECT(1 == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700608
609 /* error case: entry.StartingLBA > entry.EndingLBA */
610 BuildTestGptData(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700611 e1[3].starting_lba = e1[3].ending_lba + 1;
612 RefreshCrc32(gpt);
vbendeb3ecaf772010-06-24 16:19:53 -0700613 EXPECT(1 == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700614
615 /* case: non active entry should be ignored. */
616 BuildTestGptData(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700617 Memset(&e1[1].type, 0, sizeof(e1[1].type));
618 e1[1].starting_lba = e1[1].ending_lba + 1;
619 RefreshCrc32(gpt);
vbendeb3ecaf772010-06-24 16:19:53 -0700620 EXPECT(0 == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700621
622 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700623}
624
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700625
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700626/* Tests if overlapped partition tables can be detected. */
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700627static int OverlappedPartitionTest() {
628 GptData* gpt = GetEmptyGptData();
629 GptHeader* h = (GptHeader*)gpt->primary_header;
630 GptEntry* e = (GptEntry*)gpt->primary_entries;
631 int i, j;
632
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700633 struct {
634 int overlapped;
635 struct {
636 int active;
637 uint64_t starting_lba;
638 uint64_t ending_lba;
639 } entries[16]; /* enough for testing. */
640 } cases[] = {
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700641 {0, {{0, 100, 199}}},
642 {0, {{1, 100, 199}}},
643 {0, {{1, 100, 150}, {1, 200, 250}, {1, 300, 350}}},
644 {1, {{1, 200, 299}, {1, 100, 199}, {1, 100, 100}}},
645 {1, {{1, 200, 299}, {1, 100, 199}, {1, 299, 299}}},
646 {0, {{1, 300, 399}, {1, 200, 299}, {1, 100, 199}}},
647 {1, {{1, 100, 199}, {1, 199, 299}, {1, 299, 399}}},
648 {1, {{1, 100, 199}, {1, 200, 299}, {1, 75, 399}}},
649 {1, {{1, 100, 199}, {1, 75, 250}, {1, 200, 299}}},
650 {1, {{1, 75, 150}, {1, 100, 199}, {1, 200, 299}}},
651 {1, {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {1, 100, 399}}},
652 {0, {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {0, 100, 399}}},
653 {1, {{1, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400}}},
654 {1, {{0, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400}}},
655 {0, {{1, 200, 300}, {1, 100, 199}, {0, 100, 400}, {0, 300, 400}}},
656 {1, {{1, 200, 299}, {1, 100, 199}, {1, 199, 199}}},
657 {0, {{1, 200, 299}, {0, 100, 199}, {1, 199, 199}}},
658 {0, {{1, 200, 299}, {1, 100, 199}, {0, 199, 199}}},
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700659 {1, {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202},
660 {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206},
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700661 {1, 207, 207}, {1, 208, 208}, {1, 199, 199}}},
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700662 {0, {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202},
663 {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206},
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700664 {1, 207, 207}, {1, 208, 208}, {0, 199, 199}}},
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700665 };
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700666
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700667
668 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700669 BuildTestGptData(gpt);
670 ZeroEntries(gpt);
671 for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) {
672 if (!cases[i].entries[j].starting_lba)
673 break;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700674
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700675 if (cases[i].entries[j].active)
676 Memcpy(&e[j].type, &guid_kernel, sizeof(Guid));
Bill Richardsonaa8eda42010-08-27 09:31:26 -0700677 SetGuid(&e[j].unique, j);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700678 e[j].starting_lba = cases[i].entries[j].starting_lba;
679 e[j].ending_lba = cases[i].entries[j].ending_lba;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700680 }
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700681 RefreshCrc32(gpt);
682
vbendeb3ecaf772010-06-24 16:19:53 -0700683 EXPECT(cases[i].overlapped == CheckEntries(e, h));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700684 }
685 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700686}
687
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700688
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700689/* Test both sanity checking and repair. */
690static int SanityCheckTest() {
691 GptData* gpt = GetEmptyGptData();
692 GptHeader* h1 = (GptHeader*)gpt->primary_header;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700693
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700694 /* Unmodified test data is completely sane */
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700695 BuildTestGptData(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700696 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
697 EXPECT(MASK_BOTH == gpt->valid_headers);
698 EXPECT(MASK_BOTH == gpt->valid_entries);
699 /* Repair doesn't damage it */
700 GptRepair(gpt);
701 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
702 EXPECT(MASK_BOTH == gpt->valid_headers);
703 EXPECT(MASK_BOTH == gpt->valid_entries);
704 EXPECT(0 == gpt->modified);
705
706 /* Modify headers */
707 BuildTestGptData(gpt);
708 gpt->primary_header[0]++;
709 gpt->secondary_header[0]++;
710 EXPECT(GPT_ERROR_INVALID_HEADERS == GptSanityCheck(gpt));
711 EXPECT(0 == gpt->valid_headers);
712 EXPECT(0 == gpt->valid_entries);
713 /* Repair can't fix completely busted headers */
714 GptRepair(gpt);
715 EXPECT(GPT_ERROR_INVALID_HEADERS == GptSanityCheck(gpt));
716 EXPECT(0 == gpt->valid_headers);
717 EXPECT(0 == gpt->valid_entries);
718 EXPECT(0 == gpt->modified);
719
720 BuildTestGptData(gpt);
721 gpt->primary_header[0]++;
722 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
723 EXPECT(MASK_SECONDARY == gpt->valid_headers);
724 EXPECT(MASK_BOTH == gpt->valid_entries);
725 GptRepair(gpt);
726 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
727 EXPECT(MASK_BOTH == gpt->valid_headers);
728 EXPECT(MASK_BOTH == gpt->valid_entries);
729 EXPECT(GPT_MODIFIED_HEADER1 == gpt->modified);
730
731 BuildTestGptData(gpt);
732 gpt->secondary_header[0]++;
733 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
734 EXPECT(MASK_PRIMARY == gpt->valid_headers);
735 EXPECT(MASK_BOTH == gpt->valid_entries);
736 GptRepair(gpt);
737 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
738 EXPECT(MASK_BOTH == gpt->valid_headers);
739 EXPECT(MASK_BOTH == gpt->valid_entries);
740 EXPECT(GPT_MODIFIED_HEADER2 == gpt->modified);
741
742 /* Modify header1 and update its CRC. Since header2 is now different than
743 * header1, it'll be the one considered invalid. */
744 BuildTestGptData(gpt);
745 h1->size++;
746 RefreshCrc32(gpt);
747 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
748 EXPECT(MASK_PRIMARY == gpt->valid_headers);
749 EXPECT(MASK_BOTH == gpt->valid_entries);
750 GptRepair(gpt);
751 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
752 EXPECT(MASK_BOTH == gpt->valid_headers);
753 EXPECT(MASK_BOTH == gpt->valid_entries);
754 EXPECT(GPT_MODIFIED_HEADER2 == gpt->modified);
755
756 /* Modify entries */
757 BuildTestGptData(gpt);
758 gpt->primary_entries[0]++;
759 gpt->secondary_entries[0]++;
760 EXPECT(GPT_ERROR_INVALID_ENTRIES == GptSanityCheck(gpt));
761 EXPECT(MASK_BOTH == gpt->valid_headers);
762 EXPECT(MASK_NONE == gpt->valid_entries);
763 /* Repair can't fix both copies of entries being bad, either. */
764 GptRepair(gpt);
765 EXPECT(GPT_ERROR_INVALID_ENTRIES == GptSanityCheck(gpt));
766 EXPECT(MASK_BOTH == gpt->valid_headers);
767 EXPECT(MASK_NONE == gpt->valid_entries);
768 EXPECT(0 == gpt->modified);
769
770 BuildTestGptData(gpt);
771 gpt->primary_entries[0]++;
772 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
773 EXPECT(MASK_BOTH == gpt->valid_headers);
774 EXPECT(MASK_SECONDARY == gpt->valid_entries);
775 GptRepair(gpt);
776 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
777 EXPECT(MASK_BOTH == gpt->valid_headers);
778 EXPECT(MASK_BOTH == gpt->valid_entries);
779 EXPECT(GPT_MODIFIED_ENTRIES1 == gpt->modified);
780
781 BuildTestGptData(gpt);
782 gpt->secondary_entries[0]++;
783 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
784 EXPECT(MASK_BOTH == gpt->valid_headers);
785 EXPECT(MASK_PRIMARY == gpt->valid_entries);
786 GptRepair(gpt);
787 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
788 EXPECT(MASK_BOTH == gpt->valid_headers);
789 EXPECT(MASK_BOTH == gpt->valid_entries);
790 EXPECT(GPT_MODIFIED_ENTRIES2 == gpt->modified);
791
Bill Richardsonaa8eda42010-08-27 09:31:26 -0700792 /* Modify both header and entries */
793 BuildTestGptData(gpt);
794 gpt->primary_header[0]++;
795 gpt->primary_entries[0]++;
796 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
797 EXPECT(MASK_SECONDARY == gpt->valid_headers);
798 EXPECT(MASK_SECONDARY == gpt->valid_entries);
799 GptRepair(gpt);
800 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
801 EXPECT(MASK_BOTH == gpt->valid_headers);
802 EXPECT(MASK_BOTH == gpt->valid_entries);
803 EXPECT((GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1) == gpt->modified);
804
805 BuildTestGptData(gpt);
806 gpt->secondary_header[0]++;
807 gpt->secondary_entries[0]++;
808 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
809 EXPECT(MASK_PRIMARY == gpt->valid_headers);
810 EXPECT(MASK_PRIMARY == gpt->valid_entries);
811 GptRepair(gpt);
812 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
813 EXPECT(MASK_BOTH == gpt->valid_headers);
814 EXPECT(MASK_BOTH == gpt->valid_entries);
815 EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
816
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700817 /* Test cross-correction (h1+e2, h2+e1) */
818 BuildTestGptData(gpt);
819 gpt->primary_header[0]++;
820 gpt->secondary_entries[0]++;
821 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
822 EXPECT(MASK_SECONDARY == gpt->valid_headers);
823 EXPECT(MASK_PRIMARY == gpt->valid_entries);
824 GptRepair(gpt);
825 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
826 EXPECT(MASK_BOTH == gpt->valid_headers);
827 EXPECT(MASK_BOTH == gpt->valid_entries);
828 EXPECT((GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
829
830 BuildTestGptData(gpt);
831 gpt->secondary_header[0]++;
832 gpt->primary_entries[0]++;
833 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
834 EXPECT(MASK_PRIMARY == gpt->valid_headers);
835 EXPECT(MASK_SECONDARY == gpt->valid_entries);
836 GptRepair(gpt);
837 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
838 EXPECT(MASK_BOTH == gpt->valid_headers);
839 EXPECT(MASK_BOTH == gpt->valid_entries);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700840 EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES1) == gpt->modified);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700841
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700842 /* Test mismatched pairs (h1+e1 valid, h2+e2 valid but different.
843 * This simulates a partial update of the drive. */
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700844 BuildTestGptData(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700845 gpt->secondary_entries[0]++;
846 RefreshCrc32(gpt);
847 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
848 EXPECT(MASK_PRIMARY == gpt->valid_headers);
849 EXPECT(MASK_PRIMARY == gpt->valid_entries);
850 GptRepair(gpt);
851 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
852 EXPECT(MASK_BOTH == gpt->valid_headers);
853 EXPECT(MASK_BOTH == gpt->valid_entries);
854 EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700855
856 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700857}
858
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700859
860static int EntryAttributeGetSetTest() {
861 GptData* gpt = GetEmptyGptData();
862 GptEntry* e = (GptEntry*)(gpt->primary_entries);
863
vbendeb3ecaf772010-06-24 16:19:53 -0700864 e->attrs.whole = 0x0000000000000000ULL;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700865 SetEntrySuccessful(e, 1);
vbendeb3ecaf772010-06-24 16:19:53 -0700866 EXPECT(0x0100000000000000ULL == e->attrs.whole);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700867 EXPECT(1 == GetEntrySuccessful(e));
vbendeb3ecaf772010-06-24 16:19:53 -0700868 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700869 SetEntrySuccessful(e, 0);
vbendeb3ecaf772010-06-24 16:19:53 -0700870 EXPECT(0xFEFFFFFFFFFFFFFFULL == e->attrs.whole);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700871 EXPECT(0 == GetEntrySuccessful(e));
872
vbendeb3ecaf772010-06-24 16:19:53 -0700873 e->attrs.whole = 0x0000000000000000ULL;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700874 SetEntryTries(e, 15);
875 EXPECT(15 == GetEntryTries(e));
vbendeb3ecaf772010-06-24 16:19:53 -0700876 EXPECT(0x00F0000000000000ULL == e->attrs.whole);
877 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700878 SetEntryTries(e, 0);
vbendeb3ecaf772010-06-24 16:19:53 -0700879 EXPECT(0xFF0FFFFFFFFFFFFFULL == e->attrs.whole);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700880 EXPECT(0 == GetEntryTries(e));
881
vbendeb3ecaf772010-06-24 16:19:53 -0700882 e->attrs.whole = 0x0000000000000000ULL;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700883 SetEntryPriority(e, 15);
vbendeb3ecaf772010-06-24 16:19:53 -0700884 EXPECT(0x000F000000000000ULL == e->attrs.whole);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700885 EXPECT(15 == GetEntryPriority(e));
vbendeb3ecaf772010-06-24 16:19:53 -0700886 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700887 SetEntryPriority(e, 0);
vbendeb3ecaf772010-06-24 16:19:53 -0700888 EXPECT(0xFFF0FFFFFFFFFFFFULL == e->attrs.whole);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700889 EXPECT(0 == GetEntryPriority(e));
890
vbendeb3ecaf772010-06-24 16:19:53 -0700891 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700892 EXPECT(1 == GetEntrySuccessful(e));
893 EXPECT(15 == GetEntryPriority(e));
894 EXPECT(15 == GetEntryTries(e));
895
vbendeb3ecaf772010-06-24 16:19:53 -0700896 e->attrs.whole = 0x0123000000000000ULL;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700897 EXPECT(1 == GetEntrySuccessful(e));
898 EXPECT(2 == GetEntryTries(e));
899 EXPECT(3 == GetEntryPriority(e));
900
901 return TEST_OK;
902}
903
904
905static int EntryTypeTest() {
906 GptData* gpt = GetEmptyGptData();
907 GptEntry* e = (GptEntry*)(gpt->primary_entries);
908
909 Memcpy(&e->type, &guid_zero, sizeof(Guid));
910 EXPECT(1 == IsUnusedEntry(e));
911 EXPECT(0 == IsKernelEntry(e));
912
913 Memcpy(&e->type, &guid_kernel, sizeof(Guid));
914 EXPECT(0 == IsUnusedEntry(e));
915 EXPECT(1 == IsKernelEntry(e));
916
917 Memcpy(&e->type, &guid_rootfs, sizeof(Guid));
918 EXPECT(0 == IsUnusedEntry(e));
919 EXPECT(0 == IsKernelEntry(e));
920
921 return TEST_OK;
922}
923
924
925/* Make an entry unused by clearing its type. */
926static void FreeEntry(GptEntry* e) {
927 Memset(&e->type, 0, sizeof(Guid));
928}
929
930
931/* Set up an entry. */
932static void FillEntry(GptEntry* e, int is_kernel,
933 int priority, int successful, int tries) {
934 Memcpy(&e->type, (is_kernel ? &guid_kernel : &guid_zero), sizeof(Guid));
935 SetEntryPriority(e, priority);
936 SetEntrySuccessful(e, successful);
937 SetEntryTries(e, tries);
938}
939
940
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700941/* Invalidate all kernel entries and expect GptNextKernelEntry() cannot find
942 * any usable kernel entry.
943 */
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700944static int NoValidKernelEntryTest() {
945 GptData* gpt = GetEmptyGptData();
946 GptEntry* e1 = (GptEntry*)(gpt->primary_entries);
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700947
948 BuildTestGptData(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700949 SetEntryPriority(e1 + KERNEL_A, 0);
950 FreeEntry(e1 + KERNEL_B);
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700951 RefreshCrc32(gpt);
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700952 EXPECT(GPT_ERROR_NO_VALID_KERNEL == GptNextKernelEntry(gpt, NULL, NULL));
953
954 return TEST_OK;
955}
956
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700957
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700958static int GetNextNormalTest() {
959 GptData* gpt = GetEmptyGptData();
960 GptEntry* e1 = (GptEntry*)(gpt->primary_entries);
961 uint64_t start, size;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700962
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700963 /* Normal case - both kernels successful */
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700964 BuildTestGptData(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700965 FillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
966 FillEntry(e1 + KERNEL_B, 1, 2, 1, 0);
967 RefreshCrc32(gpt);
968 GptInit(gpt);
969
970 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
971 EXPECT(KERNEL_A == gpt->current_kernel);
972 EXPECT(34 == start);
973 EXPECT(100 == size);
974
975 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
976 EXPECT(KERNEL_B == gpt->current_kernel);
977 EXPECT(134 == start);
978 EXPECT(99 == size);
979
980 EXPECT(GPT_ERROR_NO_VALID_KERNEL == GptNextKernelEntry(gpt, &start, &size));
981 EXPECT(-1 == gpt->current_kernel);
982
983 /* Call as many times as you want; you won't get another kernel... */
984 EXPECT(GPT_ERROR_NO_VALID_KERNEL == GptNextKernelEntry(gpt, &start, &size));
985 EXPECT(-1 == gpt->current_kernel);
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700986
987 return TEST_OK;
988}
989
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700990
991static int GetNextPrioTest() {
992 GptData* gpt = GetEmptyGptData();
993 GptEntry* e1 = (GptEntry*)(gpt->primary_entries);
994 uint64_t start, size;
995
996 /* Priority 3, 4, 0, 4 - should boot order B, Y, A */
997 BuildTestGptData(gpt);
998 FillEntry(e1 + KERNEL_A, 1, 3, 1, 0);
999 FillEntry(e1 + KERNEL_B, 1, 4, 1, 0);
1000 FillEntry(e1 + KERNEL_X, 1, 0, 1, 0);
1001 FillEntry(e1 + KERNEL_Y, 1, 4, 1, 0);
1002 RefreshCrc32(gpt);
1003 GptInit(gpt);
1004
1005 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1006 EXPECT(KERNEL_B == gpt->current_kernel);
1007 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1008 EXPECT(KERNEL_Y == gpt->current_kernel);
1009 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1010 EXPECT(KERNEL_A == gpt->current_kernel);
1011 EXPECT(GPT_ERROR_NO_VALID_KERNEL == GptNextKernelEntry(gpt, &start, &size));
1012
1013 return TEST_OK;
1014}
1015
1016
1017static int GetNextTriesTest() {
1018 GptData* gpt = GetEmptyGptData();
1019 GptEntry* e1 = (GptEntry*)(gpt->primary_entries);
1020 uint64_t start, size;
1021
1022 /* Tries=nonzero is attempted just like success, but tries=0 isn't */
1023 BuildTestGptData(gpt);
1024 FillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
1025 FillEntry(e1 + KERNEL_B, 1, 3, 0, 0);
1026 FillEntry(e1 + KERNEL_X, 1, 4, 0, 1);
1027 FillEntry(e1 + KERNEL_Y, 1, 0, 0, 5);
1028 RefreshCrc32(gpt);
1029 GptInit(gpt);
1030
1031 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1032 EXPECT(KERNEL_X == gpt->current_kernel);
1033 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1034 EXPECT(KERNEL_A == gpt->current_kernel);
1035 EXPECT(GPT_ERROR_NO_VALID_KERNEL == GptNextKernelEntry(gpt, &start, &size));
1036
1037 return TEST_OK;
1038}
1039
1040
1041static int GptUpdateTest() {
1042 GptData* gpt = GetEmptyGptData();
1043 GptEntry* e = (GptEntry*)(gpt->primary_entries);
1044 GptEntry* e2 = (GptEntry*)(gpt->secondary_entries);
1045 uint64_t start, size;
1046
1047 /* Tries=nonzero is attempted just like success, but tries=0 isn't */
1048 BuildTestGptData(gpt);
1049 FillEntry(e + KERNEL_A, 1, 4, 1, 0);
1050 FillEntry(e + KERNEL_B, 1, 3, 0, 2);
1051 FillEntry(e + KERNEL_X, 1, 2, 0, 2);
1052 RefreshCrc32(gpt);
1053 GptInit(gpt);
1054 gpt->modified = 0; /* Nothing modified yet */
1055
1056 /* Successful kernel */
1057 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1058 EXPECT(KERNEL_A == gpt->current_kernel);
1059 EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
1060 EXPECT(4 == GetEntryPriority(e + KERNEL_A));
1061 EXPECT(0 == GetEntryTries(e + KERNEL_A));
1062 EXPECT(1 == GetEntrySuccessful(e2 + KERNEL_A));
1063 EXPECT(4 == GetEntryPriority(e2 + KERNEL_A));
1064 EXPECT(0 == GetEntryTries(e2 + KERNEL_A));
1065 /* Trying successful kernel changes nothing */
1066 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
1067 EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
1068 EXPECT(4 == GetEntryPriority(e + KERNEL_A));
1069 EXPECT(0 == GetEntryTries(e + KERNEL_A));
1070 EXPECT(0 == gpt->modified);
1071 /* Marking it bad does, though */
1072 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
1073 EXPECT(0 == GetEntrySuccessful(e + KERNEL_A));
1074 EXPECT(0 == GetEntryPriority(e + KERNEL_A));
1075 EXPECT(0 == GetEntryTries(e + KERNEL_A));
1076 /* Which affects both copies of the partition entries */
1077 EXPECT(0 == GetEntrySuccessful(e2 + KERNEL_A));
1078 EXPECT(0 == GetEntryPriority(e2 + KERNEL_A));
1079 EXPECT(0 == GetEntryTries(e2 + KERNEL_A));
1080 /* And that's caused the GPT to need updating */
1081 EXPECT(0x0F == gpt->modified);
1082
1083 /* Kernel with tries */
1084 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1085 EXPECT(KERNEL_B == gpt->current_kernel);
1086 EXPECT(0 == GetEntrySuccessful(e + KERNEL_B));
1087 EXPECT(3 == GetEntryPriority(e + KERNEL_B));
1088 EXPECT(2 == GetEntryTries(e + KERNEL_B));
1089 /* Marking it bad clears it */
1090 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
1091 EXPECT(0 == GetEntrySuccessful(e + KERNEL_B));
1092 EXPECT(0 == GetEntryPriority(e + KERNEL_B));
1093 EXPECT(0 == GetEntryTries(e + KERNEL_B));
1094
1095 /* Another kernel with tries */
1096 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1097 EXPECT(KERNEL_X == gpt->current_kernel);
1098 EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
1099 EXPECT(2 == GetEntryPriority(e + KERNEL_X));
1100 EXPECT(2 == GetEntryTries(e + KERNEL_X));
1101 /* Trying it uses up a try */
1102 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
1103 EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
1104 EXPECT(2 == GetEntryPriority(e + KERNEL_X));
1105 EXPECT(1 == GetEntryTries(e + KERNEL_X));
1106 EXPECT(0 == GetEntrySuccessful(e2 + KERNEL_X));
1107 EXPECT(2 == GetEntryPriority(e2 + KERNEL_X));
1108 EXPECT(1 == GetEntryTries(e2 + KERNEL_X));
1109 /* Trying it again marks it inactive */
1110 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
1111 EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
1112 EXPECT(0 == GetEntryPriority(e + KERNEL_X));
1113 EXPECT(0 == GetEntryTries(e + KERNEL_X));
1114
1115 return TEST_OK;
1116}
1117
1118
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001119/* Given an invalid kernel type, and expect GptUpdateKernelEntry() returns
1120 * GPT_ERROR_INVALID_UPDATE_TYPE. */
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001121static int UpdateInvalidKernelTypeTest() {
1122 GptData* gpt = GetEmptyGptData();
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001123
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001124 BuildTestGptData(gpt);
1125 gpt->current_kernel = 0; /* anything, but not CGPT_KERNEL_ENTRY_NOT_FOUND */
1126 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1127 GptUpdateKernelEntry(gpt, 99)); /* any invalid update_type value */
1128
1129 return TEST_OK;
1130}
1131
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001132
1133/* Tests duplicate UniqueGuids can be detected. */
1134static int DuplicateUniqueGuidTest() {
1135 GptData* gpt = GetEmptyGptData();
1136 GptHeader* h = (GptHeader*)gpt->primary_header;
1137 GptEntry* e = (GptEntry*)gpt->primary_entries;
1138 int i, j;
1139
1140 struct {
1141 int duplicate;
1142 struct {
1143 uint64_t starting_lba;
1144 uint64_t ending_lba;
1145 uint32_t type_guid;
1146 uint32_t unique_guid;
1147 } entries[16]; /* enough for testing. */
1148 } cases[] = {
1149 {0, {{100, 109, 1, 1},
1150 {110, 119, 2, 2},
1151 {120, 129, 3, 3},
1152 {130, 139, 4, 4},
1153 }},
1154 {0, {{100, 109, 1, 1},
1155 {110, 119, 1, 2},
1156 {120, 129, 2, 3},
1157 {130, 139, 2, 4},
1158 }},
1159 {1, {{100, 109, 1, 1},
1160 {110, 119, 2, 2},
1161 {120, 129, 3, 1},
1162 {130, 139, 4, 4},
1163 }},
1164 {1, {{100, 109, 1, 1},
1165 {110, 119, 1, 2},
1166 {120, 129, 2, 3},
1167 {130, 139, 2, 2},
1168 }},
1169 };
1170
1171 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
1172 BuildTestGptData(gpt);
1173 ZeroEntries(gpt);
1174 for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) {
1175 if (!cases[i].entries[j].starting_lba)
1176 break;
1177
1178 e[j].starting_lba = cases[i].entries[j].starting_lba;
1179 e[j].ending_lba = cases[i].entries[j].ending_lba;
1180 SetGuid(&e[j].type, cases[i].entries[j].type_guid);
1181 SetGuid(&e[j].unique, cases[i].entries[j].unique_guid);
1182 }
1183 RefreshCrc32(gpt);
1184
1185 EXPECT(cases[i].duplicate == CheckEntries(e, h));
1186 }
1187 return TEST_OK;
1188}
1189
1190
1191
vbendeb3ecaf772010-06-24 16:19:53 -07001192/* disable MSVC warnings on unused arguments */
1193__pragma(warning (disable: 4100))
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001194
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001195int main(int argc, char *argv[]) {
1196 int i;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001197 int error_count = 0;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001198 struct {
1199 char *name;
1200 test_func fp;
1201 int retval;
1202 } test_cases[] = {
Randall Spangler81d09962010-06-23 10:15:38 -07001203 { TEST_CASE(StructSizeTest), },
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001204 { TEST_CASE(TestBuildTestGptData), },
1205 { TEST_CASE(ParameterTests), },
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001206 { TEST_CASE(HeaderCrcTest), },
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -07001207 { TEST_CASE(SignatureTest), },
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001208 { TEST_CASE(RevisionTest), },
1209 { TEST_CASE(SizeTest), },
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001210 { TEST_CASE(CrcFieldTest), },
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001211 { TEST_CASE(ReservedFieldsTest), },
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001212 { TEST_CASE(SizeOfPartitionEntryTest), },
1213 { TEST_CASE(NumberOfPartitionEntriesTest), },
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001214 { TEST_CASE(MyLbaTest), },
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001215 { TEST_CASE(FirstUsableLbaAndLastUsableLbaTest), },
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001216 { TEST_CASE(EntriesCrcTest), },
1217 { TEST_CASE(ValidEntryTest), },
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001218 { TEST_CASE(OverlappedPartitionTest), },
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001219 { TEST_CASE(SanityCheckTest), },
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001220 { TEST_CASE(NoValidKernelEntryTest), },
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001221 { TEST_CASE(EntryAttributeGetSetTest), },
1222 { TEST_CASE(EntryTypeTest), },
1223 { TEST_CASE(GetNextNormalTest), },
1224 { TEST_CASE(GetNextPrioTest), },
1225 { TEST_CASE(GetNextTriesTest), },
1226 { TEST_CASE(GptUpdateTest), },
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001227 { TEST_CASE(UpdateInvalidKernelTypeTest), },
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001228 { TEST_CASE(DuplicateUniqueGuidTest), },
Louis Yung-Chieh Lob31ddce2010-05-21 16:35:44 +08001229 { TEST_CASE(TestCrc32TestVectors), },
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001230 };
1231
1232 for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
1233 printf("Running %s() ...\n", test_cases[i].name);
1234 test_cases[i].retval = test_cases[i].fp();
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001235 if (test_cases[i].retval) {
1236 printf(COL_RED "[ERROR]\n\n" COL_STOP);
1237 ++error_count;
1238 } else {
1239 printf(COL_GREEN "[PASS]\n\n" COL_STOP);
1240 }
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001241 }
1242
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001243 if (error_count) {
1244 printf("\n--------------------------------------------------\n");
1245 printf(COL_RED "The following %d test cases are failed:\n" COL_STOP,
1246 error_count);
1247 for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
1248 if (test_cases[i].retval)
1249 printf(" %s()\n", test_cases[i].name);
1250 }
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001251 }
1252
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001253 return (error_count) ? 1 : 0;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001254}