blob: 1ee551d0429212c439c128f76887b9b9e9bae10a [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
Albert Chaulk534723a2013-03-20 14:46:50 -07008#include "../cgpt/cgpt.h"
Louis Yung-Chieh Lo0dce41c2010-05-17 22:45:30 -07009#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"
Albert Chaulk534723a2013-03-20 14:46:50 -070013#include "errno.h"
14#include "flash_ts.h"
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070015#include "gpt.h"
Albert Chaulk5c9e4532013-03-20 16:03:49 -070016#include "mtdlib.h"
vbendeb3ecaf772010-06-24 16:19:53 -070017#include "test_common.h"
Albert Chaulk534723a2013-03-20 14:46:50 -070018#define _STUB_IMPLEMENTATION_
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070019#include "utility.h"
20
Randall Spanglere9213a72013-01-24 11:19:55 -080021/*
22 * Testing partition layout (sector_bytes=512)
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070023 *
24 * LBA Size Usage
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -070025 * ---------------------------------------------------------
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070026 * 0 1 PMBR
27 * 1 1 primary partition header
28 * 2 32 primary partition entries (128B * 128)
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -070029 * 34 100 kernel A (index: 0)
30 * 134 100 root A (index: 1)
31 * 234 100 root B (index: 2)
32 * 334 100 kernel B (index: 3)
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070033 * 434 32 secondary partition entries
34 * 466 1 secondary partition header
35 * 467
36 */
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -070037#define KERNEL_A 0
Randall Spangler3dcf9dc2010-06-02 12:46:17 -070038#define KERNEL_B 1
39#define ROOTFS_A 2
40#define ROOTFS_B 3
41#define KERNEL_X 2 /* Overload ROOTFS_A, for some GetNext tests */
42#define KERNEL_Y 3 /* Overload ROOTFS_B, for some GetNext tests */
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -070043
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070044#define DEFAULT_SECTOR_SIZE 512
45#define MAX_SECTOR_SIZE 4096
46#define DEFAULT_DRIVE_SECTORS 467
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070047#define PARTITION_ENTRIES_SIZE TOTAL_ENTRIES_SIZE /* 16384 */
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070048
Randall Spangler3dcf9dc2010-06-02 12:46:17 -070049static const Guid guid_zero = {{{0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0}}}};
50static const Guid guid_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
51static const Guid guid_rootfs = GPT_ENT_TYPE_CHROMEOS_ROOTFS;
52
Albert Chaulk534723a2013-03-20 14:46:50 -070053// cgpt_common.c requires these be defined if linked in.
54const char *progname = "CGPT-TEST";
55const char *command = "TEST";
56
57// Ramdisk for flash ts testing.
58static uint8_t *nand_drive = NULL;
59static uint32_t nand_drive_sz;
60static uint8_t *nand_bad_block_map = NULL;
61
Randall Spanglere9213a72013-01-24 11:19:55 -080062/*
63 * Copy a random-for-this-program-only Guid into the dest. The num parameter
Bill Richardsonaa8eda42010-08-27 09:31:26 -070064 * completely determines the Guid.
65 */
Randall Spanglere9213a72013-01-24 11:19:55 -080066static void SetGuid(void *dest, uint32_t num)
67{
68 Guid g = {{{num,0xd450,0x44bc,0xa6,0x93,
69 {0xb8,0xac,0x75,0x5f,0xcd,0x48}}}};
70 Memcpy(dest, &g, sizeof(Guid));
Bill Richardsonaa8eda42010-08-27 09:31:26 -070071}
Randall Spangler3dcf9dc2010-06-02 12:46:17 -070072
Randall Spanglere9213a72013-01-24 11:19:55 -080073/*
74 * Given a GptData pointer, first re-calculate entries CRC32 value, then reset
75 * header CRC32 value to 0, and calculate header CRC32 value. Both primary and
76 * secondary are updated.
77 */
78static void RefreshCrc32(GptData *gpt)
79{
80 GptHeader *header, *header2;
81 GptEntry *entries, *entries2;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070082
Randall Spanglere9213a72013-01-24 11:19:55 -080083 header = (GptHeader *)gpt->primary_header;
84 entries = (GptEntry *)gpt->primary_entries;
85 header2 = (GptHeader *)gpt->secondary_header;
86 entries2 = (GptEntry *)gpt->secondary_entries;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070087
Randall Spanglere9213a72013-01-24 11:19:55 -080088 header->entries_crc32 =
89 Crc32((uint8_t *)entries,
90 header->number_of_entries * header->size_of_entry);
91 header->header_crc32 = 0;
92 header->header_crc32 = Crc32((uint8_t *)header, header->size);
93 header2->entries_crc32 =
94 Crc32((uint8_t *)entries2,
95 header2->number_of_entries * header2->size_of_entry);
96 header2->header_crc32 = 0;
97 header2->header_crc32 = Crc32((uint8_t *)header2, header2->size);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070098}
99
Randall Spanglere9213a72013-01-24 11:19:55 -0800100static void ZeroHeaders(GptData *gpt)
101{
102 Memset(gpt->primary_header, 0, MAX_SECTOR_SIZE);
103 Memset(gpt->secondary_header, 0, MAX_SECTOR_SIZE);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700104}
105
Randall Spanglere9213a72013-01-24 11:19:55 -0800106static void ZeroEntries(GptData *gpt)
107{
108 Memset(gpt->primary_entries, 0, PARTITION_ENTRIES_SIZE);
109 Memset(gpt->secondary_entries, 0, PARTITION_ENTRIES_SIZE);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700110}
111
Randall Spanglere9213a72013-01-24 11:19:55 -0800112static void ZeroHeadersEntries(GptData *gpt)
113{
114 ZeroHeaders(gpt);
115 ZeroEntries(gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700116}
117
Randall Spanglere9213a72013-01-24 11:19:55 -0800118/*
119 * Return a pointer to a static GptData instance (no free is required).
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700120 * All fields are zero except 4 pointers linking to header and entries.
Randall Spanglere9213a72013-01-24 11:19:55 -0800121 * All content of headers and entries are zero.
122 */
123static GptData *GetEmptyGptData(void)
124{
125 static GptData gpt;
126 static uint8_t primary_header[MAX_SECTOR_SIZE];
127 static uint8_t primary_entries[PARTITION_ENTRIES_SIZE];
128 static uint8_t secondary_header[MAX_SECTOR_SIZE];
129 static uint8_t secondary_entries[PARTITION_ENTRIES_SIZE];
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700130
Randall Spanglere9213a72013-01-24 11:19:55 -0800131 Memset(&gpt, 0, sizeof(gpt));
132 gpt.primary_header = primary_header;
133 gpt.primary_entries = primary_entries;
134 gpt.secondary_header = secondary_header;
135 gpt.secondary_entries = secondary_entries;
136 ZeroHeadersEntries(&gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700137
Randall Spanglere9213a72013-01-24 11:19:55 -0800138 /* Initialize GptData internal states. */
139 gpt.current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700140
Randall Spanglere9213a72013-01-24 11:19:55 -0800141 return &gpt;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700142}
143
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700144static MtdData *GetEmptyMtdData() {
145 static MtdData mtd;
146 Memset(&mtd, 0, sizeof(mtd));
147 mtd.current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
148 return &mtd;
149}
150
Randall Spanglere9213a72013-01-24 11:19:55 -0800151/*
152 * Fill in most of fields and creates the layout described in the top of this
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700153 * file. Before calling this function, primary/secondary header/entries must
154 * have been pointed to the buffer, say, a gpt returned from GetEmptyGptData().
155 * This function returns a good (valid) copy of GPT layout described in top of
Randall Spanglere9213a72013-01-24 11:19:55 -0800156 * this file.
157 */
158static void BuildTestGptData(GptData *gpt)
159{
160 GptHeader *header, *header2;
161 GptEntry *entries, *entries2;
162 Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
163 Guid chromeos_rootfs = GPT_ENT_TYPE_CHROMEOS_ROOTFS;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700164
Randall Spanglere9213a72013-01-24 11:19:55 -0800165 gpt->sector_bytes = DEFAULT_SECTOR_SIZE;
166 gpt->drive_sectors = DEFAULT_DRIVE_SECTORS;
167 gpt->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
168 gpt->valid_headers = MASK_BOTH;
169 gpt->valid_entries = MASK_BOTH;
170 gpt->modified = 0;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700171
Randall Spanglere9213a72013-01-24 11:19:55 -0800172 /* Build primary */
173 header = (GptHeader *)gpt->primary_header;
174 entries = (GptEntry *)gpt->primary_entries;
175 Memcpy(header->signature, GPT_HEADER_SIGNATURE,
176 sizeof(GPT_HEADER_SIGNATURE));
177 header->revision = GPT_HEADER_REVISION;
178 header->size = sizeof(GptHeader);
179 header->reserved_zero = 0;
180 header->my_lba = 1;
181 header->alternate_lba = DEFAULT_DRIVE_SECTORS - 1;
182 header->first_usable_lba = 34;
183 header->last_usable_lba = DEFAULT_DRIVE_SECTORS - 1 - 32 - 1; /* 433 */
184 header->entries_lba = 2;
185 /* 512B / 128B * 32sectors = 128 entries */
186 header->number_of_entries = 128;
187 header->size_of_entry = 128; /* bytes */
188 Memcpy(&entries[0].type, &chromeos_kernel, sizeof(chromeos_kernel));
189 SetGuid(&entries[0].unique, 0);
190 entries[0].starting_lba = 34;
191 entries[0].ending_lba = 133;
192 Memcpy(&entries[1].type, &chromeos_rootfs, sizeof(chromeos_rootfs));
193 SetGuid(&entries[1].unique, 1);
194 entries[1].starting_lba = 134;
195 entries[1].ending_lba = 232;
196 Memcpy(&entries[2].type, &chromeos_rootfs, sizeof(chromeos_rootfs));
197 SetGuid(&entries[2].unique, 2);
198 entries[2].starting_lba = 234;
199 entries[2].ending_lba = 331;
200 Memcpy(&entries[3].type, &chromeos_kernel, sizeof(chromeos_kernel));
201 SetGuid(&entries[3].unique, 3);
202 entries[3].starting_lba = 334;
203 entries[3].ending_lba = 430;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700204
Randall Spanglere9213a72013-01-24 11:19:55 -0800205 /* Build secondary */
206 header2 = (GptHeader *)gpt->secondary_header;
207 entries2 = (GptEntry *)gpt->secondary_entries;
208 Memcpy(header2, header, sizeof(GptHeader));
209 Memcpy(entries2, entries, PARTITION_ENTRIES_SIZE);
210 header2->my_lba = DEFAULT_DRIVE_SECTORS - 1; /* 466 */
211 header2->alternate_lba = 1;
212 header2->entries_lba = DEFAULT_DRIVE_SECTORS - 1 - 32; /* 434 */
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700213
Randall Spanglere9213a72013-01-24 11:19:55 -0800214 RefreshCrc32(gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700215}
216
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700217static void BuildTestMtdData(MtdData *mtd) {
218 MtdDiskPartition *partitions;
219
220 mtd->sector_bytes = DEFAULT_SECTOR_SIZE;
221 mtd->drive_sectors = DEFAULT_DRIVE_SECTORS;
222 mtd->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
223 mtd->modified = 0;
224 Memset(&mtd->primary, 0, sizeof(mtd->primary));
225
226 Memcpy(mtd->primary.signature, MTD_DRIVE_SIGNATURE,
227 sizeof(mtd->primary.signature));
Albert Chaulk289b6042013-06-25 11:30:46 -0700228 mtd->primary.first_offset = 32 * DEFAULT_SECTOR_SIZE;
229 mtd->primary.last_offset = DEFAULT_DRIVE_SECTORS * DEFAULT_SECTOR_SIZE - 1;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700230 mtd->primary.size = MTD_DRIVE_V1_SIZE;
231
232 /* These values are not used directly by the library, but they are checked */
233 mtd->flash_page_bytes = mtd->sector_bytes * 8;
234 mtd->flash_block_bytes = mtd->flash_page_bytes * 8;
235 mtd->fts_block_offset = 1;
236 mtd->fts_block_size = 1;
237
238 partitions = &mtd->primary.partitions[0];
Albert Chaulk289b6042013-06-25 11:30:46 -0700239 partitions[0].starting_offset = 34 * DEFAULT_SECTOR_SIZE;
240 partitions[0].ending_offset = 134 * DEFAULT_SECTOR_SIZE - 1;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700241 partitions[0].flags =
242 MTD_PARTITION_TYPE_CHROMEOS_KERNEL << MTD_ATTRIBUTE_TYPE_OFFSET;
Albert Chaulk289b6042013-06-25 11:30:46 -0700243 partitions[1].starting_offset = 134 * DEFAULT_SECTOR_SIZE;
244 partitions[1].ending_offset = 233 * DEFAULT_SECTOR_SIZE - 1;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700245 partitions[1].flags =
246 MTD_PARTITION_TYPE_CHROMEOS_ROOTFS << MTD_ATTRIBUTE_TYPE_OFFSET;
Albert Chaulk289b6042013-06-25 11:30:46 -0700247 partitions[2].starting_offset = 234 * DEFAULT_SECTOR_SIZE;
248 partitions[2].ending_offset = 332 * DEFAULT_SECTOR_SIZE - 1;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700249 partitions[2].flags =
250 MTD_PARTITION_TYPE_CHROMEOS_KERNEL << MTD_ATTRIBUTE_TYPE_OFFSET;
Albert Chaulk289b6042013-06-25 11:30:46 -0700251 partitions[3].starting_offset = 334 * DEFAULT_SECTOR_SIZE;
252 partitions[3].ending_offset = 431 * DEFAULT_SECTOR_SIZE - 1;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700253 partitions[3].flags =
254 MTD_PARTITION_TYPE_CHROMEOS_ROOTFS << MTD_ATTRIBUTE_TYPE_OFFSET;
255
256 mtd->primary.crc32 = 0;
257 mtd->primary.crc32 = Crc32(&mtd->primary, MTD_DRIVE_V1_SIZE);
258}
259
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700260
Randall Spanglere9213a72013-01-24 11:19:55 -0800261/*
262 * Test if the structures are the expected size; if this fails, struct packing
263 * is not working properly.
264 */
265static int StructSizeTest(void)
266{
Randall Spangler81d09962010-06-23 10:15:38 -0700267
Randall Spanglere9213a72013-01-24 11:19:55 -0800268 EXPECT(GUID_EXPECTED_SIZE == sizeof(Guid));
269 EXPECT(GPTHEADER_EXPECTED_SIZE == sizeof(GptHeader));
270 EXPECT(GPTENTRY_EXPECTED_SIZE == sizeof(GptEntry));
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700271 EXPECT(MTDENTRY_EXPECTED_SIZE == sizeof(MtdDiskPartition));
272 EXPECT(MTDLAYOUT_EXPECTED_SIZE == sizeof(MtdDiskLayout));
Randall Spanglere9213a72013-01-24 11:19:55 -0800273 return TEST_OK;
Randall Spangler81d09962010-06-23 10:15:38 -0700274}
275
276
Randall Spanglere9213a72013-01-24 11:19:55 -0800277/* Test if the default structure returned by BuildTestGptData() is good. */
278static int TestBuildTestGptData(void)
279{
280 GptData *gpt;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700281
Randall Spanglere9213a72013-01-24 11:19:55 -0800282 gpt = GetEmptyGptData();
283 BuildTestGptData(gpt);
284 EXPECT(GPT_SUCCESS == GptInit(gpt));
Randall Spangler0bda13f2013-01-24 12:25:26 -0800285 gpt->sector_bytes = 0;
286 EXPECT(GPT_ERROR_INVALID_SECTOR_SIZE == GptInit(gpt));
Randall Spanglere9213a72013-01-24 11:19:55 -0800287 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700288}
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700289
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700290static int TestBuildTestMtdData() {
291 MtdData *mtd = GetEmptyMtdData();
292
293 BuildTestMtdData(mtd);
294 EXPECT(GPT_SUCCESS == MtdInit(mtd));
295 return TEST_OK;
296}
297
Randall Spanglere9213a72013-01-24 11:19:55 -0800298/*
299 * Test if wrong sector_bytes or drive_sectors is detected by GptInit().
300 * Currently we only support 512 bytes per sector. In the future, we may
301 * support other sizes. A too small drive_sectors should be rejected by
302 * GptInit().
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700303 * For MtdInit(), additionally test various flash geometries to verify
304 * that only valid ones are accepted.
Randall Spanglere9213a72013-01-24 11:19:55 -0800305 */
306static int ParameterTests(void)
307{
308 GptData *gpt;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700309 MtdData *mtd;
Randall Spanglere9213a72013-01-24 11:19:55 -0800310 struct {
311 uint32_t sector_bytes;
312 uint64_t drive_sectors;
313 int expected_retval;
314 } cases[] = {
315 {512, DEFAULT_DRIVE_SECTORS, GPT_SUCCESS},
316 {520, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
317 {512, 0, GPT_ERROR_INVALID_SECTOR_NUMBER},
318 {512, 66, GPT_ERROR_INVALID_SECTOR_NUMBER},
319 {512, GPT_PMBR_SECTOR + GPT_HEADER_SECTOR * 2 +
320 GPT_ENTRIES_SECTORS * 2, GPT_SUCCESS},
321 {4096, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
322 };
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700323 struct {
324 uint32_t sector_bytes;
325 uint32_t drive_sectors;
326 uint32_t flash_page_bytes;
327 uint32_t flash_block_bytes;
328 int expected_retval;
329 } mtdcases[] = {
330 {512, DEFAULT_DRIVE_SECTORS, 8*512,
331 8*512, GPT_SUCCESS},
332 {510, DEFAULT_DRIVE_SECTORS, 8*512,
333 8*512, GPT_ERROR_INVALID_SECTOR_SIZE},
334 {512, DEFAULT_DRIVE_SECTORS, 8*512,
335 8*512, GPT_SUCCESS},
336 {512, DEFAULT_DRIVE_SECTORS, 512,
337 8*512, GPT_SUCCESS},
338 {512, DEFAULT_DRIVE_SECTORS, 8*512,
339 10*512, GPT_ERROR_INVALID_FLASH_GEOMETRY},
340 {512, DEFAULT_DRIVE_SECTORS, 3*512,
341 9*512, GPT_SUCCESS},
342 {512, DEFAULT_DRIVE_SECTORS, 8*512,
343 6*512, GPT_ERROR_INVALID_FLASH_GEOMETRY},
344 {512, DEFAULT_DRIVE_SECTORS, 256,
345 6*512, GPT_ERROR_INVALID_FLASH_GEOMETRY},
346 {512, DEFAULT_DRIVE_SECTORS, 512,
347 6*512 + 256, GPT_ERROR_INVALID_FLASH_GEOMETRY},
348 };
Randall Spanglere9213a72013-01-24 11:19:55 -0800349 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700350
Randall Spanglere9213a72013-01-24 11:19:55 -0800351 gpt = GetEmptyGptData();
352 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
353 BuildTestGptData(gpt);
354 gpt->sector_bytes = cases[i].sector_bytes;
355 gpt->drive_sectors = cases[i].drive_sectors;
356 EXPECT(cases[i].expected_retval == CheckParameters(gpt));
357 }
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700358
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700359 mtd = GetEmptyMtdData();
360 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
361 BuildTestMtdData(mtd);
362 mtd->sector_bytes = mtdcases[i].sector_bytes;
363 mtd->drive_sectors = mtdcases[i].drive_sectors;
364 mtd->flash_block_bytes = mtdcases[i].flash_block_bytes;
365 mtd->flash_page_bytes = mtdcases[i].flash_page_bytes;
366 if(mtdcases[i].expected_retval != MtdCheckParameters(mtd)) {
367 printf("i=%d\n",i);
368 }
369 EXPECT(mtdcases[i].expected_retval == MtdCheckParameters(mtd));
370 }
371
Randall Spanglere9213a72013-01-24 11:19:55 -0800372 return TEST_OK;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700373}
374
Randall Spanglere9213a72013-01-24 11:19:55 -0800375/* Test if header CRC in two copies are calculated. */
376static int HeaderCrcTest(void)
377{
378 GptData *gpt = GetEmptyGptData();
379 GptHeader *h1 = (GptHeader *)gpt->primary_header;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700380
Randall Spanglere9213a72013-01-24 11:19:55 -0800381 BuildTestGptData(gpt);
382 EXPECT(HeaderCrc(h1) == h1->header_crc32);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700383
Randall Spanglere9213a72013-01-24 11:19:55 -0800384 /* CRC covers first byte of header */
385 BuildTestGptData(gpt);
386 gpt->primary_header[0] ^= 0xa5;
387 EXPECT(HeaderCrc(h1) != h1->header_crc32);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700388
Randall Spanglere9213a72013-01-24 11:19:55 -0800389 /* CRC covers last byte of header */
390 BuildTestGptData(gpt);
391 gpt->primary_header[h1->size - 1] ^= 0x5a;
392 EXPECT(HeaderCrc(h1) != h1->header_crc32);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700393
Randall Spanglere9213a72013-01-24 11:19:55 -0800394 /* CRC only covers header */
395 BuildTestGptData(gpt);
396 gpt->primary_header[h1->size] ^= 0x5a;
397 EXPECT(HeaderCrc(h1) == h1->header_crc32);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700398
Randall Spanglere9213a72013-01-24 11:19:55 -0800399 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700400}
401
Randall Spangler0bda13f2013-01-24 12:25:26 -0800402/* Test if header-same comparison works. */
403static int HeaderSameTest(void)
404{
405 GptData *gpt = GetEmptyGptData();
406 GptHeader *h1 = (GptHeader *)gpt->primary_header;
407 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
408 GptHeader h3;
409
410 EXPECT(0 == HeaderFieldsSame(h1, h2));
411
412 Memcpy(&h3, h2, sizeof(h3));
413 h3.signature[0] ^= 0xba;
414 EXPECT(1 == HeaderFieldsSame(h1, &h3));
415
416 Memcpy(&h3, h2, sizeof(h3));
417 h3.revision++;
418 EXPECT(1 == HeaderFieldsSame(h1, &h3));
419
420 Memcpy(&h3, h2, sizeof(h3));
421 h3.size++;
422 EXPECT(1 == HeaderFieldsSame(h1, &h3));
423
424 Memcpy(&h3, h2, sizeof(h3));
425 h3.reserved_zero++;
426 EXPECT(1 == HeaderFieldsSame(h1, &h3));
427
428 Memcpy(&h3, h2, sizeof(h3));
429 h3.first_usable_lba++;
430 EXPECT(1 == HeaderFieldsSame(h1, &h3));
431
432 Memcpy(&h3, h2, sizeof(h3));
433 h3.last_usable_lba++;
434 EXPECT(1 == HeaderFieldsSame(h1, &h3));
435
436 Memcpy(&h3, h2, sizeof(h3));
437 h3.disk_uuid.u.raw[0] ^= 0xba;
438 EXPECT(1 == HeaderFieldsSame(h1, &h3));
439
440 Memcpy(&h3, h2, sizeof(h3));
441 h3.number_of_entries++;
442 EXPECT(1 == HeaderFieldsSame(h1, &h3));
443
444 Memcpy(&h3, h2, sizeof(h3));
445 h3.size_of_entry++;
446 EXPECT(1 == HeaderFieldsSame(h1, &h3));
447
448 Memcpy(&h3, h2, sizeof(h3));
449 h3.entries_crc32++;
450 EXPECT(1 == HeaderFieldsSame(h1, &h3));
451
452 return TEST_OK;
453}
454
Randall Spanglere9213a72013-01-24 11:19:55 -0800455/* Test if signature ("EFI PART") is checked. */
456static int SignatureTest(void)
457{
458 GptData *gpt = GetEmptyGptData();
459 GptHeader *h1 = (GptHeader *)gpt->primary_header;
460 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
461 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700462
Randall Spangler0bda13f2013-01-24 12:25:26 -0800463 EXPECT(1 == CheckHeader(NULL, 0, gpt->drive_sectors));
464
Randall Spanglere9213a72013-01-24 11:19:55 -0800465 for (i = 0; i < 8; ++i) {
466 BuildTestGptData(gpt);
467 h1->signature[i] ^= 0xff;
468 h2->signature[i] ^= 0xff;
469 RefreshCrc32(gpt);
470 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
471 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
472 }
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700473
Randall Spanglere9213a72013-01-24 11:19:55 -0800474 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700475}
476
Randall Spanglere9213a72013-01-24 11:19:55 -0800477/*
478 * The revision we currently support is GPT_HEADER_REVISION. If the revision
479 * in header is not that, we expect the header is invalid.
480 */
481static int RevisionTest(void)
482{
483 GptData *gpt = GetEmptyGptData();
484 GptHeader *h1 = (GptHeader *)gpt->primary_header;
485 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
486 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700487
Randall Spanglere9213a72013-01-24 11:19:55 -0800488 struct {
489 uint32_t value_to_test;
490 int expect_rv;
491 } cases[] = {
492 {0x01000000, 1},
493 {0x00010000, 0}, /* GPT_HEADER_REVISION */
494 {0x00000100, 1},
495 {0x00000001, 1},
496 {0x23010456, 1},
497 };
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700498
Randall Spanglere9213a72013-01-24 11:19:55 -0800499 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
500 BuildTestGptData(gpt);
501 h1->revision = cases[i].value_to_test;
502 h2->revision = cases[i].value_to_test;
503 RefreshCrc32(gpt);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700504
Randall Spanglere9213a72013-01-24 11:19:55 -0800505 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
506 cases[i].expect_rv);
507 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
508 cases[i].expect_rv);
509 }
510 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700511}
512
Randall Spanglere9213a72013-01-24 11:19:55 -0800513static int SizeTest(void)
514{
515 GptData *gpt = GetEmptyGptData();
516 GptHeader *h1 = (GptHeader *)gpt->primary_header;
517 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
518 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700519
Randall Spanglere9213a72013-01-24 11:19:55 -0800520 struct {
521 uint32_t value_to_test;
522 int expect_rv;
523 } cases[] = {
524 {91, 1},
525 {92, 0},
526 {93, 0},
527 {511, 0},
528 {512, 0},
529 {513, 1},
530 };
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700531
Randall Spanglere9213a72013-01-24 11:19:55 -0800532 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
533 BuildTestGptData(gpt);
534 h1->size = cases[i].value_to_test;
535 h2->size = cases[i].value_to_test;
536 RefreshCrc32(gpt);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700537
Randall Spanglere9213a72013-01-24 11:19:55 -0800538 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
539 cases[i].expect_rv);
540 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
541 cases[i].expect_rv);
542 }
543 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700544}
545
Randall Spanglere9213a72013-01-24 11:19:55 -0800546/* Test if CRC is checked. */
547static int CrcFieldTest(void)
548{
549 GptData *gpt = GetEmptyGptData();
550 GptHeader *h1 = (GptHeader *)gpt->primary_header;
551 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700552
Randall Spanglere9213a72013-01-24 11:19:55 -0800553 BuildTestGptData(gpt);
554 /* Modify a field that the header verification doesn't care about */
555 h1->entries_crc32++;
556 h2->entries_crc32++;
557 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
558 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
559 /* Refresh the CRC; should pass now */
560 RefreshCrc32(gpt);
561 EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
562 EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700563
Randall Spanglere9213a72013-01-24 11:19:55 -0800564 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700565}
566
Randall Spanglere9213a72013-01-24 11:19:55 -0800567/* Test if reserved fields are checked. We'll try non-zero values to test. */
568static int ReservedFieldsTest(void)
569{
570 GptData *gpt = GetEmptyGptData();
571 GptHeader *h1 = (GptHeader *)gpt->primary_header;
572 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700573
Randall Spanglere9213a72013-01-24 11:19:55 -0800574 BuildTestGptData(gpt);
575 h1->reserved_zero ^= 0x12345678; /* whatever random */
576 h2->reserved_zero ^= 0x12345678; /* whatever random */
577 RefreshCrc32(gpt);
578 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
579 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700580
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700581#ifdef PADDING_CHECKED
Randall Spanglere9213a72013-01-24 11:19:55 -0800582 /* TODO: padding check is currently disabled */
583 BuildTestGptData(gpt);
584 h1->padding[12] ^= 0x34; /* whatever random */
585 h2->padding[56] ^= 0x78; /* whatever random */
586 RefreshCrc32(gpt);
587 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
588 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700589#endif
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700590
Randall Spanglere9213a72013-01-24 11:19:55 -0800591 return TEST_OK;
592}
593
594/*
595 * Technically, any size which is 2^N where N > 6 should work, but our
596 * library only supports one size.
597 */
598static int SizeOfPartitionEntryTest(void) {
599 GptData *gpt = GetEmptyGptData();
600 GptHeader *h1 = (GptHeader *)gpt->primary_header;
601 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
602 int i;
603
604 struct {
605 uint32_t value_to_test;
606 int expect_rv;
607 } cases[] = {
608 {127, 1},
609 {128, 0},
610 {129, 1},
611 {256, 1},
612 {512, 1},
613 };
614
615 /* Check size of entryes */
616 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
617 BuildTestGptData(gpt);
618 h1->size_of_entry = cases[i].value_to_test;
619 h2->size_of_entry = cases[i].value_to_test;
620 h1->number_of_entries = TOTAL_ENTRIES_SIZE /
621 cases[i].value_to_test;
622 h2->number_of_entries = TOTAL_ENTRIES_SIZE /
623 cases[i].value_to_test;
624 RefreshCrc32(gpt);
625
626 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
627 cases[i].expect_rv);
628 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
629 cases[i].expect_rv);
630 }
631
632 return TEST_OK;
633}
634
635/*
636 * Technically, any size which is 2^N where N > 6 should work, but our library
637 * only supports one size.
638 */
639static int NumberOfPartitionEntriesTest(void)
640{
641 GptData *gpt = GetEmptyGptData();
642 GptHeader *h1 = (GptHeader *)gpt->primary_header;
643 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
644
645 BuildTestGptData(gpt);
646 h1->number_of_entries--;
647 h2->number_of_entries /= 2;
648 RefreshCrc32(gpt);
649 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
650 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
651
652 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700653}
654
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700655
Randall Spanglere9213a72013-01-24 11:19:55 -0800656/* Test if myLBA field is checked (1 for primary, last for secondary). */
657static int MyLbaTest(void)
658{
659 GptData *gpt = GetEmptyGptData();
660 GptHeader *h1 = (GptHeader *)gpt->primary_header;
661 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700662
Randall Spanglere9213a72013-01-24 11:19:55 -0800663 /* myLBA depends on primary vs secondary flag */
664 BuildTestGptData(gpt);
665 EXPECT(1 == CheckHeader(h1, 1, gpt->drive_sectors));
666 EXPECT(1 == CheckHeader(h2, 0, gpt->drive_sectors));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700667
Randall Spanglere9213a72013-01-24 11:19:55 -0800668 BuildTestGptData(gpt);
669 h1->my_lba--;
670 h2->my_lba--;
671 RefreshCrc32(gpt);
672 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
673 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700674
Randall Spanglere9213a72013-01-24 11:19:55 -0800675 BuildTestGptData(gpt);
676 h1->my_lba = 2;
677 h2->my_lba--;
678 RefreshCrc32(gpt);
679 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
680 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700681
Randall Spanglere9213a72013-01-24 11:19:55 -0800682 /* We should ignore the alternate_lba field entirely */
683 BuildTestGptData(gpt);
684 h1->alternate_lba++;
685 h2->alternate_lba++;
686 RefreshCrc32(gpt);
687 EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
688 EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
689
690 BuildTestGptData(gpt);
691 h1->alternate_lba--;
692 h2->alternate_lba--;
693 RefreshCrc32(gpt);
694 EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
695 EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
696
697 BuildTestGptData(gpt);
698 h1->entries_lba++;
699 h2->entries_lba++;
700 RefreshCrc32(gpt);
701 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
702 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
703
704 BuildTestGptData(gpt);
705 h1->entries_lba--;
706 h2->entries_lba--;
707 RefreshCrc32(gpt);
708 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
709 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
710
711 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700712}
713
Randall Spanglere9213a72013-01-24 11:19:55 -0800714/* Test if FirstUsableLBA and LastUsableLBA are checked.
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700715 * FirstUsableLBA must be after the end of the primary GPT table array.
716 * LastUsableLBA must be before the start of the secondary GPT table array.
717 * FirstUsableLBA <= LastUsableLBA. */
Randall Spanglere9213a72013-01-24 11:19:55 -0800718static int FirstUsableLbaAndLastUsableLbaTest(void)
719{
720 GptData *gpt = GetEmptyGptData();
721 GptHeader *h1 = (GptHeader *)gpt->primary_header;
722 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
723 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700724
Randall Spanglere9213a72013-01-24 11:19:55 -0800725 struct {
726 uint64_t primary_entries_lba;
727 uint64_t primary_first_usable_lba;
728 uint64_t primary_last_usable_lba;
729 uint64_t secondary_first_usable_lba;
730 uint64_t secondary_last_usable_lba;
731 uint64_t secondary_entries_lba;
732 int primary_rv;
733 int secondary_rv;
734 } cases[] = {
735 {2, 34, 433, 34, 433, 434, 0, 0},
736 {2, 34, 432, 34, 430, 434, 0, 0},
737 {2, 33, 433, 33, 433, 434, 1, 1},
738 {2, 34, 434, 34, 433, 434, 1, 0},
739 {2, 34, 433, 34, 434, 434, 0, 1},
740 {2, 35, 433, 35, 433, 434, 0, 0},
741 {2, 433, 433, 433, 433, 434, 0, 0},
742 {2, 434, 433, 434, 434, 434, 1, 1},
743 {2, 433, 34, 34, 433, 434, 1, 0},
744 {2, 34, 433, 433, 34, 434, 0, 1},
745 };
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700746
Randall Spanglere9213a72013-01-24 11:19:55 -0800747 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
748 BuildTestGptData(gpt);
749 h1->entries_lba = cases[i].primary_entries_lba;
750 h1->first_usable_lba = cases[i].primary_first_usable_lba;
751 h1->last_usable_lba = cases[i].primary_last_usable_lba;
752 h2->entries_lba = cases[i].secondary_entries_lba;
753 h2->first_usable_lba = cases[i].secondary_first_usable_lba;
754 h2->last_usable_lba = cases[i].secondary_last_usable_lba;
755 RefreshCrc32(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700756
Randall Spanglere9213a72013-01-24 11:19:55 -0800757 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
758 cases[i].primary_rv);
759 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
760 cases[i].secondary_rv);
761 }
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700762
Randall Spanglere9213a72013-01-24 11:19:55 -0800763 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700764}
765
Randall Spanglere9213a72013-01-24 11:19:55 -0800766/*
767 * Test if PartitionEntryArrayCRC32 is checked. PartitionEntryArrayCRC32 must
768 * be calculated over SizeOfPartitionEntry * NumberOfPartitionEntries bytes.
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700769 */
Randall Spanglere9213a72013-01-24 11:19:55 -0800770static int EntriesCrcTest(void)
771{
772 GptData *gpt = GetEmptyGptData();
773 GptHeader *h1 = (GptHeader *)gpt->primary_header;
774 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
775 GptEntry *e2 = (GptEntry *)(gpt->secondary_entries);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700776
Randall Spanglere9213a72013-01-24 11:19:55 -0800777 /* Modify first byte of primary entries, and expect the CRC is wrong. */
778 BuildTestGptData(gpt);
779 EXPECT(0 == CheckEntries(e1, h1));
780 EXPECT(0 == CheckEntries(e2, h1));
781 gpt->primary_entries[0] ^= 0xa5; /* just XOR a non-zero value */
782 gpt->secondary_entries[TOTAL_ENTRIES_SIZE-1] ^= 0x5a;
783 EXPECT(GPT_ERROR_CRC_CORRUPTED == CheckEntries(e1, h1));
784 EXPECT(GPT_ERROR_CRC_CORRUPTED == CheckEntries(e2, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700785
Randall Spanglere9213a72013-01-24 11:19:55 -0800786 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700787}
788
Randall Spanglere9213a72013-01-24 11:19:55 -0800789/*
790 * Test if partition geometry is checked.
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700791 * All active (non-zero PartitionTypeGUID) partition entries should have:
792 * entry.StartingLBA >= header.FirstUsableLBA
793 * entry.EndingLBA <= header.LastUsableLBA
794 * entry.StartingLBA <= entry.EndingLBA
795 */
Randall Spanglere9213a72013-01-24 11:19:55 -0800796static int ValidEntryTest(void)
797{
798 GptData *gpt = GetEmptyGptData();
799 GptHeader *h1 = (GptHeader *)gpt->primary_header;
800 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700801 MtdData *mtd = GetEmptyMtdData();
802 MtdDiskLayout *mh = &mtd->primary;
803 MtdDiskPartition *me = mh->partitions;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700804
Randall Spanglere9213a72013-01-24 11:19:55 -0800805 /* error case: entry.StartingLBA < header.FirstUsableLBA */
806 BuildTestGptData(gpt);
807 e1[0].starting_lba = h1->first_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);
Albert Chaulk289b6042013-06-25 11:30:46 -0700812 if (mh->first_offset > 0) {
813 me[0].starting_offset = mh->first_offset - 1;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700814 mh->crc32 = MtdHeaderCrc(mh);
815 EXPECT(GPT_ERROR_OUT_OF_REGION == MtdCheckEntries(me, mh));
816 }
817
Randall Spanglere9213a72013-01-24 11:19:55 -0800818 /* error case: entry.EndingLBA > header.LastUsableLBA */
819 BuildTestGptData(gpt);
820 e1[2].ending_lba = h1->last_usable_lba + 1;
821 RefreshCrc32(gpt);
822 EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700823
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700824 BuildTestMtdData(mtd);
Albert Chaulk289b6042013-06-25 11:30:46 -0700825 me[0].ending_offset = mh->last_offset + 1;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700826 mh->crc32 = MtdHeaderCrc(mh);
827 EXPECT(GPT_ERROR_OUT_OF_REGION == MtdCheckEntries(me, mh));
828
Randall Spanglere9213a72013-01-24 11:19:55 -0800829 /* error case: entry.StartingLBA > entry.EndingLBA */
830 BuildTestGptData(gpt);
831 e1[3].starting_lba = e1[3].ending_lba + 1;
832 RefreshCrc32(gpt);
833 EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700834
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700835 BuildTestMtdData(mtd);
Albert Chaulk289b6042013-06-25 11:30:46 -0700836 me[0].starting_offset = me[0].ending_offset + 1;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700837 mh->crc32 = MtdHeaderCrc(mh);
838 EXPECT(GPT_ERROR_OUT_OF_REGION == MtdCheckEntries(me, mh));
839
Randall Spanglere9213a72013-01-24 11:19:55 -0800840 /* case: non active entry should be ignored. */
841 BuildTestGptData(gpt);
842 Memset(&e1[1].type, 0, sizeof(e1[1].type));
843 e1[1].starting_lba = e1[1].ending_lba + 1;
844 RefreshCrc32(gpt);
845 EXPECT(0 == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700846
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700847 BuildTestMtdData(mtd);
848 me[0].flags = 0;
Albert Chaulk289b6042013-06-25 11:30:46 -0700849 me[0].starting_offset = me[0].ending_offset + 1;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700850 mh->crc32 = MtdHeaderCrc(mh);
851 EXPECT(GPT_SUCCESS == MtdCheckEntries(me, mh));
852
Randall Spanglere9213a72013-01-24 11:19:55 -0800853 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700854}
855
Randall Spanglere9213a72013-01-24 11:19:55 -0800856/* Test if overlapped partition tables can be detected. */
857static int OverlappedPartitionTest(void) {
858 GptData *gpt = GetEmptyGptData();
859 GptHeader *h = (GptHeader *)gpt->primary_header;
860 GptEntry *e = (GptEntry *)gpt->primary_entries;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700861 MtdData *mtd = GetEmptyMtdData();
862 MtdDiskLayout *mh = &mtd->primary;
863 MtdDiskPartition *me = mh->partitions;
Randall Spanglere9213a72013-01-24 11:19:55 -0800864 int i, j;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700865
Randall Spanglere9213a72013-01-24 11:19:55 -0800866 struct {
867 int overlapped;
868 struct {
869 int active;
870 uint64_t starting_lba;
871 uint64_t ending_lba;
872 } entries[16]; /* enough for testing. */
873 } cases[] = {
874 {GPT_SUCCESS, {{0, 100, 199}}},
875 {GPT_SUCCESS, {{1, 100, 199}}},
876 {GPT_SUCCESS, {{1, 100, 150}, {1, 200, 250}, {1, 300, 350}}},
877 {GPT_ERROR_START_LBA_OVERLAP,
878 {{1, 200, 299}, {1, 100, 199}, {1, 100, 100}}},
879 {GPT_ERROR_END_LBA_OVERLAP,
880 {{1, 200, 299}, {1, 100, 199}, {1, 299, 299}}},
881 {GPT_SUCCESS, {{1, 300, 399}, {1, 200, 299}, {1, 100, 199}}},
882 {GPT_ERROR_END_LBA_OVERLAP,
883 {{1, 100, 199}, {1, 199, 299}, {1, 299, 399}}},
884 {GPT_ERROR_START_LBA_OVERLAP,
885 {{1, 100, 199}, {1, 200, 299}, {1, 75, 399}}},
886 {GPT_ERROR_START_LBA_OVERLAP,
887 {{1, 100, 199}, {1, 75, 250}, {1, 200, 299}}},
888 {GPT_ERROR_END_LBA_OVERLAP,
889 {{1, 75, 150}, {1, 100, 199}, {1, 200, 299}}},
890 {GPT_ERROR_START_LBA_OVERLAP,
891 {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {1, 100, 399}}},
892 {GPT_SUCCESS,
893 {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {0, 100, 399}}},
894 {GPT_ERROR_START_LBA_OVERLAP,
895 {{1, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400}}},
896 {GPT_ERROR_START_LBA_OVERLAP,
897 {{0, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400}}},
898 {GPT_SUCCESS,
899 {{1, 200, 300}, {1, 100, 199}, {0, 100, 400}, {0, 300, 400}}},
900 {GPT_ERROR_END_LBA_OVERLAP,
901 {{1, 200, 299}, {1, 100, 199}, {1, 199, 199}}},
902 {GPT_SUCCESS, {{1, 200, 299}, {0, 100, 199}, {1, 199, 199}}},
903 {GPT_SUCCESS, {{1, 200, 299}, {1, 100, 199}, {0, 199, 199}}},
904 {GPT_ERROR_START_LBA_OVERLAP,
905 {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202},
906 {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206},
907 {1, 207, 207}, {1, 208, 208}, {1, 199, 199}}},
908 {GPT_SUCCESS,
909 {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202},
910 {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206},
911 {1, 207, 207}, {1, 208, 208}, {0, 199, 199}}},
912 };
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700913
Randall Spanglere9213a72013-01-24 11:19:55 -0800914 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
915 BuildTestGptData(gpt);
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700916 BuildTestMtdData(mtd);
917 Memset(mh->partitions, 0, sizeof(mh->partitions));
Randall Spanglere9213a72013-01-24 11:19:55 -0800918 ZeroEntries(gpt);
919 for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) {
920 if (!cases[i].entries[j].starting_lba)
921 break;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700922
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700923 if (cases[i].entries[j].active) {
Randall Spanglere9213a72013-01-24 11:19:55 -0800924 Memcpy(&e[j].type, &guid_kernel, sizeof(Guid));
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700925 me[j].flags =
926 MTD_PARTITION_TYPE_CHROMEOS_KERNEL << MTD_ATTRIBUTE_TYPE_OFFSET;
927 }
Randall Spanglere9213a72013-01-24 11:19:55 -0800928 SetGuid(&e[j].unique, j);
929 e[j].starting_lba = cases[i].entries[j].starting_lba;
930 e[j].ending_lba = cases[i].entries[j].ending_lba;
Albert Chaulk289b6042013-06-25 11:30:46 -0700931 me[j].starting_offset = cases[i].entries[j].starting_lba *
932 DEFAULT_SECTOR_SIZE;
933 me[j].ending_offset = cases[i].entries[j].ending_lba *
934 DEFAULT_SECTOR_SIZE;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700935
Randall Spanglere9213a72013-01-24 11:19:55 -0800936 }
937 RefreshCrc32(gpt);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700938
Randall Spanglere9213a72013-01-24 11:19:55 -0800939 EXPECT(cases[i].overlapped == CheckEntries(e, h));
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700940 EXPECT(cases[i].overlapped == MtdCheckEntries(me, mh));
Randall Spanglere9213a72013-01-24 11:19:55 -0800941 }
942 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700943}
944
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700945/* Test both sanity checking and repair. */
Randall Spanglere9213a72013-01-24 11:19:55 -0800946static int SanityCheckTest(void)
947{
948 GptData *gpt = GetEmptyGptData();
949 GptHeader *h1 = (GptHeader *)gpt->primary_header;
Randall Spangler0bda13f2013-01-24 12:25:26 -0800950 GptEntry *e1 = (GptEntry *)gpt->primary_entries;
951 uint8_t *tempptr;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700952
Randall Spanglere9213a72013-01-24 11:19:55 -0800953 /* Unmodified test data is completely sane */
954 BuildTestGptData(gpt);
955 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
956 EXPECT(MASK_BOTH == gpt->valid_headers);
957 EXPECT(MASK_BOTH == gpt->valid_entries);
958 /* Repair doesn't damage it */
959 GptRepair(gpt);
960 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
961 EXPECT(MASK_BOTH == gpt->valid_headers);
962 EXPECT(MASK_BOTH == gpt->valid_entries);
963 EXPECT(0 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700964
Randall Spangler0bda13f2013-01-24 12:25:26 -0800965 /* Invalid sector size should fail */
966 BuildTestGptData(gpt);
967 gpt->sector_bytes = 1024;
968 EXPECT(GPT_ERROR_INVALID_SECTOR_SIZE == GptSanityCheck(gpt));
969
Randall Spanglere9213a72013-01-24 11:19:55 -0800970 /* Modify headers */
971 BuildTestGptData(gpt);
972 gpt->primary_header[0]++;
973 gpt->secondary_header[0]++;
974 EXPECT(GPT_ERROR_INVALID_HEADERS == GptSanityCheck(gpt));
975 EXPECT(0 == gpt->valid_headers);
976 EXPECT(0 == gpt->valid_entries);
977 /* Repair can't fix completely busted headers */
978 GptRepair(gpt);
979 EXPECT(GPT_ERROR_INVALID_HEADERS == GptSanityCheck(gpt));
980 EXPECT(0 == gpt->valid_headers);
981 EXPECT(0 == gpt->valid_entries);
982 EXPECT(0 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700983
Randall Spanglere9213a72013-01-24 11:19:55 -0800984 BuildTestGptData(gpt);
985 gpt->primary_header[0]++;
986 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
987 EXPECT(MASK_SECONDARY == gpt->valid_headers);
988 EXPECT(MASK_BOTH == gpt->valid_entries);
989 GptRepair(gpt);
990 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
991 EXPECT(MASK_BOTH == gpt->valid_headers);
992 EXPECT(MASK_BOTH == gpt->valid_entries);
993 EXPECT(GPT_MODIFIED_HEADER1 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700994
Randall Spanglere9213a72013-01-24 11:19:55 -0800995 BuildTestGptData(gpt);
996 gpt->secondary_header[0]++;
997 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
998 EXPECT(MASK_PRIMARY == gpt->valid_headers);
999 EXPECT(MASK_BOTH == gpt->valid_entries);
1000 GptRepair(gpt);
1001 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1002 EXPECT(MASK_BOTH == gpt->valid_headers);
1003 EXPECT(MASK_BOTH == gpt->valid_entries);
1004 EXPECT(GPT_MODIFIED_HEADER2 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001005
Randall Spanglere9213a72013-01-24 11:19:55 -08001006 /*
1007 * Modify header1 and update its CRC. Since header2 is now different
1008 * than header1, it'll be the one considered invalid.
1009 */
1010 BuildTestGptData(gpt);
1011 h1->size++;
1012 RefreshCrc32(gpt);
1013 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1014 EXPECT(MASK_PRIMARY == gpt->valid_headers);
1015 EXPECT(MASK_BOTH == gpt->valid_entries);
1016 GptRepair(gpt);
1017 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1018 EXPECT(MASK_BOTH == gpt->valid_headers);
1019 EXPECT(MASK_BOTH == gpt->valid_entries);
1020 EXPECT(GPT_MODIFIED_HEADER2 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001021
Randall Spanglere9213a72013-01-24 11:19:55 -08001022 /* Modify entries */
1023 BuildTestGptData(gpt);
1024 gpt->primary_entries[0]++;
1025 gpt->secondary_entries[0]++;
1026 EXPECT(GPT_ERROR_INVALID_ENTRIES == GptSanityCheck(gpt));
1027 EXPECT(MASK_BOTH == gpt->valid_headers);
1028 EXPECT(MASK_NONE == gpt->valid_entries);
1029 /* Repair can't fix both copies of entries being bad, either. */
1030 GptRepair(gpt);
1031 EXPECT(GPT_ERROR_INVALID_ENTRIES == GptSanityCheck(gpt));
1032 EXPECT(MASK_BOTH == gpt->valid_headers);
1033 EXPECT(MASK_NONE == gpt->valid_entries);
1034 EXPECT(0 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001035
Randall Spanglere9213a72013-01-24 11:19:55 -08001036 BuildTestGptData(gpt);
1037 gpt->primary_entries[0]++;
1038 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1039 EXPECT(MASK_BOTH == gpt->valid_headers);
1040 EXPECT(MASK_SECONDARY == gpt->valid_entries);
1041 GptRepair(gpt);
1042 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1043 EXPECT(MASK_BOTH == gpt->valid_headers);
1044 EXPECT(MASK_BOTH == gpt->valid_entries);
1045 EXPECT(GPT_MODIFIED_ENTRIES1 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001046
Randall Spanglere9213a72013-01-24 11:19:55 -08001047 BuildTestGptData(gpt);
1048 gpt->secondary_entries[0]++;
1049 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1050 EXPECT(MASK_BOTH == gpt->valid_headers);
1051 EXPECT(MASK_PRIMARY == gpt->valid_entries);
1052 GptRepair(gpt);
1053 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1054 EXPECT(MASK_BOTH == gpt->valid_headers);
1055 EXPECT(MASK_BOTH == gpt->valid_entries);
1056 EXPECT(GPT_MODIFIED_ENTRIES2 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001057
Randall Spangler0bda13f2013-01-24 12:25:26 -08001058 /*
1059 * Modify entries and recompute CRCs, then make both primary and
1060 * secondary entry pointers use the secondary data. The primary
1061 * header will have the wrong entries CRC, so we should fall back
1062 * to the secondary header.
1063 */
1064 BuildTestGptData(gpt);
1065 e1->starting_lba++;
1066 RefreshCrc32(gpt);
1067 tempptr = gpt->primary_entries;
1068 gpt->primary_entries = gpt->secondary_entries;
1069 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1070 EXPECT(MASK_SECONDARY == gpt->valid_headers);
1071 EXPECT(MASK_BOTH == gpt->valid_entries);
1072 gpt->primary_entries = tempptr;
1073
Randall Spanglere9213a72013-01-24 11:19:55 -08001074 /* Modify both header and entries */
1075 BuildTestGptData(gpt);
1076 gpt->primary_header[0]++;
1077 gpt->primary_entries[0]++;
1078 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1079 EXPECT(MASK_SECONDARY == gpt->valid_headers);
1080 EXPECT(MASK_SECONDARY == gpt->valid_entries);
1081 GptRepair(gpt);
1082 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1083 EXPECT(MASK_BOTH == gpt->valid_headers);
1084 EXPECT(MASK_BOTH == gpt->valid_entries);
1085 EXPECT((GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1) == gpt->modified);
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001086
Randall Spanglere9213a72013-01-24 11:19:55 -08001087 BuildTestGptData(gpt);
1088 gpt->secondary_header[0]++;
1089 gpt->secondary_entries[0]++;
1090 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1091 EXPECT(MASK_PRIMARY == gpt->valid_headers);
1092 EXPECT(MASK_PRIMARY == gpt->valid_entries);
1093 GptRepair(gpt);
1094 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1095 EXPECT(MASK_BOTH == gpt->valid_headers);
1096 EXPECT(MASK_BOTH == gpt->valid_entries);
1097 EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001098
Randall Spanglere9213a72013-01-24 11:19:55 -08001099 /* Test cross-correction (h1+e2, h2+e1) */
1100 BuildTestGptData(gpt);
1101 gpt->primary_header[0]++;
1102 gpt->secondary_entries[0]++;
1103 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1104 EXPECT(MASK_SECONDARY == gpt->valid_headers);
1105 EXPECT(MASK_PRIMARY == gpt->valid_entries);
1106 GptRepair(gpt);
1107 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1108 EXPECT(MASK_BOTH == gpt->valid_headers);
1109 EXPECT(MASK_BOTH == gpt->valid_entries);
1110 EXPECT((GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001111
Randall Spanglere9213a72013-01-24 11:19:55 -08001112 BuildTestGptData(gpt);
1113 gpt->secondary_header[0]++;
1114 gpt->primary_entries[0]++;
1115 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1116 EXPECT(MASK_PRIMARY == gpt->valid_headers);
1117 EXPECT(MASK_SECONDARY == gpt->valid_entries);
1118 GptRepair(gpt);
1119 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1120 EXPECT(MASK_BOTH == gpt->valid_headers);
1121 EXPECT(MASK_BOTH == gpt->valid_entries);
1122 EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES1) == gpt->modified);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001123
Randall Spanglere9213a72013-01-24 11:19:55 -08001124 /*
1125 * Test mismatched pairs (h1+e1 valid, h2+e2 valid but different. This
1126 * simulates a partial update of the drive.
1127 */
1128 BuildTestGptData(gpt);
1129 gpt->secondary_entries[0]++;
1130 RefreshCrc32(gpt);
1131 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1132 EXPECT(MASK_PRIMARY == gpt->valid_headers);
1133 EXPECT(MASK_PRIMARY == gpt->valid_entries);
1134 GptRepair(gpt);
1135 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1136 EXPECT(MASK_BOTH == gpt->valid_headers);
1137 EXPECT(MASK_BOTH == gpt->valid_entries);
1138 EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001139
Randall Spanglere9213a72013-01-24 11:19:55 -08001140 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001141}
1142
Randall Spanglere9213a72013-01-24 11:19:55 -08001143static int EntryAttributeGetSetTest(void)
1144{
1145 GptData *gpt = GetEmptyGptData();
1146 GptEntry *e = (GptEntry *)(gpt->primary_entries);
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001147 MtdData *mtd = GetEmptyMtdData();
1148 MtdDiskPartition *m = &mtd->primary.partitions[0];
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001149
Randall Spanglere9213a72013-01-24 11:19:55 -08001150 e->attrs.whole = 0x0000000000000000ULL;
1151 SetEntrySuccessful(e, 1);
1152 EXPECT(0x0100000000000000ULL == e->attrs.whole);
1153 EXPECT(1 == GetEntrySuccessful(e));
1154 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
1155 SetEntrySuccessful(e, 0);
1156 EXPECT(0xFEFFFFFFFFFFFFFFULL == e->attrs.whole);
1157 EXPECT(0 == GetEntrySuccessful(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001158
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001159 m->flags = 0;
1160 MtdSetEntrySuccessful(m, 1);
1161 EXPECT(0x00000100 == m->flags);
1162 EXPECT(1 == MtdGetEntrySuccessful(m));
1163 m->flags = ~0;
1164 MtdSetEntrySuccessful(m, 0);
1165 EXPECT(0xFFFFFEFF == m->flags);
1166 EXPECT(0 == MtdGetEntrySuccessful(m));
1167
Randall Spanglere9213a72013-01-24 11:19:55 -08001168 e->attrs.whole = 0x0000000000000000ULL;
1169 SetEntryTries(e, 15);
1170 EXPECT(15 == GetEntryTries(e));
1171 EXPECT(0x00F0000000000000ULL == e->attrs.whole);
1172 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
1173 SetEntryTries(e, 0);
1174 EXPECT(0xFF0FFFFFFFFFFFFFULL == e->attrs.whole);
1175 EXPECT(0 == GetEntryTries(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001176
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001177 m->flags = 0;
1178 MtdSetEntryTries(m, 15);
1179 EXPECT(0x000000F0 == m->flags);
1180 EXPECT(15 == MtdGetEntryTries(m));
1181 m->flags = ~0;
1182 MtdSetEntryTries(m, 0);
1183 EXPECT(0xFFFFFF0F == m->flags);
1184 EXPECT(0 == MtdGetEntryTries(m));
1185
Randall Spanglere9213a72013-01-24 11:19:55 -08001186 e->attrs.whole = 0x0000000000000000ULL;
1187 SetEntryPriority(e, 15);
1188 EXPECT(0x000F000000000000ULL == e->attrs.whole);
1189 EXPECT(15 == GetEntryPriority(e));
1190 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
1191 SetEntryPriority(e, 0);
1192 EXPECT(0xFFF0FFFFFFFFFFFFULL == e->attrs.whole);
1193 EXPECT(0 == GetEntryPriority(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001194
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001195 m->flags = 0;
1196 MtdSetEntryPriority(m, 15);
1197 EXPECT(0x0000000F == m->flags);
1198 EXPECT(15 == MtdGetEntryPriority(m));
1199 m->flags = ~0;
1200 MtdSetEntryPriority(m, 0);
1201 EXPECT(0xFFFFFFF0 == m->flags);
1202 EXPECT(0 == MtdGetEntryPriority(m));
1203
Randall Spanglere9213a72013-01-24 11:19:55 -08001204 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
1205 EXPECT(1 == GetEntrySuccessful(e));
1206 EXPECT(15 == GetEntryPriority(e));
1207 EXPECT(15 == GetEntryTries(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001208
Randall Spanglere9213a72013-01-24 11:19:55 -08001209 e->attrs.whole = 0x0123000000000000ULL;
1210 EXPECT(1 == GetEntrySuccessful(e));
1211 EXPECT(2 == GetEntryTries(e));
1212 EXPECT(3 == GetEntryPriority(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001213
Randall Spanglere9213a72013-01-24 11:19:55 -08001214 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001215}
1216
Randall Spanglere9213a72013-01-24 11:19:55 -08001217static int EntryTypeTest(void)
1218{
1219 GptData *gpt = GetEmptyGptData();
1220 GptEntry *e = (GptEntry *)(gpt->primary_entries);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001221
Randall Spanglere9213a72013-01-24 11:19:55 -08001222 Memcpy(&e->type, &guid_zero, sizeof(Guid));
1223 EXPECT(1 == IsUnusedEntry(e));
1224 EXPECT(0 == IsKernelEntry(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001225
Randall Spanglere9213a72013-01-24 11:19:55 -08001226 Memcpy(&e->type, &guid_kernel, sizeof(Guid));
1227 EXPECT(0 == IsUnusedEntry(e));
1228 EXPECT(1 == IsKernelEntry(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001229
Randall Spanglere9213a72013-01-24 11:19:55 -08001230 Memcpy(&e->type, &guid_rootfs, sizeof(Guid));
1231 EXPECT(0 == IsUnusedEntry(e));
1232 EXPECT(0 == IsKernelEntry(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001233
Randall Spanglere9213a72013-01-24 11:19:55 -08001234 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001235}
1236
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001237/* Make an entry unused by clearing its type. */
Randall Spanglere9213a72013-01-24 11:19:55 -08001238static void FreeEntry(GptEntry *e)
1239{
1240 Memset(&e->type, 0, sizeof(Guid));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001241}
1242
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001243static void MtdFreeEntry(MtdDiskPartition *e)
1244{
1245 MtdSetEntryType(e, MTD_PARTITION_TYPE_UNUSED);
1246}
1247
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001248/* Set up an entry. */
Randall Spanglere9213a72013-01-24 11:19:55 -08001249static void FillEntry(GptEntry *e, int is_kernel,
1250 int priority, int successful, int tries)
1251{
1252 Memcpy(&e->type, (is_kernel ? &guid_kernel : &guid_zero), sizeof(Guid));
1253 SetEntryPriority(e, priority);
1254 SetEntrySuccessful(e, successful);
1255 SetEntryTries(e, tries);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001256}
1257
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001258static void MtdFillEntry(MtdDiskPartition *e, int is_kernel,
1259 int priority, int successful, int tries)
1260{
1261 MtdSetEntryType(e, is_kernel ? MTD_PARTITION_TYPE_CHROMEOS_KERNEL :
1262 MTD_PARTITION_TYPE_CHROMEOS_FIRMWARE);
1263 MtdSetEntryPriority(e, priority);
1264 MtdSetEntrySuccessful(e, successful);
1265 MtdSetEntryTries(e, tries);
1266}
1267
Randall Spanglere9213a72013-01-24 11:19:55 -08001268/*
1269 * Invalidate all kernel entries and expect GptNextKernelEntry() cannot find
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001270 * any usable kernel entry.
1271 */
Randall Spanglere9213a72013-01-24 11:19:55 -08001272static int NoValidKernelEntryTest(void)
1273{
1274 GptData *gpt = GetEmptyGptData();
1275 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001276
Randall Spanglere9213a72013-01-24 11:19:55 -08001277 BuildTestGptData(gpt);
1278 SetEntryPriority(e1 + KERNEL_A, 0);
1279 FreeEntry(e1 + KERNEL_B);
1280 RefreshCrc32(gpt);
1281 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1282 GptNextKernelEntry(gpt, NULL, NULL));
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001283
Randall Spanglere9213a72013-01-24 11:19:55 -08001284 return TEST_OK;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001285}
1286
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001287static int MtdNoValidKernelEntryTest(void)
1288{
1289 MtdData *mtd = GetEmptyMtdData();
1290 MtdDiskPartition *e1 = mtd->primary.partitions;
1291
1292 BuildTestMtdData(mtd);
1293 MtdSetEntryPriority(e1 + KERNEL_A, 0);
1294 MtdFreeEntry(e1 + KERNEL_B);
1295 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1296 MtdNextKernelEntry(mtd, NULL, NULL));
1297
1298 return TEST_OK;
1299}
1300
Randall Spanglere9213a72013-01-24 11:19:55 -08001301static int GetNextNormalTest(void)
1302{
1303 GptData *gpt = GetEmptyGptData();
1304 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
1305 uint64_t start, size;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001306
Randall Spanglere9213a72013-01-24 11:19:55 -08001307 /* Normal case - both kernels successful */
1308 BuildTestGptData(gpt);
1309 FillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
1310 FillEntry(e1 + KERNEL_B, 1, 2, 1, 0);
1311 RefreshCrc32(gpt);
1312 GptInit(gpt);
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001313
Randall Spanglere9213a72013-01-24 11:19:55 -08001314 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1315 EXPECT(KERNEL_A == gpt->current_kernel);
1316 EXPECT(34 == start);
1317 EXPECT(100 == size);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001318
Randall Spanglere9213a72013-01-24 11:19:55 -08001319 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1320 EXPECT(KERNEL_B == gpt->current_kernel);
1321 EXPECT(134 == start);
1322 EXPECT(99 == size);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001323
Randall Spanglere9213a72013-01-24 11:19:55 -08001324 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1325 GptNextKernelEntry(gpt, &start, &size));
1326 EXPECT(-1 == gpt->current_kernel);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001327
Randall Spanglere9213a72013-01-24 11:19:55 -08001328 /* Call as many times as you want; you won't get another kernel... */
1329 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1330 GptNextKernelEntry(gpt, &start, &size));
1331 EXPECT(-1 == gpt->current_kernel);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001332
Randall Spanglere9213a72013-01-24 11:19:55 -08001333 return TEST_OK;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001334}
1335
Randall Spanglere9213a72013-01-24 11:19:55 -08001336static int GetNextPrioTest(void)
1337{
1338 GptData *gpt = GetEmptyGptData();
1339 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
1340 uint64_t start, size;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001341
Randall Spanglere9213a72013-01-24 11:19:55 -08001342 /* Priority 3, 4, 0, 4 - should boot order B, Y, A */
1343 BuildTestGptData(gpt);
1344 FillEntry(e1 + KERNEL_A, 1, 3, 1, 0);
1345 FillEntry(e1 + KERNEL_B, 1, 4, 1, 0);
1346 FillEntry(e1 + KERNEL_X, 1, 0, 1, 0);
1347 FillEntry(e1 + KERNEL_Y, 1, 4, 1, 0);
1348 RefreshCrc32(gpt);
1349 GptInit(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001350
Randall Spanglere9213a72013-01-24 11:19:55 -08001351 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1352 EXPECT(KERNEL_B == gpt->current_kernel);
1353 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1354 EXPECT(KERNEL_Y == gpt->current_kernel);
1355 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1356 EXPECT(KERNEL_A == gpt->current_kernel);
1357 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1358 GptNextKernelEntry(gpt, &start, &size));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001359
Randall Spanglere9213a72013-01-24 11:19:55 -08001360 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001361}
1362
Randall Spanglere9213a72013-01-24 11:19:55 -08001363static int GetNextTriesTest(void)
1364{
1365 GptData *gpt = GetEmptyGptData();
1366 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
1367 uint64_t start, size;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001368
Randall Spanglere9213a72013-01-24 11:19:55 -08001369 /* Tries=nonzero is attempted just like success, but tries=0 isn't */
1370 BuildTestGptData(gpt);
1371 FillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
1372 FillEntry(e1 + KERNEL_B, 1, 3, 0, 0);
1373 FillEntry(e1 + KERNEL_X, 1, 4, 0, 1);
1374 FillEntry(e1 + KERNEL_Y, 1, 0, 0, 5);
1375 RefreshCrc32(gpt);
1376 GptInit(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001377
Randall Spanglere9213a72013-01-24 11:19:55 -08001378 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1379 EXPECT(KERNEL_X == gpt->current_kernel);
1380 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1381 EXPECT(KERNEL_A == gpt->current_kernel);
1382 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1383 GptNextKernelEntry(gpt, &start, &size));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001384
Randall Spanglere9213a72013-01-24 11:19:55 -08001385 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001386}
1387
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001388static int MtdGetNextNormalTest(void)
1389{
1390 MtdData *mtd = GetEmptyMtdData();
1391 MtdDiskPartition *e1 = mtd->primary.partitions;
1392 uint64_t start, size;
1393
1394 /* Normal case - both kernels successful */
1395 BuildTestMtdData(mtd);
1396 MtdFillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
1397 MtdFillEntry(e1 + KERNEL_B, 1, 2, 1, 0);
1398 mtd->primary.crc32 = MtdHeaderCrc(&mtd->primary);
1399 MtdInit(mtd);
1400
1401 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1402 EXPECT(KERNEL_A == mtd->current_kernel);
1403 EXPECT(34 == start);
1404 EXPECT(100 == size);
1405
1406 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1407 EXPECT(KERNEL_B == mtd->current_kernel);
1408 EXPECT(134 == start);
1409 EXPECT(99 == size);
1410
1411 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1412 MtdNextKernelEntry(mtd, &start, &size));
1413 EXPECT(-1 == mtd->current_kernel);
1414
1415 /* Call as many times as you want; you won't get another kernel... */
1416 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1417 MtdNextKernelEntry(mtd, &start, &size));
1418 EXPECT(-1 == mtd->current_kernel);
1419
1420 return TEST_OK;
1421}
1422
1423static int MtdGetNextPrioTest(void)
1424{
1425 MtdData *mtd = GetEmptyMtdData();
1426 MtdDiskPartition *e1 = mtd->primary.partitions;
1427 uint64_t start, size;
1428
1429 /* Priority 3, 4, 0, 4 - should boot order B, Y, A */
1430 BuildTestMtdData(mtd);
1431 MtdFillEntry(e1 + KERNEL_A, 1, 3, 1, 0);
1432 MtdFillEntry(e1 + KERNEL_B, 1, 4, 1, 0);
1433 MtdFillEntry(e1 + KERNEL_X, 1, 0, 1, 0);
1434 MtdFillEntry(e1 + KERNEL_Y, 1, 4, 1, 0);
1435 mtd->primary.crc32 = MtdHeaderCrc(&mtd->primary);
1436 MtdInit(mtd);
1437
1438 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1439 EXPECT(KERNEL_B == mtd->current_kernel);
1440 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1441 EXPECT(KERNEL_Y == mtd->current_kernel);
1442 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1443 EXPECT(KERNEL_A == mtd->current_kernel);
1444 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1445 MtdNextKernelEntry(mtd, &start, &size));
1446
1447 return TEST_OK;
1448}
1449
1450static int MtdGetNextTriesTest(void)
1451{
1452 MtdData *mtd = GetEmptyMtdData();
1453 MtdDiskPartition *e1 = mtd->primary.partitions;
1454 uint64_t start, size;
1455
1456 /* Tries=nonzero is attempted just like success, but tries=0 isn't */
1457 BuildTestMtdData(mtd);
1458 MtdFillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
1459 MtdFillEntry(e1 + KERNEL_B, 1, 3, 0, 0);
1460 MtdFillEntry(e1 + KERNEL_X, 1, 4, 0, 1);
1461 MtdFillEntry(e1 + KERNEL_Y, 1, 0, 0, 5);
1462 mtd->primary.crc32 = MtdHeaderCrc(&mtd->primary);
1463 MtdInit(mtd);
1464
1465 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1466 EXPECT(KERNEL_X == mtd->current_kernel);
1467 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1468 EXPECT(KERNEL_A == mtd->current_kernel);
1469 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1470 MtdNextKernelEntry(mtd, &start, &size));
1471
1472 return TEST_OK;
1473}
1474
1475static int MtdUpdateTest() {
1476 MtdData *mtd = GetEmptyMtdData();
1477 MtdDiskPartition *e = &mtd->primary.partitions[0];
1478 uint64_t start, size;
1479
1480 BuildTestMtdData(mtd);
1481
1482 /* Tries=nonzero is attempted just like success, but tries=0 isn't */
1483 MtdFillEntry(e + KERNEL_A, 1, 4, 1, 0);
1484 MtdFillEntry(e + KERNEL_B, 1, 3, 0, 2);
1485 MtdFillEntry(e + KERNEL_X, 1, 2, 0, 2);
1486 mtd->primary.crc32 = MtdHeaderCrc(&mtd->primary);
1487 mtd->modified = 0;
1488 EXPECT(GPT_SUCCESS == MtdInit(mtd));
1489
1490 /* Successful kernel */
1491 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1492 EXPECT(KERNEL_A == mtd->current_kernel);
1493 EXPECT(1 == MtdGetEntrySuccessful(e + KERNEL_A));
1494 EXPECT(4 == MtdGetEntryPriority(e + KERNEL_A));
1495 EXPECT(0 == MtdGetEntryTries(e + KERNEL_A));
1496 /* Trying successful kernel changes nothing */
1497 EXPECT(GPT_SUCCESS == MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_TRY));
1498 EXPECT(1 == MtdGetEntrySuccessful(e + KERNEL_A));
1499 EXPECT(4 == MtdGetEntryPriority(e + KERNEL_A));
1500 EXPECT(0 == MtdGetEntryTries(e + KERNEL_A));
1501 EXPECT(0 == mtd->modified);
1502 /* Marking it bad also does not update it. */
1503 EXPECT(GPT_SUCCESS == MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_BAD));
1504 EXPECT(1 == MtdGetEntrySuccessful(e + KERNEL_A));
1505 EXPECT(4 == MtdGetEntryPriority(e + KERNEL_A));
1506 EXPECT(0 == MtdGetEntryTries(e + KERNEL_A));
1507 EXPECT(0 == mtd->modified);
1508
1509 /* Kernel with tries */
1510 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1511 EXPECT(KERNEL_B == mtd->current_kernel);
1512 EXPECT(0 == MtdGetEntrySuccessful(e + KERNEL_B));
1513 EXPECT(3 == MtdGetEntryPriority(e + KERNEL_B));
1514 EXPECT(2 == MtdGetEntryTries(e + KERNEL_B));
1515 /* Marking it bad clears it */
1516 EXPECT(GPT_SUCCESS == MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_BAD));
1517 EXPECT(0 == MtdGetEntrySuccessful(e + KERNEL_B));
1518 EXPECT(0 == MtdGetEntryPriority(e + KERNEL_B));
1519 EXPECT(0 == MtdGetEntryTries(e + KERNEL_B));
1520 /* And that's caused the mtd to need updating */
1521 EXPECT(1 == mtd->modified);
1522
1523 /* Another kernel with tries */
1524 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1525 EXPECT(KERNEL_X == mtd->current_kernel);
1526 EXPECT(0 == MtdGetEntrySuccessful(e + KERNEL_X));
1527 EXPECT(2 == MtdGetEntryPriority(e + KERNEL_X));
1528 EXPECT(2 == MtdGetEntryTries(e + KERNEL_X));
1529 /* Trying it uses up a try */
1530 EXPECT(GPT_SUCCESS == MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_TRY));
1531 EXPECT(0 == MtdGetEntrySuccessful(e + KERNEL_X));
1532 EXPECT(2 == MtdGetEntryPriority(e + KERNEL_X));
1533 EXPECT(1 == MtdGetEntryTries(e + KERNEL_X));
1534 /* Trying it again marks it inactive */
1535 EXPECT(GPT_SUCCESS == MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_TRY));
1536 EXPECT(0 == MtdGetEntrySuccessful(e + KERNEL_X));
1537 EXPECT(0 == MtdGetEntryPriority(e + KERNEL_X));
1538 EXPECT(0 == MtdGetEntryTries(e + KERNEL_X));
1539
1540 /* Can't update if entry isn't a kernel, or there isn't an entry */
1541 MtdSetEntryType(e + KERNEL_X, MTD_PARTITION_TYPE_UNUSED);
1542 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1543 MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_BAD));
1544 mtd->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
1545 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1546 MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_BAD));
1547
1548 return TEST_OK;
1549}
1550
Randall Spanglere9213a72013-01-24 11:19:55 -08001551static int GptUpdateTest(void)
1552{
1553 GptData *gpt = GetEmptyGptData();
1554 GptEntry *e = (GptEntry *)(gpt->primary_entries);
1555 GptEntry *e2 = (GptEntry *)(gpt->secondary_entries);
1556 uint64_t start, size;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001557
Randall Spanglere9213a72013-01-24 11:19:55 -08001558 /* Tries=nonzero is attempted just like success, but tries=0 isn't */
1559 BuildTestGptData(gpt);
1560 FillEntry(e + KERNEL_A, 1, 4, 1, 0);
1561 FillEntry(e + KERNEL_B, 1, 3, 0, 2);
1562 FillEntry(e + KERNEL_X, 1, 2, 0, 2);
1563 RefreshCrc32(gpt);
1564 GptInit(gpt);
1565 gpt->modified = 0; /* Nothing modified yet */
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001566
Randall Spanglere9213a72013-01-24 11:19:55 -08001567 /* Successful kernel */
1568 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1569 EXPECT(KERNEL_A == gpt->current_kernel);
1570 EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
1571 EXPECT(4 == GetEntryPriority(e + KERNEL_A));
1572 EXPECT(0 == GetEntryTries(e + KERNEL_A));
1573 EXPECT(1 == GetEntrySuccessful(e2 + KERNEL_A));
1574 EXPECT(4 == GetEntryPriority(e2 + KERNEL_A));
1575 EXPECT(0 == GetEntryTries(e2 + KERNEL_A));
1576 /* Trying successful kernel changes nothing */
1577 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
1578 EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
1579 EXPECT(4 == GetEntryPriority(e + KERNEL_A));
1580 EXPECT(0 == GetEntryTries(e + KERNEL_A));
1581 EXPECT(0 == gpt->modified);
1582 /* Marking it bad also does not update it. */
1583 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
1584 EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
1585 EXPECT(4 == GetEntryPriority(e + KERNEL_A));
1586 EXPECT(0 == GetEntryTries(e + KERNEL_A));
1587 EXPECT(0 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001588
Randall Spanglere9213a72013-01-24 11:19:55 -08001589 /* Kernel with tries */
1590 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1591 EXPECT(KERNEL_B == gpt->current_kernel);
1592 EXPECT(0 == GetEntrySuccessful(e + KERNEL_B));
1593 EXPECT(3 == GetEntryPriority(e + KERNEL_B));
1594 EXPECT(2 == GetEntryTries(e + KERNEL_B));
1595 /* Marking it bad clears it */
1596 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
1597 EXPECT(0 == GetEntrySuccessful(e + KERNEL_B));
1598 EXPECT(0 == GetEntryPriority(e + KERNEL_B));
1599 EXPECT(0 == GetEntryTries(e + KERNEL_B));
1600 /* Which affects both copies of the partition entries */
1601 EXPECT(0 == GetEntrySuccessful(e2 + KERNEL_B));
1602 EXPECT(0 == GetEntryPriority(e2 + KERNEL_B));
1603 EXPECT(0 == GetEntryTries(e2 + KERNEL_B));
1604 /* And that's caused the GPT to need updating */
1605 EXPECT(0x0F == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001606
Randall Spanglere9213a72013-01-24 11:19:55 -08001607 /* Another kernel with tries */
1608 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1609 EXPECT(KERNEL_X == gpt->current_kernel);
1610 EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
1611 EXPECT(2 == GetEntryPriority(e + KERNEL_X));
1612 EXPECT(2 == GetEntryTries(e + KERNEL_X));
1613 /* Trying it uses up a try */
1614 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
1615 EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
1616 EXPECT(2 == GetEntryPriority(e + KERNEL_X));
1617 EXPECT(1 == GetEntryTries(e + KERNEL_X));
1618 EXPECT(0 == GetEntrySuccessful(e2 + KERNEL_X));
1619 EXPECT(2 == GetEntryPriority(e2 + KERNEL_X));
1620 EXPECT(1 == GetEntryTries(e2 + KERNEL_X));
1621 /* Trying it again marks it inactive */
1622 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
1623 EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
1624 EXPECT(0 == GetEntryPriority(e + KERNEL_X));
1625 EXPECT(0 == GetEntryTries(e + KERNEL_X));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001626
Randall Spangler0bda13f2013-01-24 12:25:26 -08001627 /* Can't update if entry isn't a kernel, or there isn't an entry */
1628 Memcpy(&e[KERNEL_X].type, &guid_rootfs, sizeof(guid_rootfs));
1629 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1630 GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
1631 gpt->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
1632 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1633 GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
1634
1635
Randall Spanglere9213a72013-01-24 11:19:55 -08001636 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001637}
1638
Randall Spanglere9213a72013-01-24 11:19:55 -08001639/*
1640 * Give an invalid kernel type, and expect GptUpdateKernelEntry() returns
1641 * GPT_ERROR_INVALID_UPDATE_TYPE.
1642 */
1643static int UpdateInvalidKernelTypeTest(void)
1644{
1645 GptData *gpt = GetEmptyGptData();
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001646
Randall Spanglere9213a72013-01-24 11:19:55 -08001647 BuildTestGptData(gpt);
1648 /* anything, but not CGPT_KERNEL_ENTRY_NOT_FOUND */
1649 gpt->current_kernel = 0;
1650 /* any invalid update_type value */
1651 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1652 GptUpdateKernelEntry(gpt, 99));
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001653
Randall Spanglere9213a72013-01-24 11:19:55 -08001654 return TEST_OK;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001655}
1656
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001657static int MtdUpdateInvalidKernelTypeTest(void)
1658{
1659 MtdData *mtd = GetEmptyMtdData();
1660
1661 BuildTestMtdData(mtd);
1662 /* anything, but not CGPT_KERNEL_ENTRY_NOT_FOUND */
1663 mtd->current_kernel = 0;
1664 /* any invalid update_type value */
1665 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1666 MtdUpdateKernelEntry(mtd, 99));
1667
1668 return TEST_OK;
1669}
1670
Randall Spanglere9213a72013-01-24 11:19:55 -08001671/* Test duplicate UniqueGuids can be detected. */
1672static int DuplicateUniqueGuidTest(void)
1673{
1674 GptData *gpt = GetEmptyGptData();
1675 GptHeader *h = (GptHeader *)gpt->primary_header;
1676 GptEntry *e = (GptEntry *)gpt->primary_entries;
1677 int i, j;
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001678
Randall Spanglere9213a72013-01-24 11:19:55 -08001679 struct {
1680 int duplicate;
1681 struct {
1682 uint64_t starting_lba;
1683 uint64_t ending_lba;
1684 uint32_t type_guid;
1685 uint32_t unique_guid;
1686 } entries[16]; /* enough for testing. */
1687 } cases[] = {
1688 {GPT_SUCCESS, {{100, 109, 1, 1},
1689 {110, 119, 2, 2},
1690 {120, 129, 3, 3},
1691 {130, 139, 4, 4},
1692 }},
1693 {GPT_SUCCESS, {{100, 109, 1, 1},
1694 {110, 119, 1, 2},
1695 {120, 129, 2, 3},
1696 {130, 139, 2, 4},
1697 }},
1698 {GPT_ERROR_DUP_GUID, {{100, 109, 1, 1},
1699 {110, 119, 2, 2},
1700 {120, 129, 3, 1},
1701 {130, 139, 4, 4},
1702 }},
1703 {GPT_ERROR_DUP_GUID, {{100, 109, 1, 1},
1704 {110, 119, 1, 2},
1705 {120, 129, 2, 3},
1706 {130, 139, 2, 2},
1707 }},
1708 };
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001709
Randall Spanglere9213a72013-01-24 11:19:55 -08001710 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
1711 BuildTestGptData(gpt);
1712 ZeroEntries(gpt);
1713 for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) {
1714 if (!cases[i].entries[j].starting_lba)
1715 break;
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001716
Randall Spanglere9213a72013-01-24 11:19:55 -08001717 e[j].starting_lba = cases[i].entries[j].starting_lba;
1718 e[j].ending_lba = cases[i].entries[j].ending_lba;
1719 SetGuid(&e[j].type, cases[i].entries[j].type_guid);
1720 SetGuid(&e[j].unique, cases[i].entries[j].unique_guid);
1721 }
1722 RefreshCrc32(gpt);
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001723
Randall Spanglere9213a72013-01-24 11:19:55 -08001724 EXPECT(cases[i].duplicate == CheckEntries(e, h));
1725 }
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001726
Randall Spanglere9213a72013-01-24 11:19:55 -08001727 return TEST_OK;
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001728}
1729
Randall Spangler0bda13f2013-01-24 12:25:26 -08001730/* Test getting the current kernel GUID */
1731static int GetKernelGuidTest(void)
1732{
1733 GptData *gpt = GetEmptyGptData();
1734 GptEntry *e = (GptEntry *)gpt->primary_entries;
1735 Guid g;
1736
1737 BuildTestGptData(gpt);
1738 gpt->current_kernel = 0;
1739 GetCurrentKernelUniqueGuid(gpt, &g);
1740 EXPECT(!Memcmp(&g, &e[0].unique, sizeof(Guid)));
1741 gpt->current_kernel = 1;
1742 GetCurrentKernelUniqueGuid(gpt, &g);
1743 EXPECT(!Memcmp(&g, &e[1].unique, sizeof(Guid)));
1744
1745 return TEST_OK;
1746}
1747
1748/* Test getting GPT error text strings */
1749static int ErrorTextTest(void)
1750{
1751 int i;
1752
1753 /* Known errors are not unknown */
1754 for (i = 0; i < GPT_ERROR_COUNT; i++) {
1755 EXPECT(GptErrorText(i));
1756 EXPECT(strcmp(GptErrorText(i), "Unknown"));
1757 }
1758
1759 /* But other error values are */
1760 EXPECT(!strcmp(GptErrorText(GPT_ERROR_COUNT), "Unknown"));
1761
1762 return TEST_OK;
1763}
1764
Albert Chaulk534723a2013-03-20 14:46:50 -07001765int nand_read_page(const nand_geom *nand, int page, void *buf, int size) {
1766 uint32_t ofs = page * nand->szofpg;
1767 uint32_t sz = size;
1768 if (ofs + sz > nand_drive_sz) {
1769 return -1;
1770 }
1771 Memcpy(buf, nand_drive + ofs, sz);
1772 return 0;
1773}
1774
1775int nand_write_page(const nand_geom *nand, int page,
1776 const void *buf, int size) {
1777 uint32_t ofs = page * nand->szofpg;
1778 uint32_t sz = size;
1779 uint32_t i;
1780 if (ofs + sz > nand_drive_sz) {
1781 return -1;
1782 }
1783 for (i = 0; i < sz; i++) {
1784 if (nand_drive[ofs + i] != 0xff) {
1785 return -1;
1786 }
1787 }
1788 Memcpy(nand_drive + ofs, buf, sz);
1789 return 0;
1790}
1791
1792int nand_erase_block(const nand_geom *nand, int block) {
1793 uint32_t ofs = block * nand->szofblk;
1794 uint32_t sz = nand->szofblk;
1795 if (ofs + sz > nand_drive_sz) {
1796 return -1;
1797 }
1798 if (!--nand_bad_block_map[block]) {
1799 return -1;
1800 }
1801 Memset(nand_drive + ofs, 0xFF, sz);
1802 return 0;
1803}
1804
1805int nand_is_bad_block(const nand_geom *nand, int block) {
1806 return nand_bad_block_map[block] == 0;
1807}
1808
1809
1810static void nand_make_ramdisk() {
1811 if (nand_drive) {
1812 free(nand_drive);
1813 }
1814 if (nand_bad_block_map) {
1815 free(nand_bad_block_map);
1816 }
1817 nand_drive_sz = 1024 * 1024 * 16;
1818 nand_drive = (uint8_t *)malloc(nand_drive_sz);
1819 nand_bad_block_map = (uint8_t *)malloc(nand_drive_sz / 512);
1820 Memset(nand_drive, 0xff, nand_drive_sz);
1821 Memset(nand_bad_block_map, 0xff, nand_drive_sz / 512);
1822}
1823
1824static int MtdFtsTest() {
1825 int MtdLoad(struct drive *drive, int sector_bytes);
1826 int MtdSave(struct drive *drive);
1827 int FlashGet(const char *key, uint8_t *data, uint32_t *bufsz);
1828 int FlashSet(const char *key, const uint8_t *data, uint32_t bufsz);
1829
1830 int i, j, err;
1831
1832 struct {
1833 int result;
1834 unsigned int offset, size, block_size_bytes, page_size_bytes;
1835 } cases[] = {
1836 { 0, 1, 2, 1024 * 1024, 1024 * 4 },
1837 { 0, 1, 2, 1024 * 1024, 1024 * 16 },
1838
1839 /* Failure cases, non-power-of-2 */
1840 { -ENODEV, 1, 2, 5000000, 1024 * 16 },
1841 { -ENODEV, 1, 2, 1024 * 1024, 65535 },
1842
1843 /* Page > block */
1844 { -ENODEV, 1, 2, 1024 * 16, 1024 * 1024 },
1845 };
1846
1847
1848 /* Check if the FTS store works */
1849 for (i = 0; i < ARRAY_SIZE(cases); i++) {
1850 nand_make_ramdisk();
1851 EXPECT(cases[i].result == flash_ts_init(cases[i].offset, cases[i].size,
1852 cases[i].page_size_bytes,
1853 cases[i].block_size_bytes, 512, 0));
1854
1855 if (cases[i].result == 0) {
1856 /* We should have a working FTS store now */
1857 char buffer[64];
1858 uint8_t blob[256], blob_read[256];
1859 uint32_t sz = sizeof(blob_read);
1860 struct drive drive;
1861
1862 /* Test the low level API */
1863 EXPECT(0 == flash_ts_set("some_key", "some value"));
1864 flash_ts_get("some_key", buffer, sizeof(buffer));
1865 EXPECT(0 == strcmp(buffer, "some value"));
1866
1867 /* Check overwrite */
1868 EXPECT(0 == flash_ts_set("some_key", "some other value"));
1869 flash_ts_get("some_key", buffer, sizeof(buffer));
1870 EXPECT(0 == strcmp(buffer, "some other value"));
1871
1872 /* Check delete */
1873 EXPECT(0 == flash_ts_set("some_key", ""));
1874
1875 /* Verify that re-initialization pulls the right record. */
1876 flash_ts_init(cases[i].offset, cases[i].size, cases[i].page_size_bytes,
1877 cases[i].block_size_bytes, 512, 0);
1878 flash_ts_get("some_key", buffer, sizeof(buffer));
1879 EXPECT(0 == strcmp(buffer, ""));
1880
1881 /* Fill up the disk, eating all erase cycles */
1882 for (j = 0; j < nand_drive_sz / 512; j++) {
1883 nand_bad_block_map[j] = 2;
1884 }
1885 for (j = 0; j < 999999; j++) {
1886 char str[32];
1887 sprintf(str, "%d", j);
1888 err = flash_ts_set("some_new_key", str);
1889 if (err) {
1890 EXPECT(err == -ENOMEM);
1891 break;
1892 }
1893
1894 /* Make sure we can figure out where the latest is. */
1895 flash_ts_init(cases[i].offset, cases[i].size, cases[i].page_size_bytes,
1896 cases[i].block_size_bytes, 512, 0);
1897 flash_ts_get("some_new_key", buffer, sizeof(buffer));
1898 EXPECT(0 == strcmp(buffer, str));
1899 }
1900 EXPECT(j < 999999);
1901
1902 /* We need our drive back. */
1903 nand_make_ramdisk();
1904 flash_ts_init(cases[i].offset, cases[i].size, cases[i].page_size_bytes,
1905 cases[i].block_size_bytes, 512, 0);
1906
1907
1908 for (j = 0; j < 256; j++) {
1909 blob[j] = j;
1910 }
1911
1912 /* Hex conversion / blob storage */
1913 EXPECT(0 == FlashSet("some_blob", blob, sizeof(blob)));
1914 EXPECT(0 == FlashGet("some_blob", blob_read, &sz));
1915 EXPECT(sz == sizeof(blob_read));
1916 EXPECT(0 == Memcmp(blob, blob_read, sizeof(blob)));
1917
1918 BuildTestMtdData(&drive.mtd);
1919 drive.mtd.flash_block_bytes = cases[i].block_size_bytes;
1920 drive.mtd.flash_page_bytes = cases[i].page_size_bytes;
1921 drive.mtd.fts_block_offset = cases[i].offset;
1922 drive.mtd.fts_block_size = cases[i].size;
1923 drive.mtd.sector_bytes = 512;
1924 drive.mtd.drive_sectors = nand_drive_sz / 512;
1925
1926 /* MTD-level API */
1927 EXPECT(0 == MtdSave(&drive));
1928 Memset(&drive.mtd.primary, 0, sizeof(drive.mtd.primary));
1929 EXPECT(0 == MtdLoad(&drive, 512));
1930 }
1931 }
1932
1933 return TEST_OK;
1934}
1935
Randall Spanglere9213a72013-01-24 11:19:55 -08001936int main(int argc, char *argv[])
1937{
1938 int i;
1939 int error_count = 0;
1940 struct {
1941 char *name;
1942 test_func fp;
1943 int retval;
1944 } test_cases[] = {
1945 { TEST_CASE(StructSizeTest), },
1946 { TEST_CASE(TestBuildTestGptData), },
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001947 { TEST_CASE(TestBuildTestMtdData), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001948 { TEST_CASE(ParameterTests), },
1949 { TEST_CASE(HeaderCrcTest), },
Randall Spangler0bda13f2013-01-24 12:25:26 -08001950 { TEST_CASE(HeaderSameTest), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001951 { TEST_CASE(SignatureTest), },
1952 { TEST_CASE(RevisionTest), },
1953 { TEST_CASE(SizeTest), },
1954 { TEST_CASE(CrcFieldTest), },
1955 { TEST_CASE(ReservedFieldsTest), },
1956 { TEST_CASE(SizeOfPartitionEntryTest), },
1957 { TEST_CASE(NumberOfPartitionEntriesTest), },
1958 { TEST_CASE(MyLbaTest), },
1959 { TEST_CASE(FirstUsableLbaAndLastUsableLbaTest), },
1960 { TEST_CASE(EntriesCrcTest), },
1961 { TEST_CASE(ValidEntryTest), },
1962 { TEST_CASE(OverlappedPartitionTest), },
1963 { TEST_CASE(SanityCheckTest), },
1964 { TEST_CASE(NoValidKernelEntryTest), },
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001965 { TEST_CASE(MtdNoValidKernelEntryTest), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001966 { TEST_CASE(EntryAttributeGetSetTest), },
1967 { TEST_CASE(EntryTypeTest), },
1968 { TEST_CASE(GetNextNormalTest), },
1969 { TEST_CASE(GetNextPrioTest), },
1970 { TEST_CASE(GetNextTriesTest), },
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001971 { TEST_CASE(MtdGetNextNormalTest), },
1972 { TEST_CASE(MtdGetNextPrioTest), },
1973 { TEST_CASE(MtdGetNextTriesTest), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001974 { TEST_CASE(GptUpdateTest), },
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001975 { TEST_CASE(MtdUpdateTest), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001976 { TEST_CASE(UpdateInvalidKernelTypeTest), },
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001977 { TEST_CASE(MtdUpdateInvalidKernelTypeTest), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001978 { TEST_CASE(DuplicateUniqueGuidTest), },
1979 { TEST_CASE(TestCrc32TestVectors), },
Randall Spangler0bda13f2013-01-24 12:25:26 -08001980 { TEST_CASE(GetKernelGuidTest), },
1981 { TEST_CASE(ErrorTextTest), },
Albert Chaulk534723a2013-03-20 14:46:50 -07001982 { TEST_CASE(MtdFtsTest), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001983 };
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001984
Randall Spanglere9213a72013-01-24 11:19:55 -08001985 for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
1986 printf("Running %s() ...\n", test_cases[i].name);
1987 test_cases[i].retval = test_cases[i].fp();
1988 if (test_cases[i].retval) {
1989 printf(COL_RED "[ERROR]\n\n" COL_STOP);
1990 ++error_count;
1991 } else {
1992 printf(COL_GREEN "[PASS]\n\n" COL_STOP);
1993 }
1994 }
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001995
Randall Spanglere9213a72013-01-24 11:19:55 -08001996 if (error_count) {
1997 printf("\n------------------------------------------------\n");
1998 printf(COL_RED "The following %d test cases are failed:\n"
1999 COL_STOP, error_count);
2000 for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
2001 if (test_cases[i].retval)
2002 printf(" %s()\n", test_cases[i].name);
2003 }
2004 }
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07002005
Randall Spanglere9213a72013-01-24 11:19:55 -08002006 return error_count ? 1 : 0;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07002007}