blob: 9e446c261ecb05b12f760252ed9ac8246c5b87b3 [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"
Albert Chaulk5c9e4532013-03-20 16:03:49 -070013#include "mtdlib.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
Randall Spanglere9213a72013-01-24 11:19:55 -080017/*
18 * Testing partition layout (sector_bytes=512)
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070019 *
20 * LBA Size Usage
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -070021 * ---------------------------------------------------------
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070022 * 0 1 PMBR
23 * 1 1 primary partition header
24 * 2 32 primary partition entries (128B * 128)
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -070025 * 34 100 kernel A (index: 0)
26 * 134 100 root A (index: 1)
27 * 234 100 root B (index: 2)
28 * 334 100 kernel B (index: 3)
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070029 * 434 32 secondary partition entries
30 * 466 1 secondary partition header
31 * 467
32 */
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -070033#define KERNEL_A 0
Randall Spangler3dcf9dc2010-06-02 12:46:17 -070034#define KERNEL_B 1
35#define ROOTFS_A 2
36#define ROOTFS_B 3
37#define KERNEL_X 2 /* Overload ROOTFS_A, for some GetNext tests */
38#define KERNEL_Y 3 /* Overload ROOTFS_B, for some GetNext tests */
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -070039
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070040#define DEFAULT_SECTOR_SIZE 512
41#define MAX_SECTOR_SIZE 4096
42#define DEFAULT_DRIVE_SECTORS 467
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070043#define PARTITION_ENTRIES_SIZE TOTAL_ENTRIES_SIZE /* 16384 */
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070044
Randall Spangler3dcf9dc2010-06-02 12:46:17 -070045static const Guid guid_zero = {{{0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0}}}};
46static const Guid guid_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
47static const Guid guid_rootfs = GPT_ENT_TYPE_CHROMEOS_ROOTFS;
48
Randall Spanglere9213a72013-01-24 11:19:55 -080049/*
50 * Copy a random-for-this-program-only Guid into the dest. The num parameter
Bill Richardsonaa8eda42010-08-27 09:31:26 -070051 * completely determines the Guid.
52 */
Randall Spanglere9213a72013-01-24 11:19:55 -080053static void SetGuid(void *dest, uint32_t num)
54{
55 Guid g = {{{num,0xd450,0x44bc,0xa6,0x93,
56 {0xb8,0xac,0x75,0x5f,0xcd,0x48}}}};
57 Memcpy(dest, &g, sizeof(Guid));
Bill Richardsonaa8eda42010-08-27 09:31:26 -070058}
Randall Spangler3dcf9dc2010-06-02 12:46:17 -070059
Randall Spanglere9213a72013-01-24 11:19:55 -080060/*
61 * Given a GptData pointer, first re-calculate entries CRC32 value, then reset
62 * header CRC32 value to 0, and calculate header CRC32 value. Both primary and
63 * secondary are updated.
64 */
65static void RefreshCrc32(GptData *gpt)
66{
67 GptHeader *header, *header2;
68 GptEntry *entries, *entries2;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070069
Randall Spanglere9213a72013-01-24 11:19:55 -080070 header = (GptHeader *)gpt->primary_header;
71 entries = (GptEntry *)gpt->primary_entries;
72 header2 = (GptHeader *)gpt->secondary_header;
73 entries2 = (GptEntry *)gpt->secondary_entries;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070074
Randall Spanglere9213a72013-01-24 11:19:55 -080075 header->entries_crc32 =
76 Crc32((uint8_t *)entries,
77 header->number_of_entries * header->size_of_entry);
78 header->header_crc32 = 0;
79 header->header_crc32 = Crc32((uint8_t *)header, header->size);
80 header2->entries_crc32 =
81 Crc32((uint8_t *)entries2,
82 header2->number_of_entries * header2->size_of_entry);
83 header2->header_crc32 = 0;
84 header2->header_crc32 = Crc32((uint8_t *)header2, header2->size);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070085}
86
Randall Spanglere9213a72013-01-24 11:19:55 -080087static void ZeroHeaders(GptData *gpt)
88{
89 Memset(gpt->primary_header, 0, MAX_SECTOR_SIZE);
90 Memset(gpt->secondary_header, 0, MAX_SECTOR_SIZE);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070091}
92
Randall Spanglere9213a72013-01-24 11:19:55 -080093static void ZeroEntries(GptData *gpt)
94{
95 Memset(gpt->primary_entries, 0, PARTITION_ENTRIES_SIZE);
96 Memset(gpt->secondary_entries, 0, PARTITION_ENTRIES_SIZE);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070097}
98
Randall Spanglere9213a72013-01-24 11:19:55 -080099static void ZeroHeadersEntries(GptData *gpt)
100{
101 ZeroHeaders(gpt);
102 ZeroEntries(gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700103}
104
Randall Spanglere9213a72013-01-24 11:19:55 -0800105/*
106 * Return a pointer to a static GptData instance (no free is required).
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700107 * All fields are zero except 4 pointers linking to header and entries.
Randall Spanglere9213a72013-01-24 11:19:55 -0800108 * All content of headers and entries are zero.
109 */
110static GptData *GetEmptyGptData(void)
111{
112 static GptData gpt;
113 static uint8_t primary_header[MAX_SECTOR_SIZE];
114 static uint8_t primary_entries[PARTITION_ENTRIES_SIZE];
115 static uint8_t secondary_header[MAX_SECTOR_SIZE];
116 static uint8_t secondary_entries[PARTITION_ENTRIES_SIZE];
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700117
Randall Spanglere9213a72013-01-24 11:19:55 -0800118 Memset(&gpt, 0, sizeof(gpt));
119 gpt.primary_header = primary_header;
120 gpt.primary_entries = primary_entries;
121 gpt.secondary_header = secondary_header;
122 gpt.secondary_entries = secondary_entries;
123 ZeroHeadersEntries(&gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700124
Randall Spanglere9213a72013-01-24 11:19:55 -0800125 /* Initialize GptData internal states. */
126 gpt.current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700127
Randall Spanglere9213a72013-01-24 11:19:55 -0800128 return &gpt;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700129}
130
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700131static MtdData *GetEmptyMtdData() {
132 static MtdData mtd;
133 Memset(&mtd, 0, sizeof(mtd));
134 mtd.current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
135 return &mtd;
136}
137
Randall Spanglere9213a72013-01-24 11:19:55 -0800138/*
139 * Fill in most of fields and creates the layout described in the top of this
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700140 * file. Before calling this function, primary/secondary header/entries must
141 * have been pointed to the buffer, say, a gpt returned from GetEmptyGptData().
142 * This function returns a good (valid) copy of GPT layout described in top of
Randall Spanglere9213a72013-01-24 11:19:55 -0800143 * this file.
144 */
145static void BuildTestGptData(GptData *gpt)
146{
147 GptHeader *header, *header2;
148 GptEntry *entries, *entries2;
149 Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
150 Guid chromeos_rootfs = GPT_ENT_TYPE_CHROMEOS_ROOTFS;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700151
Randall Spanglere9213a72013-01-24 11:19:55 -0800152 gpt->sector_bytes = DEFAULT_SECTOR_SIZE;
153 gpt->drive_sectors = DEFAULT_DRIVE_SECTORS;
154 gpt->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
155 gpt->valid_headers = MASK_BOTH;
156 gpt->valid_entries = MASK_BOTH;
157 gpt->modified = 0;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700158
Randall Spanglere9213a72013-01-24 11:19:55 -0800159 /* Build primary */
160 header = (GptHeader *)gpt->primary_header;
161 entries = (GptEntry *)gpt->primary_entries;
162 Memcpy(header->signature, GPT_HEADER_SIGNATURE,
163 sizeof(GPT_HEADER_SIGNATURE));
164 header->revision = GPT_HEADER_REVISION;
165 header->size = sizeof(GptHeader);
166 header->reserved_zero = 0;
167 header->my_lba = 1;
168 header->alternate_lba = DEFAULT_DRIVE_SECTORS - 1;
169 header->first_usable_lba = 34;
170 header->last_usable_lba = DEFAULT_DRIVE_SECTORS - 1 - 32 - 1; /* 433 */
171 header->entries_lba = 2;
172 /* 512B / 128B * 32sectors = 128 entries */
173 header->number_of_entries = 128;
174 header->size_of_entry = 128; /* bytes */
175 Memcpy(&entries[0].type, &chromeos_kernel, sizeof(chromeos_kernel));
176 SetGuid(&entries[0].unique, 0);
177 entries[0].starting_lba = 34;
178 entries[0].ending_lba = 133;
179 Memcpy(&entries[1].type, &chromeos_rootfs, sizeof(chromeos_rootfs));
180 SetGuid(&entries[1].unique, 1);
181 entries[1].starting_lba = 134;
182 entries[1].ending_lba = 232;
183 Memcpy(&entries[2].type, &chromeos_rootfs, sizeof(chromeos_rootfs));
184 SetGuid(&entries[2].unique, 2);
185 entries[2].starting_lba = 234;
186 entries[2].ending_lba = 331;
187 Memcpy(&entries[3].type, &chromeos_kernel, sizeof(chromeos_kernel));
188 SetGuid(&entries[3].unique, 3);
189 entries[3].starting_lba = 334;
190 entries[3].ending_lba = 430;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700191
Randall Spanglere9213a72013-01-24 11:19:55 -0800192 /* Build secondary */
193 header2 = (GptHeader *)gpt->secondary_header;
194 entries2 = (GptEntry *)gpt->secondary_entries;
195 Memcpy(header2, header, sizeof(GptHeader));
196 Memcpy(entries2, entries, PARTITION_ENTRIES_SIZE);
197 header2->my_lba = DEFAULT_DRIVE_SECTORS - 1; /* 466 */
198 header2->alternate_lba = 1;
199 header2->entries_lba = DEFAULT_DRIVE_SECTORS - 1 - 32; /* 434 */
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700200
Randall Spanglere9213a72013-01-24 11:19:55 -0800201 RefreshCrc32(gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700202}
203
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700204static void BuildTestMtdData(MtdData *mtd) {
205 MtdDiskPartition *partitions;
206
207 mtd->sector_bytes = DEFAULT_SECTOR_SIZE;
208 mtd->drive_sectors = DEFAULT_DRIVE_SECTORS;
209 mtd->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
210 mtd->modified = 0;
211 Memset(&mtd->primary, 0, sizeof(mtd->primary));
212
213 Memcpy(mtd->primary.signature, MTD_DRIVE_SIGNATURE,
214 sizeof(mtd->primary.signature));
215 mtd->primary.first_lba = 32;
216 mtd->primary.last_lba = DEFAULT_DRIVE_SECTORS - 1;
217 mtd->primary.size = MTD_DRIVE_V1_SIZE;
218
219 /* These values are not used directly by the library, but they are checked */
220 mtd->flash_page_bytes = mtd->sector_bytes * 8;
221 mtd->flash_block_bytes = mtd->flash_page_bytes * 8;
222 mtd->fts_block_offset = 1;
223 mtd->fts_block_size = 1;
224
225 partitions = &mtd->primary.partitions[0];
226 partitions[0].starting_lba = 34;
227 partitions[0].ending_lba = 133;
228 partitions[0].flags =
229 MTD_PARTITION_TYPE_CHROMEOS_KERNEL << MTD_ATTRIBUTE_TYPE_OFFSET;
230 partitions[1].starting_lba = 134;
231 partitions[1].ending_lba = 232;
232 partitions[1].flags =
233 MTD_PARTITION_TYPE_CHROMEOS_ROOTFS << MTD_ATTRIBUTE_TYPE_OFFSET;
234 partitions[2].starting_lba = 234;
235 partitions[2].ending_lba = 331;
236 partitions[2].flags =
237 MTD_PARTITION_TYPE_CHROMEOS_KERNEL << MTD_ATTRIBUTE_TYPE_OFFSET;
238 partitions[3].starting_lba = 334;
239 partitions[3].ending_lba = 430;
240 partitions[3].flags =
241 MTD_PARTITION_TYPE_CHROMEOS_ROOTFS << MTD_ATTRIBUTE_TYPE_OFFSET;
242
243 mtd->primary.crc32 = 0;
244 mtd->primary.crc32 = Crc32(&mtd->primary, MTD_DRIVE_V1_SIZE);
245}
246
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700247
Randall Spanglere9213a72013-01-24 11:19:55 -0800248/*
249 * Test if the structures are the expected size; if this fails, struct packing
250 * is not working properly.
251 */
252static int StructSizeTest(void)
253{
Randall Spangler81d09962010-06-23 10:15:38 -0700254
Randall Spanglere9213a72013-01-24 11:19:55 -0800255 EXPECT(GUID_EXPECTED_SIZE == sizeof(Guid));
256 EXPECT(GPTHEADER_EXPECTED_SIZE == sizeof(GptHeader));
257 EXPECT(GPTENTRY_EXPECTED_SIZE == sizeof(GptEntry));
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700258 EXPECT(MTDENTRY_EXPECTED_SIZE == sizeof(MtdDiskPartition));
259 EXPECT(MTDLAYOUT_EXPECTED_SIZE == sizeof(MtdDiskLayout));
Randall Spanglere9213a72013-01-24 11:19:55 -0800260 return TEST_OK;
Randall Spangler81d09962010-06-23 10:15:38 -0700261}
262
263
Randall Spanglere9213a72013-01-24 11:19:55 -0800264/* Test if the default structure returned by BuildTestGptData() is good. */
265static int TestBuildTestGptData(void)
266{
267 GptData *gpt;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700268
Randall Spanglere9213a72013-01-24 11:19:55 -0800269 gpt = GetEmptyGptData();
270 BuildTestGptData(gpt);
271 EXPECT(GPT_SUCCESS == GptInit(gpt));
Randall Spangler0bda13f2013-01-24 12:25:26 -0800272 gpt->sector_bytes = 0;
273 EXPECT(GPT_ERROR_INVALID_SECTOR_SIZE == GptInit(gpt));
Randall Spanglere9213a72013-01-24 11:19:55 -0800274 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700275}
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700276
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700277static int TestBuildTestMtdData() {
278 MtdData *mtd = GetEmptyMtdData();
279
280 BuildTestMtdData(mtd);
281 EXPECT(GPT_SUCCESS == MtdInit(mtd));
282 return TEST_OK;
283}
284
Randall Spanglere9213a72013-01-24 11:19:55 -0800285/*
286 * Test if wrong sector_bytes or drive_sectors is detected by GptInit().
287 * Currently we only support 512 bytes per sector. In the future, we may
288 * support other sizes. A too small drive_sectors should be rejected by
289 * GptInit().
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700290 * For MtdInit(), additionally test various flash geometries to verify
291 * that only valid ones are accepted.
Randall Spanglere9213a72013-01-24 11:19:55 -0800292 */
293static int ParameterTests(void)
294{
295 GptData *gpt;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700296 MtdData *mtd;
Randall Spanglere9213a72013-01-24 11:19:55 -0800297 struct {
298 uint32_t sector_bytes;
299 uint64_t drive_sectors;
300 int expected_retval;
301 } cases[] = {
302 {512, DEFAULT_DRIVE_SECTORS, GPT_SUCCESS},
303 {520, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
304 {512, 0, GPT_ERROR_INVALID_SECTOR_NUMBER},
305 {512, 66, GPT_ERROR_INVALID_SECTOR_NUMBER},
306 {512, GPT_PMBR_SECTOR + GPT_HEADER_SECTOR * 2 +
307 GPT_ENTRIES_SECTORS * 2, GPT_SUCCESS},
308 {4096, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
309 };
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700310 struct {
311 uint32_t sector_bytes;
312 uint32_t drive_sectors;
313 uint32_t flash_page_bytes;
314 uint32_t flash_block_bytes;
315 int expected_retval;
316 } mtdcases[] = {
317 {512, DEFAULT_DRIVE_SECTORS, 8*512,
318 8*512, GPT_SUCCESS},
319 {510, DEFAULT_DRIVE_SECTORS, 8*512,
320 8*512, GPT_ERROR_INVALID_SECTOR_SIZE},
321 {512, DEFAULT_DRIVE_SECTORS, 8*512,
322 8*512, GPT_SUCCESS},
323 {512, DEFAULT_DRIVE_SECTORS, 512,
324 8*512, GPT_SUCCESS},
325 {512, DEFAULT_DRIVE_SECTORS, 8*512,
326 10*512, GPT_ERROR_INVALID_FLASH_GEOMETRY},
327 {512, DEFAULT_DRIVE_SECTORS, 3*512,
328 9*512, GPT_SUCCESS},
329 {512, DEFAULT_DRIVE_SECTORS, 8*512,
330 6*512, GPT_ERROR_INVALID_FLASH_GEOMETRY},
331 {512, DEFAULT_DRIVE_SECTORS, 256,
332 6*512, GPT_ERROR_INVALID_FLASH_GEOMETRY},
333 {512, DEFAULT_DRIVE_SECTORS, 512,
334 6*512 + 256, GPT_ERROR_INVALID_FLASH_GEOMETRY},
335 };
Randall Spanglere9213a72013-01-24 11:19:55 -0800336 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700337
Randall Spanglere9213a72013-01-24 11:19:55 -0800338 gpt = GetEmptyGptData();
339 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
340 BuildTestGptData(gpt);
341 gpt->sector_bytes = cases[i].sector_bytes;
342 gpt->drive_sectors = cases[i].drive_sectors;
343 EXPECT(cases[i].expected_retval == CheckParameters(gpt));
344 }
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700345
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700346 mtd = GetEmptyMtdData();
347 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
348 BuildTestMtdData(mtd);
349 mtd->sector_bytes = mtdcases[i].sector_bytes;
350 mtd->drive_sectors = mtdcases[i].drive_sectors;
351 mtd->flash_block_bytes = mtdcases[i].flash_block_bytes;
352 mtd->flash_page_bytes = mtdcases[i].flash_page_bytes;
353 if(mtdcases[i].expected_retval != MtdCheckParameters(mtd)) {
354 printf("i=%d\n",i);
355 }
356 EXPECT(mtdcases[i].expected_retval == MtdCheckParameters(mtd));
357 }
358
Randall Spanglere9213a72013-01-24 11:19:55 -0800359 return TEST_OK;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700360}
361
Randall Spanglere9213a72013-01-24 11:19:55 -0800362/* Test if header CRC in two copies are calculated. */
363static int HeaderCrcTest(void)
364{
365 GptData *gpt = GetEmptyGptData();
366 GptHeader *h1 = (GptHeader *)gpt->primary_header;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700367
Randall Spanglere9213a72013-01-24 11:19:55 -0800368 BuildTestGptData(gpt);
369 EXPECT(HeaderCrc(h1) == h1->header_crc32);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700370
Randall Spanglere9213a72013-01-24 11:19:55 -0800371 /* CRC covers first byte of header */
372 BuildTestGptData(gpt);
373 gpt->primary_header[0] ^= 0xa5;
374 EXPECT(HeaderCrc(h1) != h1->header_crc32);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700375
Randall Spanglere9213a72013-01-24 11:19:55 -0800376 /* CRC covers last byte of header */
377 BuildTestGptData(gpt);
378 gpt->primary_header[h1->size - 1] ^= 0x5a;
379 EXPECT(HeaderCrc(h1) != h1->header_crc32);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700380
Randall Spanglere9213a72013-01-24 11:19:55 -0800381 /* CRC only covers header */
382 BuildTestGptData(gpt);
383 gpt->primary_header[h1->size] ^= 0x5a;
384 EXPECT(HeaderCrc(h1) == h1->header_crc32);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700385
Randall Spanglere9213a72013-01-24 11:19:55 -0800386 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700387}
388
Randall Spangler0bda13f2013-01-24 12:25:26 -0800389/* Test if header-same comparison works. */
390static int HeaderSameTest(void)
391{
392 GptData *gpt = GetEmptyGptData();
393 GptHeader *h1 = (GptHeader *)gpt->primary_header;
394 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
395 GptHeader h3;
396
397 EXPECT(0 == HeaderFieldsSame(h1, h2));
398
399 Memcpy(&h3, h2, sizeof(h3));
400 h3.signature[0] ^= 0xba;
401 EXPECT(1 == HeaderFieldsSame(h1, &h3));
402
403 Memcpy(&h3, h2, sizeof(h3));
404 h3.revision++;
405 EXPECT(1 == HeaderFieldsSame(h1, &h3));
406
407 Memcpy(&h3, h2, sizeof(h3));
408 h3.size++;
409 EXPECT(1 == HeaderFieldsSame(h1, &h3));
410
411 Memcpy(&h3, h2, sizeof(h3));
412 h3.reserved_zero++;
413 EXPECT(1 == HeaderFieldsSame(h1, &h3));
414
415 Memcpy(&h3, h2, sizeof(h3));
416 h3.first_usable_lba++;
417 EXPECT(1 == HeaderFieldsSame(h1, &h3));
418
419 Memcpy(&h3, h2, sizeof(h3));
420 h3.last_usable_lba++;
421 EXPECT(1 == HeaderFieldsSame(h1, &h3));
422
423 Memcpy(&h3, h2, sizeof(h3));
424 h3.disk_uuid.u.raw[0] ^= 0xba;
425 EXPECT(1 == HeaderFieldsSame(h1, &h3));
426
427 Memcpy(&h3, h2, sizeof(h3));
428 h3.number_of_entries++;
429 EXPECT(1 == HeaderFieldsSame(h1, &h3));
430
431 Memcpy(&h3, h2, sizeof(h3));
432 h3.size_of_entry++;
433 EXPECT(1 == HeaderFieldsSame(h1, &h3));
434
435 Memcpy(&h3, h2, sizeof(h3));
436 h3.entries_crc32++;
437 EXPECT(1 == HeaderFieldsSame(h1, &h3));
438
439 return TEST_OK;
440}
441
Randall Spanglere9213a72013-01-24 11:19:55 -0800442/* Test if signature ("EFI PART") is checked. */
443static int SignatureTest(void)
444{
445 GptData *gpt = GetEmptyGptData();
446 GptHeader *h1 = (GptHeader *)gpt->primary_header;
447 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
448 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700449
Randall Spangler0bda13f2013-01-24 12:25:26 -0800450 EXPECT(1 == CheckHeader(NULL, 0, gpt->drive_sectors));
451
Randall Spanglere9213a72013-01-24 11:19:55 -0800452 for (i = 0; i < 8; ++i) {
453 BuildTestGptData(gpt);
454 h1->signature[i] ^= 0xff;
455 h2->signature[i] ^= 0xff;
456 RefreshCrc32(gpt);
457 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
458 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
459 }
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700460
Randall Spanglere9213a72013-01-24 11:19:55 -0800461 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700462}
463
Randall Spanglere9213a72013-01-24 11:19:55 -0800464/*
465 * The revision we currently support is GPT_HEADER_REVISION. If the revision
466 * in header is not that, we expect the header is invalid.
467 */
468static int RevisionTest(void)
469{
470 GptData *gpt = GetEmptyGptData();
471 GptHeader *h1 = (GptHeader *)gpt->primary_header;
472 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
473 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700474
Randall Spanglere9213a72013-01-24 11:19:55 -0800475 struct {
476 uint32_t value_to_test;
477 int expect_rv;
478 } cases[] = {
479 {0x01000000, 1},
480 {0x00010000, 0}, /* GPT_HEADER_REVISION */
481 {0x00000100, 1},
482 {0x00000001, 1},
483 {0x23010456, 1},
484 };
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700485
Randall Spanglere9213a72013-01-24 11:19:55 -0800486 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
487 BuildTestGptData(gpt);
488 h1->revision = cases[i].value_to_test;
489 h2->revision = cases[i].value_to_test;
490 RefreshCrc32(gpt);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700491
Randall Spanglere9213a72013-01-24 11:19:55 -0800492 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
493 cases[i].expect_rv);
494 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
495 cases[i].expect_rv);
496 }
497 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700498}
499
Randall Spanglere9213a72013-01-24 11:19:55 -0800500static int SizeTest(void)
501{
502 GptData *gpt = GetEmptyGptData();
503 GptHeader *h1 = (GptHeader *)gpt->primary_header;
504 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
505 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700506
Randall Spanglere9213a72013-01-24 11:19:55 -0800507 struct {
508 uint32_t value_to_test;
509 int expect_rv;
510 } cases[] = {
511 {91, 1},
512 {92, 0},
513 {93, 0},
514 {511, 0},
515 {512, 0},
516 {513, 1},
517 };
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700518
Randall Spanglere9213a72013-01-24 11:19:55 -0800519 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
520 BuildTestGptData(gpt);
521 h1->size = cases[i].value_to_test;
522 h2->size = cases[i].value_to_test;
523 RefreshCrc32(gpt);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700524
Randall Spanglere9213a72013-01-24 11:19:55 -0800525 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
526 cases[i].expect_rv);
527 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
528 cases[i].expect_rv);
529 }
530 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700531}
532
Randall Spanglere9213a72013-01-24 11:19:55 -0800533/* Test if CRC is checked. */
534static int CrcFieldTest(void)
535{
536 GptData *gpt = GetEmptyGptData();
537 GptHeader *h1 = (GptHeader *)gpt->primary_header;
538 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700539
Randall Spanglere9213a72013-01-24 11:19:55 -0800540 BuildTestGptData(gpt);
541 /* Modify a field that the header verification doesn't care about */
542 h1->entries_crc32++;
543 h2->entries_crc32++;
544 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
545 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
546 /* Refresh the CRC; should pass now */
547 RefreshCrc32(gpt);
548 EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
549 EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700550
Randall Spanglere9213a72013-01-24 11:19:55 -0800551 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700552}
553
Randall Spanglere9213a72013-01-24 11:19:55 -0800554/* Test if reserved fields are checked. We'll try non-zero values to test. */
555static int ReservedFieldsTest(void)
556{
557 GptData *gpt = GetEmptyGptData();
558 GptHeader *h1 = (GptHeader *)gpt->primary_header;
559 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700560
Randall Spanglere9213a72013-01-24 11:19:55 -0800561 BuildTestGptData(gpt);
562 h1->reserved_zero ^= 0x12345678; /* whatever random */
563 h2->reserved_zero ^= 0x12345678; /* whatever random */
564 RefreshCrc32(gpt);
565 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
566 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700567
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700568#ifdef PADDING_CHECKED
Randall Spanglere9213a72013-01-24 11:19:55 -0800569 /* TODO: padding check is currently disabled */
570 BuildTestGptData(gpt);
571 h1->padding[12] ^= 0x34; /* whatever random */
572 h2->padding[56] ^= 0x78; /* whatever random */
573 RefreshCrc32(gpt);
574 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
575 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700576#endif
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700577
Randall Spanglere9213a72013-01-24 11:19:55 -0800578 return TEST_OK;
579}
580
581/*
582 * Technically, any size which is 2^N where N > 6 should work, but our
583 * library only supports one size.
584 */
585static int SizeOfPartitionEntryTest(void) {
586 GptData *gpt = GetEmptyGptData();
587 GptHeader *h1 = (GptHeader *)gpt->primary_header;
588 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
589 int i;
590
591 struct {
592 uint32_t value_to_test;
593 int expect_rv;
594 } cases[] = {
595 {127, 1},
596 {128, 0},
597 {129, 1},
598 {256, 1},
599 {512, 1},
600 };
601
602 /* Check size of entryes */
603 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
604 BuildTestGptData(gpt);
605 h1->size_of_entry = cases[i].value_to_test;
606 h2->size_of_entry = cases[i].value_to_test;
607 h1->number_of_entries = TOTAL_ENTRIES_SIZE /
608 cases[i].value_to_test;
609 h2->number_of_entries = TOTAL_ENTRIES_SIZE /
610 cases[i].value_to_test;
611 RefreshCrc32(gpt);
612
613 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
614 cases[i].expect_rv);
615 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
616 cases[i].expect_rv);
617 }
618
619 return TEST_OK;
620}
621
622/*
623 * Technically, any size which is 2^N where N > 6 should work, but our library
624 * only supports one size.
625 */
626static int NumberOfPartitionEntriesTest(void)
627{
628 GptData *gpt = GetEmptyGptData();
629 GptHeader *h1 = (GptHeader *)gpt->primary_header;
630 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
631
632 BuildTestGptData(gpt);
633 h1->number_of_entries--;
634 h2->number_of_entries /= 2;
635 RefreshCrc32(gpt);
636 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
637 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
638
639 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700640}
641
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700642
Randall Spanglere9213a72013-01-24 11:19:55 -0800643/* Test if myLBA field is checked (1 for primary, last for secondary). */
644static int MyLbaTest(void)
645{
646 GptData *gpt = GetEmptyGptData();
647 GptHeader *h1 = (GptHeader *)gpt->primary_header;
648 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700649
Randall Spanglere9213a72013-01-24 11:19:55 -0800650 /* myLBA depends on primary vs secondary flag */
651 BuildTestGptData(gpt);
652 EXPECT(1 == CheckHeader(h1, 1, gpt->drive_sectors));
653 EXPECT(1 == CheckHeader(h2, 0, gpt->drive_sectors));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700654
Randall Spanglere9213a72013-01-24 11:19:55 -0800655 BuildTestGptData(gpt);
656 h1->my_lba--;
657 h2->my_lba--;
658 RefreshCrc32(gpt);
659 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
660 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700661
Randall Spanglere9213a72013-01-24 11:19:55 -0800662 BuildTestGptData(gpt);
663 h1->my_lba = 2;
664 h2->my_lba--;
665 RefreshCrc32(gpt);
666 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
667 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700668
Randall Spanglere9213a72013-01-24 11:19:55 -0800669 /* We should ignore the alternate_lba field entirely */
670 BuildTestGptData(gpt);
671 h1->alternate_lba++;
672 h2->alternate_lba++;
673 RefreshCrc32(gpt);
674 EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
675 EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
676
677 BuildTestGptData(gpt);
678 h1->alternate_lba--;
679 h2->alternate_lba--;
680 RefreshCrc32(gpt);
681 EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
682 EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
683
684 BuildTestGptData(gpt);
685 h1->entries_lba++;
686 h2->entries_lba++;
687 RefreshCrc32(gpt);
688 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
689 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
690
691 BuildTestGptData(gpt);
692 h1->entries_lba--;
693 h2->entries_lba--;
694 RefreshCrc32(gpt);
695 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
696 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
697
698 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700699}
700
Randall Spanglere9213a72013-01-24 11:19:55 -0800701/* Test if FirstUsableLBA and LastUsableLBA are checked.
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700702 * FirstUsableLBA must be after the end of the primary GPT table array.
703 * LastUsableLBA must be before the start of the secondary GPT table array.
704 * FirstUsableLBA <= LastUsableLBA. */
Randall Spanglere9213a72013-01-24 11:19:55 -0800705static int FirstUsableLbaAndLastUsableLbaTest(void)
706{
707 GptData *gpt = GetEmptyGptData();
708 GptHeader *h1 = (GptHeader *)gpt->primary_header;
709 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
710 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700711
Randall Spanglere9213a72013-01-24 11:19:55 -0800712 struct {
713 uint64_t primary_entries_lba;
714 uint64_t primary_first_usable_lba;
715 uint64_t primary_last_usable_lba;
716 uint64_t secondary_first_usable_lba;
717 uint64_t secondary_last_usable_lba;
718 uint64_t secondary_entries_lba;
719 int primary_rv;
720 int secondary_rv;
721 } cases[] = {
722 {2, 34, 433, 34, 433, 434, 0, 0},
723 {2, 34, 432, 34, 430, 434, 0, 0},
724 {2, 33, 433, 33, 433, 434, 1, 1},
725 {2, 34, 434, 34, 433, 434, 1, 0},
726 {2, 34, 433, 34, 434, 434, 0, 1},
727 {2, 35, 433, 35, 433, 434, 0, 0},
728 {2, 433, 433, 433, 433, 434, 0, 0},
729 {2, 434, 433, 434, 434, 434, 1, 1},
730 {2, 433, 34, 34, 433, 434, 1, 0},
731 {2, 34, 433, 433, 34, 434, 0, 1},
732 };
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700733
Randall Spanglere9213a72013-01-24 11:19:55 -0800734 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
735 BuildTestGptData(gpt);
736 h1->entries_lba = cases[i].primary_entries_lba;
737 h1->first_usable_lba = cases[i].primary_first_usable_lba;
738 h1->last_usable_lba = cases[i].primary_last_usable_lba;
739 h2->entries_lba = cases[i].secondary_entries_lba;
740 h2->first_usable_lba = cases[i].secondary_first_usable_lba;
741 h2->last_usable_lba = cases[i].secondary_last_usable_lba;
742 RefreshCrc32(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700743
Randall Spanglere9213a72013-01-24 11:19:55 -0800744 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
745 cases[i].primary_rv);
746 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
747 cases[i].secondary_rv);
748 }
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700749
Randall Spanglere9213a72013-01-24 11:19:55 -0800750 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700751}
752
Randall Spanglere9213a72013-01-24 11:19:55 -0800753/*
754 * Test if PartitionEntryArrayCRC32 is checked. PartitionEntryArrayCRC32 must
755 * be calculated over SizeOfPartitionEntry * NumberOfPartitionEntries bytes.
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700756 */
Randall Spanglere9213a72013-01-24 11:19:55 -0800757static int EntriesCrcTest(void)
758{
759 GptData *gpt = GetEmptyGptData();
760 GptHeader *h1 = (GptHeader *)gpt->primary_header;
761 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
762 GptEntry *e2 = (GptEntry *)(gpt->secondary_entries);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700763
Randall Spanglere9213a72013-01-24 11:19:55 -0800764 /* Modify first byte of primary entries, and expect the CRC is wrong. */
765 BuildTestGptData(gpt);
766 EXPECT(0 == CheckEntries(e1, h1));
767 EXPECT(0 == CheckEntries(e2, h1));
768 gpt->primary_entries[0] ^= 0xa5; /* just XOR a non-zero value */
769 gpt->secondary_entries[TOTAL_ENTRIES_SIZE-1] ^= 0x5a;
770 EXPECT(GPT_ERROR_CRC_CORRUPTED == CheckEntries(e1, h1));
771 EXPECT(GPT_ERROR_CRC_CORRUPTED == CheckEntries(e2, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700772
Randall Spanglere9213a72013-01-24 11:19:55 -0800773 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700774}
775
Randall Spanglere9213a72013-01-24 11:19:55 -0800776/*
777 * Test if partition geometry is checked.
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700778 * All active (non-zero PartitionTypeGUID) partition entries should have:
779 * entry.StartingLBA >= header.FirstUsableLBA
780 * entry.EndingLBA <= header.LastUsableLBA
781 * entry.StartingLBA <= entry.EndingLBA
782 */
Randall Spanglere9213a72013-01-24 11:19:55 -0800783static int ValidEntryTest(void)
784{
785 GptData *gpt = GetEmptyGptData();
786 GptHeader *h1 = (GptHeader *)gpt->primary_header;
787 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700788 MtdData *mtd = GetEmptyMtdData();
789 MtdDiskLayout *mh = &mtd->primary;
790 MtdDiskPartition *me = mh->partitions;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700791
Randall Spanglere9213a72013-01-24 11:19:55 -0800792 /* error case: entry.StartingLBA < header.FirstUsableLBA */
793 BuildTestGptData(gpt);
794 e1[0].starting_lba = h1->first_usable_lba - 1;
795 RefreshCrc32(gpt);
796 EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700797
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700798 BuildTestMtdData(mtd);
799 if (mh->first_lba > 0) {
800 me[0].starting_lba = mh->first_lba - 1;
801 mh->crc32 = MtdHeaderCrc(mh);
802 EXPECT(GPT_ERROR_OUT_OF_REGION == MtdCheckEntries(me, mh));
803 }
804
Randall Spanglere9213a72013-01-24 11:19:55 -0800805 /* error case: entry.EndingLBA > header.LastUsableLBA */
806 BuildTestGptData(gpt);
807 e1[2].ending_lba = h1->last_usable_lba + 1;
808 RefreshCrc32(gpt);
809 EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700810
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700811 BuildTestMtdData(mtd);
812 me[0].ending_lba = mh->last_lba + 1;
813 mh->crc32 = MtdHeaderCrc(mh);
814 EXPECT(GPT_ERROR_OUT_OF_REGION == MtdCheckEntries(me, mh));
815
Randall Spanglere9213a72013-01-24 11:19:55 -0800816 /* error case: entry.StartingLBA > entry.EndingLBA */
817 BuildTestGptData(gpt);
818 e1[3].starting_lba = e1[3].ending_lba + 1;
819 RefreshCrc32(gpt);
820 EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700821
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700822 BuildTestMtdData(mtd);
823 me[0].starting_lba = me[0].ending_lba + 1;
824 mh->crc32 = MtdHeaderCrc(mh);
825 EXPECT(GPT_ERROR_OUT_OF_REGION == MtdCheckEntries(me, mh));
826
Randall Spanglere9213a72013-01-24 11:19:55 -0800827 /* case: non active entry should be ignored. */
828 BuildTestGptData(gpt);
829 Memset(&e1[1].type, 0, sizeof(e1[1].type));
830 e1[1].starting_lba = e1[1].ending_lba + 1;
831 RefreshCrc32(gpt);
832 EXPECT(0 == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700833
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700834 BuildTestMtdData(mtd);
835 me[0].flags = 0;
836 me[0].starting_lba = me[0].ending_lba + 1;
837 mh->crc32 = MtdHeaderCrc(mh);
838 EXPECT(GPT_SUCCESS == MtdCheckEntries(me, mh));
839
Randall Spanglere9213a72013-01-24 11:19:55 -0800840 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700841}
842
Randall Spanglere9213a72013-01-24 11:19:55 -0800843/* Test if overlapped partition tables can be detected. */
844static int OverlappedPartitionTest(void) {
845 GptData *gpt = GetEmptyGptData();
846 GptHeader *h = (GptHeader *)gpt->primary_header;
847 GptEntry *e = (GptEntry *)gpt->primary_entries;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700848 MtdData *mtd = GetEmptyMtdData();
849 MtdDiskLayout *mh = &mtd->primary;
850 MtdDiskPartition *me = mh->partitions;
Randall Spanglere9213a72013-01-24 11:19:55 -0800851 int i, j;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700852
Randall Spanglere9213a72013-01-24 11:19:55 -0800853 struct {
854 int overlapped;
855 struct {
856 int active;
857 uint64_t starting_lba;
858 uint64_t ending_lba;
859 } entries[16]; /* enough for testing. */
860 } cases[] = {
861 {GPT_SUCCESS, {{0, 100, 199}}},
862 {GPT_SUCCESS, {{1, 100, 199}}},
863 {GPT_SUCCESS, {{1, 100, 150}, {1, 200, 250}, {1, 300, 350}}},
864 {GPT_ERROR_START_LBA_OVERLAP,
865 {{1, 200, 299}, {1, 100, 199}, {1, 100, 100}}},
866 {GPT_ERROR_END_LBA_OVERLAP,
867 {{1, 200, 299}, {1, 100, 199}, {1, 299, 299}}},
868 {GPT_SUCCESS, {{1, 300, 399}, {1, 200, 299}, {1, 100, 199}}},
869 {GPT_ERROR_END_LBA_OVERLAP,
870 {{1, 100, 199}, {1, 199, 299}, {1, 299, 399}}},
871 {GPT_ERROR_START_LBA_OVERLAP,
872 {{1, 100, 199}, {1, 200, 299}, {1, 75, 399}}},
873 {GPT_ERROR_START_LBA_OVERLAP,
874 {{1, 100, 199}, {1, 75, 250}, {1, 200, 299}}},
875 {GPT_ERROR_END_LBA_OVERLAP,
876 {{1, 75, 150}, {1, 100, 199}, {1, 200, 299}}},
877 {GPT_ERROR_START_LBA_OVERLAP,
878 {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {1, 100, 399}}},
879 {GPT_SUCCESS,
880 {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {0, 100, 399}}},
881 {GPT_ERROR_START_LBA_OVERLAP,
882 {{1, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400}}},
883 {GPT_ERROR_START_LBA_OVERLAP,
884 {{0, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400}}},
885 {GPT_SUCCESS,
886 {{1, 200, 300}, {1, 100, 199}, {0, 100, 400}, {0, 300, 400}}},
887 {GPT_ERROR_END_LBA_OVERLAP,
888 {{1, 200, 299}, {1, 100, 199}, {1, 199, 199}}},
889 {GPT_SUCCESS, {{1, 200, 299}, {0, 100, 199}, {1, 199, 199}}},
890 {GPT_SUCCESS, {{1, 200, 299}, {1, 100, 199}, {0, 199, 199}}},
891 {GPT_ERROR_START_LBA_OVERLAP,
892 {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202},
893 {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206},
894 {1, 207, 207}, {1, 208, 208}, {1, 199, 199}}},
895 {GPT_SUCCESS,
896 {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202},
897 {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206},
898 {1, 207, 207}, {1, 208, 208}, {0, 199, 199}}},
899 };
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700900
Randall Spanglere9213a72013-01-24 11:19:55 -0800901 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
902 BuildTestGptData(gpt);
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700903 BuildTestMtdData(mtd);
904 Memset(mh->partitions, 0, sizeof(mh->partitions));
Randall Spanglere9213a72013-01-24 11:19:55 -0800905 ZeroEntries(gpt);
906 for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) {
907 if (!cases[i].entries[j].starting_lba)
908 break;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700909
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700910 if (cases[i].entries[j].active) {
Randall Spanglere9213a72013-01-24 11:19:55 -0800911 Memcpy(&e[j].type, &guid_kernel, sizeof(Guid));
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700912 me[j].flags =
913 MTD_PARTITION_TYPE_CHROMEOS_KERNEL << MTD_ATTRIBUTE_TYPE_OFFSET;
914 }
Randall Spanglere9213a72013-01-24 11:19:55 -0800915 SetGuid(&e[j].unique, j);
916 e[j].starting_lba = cases[i].entries[j].starting_lba;
917 e[j].ending_lba = cases[i].entries[j].ending_lba;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700918 me[j].starting_lba = cases[i].entries[j].starting_lba;
919 me[j].ending_lba = cases[i].entries[j].ending_lba;
920
Randall Spanglere9213a72013-01-24 11:19:55 -0800921 }
922 RefreshCrc32(gpt);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700923
Randall Spanglere9213a72013-01-24 11:19:55 -0800924 EXPECT(cases[i].overlapped == CheckEntries(e, h));
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700925 EXPECT(cases[i].overlapped == MtdCheckEntries(me, mh));
Randall Spanglere9213a72013-01-24 11:19:55 -0800926 }
927 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700928}
929
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700930/* Test both sanity checking and repair. */
Randall Spanglere9213a72013-01-24 11:19:55 -0800931static int SanityCheckTest(void)
932{
933 GptData *gpt = GetEmptyGptData();
934 GptHeader *h1 = (GptHeader *)gpt->primary_header;
Randall Spangler0bda13f2013-01-24 12:25:26 -0800935 GptEntry *e1 = (GptEntry *)gpt->primary_entries;
936 uint8_t *tempptr;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700937
Randall Spanglere9213a72013-01-24 11:19:55 -0800938 /* Unmodified test data is completely sane */
939 BuildTestGptData(gpt);
940 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
941 EXPECT(MASK_BOTH == gpt->valid_headers);
942 EXPECT(MASK_BOTH == gpt->valid_entries);
943 /* Repair doesn't damage it */
944 GptRepair(gpt);
945 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
946 EXPECT(MASK_BOTH == gpt->valid_headers);
947 EXPECT(MASK_BOTH == gpt->valid_entries);
948 EXPECT(0 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700949
Randall Spangler0bda13f2013-01-24 12:25:26 -0800950 /* Invalid sector size should fail */
951 BuildTestGptData(gpt);
952 gpt->sector_bytes = 1024;
953 EXPECT(GPT_ERROR_INVALID_SECTOR_SIZE == GptSanityCheck(gpt));
954
Randall Spanglere9213a72013-01-24 11:19:55 -0800955 /* Modify headers */
956 BuildTestGptData(gpt);
957 gpt->primary_header[0]++;
958 gpt->secondary_header[0]++;
959 EXPECT(GPT_ERROR_INVALID_HEADERS == GptSanityCheck(gpt));
960 EXPECT(0 == gpt->valid_headers);
961 EXPECT(0 == gpt->valid_entries);
962 /* Repair can't fix completely busted headers */
963 GptRepair(gpt);
964 EXPECT(GPT_ERROR_INVALID_HEADERS == GptSanityCheck(gpt));
965 EXPECT(0 == gpt->valid_headers);
966 EXPECT(0 == gpt->valid_entries);
967 EXPECT(0 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700968
Randall Spanglere9213a72013-01-24 11:19:55 -0800969 BuildTestGptData(gpt);
970 gpt->primary_header[0]++;
971 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
972 EXPECT(MASK_SECONDARY == gpt->valid_headers);
973 EXPECT(MASK_BOTH == gpt->valid_entries);
974 GptRepair(gpt);
975 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
976 EXPECT(MASK_BOTH == gpt->valid_headers);
977 EXPECT(MASK_BOTH == gpt->valid_entries);
978 EXPECT(GPT_MODIFIED_HEADER1 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700979
Randall Spanglere9213a72013-01-24 11:19:55 -0800980 BuildTestGptData(gpt);
981 gpt->secondary_header[0]++;
982 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
983 EXPECT(MASK_PRIMARY == gpt->valid_headers);
984 EXPECT(MASK_BOTH == gpt->valid_entries);
985 GptRepair(gpt);
986 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
987 EXPECT(MASK_BOTH == gpt->valid_headers);
988 EXPECT(MASK_BOTH == gpt->valid_entries);
989 EXPECT(GPT_MODIFIED_HEADER2 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700990
Randall Spanglere9213a72013-01-24 11:19:55 -0800991 /*
992 * Modify header1 and update its CRC. Since header2 is now different
993 * than header1, it'll be the one considered invalid.
994 */
995 BuildTestGptData(gpt);
996 h1->size++;
997 RefreshCrc32(gpt);
998 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
999 EXPECT(MASK_PRIMARY == gpt->valid_headers);
1000 EXPECT(MASK_BOTH == gpt->valid_entries);
1001 GptRepair(gpt);
1002 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1003 EXPECT(MASK_BOTH == gpt->valid_headers);
1004 EXPECT(MASK_BOTH == gpt->valid_entries);
1005 EXPECT(GPT_MODIFIED_HEADER2 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001006
Randall Spanglere9213a72013-01-24 11:19:55 -08001007 /* Modify entries */
1008 BuildTestGptData(gpt);
1009 gpt->primary_entries[0]++;
1010 gpt->secondary_entries[0]++;
1011 EXPECT(GPT_ERROR_INVALID_ENTRIES == GptSanityCheck(gpt));
1012 EXPECT(MASK_BOTH == gpt->valid_headers);
1013 EXPECT(MASK_NONE == gpt->valid_entries);
1014 /* Repair can't fix both copies of entries being bad, either. */
1015 GptRepair(gpt);
1016 EXPECT(GPT_ERROR_INVALID_ENTRIES == GptSanityCheck(gpt));
1017 EXPECT(MASK_BOTH == gpt->valid_headers);
1018 EXPECT(MASK_NONE == gpt->valid_entries);
1019 EXPECT(0 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001020
Randall Spanglere9213a72013-01-24 11:19:55 -08001021 BuildTestGptData(gpt);
1022 gpt->primary_entries[0]++;
1023 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1024 EXPECT(MASK_BOTH == gpt->valid_headers);
1025 EXPECT(MASK_SECONDARY == gpt->valid_entries);
1026 GptRepair(gpt);
1027 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1028 EXPECT(MASK_BOTH == gpt->valid_headers);
1029 EXPECT(MASK_BOTH == gpt->valid_entries);
1030 EXPECT(GPT_MODIFIED_ENTRIES1 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001031
Randall Spanglere9213a72013-01-24 11:19:55 -08001032 BuildTestGptData(gpt);
1033 gpt->secondary_entries[0]++;
1034 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1035 EXPECT(MASK_BOTH == gpt->valid_headers);
1036 EXPECT(MASK_PRIMARY == gpt->valid_entries);
1037 GptRepair(gpt);
1038 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1039 EXPECT(MASK_BOTH == gpt->valid_headers);
1040 EXPECT(MASK_BOTH == gpt->valid_entries);
1041 EXPECT(GPT_MODIFIED_ENTRIES2 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001042
Randall Spangler0bda13f2013-01-24 12:25:26 -08001043 /*
1044 * Modify entries and recompute CRCs, then make both primary and
1045 * secondary entry pointers use the secondary data. The primary
1046 * header will have the wrong entries CRC, so we should fall back
1047 * to the secondary header.
1048 */
1049 BuildTestGptData(gpt);
1050 e1->starting_lba++;
1051 RefreshCrc32(gpt);
1052 tempptr = gpt->primary_entries;
1053 gpt->primary_entries = gpt->secondary_entries;
1054 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1055 EXPECT(MASK_SECONDARY == gpt->valid_headers);
1056 EXPECT(MASK_BOTH == gpt->valid_entries);
1057 gpt->primary_entries = tempptr;
1058
Randall Spanglere9213a72013-01-24 11:19:55 -08001059 /* Modify both header and entries */
1060 BuildTestGptData(gpt);
1061 gpt->primary_header[0]++;
1062 gpt->primary_entries[0]++;
1063 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1064 EXPECT(MASK_SECONDARY == gpt->valid_headers);
1065 EXPECT(MASK_SECONDARY == gpt->valid_entries);
1066 GptRepair(gpt);
1067 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1068 EXPECT(MASK_BOTH == gpt->valid_headers);
1069 EXPECT(MASK_BOTH == gpt->valid_entries);
1070 EXPECT((GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1) == gpt->modified);
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001071
Randall Spanglere9213a72013-01-24 11:19:55 -08001072 BuildTestGptData(gpt);
1073 gpt->secondary_header[0]++;
1074 gpt->secondary_entries[0]++;
1075 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1076 EXPECT(MASK_PRIMARY == gpt->valid_headers);
1077 EXPECT(MASK_PRIMARY == gpt->valid_entries);
1078 GptRepair(gpt);
1079 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1080 EXPECT(MASK_BOTH == gpt->valid_headers);
1081 EXPECT(MASK_BOTH == gpt->valid_entries);
1082 EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001083
Randall Spanglere9213a72013-01-24 11:19:55 -08001084 /* Test cross-correction (h1+e2, h2+e1) */
1085 BuildTestGptData(gpt);
1086 gpt->primary_header[0]++;
1087 gpt->secondary_entries[0]++;
1088 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1089 EXPECT(MASK_SECONDARY == gpt->valid_headers);
1090 EXPECT(MASK_PRIMARY == gpt->valid_entries);
1091 GptRepair(gpt);
1092 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1093 EXPECT(MASK_BOTH == gpt->valid_headers);
1094 EXPECT(MASK_BOTH == gpt->valid_entries);
1095 EXPECT((GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001096
Randall Spanglere9213a72013-01-24 11:19:55 -08001097 BuildTestGptData(gpt);
1098 gpt->secondary_header[0]++;
1099 gpt->primary_entries[0]++;
1100 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1101 EXPECT(MASK_PRIMARY == gpt->valid_headers);
1102 EXPECT(MASK_SECONDARY == gpt->valid_entries);
1103 GptRepair(gpt);
1104 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1105 EXPECT(MASK_BOTH == gpt->valid_headers);
1106 EXPECT(MASK_BOTH == gpt->valid_entries);
1107 EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES1) == gpt->modified);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001108
Randall Spanglere9213a72013-01-24 11:19:55 -08001109 /*
1110 * Test mismatched pairs (h1+e1 valid, h2+e2 valid but different. This
1111 * simulates a partial update of the drive.
1112 */
1113 BuildTestGptData(gpt);
1114 gpt->secondary_entries[0]++;
1115 RefreshCrc32(gpt);
1116 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1117 EXPECT(MASK_PRIMARY == gpt->valid_headers);
1118 EXPECT(MASK_PRIMARY == gpt->valid_entries);
1119 GptRepair(gpt);
1120 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1121 EXPECT(MASK_BOTH == gpt->valid_headers);
1122 EXPECT(MASK_BOTH == gpt->valid_entries);
1123 EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001124
Randall Spanglere9213a72013-01-24 11:19:55 -08001125 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001126}
1127
Randall Spanglere9213a72013-01-24 11:19:55 -08001128static int EntryAttributeGetSetTest(void)
1129{
1130 GptData *gpt = GetEmptyGptData();
1131 GptEntry *e = (GptEntry *)(gpt->primary_entries);
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001132 MtdData *mtd = GetEmptyMtdData();
1133 MtdDiskPartition *m = &mtd->primary.partitions[0];
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001134
Randall Spanglere9213a72013-01-24 11:19:55 -08001135 e->attrs.whole = 0x0000000000000000ULL;
1136 SetEntrySuccessful(e, 1);
1137 EXPECT(0x0100000000000000ULL == e->attrs.whole);
1138 EXPECT(1 == GetEntrySuccessful(e));
1139 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
1140 SetEntrySuccessful(e, 0);
1141 EXPECT(0xFEFFFFFFFFFFFFFFULL == e->attrs.whole);
1142 EXPECT(0 == GetEntrySuccessful(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001143
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001144 m->flags = 0;
1145 MtdSetEntrySuccessful(m, 1);
1146 EXPECT(0x00000100 == m->flags);
1147 EXPECT(1 == MtdGetEntrySuccessful(m));
1148 m->flags = ~0;
1149 MtdSetEntrySuccessful(m, 0);
1150 EXPECT(0xFFFFFEFF == m->flags);
1151 EXPECT(0 == MtdGetEntrySuccessful(m));
1152
Randall Spanglere9213a72013-01-24 11:19:55 -08001153 e->attrs.whole = 0x0000000000000000ULL;
1154 SetEntryTries(e, 15);
1155 EXPECT(15 == GetEntryTries(e));
1156 EXPECT(0x00F0000000000000ULL == e->attrs.whole);
1157 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
1158 SetEntryTries(e, 0);
1159 EXPECT(0xFF0FFFFFFFFFFFFFULL == e->attrs.whole);
1160 EXPECT(0 == GetEntryTries(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001161
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001162 m->flags = 0;
1163 MtdSetEntryTries(m, 15);
1164 EXPECT(0x000000F0 == m->flags);
1165 EXPECT(15 == MtdGetEntryTries(m));
1166 m->flags = ~0;
1167 MtdSetEntryTries(m, 0);
1168 EXPECT(0xFFFFFF0F == m->flags);
1169 EXPECT(0 == MtdGetEntryTries(m));
1170
Randall Spanglere9213a72013-01-24 11:19:55 -08001171 e->attrs.whole = 0x0000000000000000ULL;
1172 SetEntryPriority(e, 15);
1173 EXPECT(0x000F000000000000ULL == e->attrs.whole);
1174 EXPECT(15 == GetEntryPriority(e));
1175 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
1176 SetEntryPriority(e, 0);
1177 EXPECT(0xFFF0FFFFFFFFFFFFULL == e->attrs.whole);
1178 EXPECT(0 == GetEntryPriority(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001179
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001180 m->flags = 0;
1181 MtdSetEntryPriority(m, 15);
1182 EXPECT(0x0000000F == m->flags);
1183 EXPECT(15 == MtdGetEntryPriority(m));
1184 m->flags = ~0;
1185 MtdSetEntryPriority(m, 0);
1186 EXPECT(0xFFFFFFF0 == m->flags);
1187 EXPECT(0 == MtdGetEntryPriority(m));
1188
Randall Spanglere9213a72013-01-24 11:19:55 -08001189 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
1190 EXPECT(1 == GetEntrySuccessful(e));
1191 EXPECT(15 == GetEntryPriority(e));
1192 EXPECT(15 == GetEntryTries(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001193
Randall Spanglere9213a72013-01-24 11:19:55 -08001194 e->attrs.whole = 0x0123000000000000ULL;
1195 EXPECT(1 == GetEntrySuccessful(e));
1196 EXPECT(2 == GetEntryTries(e));
1197 EXPECT(3 == GetEntryPriority(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001198
Randall Spanglere9213a72013-01-24 11:19:55 -08001199 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001200}
1201
Randall Spanglere9213a72013-01-24 11:19:55 -08001202static int EntryTypeTest(void)
1203{
1204 GptData *gpt = GetEmptyGptData();
1205 GptEntry *e = (GptEntry *)(gpt->primary_entries);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001206
Randall Spanglere9213a72013-01-24 11:19:55 -08001207 Memcpy(&e->type, &guid_zero, sizeof(Guid));
1208 EXPECT(1 == IsUnusedEntry(e));
1209 EXPECT(0 == IsKernelEntry(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001210
Randall Spanglere9213a72013-01-24 11:19:55 -08001211 Memcpy(&e->type, &guid_kernel, sizeof(Guid));
1212 EXPECT(0 == IsUnusedEntry(e));
1213 EXPECT(1 == IsKernelEntry(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001214
Randall Spanglere9213a72013-01-24 11:19:55 -08001215 Memcpy(&e->type, &guid_rootfs, sizeof(Guid));
1216 EXPECT(0 == IsUnusedEntry(e));
1217 EXPECT(0 == IsKernelEntry(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001218
Randall Spanglere9213a72013-01-24 11:19:55 -08001219 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001220}
1221
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001222/* Make an entry unused by clearing its type. */
Randall Spanglere9213a72013-01-24 11:19:55 -08001223static void FreeEntry(GptEntry *e)
1224{
1225 Memset(&e->type, 0, sizeof(Guid));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001226}
1227
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001228static void MtdFreeEntry(MtdDiskPartition *e)
1229{
1230 MtdSetEntryType(e, MTD_PARTITION_TYPE_UNUSED);
1231}
1232
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001233/* Set up an entry. */
Randall Spanglere9213a72013-01-24 11:19:55 -08001234static void FillEntry(GptEntry *e, int is_kernel,
1235 int priority, int successful, int tries)
1236{
1237 Memcpy(&e->type, (is_kernel ? &guid_kernel : &guid_zero), sizeof(Guid));
1238 SetEntryPriority(e, priority);
1239 SetEntrySuccessful(e, successful);
1240 SetEntryTries(e, tries);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001241}
1242
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001243static void MtdFillEntry(MtdDiskPartition *e, int is_kernel,
1244 int priority, int successful, int tries)
1245{
1246 MtdSetEntryType(e, is_kernel ? MTD_PARTITION_TYPE_CHROMEOS_KERNEL :
1247 MTD_PARTITION_TYPE_CHROMEOS_FIRMWARE);
1248 MtdSetEntryPriority(e, priority);
1249 MtdSetEntrySuccessful(e, successful);
1250 MtdSetEntryTries(e, tries);
1251}
1252
Randall Spanglere9213a72013-01-24 11:19:55 -08001253/*
1254 * Invalidate all kernel entries and expect GptNextKernelEntry() cannot find
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001255 * any usable kernel entry.
1256 */
Randall Spanglere9213a72013-01-24 11:19:55 -08001257static int NoValidKernelEntryTest(void)
1258{
1259 GptData *gpt = GetEmptyGptData();
1260 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001261
Randall Spanglere9213a72013-01-24 11:19:55 -08001262 BuildTestGptData(gpt);
1263 SetEntryPriority(e1 + KERNEL_A, 0);
1264 FreeEntry(e1 + KERNEL_B);
1265 RefreshCrc32(gpt);
1266 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1267 GptNextKernelEntry(gpt, NULL, NULL));
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001268
Randall Spanglere9213a72013-01-24 11:19:55 -08001269 return TEST_OK;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001270}
1271
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001272static int MtdNoValidKernelEntryTest(void)
1273{
1274 MtdData *mtd = GetEmptyMtdData();
1275 MtdDiskPartition *e1 = mtd->primary.partitions;
1276
1277 BuildTestMtdData(mtd);
1278 MtdSetEntryPriority(e1 + KERNEL_A, 0);
1279 MtdFreeEntry(e1 + KERNEL_B);
1280 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1281 MtdNextKernelEntry(mtd, NULL, NULL));
1282
1283 return TEST_OK;
1284}
1285
Randall Spanglere9213a72013-01-24 11:19:55 -08001286static int GetNextNormalTest(void)
1287{
1288 GptData *gpt = GetEmptyGptData();
1289 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
1290 uint64_t start, size;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001291
Randall Spanglere9213a72013-01-24 11:19:55 -08001292 /* Normal case - both kernels successful */
1293 BuildTestGptData(gpt);
1294 FillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
1295 FillEntry(e1 + KERNEL_B, 1, 2, 1, 0);
1296 RefreshCrc32(gpt);
1297 GptInit(gpt);
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001298
Randall Spanglere9213a72013-01-24 11:19:55 -08001299 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1300 EXPECT(KERNEL_A == gpt->current_kernel);
1301 EXPECT(34 == start);
1302 EXPECT(100 == size);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001303
Randall Spanglere9213a72013-01-24 11:19:55 -08001304 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1305 EXPECT(KERNEL_B == gpt->current_kernel);
1306 EXPECT(134 == start);
1307 EXPECT(99 == size);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001308
Randall Spanglere9213a72013-01-24 11:19:55 -08001309 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1310 GptNextKernelEntry(gpt, &start, &size));
1311 EXPECT(-1 == gpt->current_kernel);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001312
Randall Spanglere9213a72013-01-24 11:19:55 -08001313 /* Call as many times as you want; you won't get another kernel... */
1314 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1315 GptNextKernelEntry(gpt, &start, &size));
1316 EXPECT(-1 == gpt->current_kernel);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001317
Randall Spanglere9213a72013-01-24 11:19:55 -08001318 return TEST_OK;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001319}
1320
Randall Spanglere9213a72013-01-24 11:19:55 -08001321static int GetNextPrioTest(void)
1322{
1323 GptData *gpt = GetEmptyGptData();
1324 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
1325 uint64_t start, size;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001326
Randall Spanglere9213a72013-01-24 11:19:55 -08001327 /* Priority 3, 4, 0, 4 - should boot order B, Y, A */
1328 BuildTestGptData(gpt);
1329 FillEntry(e1 + KERNEL_A, 1, 3, 1, 0);
1330 FillEntry(e1 + KERNEL_B, 1, 4, 1, 0);
1331 FillEntry(e1 + KERNEL_X, 1, 0, 1, 0);
1332 FillEntry(e1 + KERNEL_Y, 1, 4, 1, 0);
1333 RefreshCrc32(gpt);
1334 GptInit(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001335
Randall Spanglere9213a72013-01-24 11:19:55 -08001336 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1337 EXPECT(KERNEL_B == gpt->current_kernel);
1338 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1339 EXPECT(KERNEL_Y == gpt->current_kernel);
1340 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1341 EXPECT(KERNEL_A == gpt->current_kernel);
1342 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1343 GptNextKernelEntry(gpt, &start, &size));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001344
Randall Spanglere9213a72013-01-24 11:19:55 -08001345 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001346}
1347
Randall Spanglere9213a72013-01-24 11:19:55 -08001348static int GetNextTriesTest(void)
1349{
1350 GptData *gpt = GetEmptyGptData();
1351 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
1352 uint64_t start, size;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001353
Randall Spanglere9213a72013-01-24 11:19:55 -08001354 /* Tries=nonzero is attempted just like success, but tries=0 isn't */
1355 BuildTestGptData(gpt);
1356 FillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
1357 FillEntry(e1 + KERNEL_B, 1, 3, 0, 0);
1358 FillEntry(e1 + KERNEL_X, 1, 4, 0, 1);
1359 FillEntry(e1 + KERNEL_Y, 1, 0, 0, 5);
1360 RefreshCrc32(gpt);
1361 GptInit(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001362
Randall Spanglere9213a72013-01-24 11:19:55 -08001363 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1364 EXPECT(KERNEL_X == gpt->current_kernel);
1365 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1366 EXPECT(KERNEL_A == gpt->current_kernel);
1367 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1368 GptNextKernelEntry(gpt, &start, &size));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001369
Randall Spanglere9213a72013-01-24 11:19:55 -08001370 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001371}
1372
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001373static int MtdGetNextNormalTest(void)
1374{
1375 MtdData *mtd = GetEmptyMtdData();
1376 MtdDiskPartition *e1 = mtd->primary.partitions;
1377 uint64_t start, size;
1378
1379 /* Normal case - both kernels successful */
1380 BuildTestMtdData(mtd);
1381 MtdFillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
1382 MtdFillEntry(e1 + KERNEL_B, 1, 2, 1, 0);
1383 mtd->primary.crc32 = MtdHeaderCrc(&mtd->primary);
1384 MtdInit(mtd);
1385
1386 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1387 EXPECT(KERNEL_A == mtd->current_kernel);
1388 EXPECT(34 == start);
1389 EXPECT(100 == size);
1390
1391 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1392 EXPECT(KERNEL_B == mtd->current_kernel);
1393 EXPECT(134 == start);
1394 EXPECT(99 == size);
1395
1396 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1397 MtdNextKernelEntry(mtd, &start, &size));
1398 EXPECT(-1 == mtd->current_kernel);
1399
1400 /* Call as many times as you want; you won't get another kernel... */
1401 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1402 MtdNextKernelEntry(mtd, &start, &size));
1403 EXPECT(-1 == mtd->current_kernel);
1404
1405 return TEST_OK;
1406}
1407
1408static int MtdGetNextPrioTest(void)
1409{
1410 MtdData *mtd = GetEmptyMtdData();
1411 MtdDiskPartition *e1 = mtd->primary.partitions;
1412 uint64_t start, size;
1413
1414 /* Priority 3, 4, 0, 4 - should boot order B, Y, A */
1415 BuildTestMtdData(mtd);
1416 MtdFillEntry(e1 + KERNEL_A, 1, 3, 1, 0);
1417 MtdFillEntry(e1 + KERNEL_B, 1, 4, 1, 0);
1418 MtdFillEntry(e1 + KERNEL_X, 1, 0, 1, 0);
1419 MtdFillEntry(e1 + KERNEL_Y, 1, 4, 1, 0);
1420 mtd->primary.crc32 = MtdHeaderCrc(&mtd->primary);
1421 MtdInit(mtd);
1422
1423 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1424 EXPECT(KERNEL_B == mtd->current_kernel);
1425 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1426 EXPECT(KERNEL_Y == mtd->current_kernel);
1427 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1428 EXPECT(KERNEL_A == mtd->current_kernel);
1429 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1430 MtdNextKernelEntry(mtd, &start, &size));
1431
1432 return TEST_OK;
1433}
1434
1435static int MtdGetNextTriesTest(void)
1436{
1437 MtdData *mtd = GetEmptyMtdData();
1438 MtdDiskPartition *e1 = mtd->primary.partitions;
1439 uint64_t start, size;
1440
1441 /* Tries=nonzero is attempted just like success, but tries=0 isn't */
1442 BuildTestMtdData(mtd);
1443 MtdFillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
1444 MtdFillEntry(e1 + KERNEL_B, 1, 3, 0, 0);
1445 MtdFillEntry(e1 + KERNEL_X, 1, 4, 0, 1);
1446 MtdFillEntry(e1 + KERNEL_Y, 1, 0, 0, 5);
1447 mtd->primary.crc32 = MtdHeaderCrc(&mtd->primary);
1448 MtdInit(mtd);
1449
1450 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1451 EXPECT(KERNEL_X == mtd->current_kernel);
1452 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1453 EXPECT(KERNEL_A == mtd->current_kernel);
1454 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1455 MtdNextKernelEntry(mtd, &start, &size));
1456
1457 return TEST_OK;
1458}
1459
1460static int MtdUpdateTest() {
1461 MtdData *mtd = GetEmptyMtdData();
1462 MtdDiskPartition *e = &mtd->primary.partitions[0];
1463 uint64_t start, size;
1464
1465 BuildTestMtdData(mtd);
1466
1467 /* Tries=nonzero is attempted just like success, but tries=0 isn't */
1468 MtdFillEntry(e + KERNEL_A, 1, 4, 1, 0);
1469 MtdFillEntry(e + KERNEL_B, 1, 3, 0, 2);
1470 MtdFillEntry(e + KERNEL_X, 1, 2, 0, 2);
1471 mtd->primary.crc32 = MtdHeaderCrc(&mtd->primary);
1472 mtd->modified = 0;
1473 EXPECT(GPT_SUCCESS == MtdInit(mtd));
1474
1475 /* Successful kernel */
1476 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1477 EXPECT(KERNEL_A == mtd->current_kernel);
1478 EXPECT(1 == MtdGetEntrySuccessful(e + KERNEL_A));
1479 EXPECT(4 == MtdGetEntryPriority(e + KERNEL_A));
1480 EXPECT(0 == MtdGetEntryTries(e + KERNEL_A));
1481 /* Trying successful kernel changes nothing */
1482 EXPECT(GPT_SUCCESS == MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_TRY));
1483 EXPECT(1 == MtdGetEntrySuccessful(e + KERNEL_A));
1484 EXPECT(4 == MtdGetEntryPriority(e + KERNEL_A));
1485 EXPECT(0 == MtdGetEntryTries(e + KERNEL_A));
1486 EXPECT(0 == mtd->modified);
1487 /* Marking it bad also does not update it. */
1488 EXPECT(GPT_SUCCESS == MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_BAD));
1489 EXPECT(1 == MtdGetEntrySuccessful(e + KERNEL_A));
1490 EXPECT(4 == MtdGetEntryPriority(e + KERNEL_A));
1491 EXPECT(0 == MtdGetEntryTries(e + KERNEL_A));
1492 EXPECT(0 == mtd->modified);
1493
1494 /* Kernel with tries */
1495 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1496 EXPECT(KERNEL_B == mtd->current_kernel);
1497 EXPECT(0 == MtdGetEntrySuccessful(e + KERNEL_B));
1498 EXPECT(3 == MtdGetEntryPriority(e + KERNEL_B));
1499 EXPECT(2 == MtdGetEntryTries(e + KERNEL_B));
1500 /* Marking it bad clears it */
1501 EXPECT(GPT_SUCCESS == MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_BAD));
1502 EXPECT(0 == MtdGetEntrySuccessful(e + KERNEL_B));
1503 EXPECT(0 == MtdGetEntryPriority(e + KERNEL_B));
1504 EXPECT(0 == MtdGetEntryTries(e + KERNEL_B));
1505 /* And that's caused the mtd to need updating */
1506 EXPECT(1 == mtd->modified);
1507
1508 /* Another kernel with tries */
1509 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1510 EXPECT(KERNEL_X == mtd->current_kernel);
1511 EXPECT(0 == MtdGetEntrySuccessful(e + KERNEL_X));
1512 EXPECT(2 == MtdGetEntryPriority(e + KERNEL_X));
1513 EXPECT(2 == MtdGetEntryTries(e + KERNEL_X));
1514 /* Trying it uses up a try */
1515 EXPECT(GPT_SUCCESS == MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_TRY));
1516 EXPECT(0 == MtdGetEntrySuccessful(e + KERNEL_X));
1517 EXPECT(2 == MtdGetEntryPriority(e + KERNEL_X));
1518 EXPECT(1 == MtdGetEntryTries(e + KERNEL_X));
1519 /* Trying it again marks it inactive */
1520 EXPECT(GPT_SUCCESS == MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_TRY));
1521 EXPECT(0 == MtdGetEntrySuccessful(e + KERNEL_X));
1522 EXPECT(0 == MtdGetEntryPriority(e + KERNEL_X));
1523 EXPECT(0 == MtdGetEntryTries(e + KERNEL_X));
1524
1525 /* Can't update if entry isn't a kernel, or there isn't an entry */
1526 MtdSetEntryType(e + KERNEL_X, MTD_PARTITION_TYPE_UNUSED);
1527 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1528 MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_BAD));
1529 mtd->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
1530 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1531 MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_BAD));
1532
1533 return TEST_OK;
1534}
1535
Randall Spanglere9213a72013-01-24 11:19:55 -08001536static int GptUpdateTest(void)
1537{
1538 GptData *gpt = GetEmptyGptData();
1539 GptEntry *e = (GptEntry *)(gpt->primary_entries);
1540 GptEntry *e2 = (GptEntry *)(gpt->secondary_entries);
1541 uint64_t start, size;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001542
Randall Spanglere9213a72013-01-24 11:19:55 -08001543 /* Tries=nonzero is attempted just like success, but tries=0 isn't */
1544 BuildTestGptData(gpt);
1545 FillEntry(e + KERNEL_A, 1, 4, 1, 0);
1546 FillEntry(e + KERNEL_B, 1, 3, 0, 2);
1547 FillEntry(e + KERNEL_X, 1, 2, 0, 2);
1548 RefreshCrc32(gpt);
1549 GptInit(gpt);
1550 gpt->modified = 0; /* Nothing modified yet */
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001551
Randall Spanglere9213a72013-01-24 11:19:55 -08001552 /* Successful kernel */
1553 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1554 EXPECT(KERNEL_A == gpt->current_kernel);
1555 EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
1556 EXPECT(4 == GetEntryPriority(e + KERNEL_A));
1557 EXPECT(0 == GetEntryTries(e + KERNEL_A));
1558 EXPECT(1 == GetEntrySuccessful(e2 + KERNEL_A));
1559 EXPECT(4 == GetEntryPriority(e2 + KERNEL_A));
1560 EXPECT(0 == GetEntryTries(e2 + KERNEL_A));
1561 /* Trying successful kernel changes nothing */
1562 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
1563 EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
1564 EXPECT(4 == GetEntryPriority(e + KERNEL_A));
1565 EXPECT(0 == GetEntryTries(e + KERNEL_A));
1566 EXPECT(0 == gpt->modified);
1567 /* Marking it bad also does not update it. */
1568 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
1569 EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
1570 EXPECT(4 == GetEntryPriority(e + KERNEL_A));
1571 EXPECT(0 == GetEntryTries(e + KERNEL_A));
1572 EXPECT(0 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001573
Randall Spanglere9213a72013-01-24 11:19:55 -08001574 /* Kernel with tries */
1575 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1576 EXPECT(KERNEL_B == gpt->current_kernel);
1577 EXPECT(0 == GetEntrySuccessful(e + KERNEL_B));
1578 EXPECT(3 == GetEntryPriority(e + KERNEL_B));
1579 EXPECT(2 == GetEntryTries(e + KERNEL_B));
1580 /* Marking it bad clears it */
1581 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
1582 EXPECT(0 == GetEntrySuccessful(e + KERNEL_B));
1583 EXPECT(0 == GetEntryPriority(e + KERNEL_B));
1584 EXPECT(0 == GetEntryTries(e + KERNEL_B));
1585 /* Which affects both copies of the partition entries */
1586 EXPECT(0 == GetEntrySuccessful(e2 + KERNEL_B));
1587 EXPECT(0 == GetEntryPriority(e2 + KERNEL_B));
1588 EXPECT(0 == GetEntryTries(e2 + KERNEL_B));
1589 /* And that's caused the GPT to need updating */
1590 EXPECT(0x0F == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001591
Randall Spanglere9213a72013-01-24 11:19:55 -08001592 /* Another kernel with tries */
1593 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1594 EXPECT(KERNEL_X == gpt->current_kernel);
1595 EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
1596 EXPECT(2 == GetEntryPriority(e + KERNEL_X));
1597 EXPECT(2 == GetEntryTries(e + KERNEL_X));
1598 /* Trying it uses up a try */
1599 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
1600 EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
1601 EXPECT(2 == GetEntryPriority(e + KERNEL_X));
1602 EXPECT(1 == GetEntryTries(e + KERNEL_X));
1603 EXPECT(0 == GetEntrySuccessful(e2 + KERNEL_X));
1604 EXPECT(2 == GetEntryPriority(e2 + KERNEL_X));
1605 EXPECT(1 == GetEntryTries(e2 + KERNEL_X));
1606 /* Trying it again marks it inactive */
1607 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
1608 EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
1609 EXPECT(0 == GetEntryPriority(e + KERNEL_X));
1610 EXPECT(0 == GetEntryTries(e + KERNEL_X));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001611
Randall Spangler0bda13f2013-01-24 12:25:26 -08001612 /* Can't update if entry isn't a kernel, or there isn't an entry */
1613 Memcpy(&e[KERNEL_X].type, &guid_rootfs, sizeof(guid_rootfs));
1614 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1615 GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
1616 gpt->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
1617 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1618 GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
1619
1620
Randall Spanglere9213a72013-01-24 11:19:55 -08001621 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001622}
1623
Randall Spanglere9213a72013-01-24 11:19:55 -08001624/*
1625 * Give an invalid kernel type, and expect GptUpdateKernelEntry() returns
1626 * GPT_ERROR_INVALID_UPDATE_TYPE.
1627 */
1628static int UpdateInvalidKernelTypeTest(void)
1629{
1630 GptData *gpt = GetEmptyGptData();
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001631
Randall Spanglere9213a72013-01-24 11:19:55 -08001632 BuildTestGptData(gpt);
1633 /* anything, but not CGPT_KERNEL_ENTRY_NOT_FOUND */
1634 gpt->current_kernel = 0;
1635 /* any invalid update_type value */
1636 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1637 GptUpdateKernelEntry(gpt, 99));
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001638
Randall Spanglere9213a72013-01-24 11:19:55 -08001639 return TEST_OK;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001640}
1641
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001642static int MtdUpdateInvalidKernelTypeTest(void)
1643{
1644 MtdData *mtd = GetEmptyMtdData();
1645
1646 BuildTestMtdData(mtd);
1647 /* anything, but not CGPT_KERNEL_ENTRY_NOT_FOUND */
1648 mtd->current_kernel = 0;
1649 /* any invalid update_type value */
1650 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1651 MtdUpdateKernelEntry(mtd, 99));
1652
1653 return TEST_OK;
1654}
1655
Randall Spanglere9213a72013-01-24 11:19:55 -08001656/* Test duplicate UniqueGuids can be detected. */
1657static int DuplicateUniqueGuidTest(void)
1658{
1659 GptData *gpt = GetEmptyGptData();
1660 GptHeader *h = (GptHeader *)gpt->primary_header;
1661 GptEntry *e = (GptEntry *)gpt->primary_entries;
1662 int i, j;
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001663
Randall Spanglere9213a72013-01-24 11:19:55 -08001664 struct {
1665 int duplicate;
1666 struct {
1667 uint64_t starting_lba;
1668 uint64_t ending_lba;
1669 uint32_t type_guid;
1670 uint32_t unique_guid;
1671 } entries[16]; /* enough for testing. */
1672 } cases[] = {
1673 {GPT_SUCCESS, {{100, 109, 1, 1},
1674 {110, 119, 2, 2},
1675 {120, 129, 3, 3},
1676 {130, 139, 4, 4},
1677 }},
1678 {GPT_SUCCESS, {{100, 109, 1, 1},
1679 {110, 119, 1, 2},
1680 {120, 129, 2, 3},
1681 {130, 139, 2, 4},
1682 }},
1683 {GPT_ERROR_DUP_GUID, {{100, 109, 1, 1},
1684 {110, 119, 2, 2},
1685 {120, 129, 3, 1},
1686 {130, 139, 4, 4},
1687 }},
1688 {GPT_ERROR_DUP_GUID, {{100, 109, 1, 1},
1689 {110, 119, 1, 2},
1690 {120, 129, 2, 3},
1691 {130, 139, 2, 2},
1692 }},
1693 };
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001694
Randall Spanglere9213a72013-01-24 11:19:55 -08001695 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
1696 BuildTestGptData(gpt);
1697 ZeroEntries(gpt);
1698 for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) {
1699 if (!cases[i].entries[j].starting_lba)
1700 break;
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001701
Randall Spanglere9213a72013-01-24 11:19:55 -08001702 e[j].starting_lba = cases[i].entries[j].starting_lba;
1703 e[j].ending_lba = cases[i].entries[j].ending_lba;
1704 SetGuid(&e[j].type, cases[i].entries[j].type_guid);
1705 SetGuid(&e[j].unique, cases[i].entries[j].unique_guid);
1706 }
1707 RefreshCrc32(gpt);
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001708
Randall Spanglere9213a72013-01-24 11:19:55 -08001709 EXPECT(cases[i].duplicate == CheckEntries(e, h));
1710 }
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001711
Randall Spanglere9213a72013-01-24 11:19:55 -08001712 return TEST_OK;
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001713}
1714
Randall Spangler0bda13f2013-01-24 12:25:26 -08001715/* Test getting the current kernel GUID */
1716static int GetKernelGuidTest(void)
1717{
1718 GptData *gpt = GetEmptyGptData();
1719 GptEntry *e = (GptEntry *)gpt->primary_entries;
1720 Guid g;
1721
1722 BuildTestGptData(gpt);
1723 gpt->current_kernel = 0;
1724 GetCurrentKernelUniqueGuid(gpt, &g);
1725 EXPECT(!Memcmp(&g, &e[0].unique, sizeof(Guid)));
1726 gpt->current_kernel = 1;
1727 GetCurrentKernelUniqueGuid(gpt, &g);
1728 EXPECT(!Memcmp(&g, &e[1].unique, sizeof(Guid)));
1729
1730 return TEST_OK;
1731}
1732
1733/* Test getting GPT error text strings */
1734static int ErrorTextTest(void)
1735{
1736 int i;
1737
1738 /* Known errors are not unknown */
1739 for (i = 0; i < GPT_ERROR_COUNT; i++) {
1740 EXPECT(GptErrorText(i));
1741 EXPECT(strcmp(GptErrorText(i), "Unknown"));
1742 }
1743
1744 /* But other error values are */
1745 EXPECT(!strcmp(GptErrorText(GPT_ERROR_COUNT), "Unknown"));
1746
1747 return TEST_OK;
1748}
1749
Randall Spanglere9213a72013-01-24 11:19:55 -08001750int main(int argc, char *argv[])
1751{
1752 int i;
1753 int error_count = 0;
1754 struct {
1755 char *name;
1756 test_func fp;
1757 int retval;
1758 } test_cases[] = {
1759 { TEST_CASE(StructSizeTest), },
1760 { TEST_CASE(TestBuildTestGptData), },
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001761 { TEST_CASE(TestBuildTestMtdData), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001762 { TEST_CASE(ParameterTests), },
1763 { TEST_CASE(HeaderCrcTest), },
Randall Spangler0bda13f2013-01-24 12:25:26 -08001764 { TEST_CASE(HeaderSameTest), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001765 { TEST_CASE(SignatureTest), },
1766 { TEST_CASE(RevisionTest), },
1767 { TEST_CASE(SizeTest), },
1768 { TEST_CASE(CrcFieldTest), },
1769 { TEST_CASE(ReservedFieldsTest), },
1770 { TEST_CASE(SizeOfPartitionEntryTest), },
1771 { TEST_CASE(NumberOfPartitionEntriesTest), },
1772 { TEST_CASE(MyLbaTest), },
1773 { TEST_CASE(FirstUsableLbaAndLastUsableLbaTest), },
1774 { TEST_CASE(EntriesCrcTest), },
1775 { TEST_CASE(ValidEntryTest), },
1776 { TEST_CASE(OverlappedPartitionTest), },
1777 { TEST_CASE(SanityCheckTest), },
1778 { TEST_CASE(NoValidKernelEntryTest), },
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001779 { TEST_CASE(MtdNoValidKernelEntryTest), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001780 { TEST_CASE(EntryAttributeGetSetTest), },
1781 { TEST_CASE(EntryTypeTest), },
1782 { TEST_CASE(GetNextNormalTest), },
1783 { TEST_CASE(GetNextPrioTest), },
1784 { TEST_CASE(GetNextTriesTest), },
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001785 { TEST_CASE(MtdGetNextNormalTest), },
1786 { TEST_CASE(MtdGetNextPrioTest), },
1787 { TEST_CASE(MtdGetNextTriesTest), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001788 { TEST_CASE(GptUpdateTest), },
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001789 { TEST_CASE(MtdUpdateTest), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001790 { TEST_CASE(UpdateInvalidKernelTypeTest), },
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001791 { TEST_CASE(MtdUpdateInvalidKernelTypeTest), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001792 { TEST_CASE(DuplicateUniqueGuidTest), },
1793 { TEST_CASE(TestCrc32TestVectors), },
Randall Spangler0bda13f2013-01-24 12:25:26 -08001794 { TEST_CASE(GetKernelGuidTest), },
1795 { TEST_CASE(ErrorTextTest), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001796 };
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001797
Randall Spanglere9213a72013-01-24 11:19:55 -08001798 for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
1799 printf("Running %s() ...\n", test_cases[i].name);
1800 test_cases[i].retval = test_cases[i].fp();
1801 if (test_cases[i].retval) {
1802 printf(COL_RED "[ERROR]\n\n" COL_STOP);
1803 ++error_count;
1804 } else {
1805 printf(COL_GREEN "[PASS]\n\n" COL_STOP);
1806 }
1807 }
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001808
Randall Spanglere9213a72013-01-24 11:19:55 -08001809 if (error_count) {
1810 printf("\n------------------------------------------------\n");
1811 printf(COL_RED "The following %d test cases are failed:\n"
1812 COL_STOP, error_count);
1813 for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
1814 if (test_cases[i].retval)
1815 printf(" %s()\n", test_cases[i].name);
1816 }
1817 }
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001818
Randall Spanglere9213a72013-01-24 11:19:55 -08001819 return error_count ? 1 : 0;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001820}