blob: be4c7159b7a657387b9d40d85da80a9db728ef73 [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
Alex Deymof5109732014-08-25 16:34:52 -07006#include <errno.h>
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -07007#include <string.h>
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07008
Albert Chaulk534723a2013-03-20 14:46:50 -07009#include "../cgpt/cgpt.h"
Bill Richardson18e03702014-06-23 17:48:33 -070010#include "../cgpt/flash_ts.h"
Louis Yung-Chieh Lo0dce41c2010-05-17 22:45:30 -070011#include "cgptlib_internal.h"
Randall Spangler3dcf9dc2010-06-02 12:46:17 -070012#include "cgptlib_test.h"
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070013#include "crc32.h"
Louis Yung-Chieh Lob31ddce2010-05-21 16:35:44 +080014#include "crc32_test.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"
Bill Richardson18e03702014-06-23 17:48:33 -070017#include "mtdlib_unused.h"
vbendeb3ecaf772010-06-24 16:19:53 -070018#include "test_common.h"
Albert Chaulk534723a2013-03-20 14:46:50 -070019#define _STUB_IMPLEMENTATION_
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070020#include "utility.h"
21
Randall Spanglere9213a72013-01-24 11:19:55 -080022/*
23 * Testing partition layout (sector_bytes=512)
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070024 *
25 * LBA Size Usage
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -070026 * ---------------------------------------------------------
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070027 * 0 1 PMBR
28 * 1 1 primary partition header
29 * 2 32 primary partition entries (128B * 128)
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -070030 * 34 100 kernel A (index: 0)
31 * 134 100 root A (index: 1)
32 * 234 100 root B (index: 2)
33 * 334 100 kernel B (index: 3)
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070034 * 434 32 secondary partition entries
35 * 466 1 secondary partition header
36 * 467
37 */
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -070038#define KERNEL_A 0
Randall Spangler3dcf9dc2010-06-02 12:46:17 -070039#define KERNEL_B 1
40#define ROOTFS_A 2
41#define ROOTFS_B 3
42#define KERNEL_X 2 /* Overload ROOTFS_A, for some GetNext tests */
43#define KERNEL_Y 3 /* Overload ROOTFS_B, for some GetNext tests */
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -070044
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070045#define DEFAULT_SECTOR_SIZE 512
46#define MAX_SECTOR_SIZE 4096
47#define DEFAULT_DRIVE_SECTORS 467
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070048#define PARTITION_ENTRIES_SIZE TOTAL_ENTRIES_SIZE /* 16384 */
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070049
Randall Spangler3dcf9dc2010-06-02 12:46:17 -070050static const Guid guid_zero = {{{0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0}}}};
51static const Guid guid_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
52static const Guid guid_rootfs = GPT_ENT_TYPE_CHROMEOS_ROOTFS;
53
Albert Chaulk534723a2013-03-20 14:46:50 -070054// cgpt_common.c requires these be defined if linked in.
55const char *progname = "CGPT-TEST";
56const char *command = "TEST";
57
58// Ramdisk for flash ts testing.
59static uint8_t *nand_drive = NULL;
60static uint32_t nand_drive_sz;
61static uint8_t *nand_bad_block_map = NULL;
62
Randall Spanglere9213a72013-01-24 11:19:55 -080063/*
64 * Copy a random-for-this-program-only Guid into the dest. The num parameter
Bill Richardsonaa8eda42010-08-27 09:31:26 -070065 * completely determines the Guid.
66 */
Randall Spanglere9213a72013-01-24 11:19:55 -080067static void SetGuid(void *dest, uint32_t num)
68{
69 Guid g = {{{num,0xd450,0x44bc,0xa6,0x93,
70 {0xb8,0xac,0x75,0x5f,0xcd,0x48}}}};
71 Memcpy(dest, &g, sizeof(Guid));
Bill Richardsonaa8eda42010-08-27 09:31:26 -070072}
Randall Spangler3dcf9dc2010-06-02 12:46:17 -070073
Randall Spanglere9213a72013-01-24 11:19:55 -080074/*
75 * Given a GptData pointer, first re-calculate entries CRC32 value, then reset
76 * header CRC32 value to 0, and calculate header CRC32 value. Both primary and
77 * secondary are updated.
78 */
79static void RefreshCrc32(GptData *gpt)
80{
81 GptHeader *header, *header2;
82 GptEntry *entries, *entries2;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070083
Randall Spanglere9213a72013-01-24 11:19:55 -080084 header = (GptHeader *)gpt->primary_header;
85 entries = (GptEntry *)gpt->primary_entries;
86 header2 = (GptHeader *)gpt->secondary_header;
87 entries2 = (GptEntry *)gpt->secondary_entries;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070088
Randall Spanglere9213a72013-01-24 11:19:55 -080089 header->entries_crc32 =
90 Crc32((uint8_t *)entries,
91 header->number_of_entries * header->size_of_entry);
92 header->header_crc32 = 0;
93 header->header_crc32 = Crc32((uint8_t *)header, header->size);
94 header2->entries_crc32 =
95 Crc32((uint8_t *)entries2,
96 header2->number_of_entries * header2->size_of_entry);
97 header2->header_crc32 = 0;
98 header2->header_crc32 = Crc32((uint8_t *)header2, header2->size);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070099}
100
Randall Spanglere9213a72013-01-24 11:19:55 -0800101static void ZeroHeaders(GptData *gpt)
102{
103 Memset(gpt->primary_header, 0, MAX_SECTOR_SIZE);
104 Memset(gpt->secondary_header, 0, MAX_SECTOR_SIZE);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700105}
106
Randall Spanglere9213a72013-01-24 11:19:55 -0800107static void ZeroEntries(GptData *gpt)
108{
109 Memset(gpt->primary_entries, 0, PARTITION_ENTRIES_SIZE);
110 Memset(gpt->secondary_entries, 0, PARTITION_ENTRIES_SIZE);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700111}
112
Randall Spanglere9213a72013-01-24 11:19:55 -0800113static void ZeroHeadersEntries(GptData *gpt)
114{
115 ZeroHeaders(gpt);
116 ZeroEntries(gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700117}
118
Randall Spanglere9213a72013-01-24 11:19:55 -0800119/*
120 * Return a pointer to a static GptData instance (no free is required).
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700121 * All fields are zero except 4 pointers linking to header and entries.
Randall Spanglere9213a72013-01-24 11:19:55 -0800122 * All content of headers and entries are zero.
123 */
124static GptData *GetEmptyGptData(void)
125{
126 static GptData gpt;
127 static uint8_t primary_header[MAX_SECTOR_SIZE];
128 static uint8_t primary_entries[PARTITION_ENTRIES_SIZE];
129 static uint8_t secondary_header[MAX_SECTOR_SIZE];
130 static uint8_t secondary_entries[PARTITION_ENTRIES_SIZE];
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700131
Randall Spanglere9213a72013-01-24 11:19:55 -0800132 Memset(&gpt, 0, sizeof(gpt));
133 gpt.primary_header = primary_header;
134 gpt.primary_entries = primary_entries;
135 gpt.secondary_header = secondary_header;
136 gpt.secondary_entries = secondary_entries;
137 ZeroHeadersEntries(&gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700138
Randall Spanglere9213a72013-01-24 11:19:55 -0800139 /* Initialize GptData internal states. */
140 gpt.current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -0700141
Randall Spanglere9213a72013-01-24 11:19:55 -0800142 return &gpt;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700143}
144
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700145static MtdData *GetEmptyMtdData() {
146 static MtdData mtd;
147 Memset(&mtd, 0, sizeof(mtd));
148 mtd.current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
149 return &mtd;
150}
151
Randall Spanglere9213a72013-01-24 11:19:55 -0800152/*
153 * Fill in most of fields and creates the layout described in the top of this
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700154 * file. Before calling this function, primary/secondary header/entries must
155 * have been pointed to the buffer, say, a gpt returned from GetEmptyGptData().
156 * This function returns a good (valid) copy of GPT layout described in top of
Randall Spanglere9213a72013-01-24 11:19:55 -0800157 * this file.
158 */
159static void BuildTestGptData(GptData *gpt)
160{
161 GptHeader *header, *header2;
162 GptEntry *entries, *entries2;
163 Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
164 Guid chromeos_rootfs = GPT_ENT_TYPE_CHROMEOS_ROOTFS;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700165
Randall Spanglere9213a72013-01-24 11:19:55 -0800166 gpt->sector_bytes = DEFAULT_SECTOR_SIZE;
167 gpt->drive_sectors = DEFAULT_DRIVE_SECTORS;
168 gpt->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
169 gpt->valid_headers = MASK_BOTH;
170 gpt->valid_entries = MASK_BOTH;
171 gpt->modified = 0;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700172
Randall Spanglere9213a72013-01-24 11:19:55 -0800173 /* Build primary */
174 header = (GptHeader *)gpt->primary_header;
175 entries = (GptEntry *)gpt->primary_entries;
176 Memcpy(header->signature, GPT_HEADER_SIGNATURE,
177 sizeof(GPT_HEADER_SIGNATURE));
178 header->revision = GPT_HEADER_REVISION;
179 header->size = sizeof(GptHeader);
180 header->reserved_zero = 0;
181 header->my_lba = 1;
182 header->alternate_lba = DEFAULT_DRIVE_SECTORS - 1;
183 header->first_usable_lba = 34;
184 header->last_usable_lba = DEFAULT_DRIVE_SECTORS - 1 - 32 - 1; /* 433 */
185 header->entries_lba = 2;
186 /* 512B / 128B * 32sectors = 128 entries */
187 header->number_of_entries = 128;
188 header->size_of_entry = 128; /* bytes */
189 Memcpy(&entries[0].type, &chromeos_kernel, sizeof(chromeos_kernel));
190 SetGuid(&entries[0].unique, 0);
191 entries[0].starting_lba = 34;
192 entries[0].ending_lba = 133;
193 Memcpy(&entries[1].type, &chromeos_rootfs, sizeof(chromeos_rootfs));
194 SetGuid(&entries[1].unique, 1);
195 entries[1].starting_lba = 134;
196 entries[1].ending_lba = 232;
197 Memcpy(&entries[2].type, &chromeos_rootfs, sizeof(chromeos_rootfs));
198 SetGuid(&entries[2].unique, 2);
199 entries[2].starting_lba = 234;
200 entries[2].ending_lba = 331;
201 Memcpy(&entries[3].type, &chromeos_kernel, sizeof(chromeos_kernel));
202 SetGuid(&entries[3].unique, 3);
203 entries[3].starting_lba = 334;
204 entries[3].ending_lba = 430;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700205
Randall Spanglere9213a72013-01-24 11:19:55 -0800206 /* Build secondary */
207 header2 = (GptHeader *)gpt->secondary_header;
208 entries2 = (GptEntry *)gpt->secondary_entries;
209 Memcpy(header2, header, sizeof(GptHeader));
210 Memcpy(entries2, entries, PARTITION_ENTRIES_SIZE);
211 header2->my_lba = DEFAULT_DRIVE_SECTORS - 1; /* 466 */
212 header2->alternate_lba = 1;
213 header2->entries_lba = DEFAULT_DRIVE_SECTORS - 1 - 32; /* 434 */
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700214
Randall Spanglere9213a72013-01-24 11:19:55 -0800215 RefreshCrc32(gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700216}
217
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700218static void BuildTestMtdData(MtdData *mtd) {
219 MtdDiskPartition *partitions;
220
221 mtd->sector_bytes = DEFAULT_SECTOR_SIZE;
222 mtd->drive_sectors = DEFAULT_DRIVE_SECTORS;
223 mtd->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
224 mtd->modified = 0;
225 Memset(&mtd->primary, 0, sizeof(mtd->primary));
226
227 Memcpy(mtd->primary.signature, MTD_DRIVE_SIGNATURE,
228 sizeof(mtd->primary.signature));
Albert Chaulk289b6042013-06-25 11:30:46 -0700229 mtd->primary.first_offset = 32 * DEFAULT_SECTOR_SIZE;
230 mtd->primary.last_offset = DEFAULT_DRIVE_SECTORS * DEFAULT_SECTOR_SIZE - 1;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700231 mtd->primary.size = MTD_DRIVE_V1_SIZE;
232
233 /* These values are not used directly by the library, but they are checked */
234 mtd->flash_page_bytes = mtd->sector_bytes * 8;
235 mtd->flash_block_bytes = mtd->flash_page_bytes * 8;
236 mtd->fts_block_offset = 1;
237 mtd->fts_block_size = 1;
238
239 partitions = &mtd->primary.partitions[0];
Albert Chaulk289b6042013-06-25 11:30:46 -0700240 partitions[0].starting_offset = 34 * DEFAULT_SECTOR_SIZE;
241 partitions[0].ending_offset = 134 * DEFAULT_SECTOR_SIZE - 1;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700242 partitions[0].flags =
243 MTD_PARTITION_TYPE_CHROMEOS_KERNEL << MTD_ATTRIBUTE_TYPE_OFFSET;
Albert Chaulk289b6042013-06-25 11:30:46 -0700244 partitions[1].starting_offset = 134 * DEFAULT_SECTOR_SIZE;
245 partitions[1].ending_offset = 233 * DEFAULT_SECTOR_SIZE - 1;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700246 partitions[1].flags =
247 MTD_PARTITION_TYPE_CHROMEOS_ROOTFS << MTD_ATTRIBUTE_TYPE_OFFSET;
Albert Chaulk289b6042013-06-25 11:30:46 -0700248 partitions[2].starting_offset = 234 * DEFAULT_SECTOR_SIZE;
249 partitions[2].ending_offset = 332 * DEFAULT_SECTOR_SIZE - 1;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700250 partitions[2].flags =
251 MTD_PARTITION_TYPE_CHROMEOS_KERNEL << MTD_ATTRIBUTE_TYPE_OFFSET;
Albert Chaulk289b6042013-06-25 11:30:46 -0700252 partitions[3].starting_offset = 334 * DEFAULT_SECTOR_SIZE;
253 partitions[3].ending_offset = 431 * DEFAULT_SECTOR_SIZE - 1;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700254 partitions[3].flags =
255 MTD_PARTITION_TYPE_CHROMEOS_ROOTFS << MTD_ATTRIBUTE_TYPE_OFFSET;
256
257 mtd->primary.crc32 = 0;
258 mtd->primary.crc32 = Crc32(&mtd->primary, MTD_DRIVE_V1_SIZE);
259}
260
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700261
Randall Spanglere9213a72013-01-24 11:19:55 -0800262/*
263 * Test if the structures are the expected size; if this fails, struct packing
264 * is not working properly.
265 */
266static int StructSizeTest(void)
267{
Randall Spangler81d09962010-06-23 10:15:38 -0700268
Randall Spanglere9213a72013-01-24 11:19:55 -0800269 EXPECT(GUID_EXPECTED_SIZE == sizeof(Guid));
270 EXPECT(GPTHEADER_EXPECTED_SIZE == sizeof(GptHeader));
271 EXPECT(GPTENTRY_EXPECTED_SIZE == sizeof(GptEntry));
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700272 EXPECT(MTDENTRY_EXPECTED_SIZE == sizeof(MtdDiskPartition));
273 EXPECT(MTDLAYOUT_EXPECTED_SIZE == sizeof(MtdDiskLayout));
Randall Spanglere9213a72013-01-24 11:19:55 -0800274 return TEST_OK;
Randall Spangler81d09962010-06-23 10:15:38 -0700275}
276
277
Randall Spanglere9213a72013-01-24 11:19:55 -0800278/* Test if the default structure returned by BuildTestGptData() is good. */
279static int TestBuildTestGptData(void)
280{
281 GptData *gpt;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700282
Randall Spanglere9213a72013-01-24 11:19:55 -0800283 gpt = GetEmptyGptData();
284 BuildTestGptData(gpt);
285 EXPECT(GPT_SUCCESS == GptInit(gpt));
Randall Spangler0bda13f2013-01-24 12:25:26 -0800286 gpt->sector_bytes = 0;
287 EXPECT(GPT_ERROR_INVALID_SECTOR_SIZE == GptInit(gpt));
Randall Spanglere9213a72013-01-24 11:19:55 -0800288 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700289}
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700290
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700291static int TestBuildTestMtdData() {
292 MtdData *mtd = GetEmptyMtdData();
293
294 BuildTestMtdData(mtd);
295 EXPECT(GPT_SUCCESS == MtdInit(mtd));
296 return TEST_OK;
297}
298
Randall Spanglere9213a72013-01-24 11:19:55 -0800299/*
300 * Test if wrong sector_bytes or drive_sectors is detected by GptInit().
301 * Currently we only support 512 bytes per sector. In the future, we may
302 * support other sizes. A too small drive_sectors should be rejected by
303 * GptInit().
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700304 * For MtdInit(), additionally test various flash geometries to verify
305 * that only valid ones are accepted.
Randall Spanglere9213a72013-01-24 11:19:55 -0800306 */
307static int ParameterTests(void)
308{
309 GptData *gpt;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700310 MtdData *mtd;
Randall Spanglere9213a72013-01-24 11:19:55 -0800311 struct {
312 uint32_t sector_bytes;
313 uint64_t drive_sectors;
314 int expected_retval;
315 } cases[] = {
316 {512, DEFAULT_DRIVE_SECTORS, GPT_SUCCESS},
317 {520, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
318 {512, 0, GPT_ERROR_INVALID_SECTOR_NUMBER},
319 {512, 66, GPT_ERROR_INVALID_SECTOR_NUMBER},
320 {512, GPT_PMBR_SECTOR + GPT_HEADER_SECTOR * 2 +
321 GPT_ENTRIES_SECTORS * 2, GPT_SUCCESS},
322 {4096, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
323 };
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700324 struct {
325 uint32_t sector_bytes;
326 uint32_t drive_sectors;
327 uint32_t flash_page_bytes;
328 uint32_t flash_block_bytes;
329 int expected_retval;
330 } mtdcases[] = {
331 {512, DEFAULT_DRIVE_SECTORS, 8*512,
332 8*512, GPT_SUCCESS},
333 {510, DEFAULT_DRIVE_SECTORS, 8*512,
334 8*512, GPT_ERROR_INVALID_SECTOR_SIZE},
335 {512, DEFAULT_DRIVE_SECTORS, 8*512,
336 8*512, GPT_SUCCESS},
337 {512, DEFAULT_DRIVE_SECTORS, 512,
338 8*512, GPT_SUCCESS},
339 {512, DEFAULT_DRIVE_SECTORS, 8*512,
340 10*512, GPT_ERROR_INVALID_FLASH_GEOMETRY},
341 {512, DEFAULT_DRIVE_SECTORS, 3*512,
342 9*512, GPT_SUCCESS},
343 {512, DEFAULT_DRIVE_SECTORS, 8*512,
344 6*512, GPT_ERROR_INVALID_FLASH_GEOMETRY},
345 {512, DEFAULT_DRIVE_SECTORS, 256,
346 6*512, GPT_ERROR_INVALID_FLASH_GEOMETRY},
347 {512, DEFAULT_DRIVE_SECTORS, 512,
348 6*512 + 256, GPT_ERROR_INVALID_FLASH_GEOMETRY},
349 };
Randall Spanglere9213a72013-01-24 11:19:55 -0800350 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700351
Randall Spanglere9213a72013-01-24 11:19:55 -0800352 gpt = GetEmptyGptData();
353 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
354 BuildTestGptData(gpt);
355 gpt->sector_bytes = cases[i].sector_bytes;
356 gpt->drive_sectors = cases[i].drive_sectors;
357 EXPECT(cases[i].expected_retval == CheckParameters(gpt));
358 }
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700359
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700360 mtd = GetEmptyMtdData();
361 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
362 BuildTestMtdData(mtd);
363 mtd->sector_bytes = mtdcases[i].sector_bytes;
364 mtd->drive_sectors = mtdcases[i].drive_sectors;
365 mtd->flash_block_bytes = mtdcases[i].flash_block_bytes;
366 mtd->flash_page_bytes = mtdcases[i].flash_page_bytes;
367 if(mtdcases[i].expected_retval != MtdCheckParameters(mtd)) {
368 printf("i=%d\n",i);
369 }
370 EXPECT(mtdcases[i].expected_retval == MtdCheckParameters(mtd));
371 }
372
Randall Spanglere9213a72013-01-24 11:19:55 -0800373 return TEST_OK;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700374}
375
Randall Spanglere9213a72013-01-24 11:19:55 -0800376/* Test if header CRC in two copies are calculated. */
377static int HeaderCrcTest(void)
378{
379 GptData *gpt = GetEmptyGptData();
380 GptHeader *h1 = (GptHeader *)gpt->primary_header;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700381
Randall Spanglere9213a72013-01-24 11:19:55 -0800382 BuildTestGptData(gpt);
383 EXPECT(HeaderCrc(h1) == h1->header_crc32);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700384
Randall Spanglere9213a72013-01-24 11:19:55 -0800385 /* CRC covers first byte of header */
386 BuildTestGptData(gpt);
387 gpt->primary_header[0] ^= 0xa5;
388 EXPECT(HeaderCrc(h1) != h1->header_crc32);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700389
Randall Spanglere9213a72013-01-24 11:19:55 -0800390 /* CRC covers last byte of header */
391 BuildTestGptData(gpt);
392 gpt->primary_header[h1->size - 1] ^= 0x5a;
393 EXPECT(HeaderCrc(h1) != h1->header_crc32);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700394
Randall Spanglere9213a72013-01-24 11:19:55 -0800395 /* CRC only covers header */
396 BuildTestGptData(gpt);
397 gpt->primary_header[h1->size] ^= 0x5a;
398 EXPECT(HeaderCrc(h1) == h1->header_crc32);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700399
Randall Spanglere9213a72013-01-24 11:19:55 -0800400 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700401}
402
Randall Spangler0bda13f2013-01-24 12:25:26 -0800403/* Test if header-same comparison works. */
404static int HeaderSameTest(void)
405{
406 GptData *gpt = GetEmptyGptData();
407 GptHeader *h1 = (GptHeader *)gpt->primary_header;
408 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
409 GptHeader h3;
410
411 EXPECT(0 == HeaderFieldsSame(h1, h2));
412
413 Memcpy(&h3, h2, sizeof(h3));
414 h3.signature[0] ^= 0xba;
415 EXPECT(1 == HeaderFieldsSame(h1, &h3));
416
417 Memcpy(&h3, h2, sizeof(h3));
418 h3.revision++;
419 EXPECT(1 == HeaderFieldsSame(h1, &h3));
420
421 Memcpy(&h3, h2, sizeof(h3));
422 h3.size++;
423 EXPECT(1 == HeaderFieldsSame(h1, &h3));
424
425 Memcpy(&h3, h2, sizeof(h3));
426 h3.reserved_zero++;
427 EXPECT(1 == HeaderFieldsSame(h1, &h3));
428
429 Memcpy(&h3, h2, sizeof(h3));
430 h3.first_usable_lba++;
431 EXPECT(1 == HeaderFieldsSame(h1, &h3));
432
433 Memcpy(&h3, h2, sizeof(h3));
434 h3.last_usable_lba++;
435 EXPECT(1 == HeaderFieldsSame(h1, &h3));
436
437 Memcpy(&h3, h2, sizeof(h3));
438 h3.disk_uuid.u.raw[0] ^= 0xba;
439 EXPECT(1 == HeaderFieldsSame(h1, &h3));
440
441 Memcpy(&h3, h2, sizeof(h3));
442 h3.number_of_entries++;
443 EXPECT(1 == HeaderFieldsSame(h1, &h3));
444
445 Memcpy(&h3, h2, sizeof(h3));
446 h3.size_of_entry++;
447 EXPECT(1 == HeaderFieldsSame(h1, &h3));
448
449 Memcpy(&h3, h2, sizeof(h3));
450 h3.entries_crc32++;
451 EXPECT(1 == HeaderFieldsSame(h1, &h3));
452
453 return TEST_OK;
454}
455
Randall Spanglere9213a72013-01-24 11:19:55 -0800456/* Test if signature ("EFI PART") is checked. */
457static int SignatureTest(void)
458{
459 GptData *gpt = GetEmptyGptData();
460 GptHeader *h1 = (GptHeader *)gpt->primary_header;
461 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
462 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700463
Randall Spangler0bda13f2013-01-24 12:25:26 -0800464 EXPECT(1 == CheckHeader(NULL, 0, gpt->drive_sectors));
465
Randall Spanglere9213a72013-01-24 11:19:55 -0800466 for (i = 0; i < 8; ++i) {
467 BuildTestGptData(gpt);
468 h1->signature[i] ^= 0xff;
469 h2->signature[i] ^= 0xff;
470 RefreshCrc32(gpt);
471 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
472 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
473 }
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700474
Randall Spanglere9213a72013-01-24 11:19:55 -0800475 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700476}
477
Randall Spanglere9213a72013-01-24 11:19:55 -0800478/*
479 * The revision we currently support is GPT_HEADER_REVISION. If the revision
480 * in header is not that, we expect the header is invalid.
481 */
482static int RevisionTest(void)
483{
484 GptData *gpt = GetEmptyGptData();
485 GptHeader *h1 = (GptHeader *)gpt->primary_header;
486 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
487 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700488
Randall Spanglere9213a72013-01-24 11:19:55 -0800489 struct {
490 uint32_t value_to_test;
491 int expect_rv;
492 } cases[] = {
493 {0x01000000, 1},
494 {0x00010000, 0}, /* GPT_HEADER_REVISION */
495 {0x00000100, 1},
496 {0x00000001, 1},
497 {0x23010456, 1},
498 };
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700499
Randall Spanglere9213a72013-01-24 11:19:55 -0800500 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
501 BuildTestGptData(gpt);
502 h1->revision = cases[i].value_to_test;
503 h2->revision = cases[i].value_to_test;
504 RefreshCrc32(gpt);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700505
Randall Spanglere9213a72013-01-24 11:19:55 -0800506 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
507 cases[i].expect_rv);
508 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
509 cases[i].expect_rv);
510 }
511 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700512}
513
Randall Spanglere9213a72013-01-24 11:19:55 -0800514static int SizeTest(void)
515{
516 GptData *gpt = GetEmptyGptData();
517 GptHeader *h1 = (GptHeader *)gpt->primary_header;
518 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
519 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700520
Randall Spanglere9213a72013-01-24 11:19:55 -0800521 struct {
522 uint32_t value_to_test;
523 int expect_rv;
524 } cases[] = {
525 {91, 1},
526 {92, 0},
527 {93, 0},
528 {511, 0},
529 {512, 0},
530 {513, 1},
531 };
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700532
Randall Spanglere9213a72013-01-24 11:19:55 -0800533 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
534 BuildTestGptData(gpt);
535 h1->size = cases[i].value_to_test;
536 h2->size = cases[i].value_to_test;
537 RefreshCrc32(gpt);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700538
Randall Spanglere9213a72013-01-24 11:19:55 -0800539 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
540 cases[i].expect_rv);
541 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
542 cases[i].expect_rv);
543 }
544 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700545}
546
Randall Spanglere9213a72013-01-24 11:19:55 -0800547/* Test if CRC is checked. */
548static int CrcFieldTest(void)
549{
550 GptData *gpt = GetEmptyGptData();
551 GptHeader *h1 = (GptHeader *)gpt->primary_header;
552 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700553
Randall Spanglere9213a72013-01-24 11:19:55 -0800554 BuildTestGptData(gpt);
555 /* Modify a field that the header verification doesn't care about */
556 h1->entries_crc32++;
557 h2->entries_crc32++;
558 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
559 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
560 /* Refresh the CRC; should pass now */
561 RefreshCrc32(gpt);
562 EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
563 EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700564
Randall Spanglere9213a72013-01-24 11:19:55 -0800565 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700566}
567
Randall Spanglere9213a72013-01-24 11:19:55 -0800568/* Test if reserved fields are checked. We'll try non-zero values to test. */
569static int ReservedFieldsTest(void)
570{
571 GptData *gpt = GetEmptyGptData();
572 GptHeader *h1 = (GptHeader *)gpt->primary_header;
573 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700574
Randall Spanglere9213a72013-01-24 11:19:55 -0800575 BuildTestGptData(gpt);
576 h1->reserved_zero ^= 0x12345678; /* whatever random */
577 h2->reserved_zero ^= 0x12345678; /* whatever random */
578 RefreshCrc32(gpt);
579 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
580 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700581
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700582#ifdef PADDING_CHECKED
Randall Spanglere9213a72013-01-24 11:19:55 -0800583 /* TODO: padding check is currently disabled */
584 BuildTestGptData(gpt);
585 h1->padding[12] ^= 0x34; /* whatever random */
586 h2->padding[56] ^= 0x78; /* whatever random */
587 RefreshCrc32(gpt);
588 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
589 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700590#endif
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700591
Randall Spanglere9213a72013-01-24 11:19:55 -0800592 return TEST_OK;
593}
594
595/*
596 * Technically, any size which is 2^N where N > 6 should work, but our
597 * library only supports one size.
598 */
599static int SizeOfPartitionEntryTest(void) {
600 GptData *gpt = GetEmptyGptData();
601 GptHeader *h1 = (GptHeader *)gpt->primary_header;
602 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
603 int i;
604
605 struct {
606 uint32_t value_to_test;
607 int expect_rv;
608 } cases[] = {
609 {127, 1},
610 {128, 0},
611 {129, 1},
612 {256, 1},
613 {512, 1},
614 };
615
616 /* Check size of entryes */
617 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
618 BuildTestGptData(gpt);
619 h1->size_of_entry = cases[i].value_to_test;
620 h2->size_of_entry = cases[i].value_to_test;
621 h1->number_of_entries = TOTAL_ENTRIES_SIZE /
622 cases[i].value_to_test;
623 h2->number_of_entries = TOTAL_ENTRIES_SIZE /
624 cases[i].value_to_test;
625 RefreshCrc32(gpt);
626
627 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
628 cases[i].expect_rv);
629 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
630 cases[i].expect_rv);
631 }
632
633 return TEST_OK;
634}
635
636/*
637 * Technically, any size which is 2^N where N > 6 should work, but our library
638 * only supports one size.
639 */
640static int NumberOfPartitionEntriesTest(void)
641{
642 GptData *gpt = GetEmptyGptData();
643 GptHeader *h1 = (GptHeader *)gpt->primary_header;
644 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
645
646 BuildTestGptData(gpt);
647 h1->number_of_entries--;
648 h2->number_of_entries /= 2;
649 RefreshCrc32(gpt);
650 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
651 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
652
653 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700654}
655
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700656
Randall Spanglere9213a72013-01-24 11:19:55 -0800657/* Test if myLBA field is checked (1 for primary, last for secondary). */
658static int MyLbaTest(void)
659{
660 GptData *gpt = GetEmptyGptData();
661 GptHeader *h1 = (GptHeader *)gpt->primary_header;
662 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700663
Randall Spanglere9213a72013-01-24 11:19:55 -0800664 /* myLBA depends on primary vs secondary flag */
665 BuildTestGptData(gpt);
666 EXPECT(1 == CheckHeader(h1, 1, gpt->drive_sectors));
667 EXPECT(1 == CheckHeader(h2, 0, gpt->drive_sectors));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700668
Randall Spanglere9213a72013-01-24 11:19:55 -0800669 BuildTestGptData(gpt);
670 h1->my_lba--;
671 h2->my_lba--;
672 RefreshCrc32(gpt);
673 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
674 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700675
Randall Spanglere9213a72013-01-24 11:19:55 -0800676 BuildTestGptData(gpt);
677 h1->my_lba = 2;
678 h2->my_lba--;
679 RefreshCrc32(gpt);
680 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
681 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700682
Randall Spanglere9213a72013-01-24 11:19:55 -0800683 /* We should ignore the alternate_lba field entirely */
684 BuildTestGptData(gpt);
685 h1->alternate_lba++;
686 h2->alternate_lba++;
687 RefreshCrc32(gpt);
688 EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
689 EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
690
691 BuildTestGptData(gpt);
692 h1->alternate_lba--;
693 h2->alternate_lba--;
694 RefreshCrc32(gpt);
695 EXPECT(0 == CheckHeader(h1, 0, gpt->drive_sectors));
696 EXPECT(0 == CheckHeader(h2, 1, gpt->drive_sectors));
697
698 BuildTestGptData(gpt);
699 h1->entries_lba++;
700 h2->entries_lba++;
701 RefreshCrc32(gpt);
702 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
703 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
704
705 BuildTestGptData(gpt);
706 h1->entries_lba--;
707 h2->entries_lba--;
708 RefreshCrc32(gpt);
709 EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
710 EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));
711
712 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700713}
714
Randall Spanglere9213a72013-01-24 11:19:55 -0800715/* Test if FirstUsableLBA and LastUsableLBA are checked.
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700716 * FirstUsableLBA must be after the end of the primary GPT table array.
717 * LastUsableLBA must be before the start of the secondary GPT table array.
718 * FirstUsableLBA <= LastUsableLBA. */
Randall Spanglere9213a72013-01-24 11:19:55 -0800719static int FirstUsableLbaAndLastUsableLbaTest(void)
720{
721 GptData *gpt = GetEmptyGptData();
722 GptHeader *h1 = (GptHeader *)gpt->primary_header;
723 GptHeader *h2 = (GptHeader *)gpt->secondary_header;
724 int i;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700725
Randall Spanglere9213a72013-01-24 11:19:55 -0800726 struct {
727 uint64_t primary_entries_lba;
728 uint64_t primary_first_usable_lba;
729 uint64_t primary_last_usable_lba;
730 uint64_t secondary_first_usable_lba;
731 uint64_t secondary_last_usable_lba;
732 uint64_t secondary_entries_lba;
733 int primary_rv;
734 int secondary_rv;
735 } cases[] = {
736 {2, 34, 433, 34, 433, 434, 0, 0},
737 {2, 34, 432, 34, 430, 434, 0, 0},
738 {2, 33, 433, 33, 433, 434, 1, 1},
739 {2, 34, 434, 34, 433, 434, 1, 0},
740 {2, 34, 433, 34, 434, 434, 0, 1},
741 {2, 35, 433, 35, 433, 434, 0, 0},
742 {2, 433, 433, 433, 433, 434, 0, 0},
743 {2, 434, 433, 434, 434, 434, 1, 1},
744 {2, 433, 34, 34, 433, 434, 1, 0},
745 {2, 34, 433, 433, 34, 434, 0, 1},
746 };
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700747
Randall Spanglere9213a72013-01-24 11:19:55 -0800748 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
749 BuildTestGptData(gpt);
750 h1->entries_lba = cases[i].primary_entries_lba;
751 h1->first_usable_lba = cases[i].primary_first_usable_lba;
752 h1->last_usable_lba = cases[i].primary_last_usable_lba;
753 h2->entries_lba = cases[i].secondary_entries_lba;
754 h2->first_usable_lba = cases[i].secondary_first_usable_lba;
755 h2->last_usable_lba = cases[i].secondary_last_usable_lba;
756 RefreshCrc32(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700757
Randall Spanglere9213a72013-01-24 11:19:55 -0800758 EXPECT(CheckHeader(h1, 0, gpt->drive_sectors) ==
759 cases[i].primary_rv);
760 EXPECT(CheckHeader(h2, 1, gpt->drive_sectors) ==
761 cases[i].secondary_rv);
762 }
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700763
Randall Spanglere9213a72013-01-24 11:19:55 -0800764 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700765}
766
Randall Spanglere9213a72013-01-24 11:19:55 -0800767/*
768 * Test if PartitionEntryArrayCRC32 is checked. PartitionEntryArrayCRC32 must
769 * be calculated over SizeOfPartitionEntry * NumberOfPartitionEntries bytes.
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700770 */
Randall Spanglere9213a72013-01-24 11:19:55 -0800771static int EntriesCrcTest(void)
772{
773 GptData *gpt = GetEmptyGptData();
774 GptHeader *h1 = (GptHeader *)gpt->primary_header;
775 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
776 GptEntry *e2 = (GptEntry *)(gpt->secondary_entries);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700777
Randall Spanglere9213a72013-01-24 11:19:55 -0800778 /* Modify first byte of primary entries, and expect the CRC is wrong. */
779 BuildTestGptData(gpt);
780 EXPECT(0 == CheckEntries(e1, h1));
781 EXPECT(0 == CheckEntries(e2, h1));
782 gpt->primary_entries[0] ^= 0xa5; /* just XOR a non-zero value */
783 gpt->secondary_entries[TOTAL_ENTRIES_SIZE-1] ^= 0x5a;
784 EXPECT(GPT_ERROR_CRC_CORRUPTED == CheckEntries(e1, h1));
785 EXPECT(GPT_ERROR_CRC_CORRUPTED == CheckEntries(e2, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700786
Randall Spanglere9213a72013-01-24 11:19:55 -0800787 return TEST_OK;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700788}
789
Randall Spanglere9213a72013-01-24 11:19:55 -0800790/*
791 * Test if partition geometry is checked.
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700792 * All active (non-zero PartitionTypeGUID) partition entries should have:
793 * entry.StartingLBA >= header.FirstUsableLBA
794 * entry.EndingLBA <= header.LastUsableLBA
795 * entry.StartingLBA <= entry.EndingLBA
796 */
Randall Spanglere9213a72013-01-24 11:19:55 -0800797static int ValidEntryTest(void)
798{
799 GptData *gpt = GetEmptyGptData();
800 GptHeader *h1 = (GptHeader *)gpt->primary_header;
801 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700802 MtdData *mtd = GetEmptyMtdData();
803 MtdDiskLayout *mh = &mtd->primary;
804 MtdDiskPartition *me = mh->partitions;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700805
Randall Spanglere9213a72013-01-24 11:19:55 -0800806 /* error case: entry.StartingLBA < header.FirstUsableLBA */
807 BuildTestGptData(gpt);
808 e1[0].starting_lba = h1->first_usable_lba - 1;
809 RefreshCrc32(gpt);
810 EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700811
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700812 BuildTestMtdData(mtd);
Albert Chaulk289b6042013-06-25 11:30:46 -0700813 if (mh->first_offset > 0) {
814 me[0].starting_offset = mh->first_offset - 1;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700815 mh->crc32 = MtdHeaderCrc(mh);
816 EXPECT(GPT_ERROR_OUT_OF_REGION == MtdCheckEntries(me, mh));
817 }
818
Randall Spanglere9213a72013-01-24 11:19:55 -0800819 /* error case: entry.EndingLBA > header.LastUsableLBA */
820 BuildTestGptData(gpt);
821 e1[2].ending_lba = h1->last_usable_lba + 1;
822 RefreshCrc32(gpt);
823 EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700824
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700825 BuildTestMtdData(mtd);
Albert Chaulk289b6042013-06-25 11:30:46 -0700826 me[0].ending_offset = mh->last_offset + 1;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700827 mh->crc32 = MtdHeaderCrc(mh);
828 EXPECT(GPT_ERROR_OUT_OF_REGION == MtdCheckEntries(me, mh));
829
Randall Spanglere9213a72013-01-24 11:19:55 -0800830 /* error case: entry.StartingLBA > entry.EndingLBA */
831 BuildTestGptData(gpt);
832 e1[3].starting_lba = e1[3].ending_lba + 1;
833 RefreshCrc32(gpt);
834 EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700835
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700836 BuildTestMtdData(mtd);
Albert Chaulk289b6042013-06-25 11:30:46 -0700837 me[0].starting_offset = me[0].ending_offset + 1;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700838 mh->crc32 = MtdHeaderCrc(mh);
839 EXPECT(GPT_ERROR_OUT_OF_REGION == MtdCheckEntries(me, mh));
840
Randall Spanglere9213a72013-01-24 11:19:55 -0800841 /* case: non active entry should be ignored. */
842 BuildTestGptData(gpt);
843 Memset(&e1[1].type, 0, sizeof(e1[1].type));
844 e1[1].starting_lba = e1[1].ending_lba + 1;
845 RefreshCrc32(gpt);
846 EXPECT(0 == CheckEntries(e1, h1));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700847
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700848 BuildTestMtdData(mtd);
849 me[0].flags = 0;
Albert Chaulk289b6042013-06-25 11:30:46 -0700850 me[0].starting_offset = me[0].ending_offset + 1;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700851 mh->crc32 = MtdHeaderCrc(mh);
852 EXPECT(GPT_SUCCESS == MtdCheckEntries(me, mh));
853
Randall Spanglere9213a72013-01-24 11:19:55 -0800854 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700855}
856
Randall Spanglere9213a72013-01-24 11:19:55 -0800857/* Test if overlapped partition tables can be detected. */
858static int OverlappedPartitionTest(void) {
859 GptData *gpt = GetEmptyGptData();
860 GptHeader *h = (GptHeader *)gpt->primary_header;
861 GptEntry *e = (GptEntry *)gpt->primary_entries;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700862 MtdData *mtd = GetEmptyMtdData();
863 MtdDiskLayout *mh = &mtd->primary;
864 MtdDiskPartition *me = mh->partitions;
Randall Spanglere9213a72013-01-24 11:19:55 -0800865 int i, j;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700866
Randall Spanglere9213a72013-01-24 11:19:55 -0800867 struct {
868 int overlapped;
869 struct {
870 int active;
871 uint64_t starting_lba;
872 uint64_t ending_lba;
873 } entries[16]; /* enough for testing. */
874 } cases[] = {
875 {GPT_SUCCESS, {{0, 100, 199}}},
876 {GPT_SUCCESS, {{1, 100, 199}}},
877 {GPT_SUCCESS, {{1, 100, 150}, {1, 200, 250}, {1, 300, 350}}},
878 {GPT_ERROR_START_LBA_OVERLAP,
879 {{1, 200, 299}, {1, 100, 199}, {1, 100, 100}}},
880 {GPT_ERROR_END_LBA_OVERLAP,
881 {{1, 200, 299}, {1, 100, 199}, {1, 299, 299}}},
882 {GPT_SUCCESS, {{1, 300, 399}, {1, 200, 299}, {1, 100, 199}}},
883 {GPT_ERROR_END_LBA_OVERLAP,
884 {{1, 100, 199}, {1, 199, 299}, {1, 299, 399}}},
885 {GPT_ERROR_START_LBA_OVERLAP,
886 {{1, 100, 199}, {1, 200, 299}, {1, 75, 399}}},
887 {GPT_ERROR_START_LBA_OVERLAP,
888 {{1, 100, 199}, {1, 75, 250}, {1, 200, 299}}},
889 {GPT_ERROR_END_LBA_OVERLAP,
890 {{1, 75, 150}, {1, 100, 199}, {1, 200, 299}}},
891 {GPT_ERROR_START_LBA_OVERLAP,
892 {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {1, 100, 399}}},
893 {GPT_SUCCESS,
894 {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {0, 100, 399}}},
895 {GPT_ERROR_START_LBA_OVERLAP,
896 {{1, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400}}},
897 {GPT_ERROR_START_LBA_OVERLAP,
898 {{0, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400}}},
899 {GPT_SUCCESS,
900 {{1, 200, 300}, {1, 100, 199}, {0, 100, 400}, {0, 300, 400}}},
901 {GPT_ERROR_END_LBA_OVERLAP,
902 {{1, 200, 299}, {1, 100, 199}, {1, 199, 199}}},
903 {GPT_SUCCESS, {{1, 200, 299}, {0, 100, 199}, {1, 199, 199}}},
904 {GPT_SUCCESS, {{1, 200, 299}, {1, 100, 199}, {0, 199, 199}}},
905 {GPT_ERROR_START_LBA_OVERLAP,
906 {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202},
907 {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206},
908 {1, 207, 207}, {1, 208, 208}, {1, 199, 199}}},
909 {GPT_SUCCESS,
910 {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202},
911 {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206},
912 {1, 207, 207}, {1, 208, 208}, {0, 199, 199}}},
913 };
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700914
Randall Spanglere9213a72013-01-24 11:19:55 -0800915 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
916 BuildTestGptData(gpt);
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700917 BuildTestMtdData(mtd);
918 Memset(mh->partitions, 0, sizeof(mh->partitions));
Randall Spanglere9213a72013-01-24 11:19:55 -0800919 ZeroEntries(gpt);
920 for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) {
921 if (!cases[i].entries[j].starting_lba)
922 break;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700923
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700924 if (cases[i].entries[j].active) {
Randall Spanglere9213a72013-01-24 11:19:55 -0800925 Memcpy(&e[j].type, &guid_kernel, sizeof(Guid));
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700926 me[j].flags =
927 MTD_PARTITION_TYPE_CHROMEOS_KERNEL << MTD_ATTRIBUTE_TYPE_OFFSET;
928 }
Randall Spanglere9213a72013-01-24 11:19:55 -0800929 SetGuid(&e[j].unique, j);
930 e[j].starting_lba = cases[i].entries[j].starting_lba;
931 e[j].ending_lba = cases[i].entries[j].ending_lba;
Albert Chaulk289b6042013-06-25 11:30:46 -0700932 me[j].starting_offset = cases[i].entries[j].starting_lba *
933 DEFAULT_SECTOR_SIZE;
934 me[j].ending_offset = cases[i].entries[j].ending_lba *
935 DEFAULT_SECTOR_SIZE;
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700936
Randall Spanglere9213a72013-01-24 11:19:55 -0800937 }
938 RefreshCrc32(gpt);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700939
Randall Spanglere9213a72013-01-24 11:19:55 -0800940 EXPECT(cases[i].overlapped == CheckEntries(e, h));
Albert Chaulk5c9e4532013-03-20 16:03:49 -0700941 EXPECT(cases[i].overlapped == MtdCheckEntries(me, mh));
Randall Spanglere9213a72013-01-24 11:19:55 -0800942 }
943 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700944}
945
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700946/* Test both sanity checking and repair. */
Randall Spanglere9213a72013-01-24 11:19:55 -0800947static int SanityCheckTest(void)
948{
949 GptData *gpt = GetEmptyGptData();
950 GptHeader *h1 = (GptHeader *)gpt->primary_header;
Randall Spangler0bda13f2013-01-24 12:25:26 -0800951 GptEntry *e1 = (GptEntry *)gpt->primary_entries;
952 uint8_t *tempptr;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700953
Randall Spanglere9213a72013-01-24 11:19:55 -0800954 /* Unmodified test data is completely sane */
955 BuildTestGptData(gpt);
956 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
957 EXPECT(MASK_BOTH == gpt->valid_headers);
958 EXPECT(MASK_BOTH == gpt->valid_entries);
959 /* Repair doesn't damage it */
960 GptRepair(gpt);
961 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
962 EXPECT(MASK_BOTH == gpt->valid_headers);
963 EXPECT(MASK_BOTH == gpt->valid_entries);
964 EXPECT(0 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700965
Randall Spangler0bda13f2013-01-24 12:25:26 -0800966 /* Invalid sector size should fail */
967 BuildTestGptData(gpt);
968 gpt->sector_bytes = 1024;
969 EXPECT(GPT_ERROR_INVALID_SECTOR_SIZE == GptSanityCheck(gpt));
970
Randall Spanglere9213a72013-01-24 11:19:55 -0800971 /* Modify headers */
972 BuildTestGptData(gpt);
973 gpt->primary_header[0]++;
974 gpt->secondary_header[0]++;
975 EXPECT(GPT_ERROR_INVALID_HEADERS == GptSanityCheck(gpt));
976 EXPECT(0 == gpt->valid_headers);
977 EXPECT(0 == gpt->valid_entries);
978 /* Repair can't fix completely busted headers */
979 GptRepair(gpt);
980 EXPECT(GPT_ERROR_INVALID_HEADERS == GptSanityCheck(gpt));
981 EXPECT(0 == gpt->valid_headers);
982 EXPECT(0 == gpt->valid_entries);
983 EXPECT(0 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700984
Randall Spanglere9213a72013-01-24 11:19:55 -0800985 BuildTestGptData(gpt);
986 gpt->primary_header[0]++;
987 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
988 EXPECT(MASK_SECONDARY == gpt->valid_headers);
989 EXPECT(MASK_BOTH == gpt->valid_entries);
990 GptRepair(gpt);
991 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
992 EXPECT(MASK_BOTH == gpt->valid_headers);
993 EXPECT(MASK_BOTH == gpt->valid_entries);
994 EXPECT(GPT_MODIFIED_HEADER1 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -0700995
Randall Spanglere9213a72013-01-24 11:19:55 -0800996 BuildTestGptData(gpt);
997 gpt->secondary_header[0]++;
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 /*
1008 * Modify header1 and update its CRC. Since header2 is now different
1009 * than header1, it'll be the one considered invalid.
1010 */
1011 BuildTestGptData(gpt);
1012 h1->size++;
1013 RefreshCrc32(gpt);
1014 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1015 EXPECT(MASK_PRIMARY == gpt->valid_headers);
1016 EXPECT(MASK_BOTH == gpt->valid_entries);
1017 GptRepair(gpt);
1018 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1019 EXPECT(MASK_BOTH == gpt->valid_headers);
1020 EXPECT(MASK_BOTH == gpt->valid_entries);
1021 EXPECT(GPT_MODIFIED_HEADER2 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001022
Randall Spanglere9213a72013-01-24 11:19:55 -08001023 /* Modify entries */
1024 BuildTestGptData(gpt);
1025 gpt->primary_entries[0]++;
1026 gpt->secondary_entries[0]++;
1027 EXPECT(GPT_ERROR_INVALID_ENTRIES == GptSanityCheck(gpt));
1028 EXPECT(MASK_BOTH == gpt->valid_headers);
1029 EXPECT(MASK_NONE == gpt->valid_entries);
1030 /* Repair can't fix both copies of entries being bad, either. */
1031 GptRepair(gpt);
1032 EXPECT(GPT_ERROR_INVALID_ENTRIES == GptSanityCheck(gpt));
1033 EXPECT(MASK_BOTH == gpt->valid_headers);
1034 EXPECT(MASK_NONE == gpt->valid_entries);
1035 EXPECT(0 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001036
Randall Spanglere9213a72013-01-24 11:19:55 -08001037 BuildTestGptData(gpt);
1038 gpt->primary_entries[0]++;
1039 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1040 EXPECT(MASK_BOTH == gpt->valid_headers);
1041 EXPECT(MASK_SECONDARY == gpt->valid_entries);
1042 GptRepair(gpt);
1043 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1044 EXPECT(MASK_BOTH == gpt->valid_headers);
1045 EXPECT(MASK_BOTH == gpt->valid_entries);
1046 EXPECT(GPT_MODIFIED_ENTRIES1 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001047
Randall Spanglere9213a72013-01-24 11:19:55 -08001048 BuildTestGptData(gpt);
1049 gpt->secondary_entries[0]++;
1050 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1051 EXPECT(MASK_BOTH == gpt->valid_headers);
1052 EXPECT(MASK_PRIMARY == gpt->valid_entries);
1053 GptRepair(gpt);
1054 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1055 EXPECT(MASK_BOTH == gpt->valid_headers);
1056 EXPECT(MASK_BOTH == gpt->valid_entries);
1057 EXPECT(GPT_MODIFIED_ENTRIES2 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001058
Randall Spangler0bda13f2013-01-24 12:25:26 -08001059 /*
1060 * Modify entries and recompute CRCs, then make both primary and
1061 * secondary entry pointers use the secondary data. The primary
1062 * header will have the wrong entries CRC, so we should fall back
1063 * to the secondary header.
1064 */
1065 BuildTestGptData(gpt);
1066 e1->starting_lba++;
1067 RefreshCrc32(gpt);
1068 tempptr = gpt->primary_entries;
1069 gpt->primary_entries = gpt->secondary_entries;
1070 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1071 EXPECT(MASK_SECONDARY == gpt->valid_headers);
1072 EXPECT(MASK_BOTH == gpt->valid_entries);
1073 gpt->primary_entries = tempptr;
1074
Randall Spanglere9213a72013-01-24 11:19:55 -08001075 /* Modify both header and entries */
1076 BuildTestGptData(gpt);
1077 gpt->primary_header[0]++;
1078 gpt->primary_entries[0]++;
1079 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1080 EXPECT(MASK_SECONDARY == gpt->valid_headers);
1081 EXPECT(MASK_SECONDARY == gpt->valid_entries);
1082 GptRepair(gpt);
1083 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1084 EXPECT(MASK_BOTH == gpt->valid_headers);
1085 EXPECT(MASK_BOTH == gpt->valid_entries);
1086 EXPECT((GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1) == gpt->modified);
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001087
Randall Spanglere9213a72013-01-24 11:19:55 -08001088 BuildTestGptData(gpt);
1089 gpt->secondary_header[0]++;
1090 gpt->secondary_entries[0]++;
1091 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1092 EXPECT(MASK_PRIMARY == gpt->valid_headers);
1093 EXPECT(MASK_PRIMARY == gpt->valid_entries);
1094 GptRepair(gpt);
1095 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1096 EXPECT(MASK_BOTH == gpt->valid_headers);
1097 EXPECT(MASK_BOTH == gpt->valid_entries);
1098 EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001099
Randall Spanglere9213a72013-01-24 11:19:55 -08001100 /* Test cross-correction (h1+e2, h2+e1) */
1101 BuildTestGptData(gpt);
1102 gpt->primary_header[0]++;
1103 gpt->secondary_entries[0]++;
1104 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1105 EXPECT(MASK_SECONDARY == gpt->valid_headers);
1106 EXPECT(MASK_PRIMARY == gpt->valid_entries);
1107 GptRepair(gpt);
1108 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1109 EXPECT(MASK_BOTH == gpt->valid_headers);
1110 EXPECT(MASK_BOTH == gpt->valid_entries);
1111 EXPECT((GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001112
Randall Spanglere9213a72013-01-24 11:19:55 -08001113 BuildTestGptData(gpt);
1114 gpt->secondary_header[0]++;
1115 gpt->primary_entries[0]++;
1116 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1117 EXPECT(MASK_PRIMARY == gpt->valid_headers);
1118 EXPECT(MASK_SECONDARY == 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_ENTRIES1) == gpt->modified);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001124
Randall Spanglere9213a72013-01-24 11:19:55 -08001125 /*
1126 * Test mismatched pairs (h1+e1 valid, h2+e2 valid but different. This
1127 * simulates a partial update of the drive.
1128 */
1129 BuildTestGptData(gpt);
1130 gpt->secondary_entries[0]++;
1131 RefreshCrc32(gpt);
1132 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1133 EXPECT(MASK_PRIMARY == gpt->valid_headers);
1134 EXPECT(MASK_PRIMARY == gpt->valid_entries);
1135 GptRepair(gpt);
1136 EXPECT(GPT_SUCCESS == GptSanityCheck(gpt));
1137 EXPECT(MASK_BOTH == gpt->valid_headers);
1138 EXPECT(MASK_BOTH == gpt->valid_entries);
1139 EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2) == gpt->modified);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07001140
Randall Spanglere9213a72013-01-24 11:19:55 -08001141 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001142}
1143
Randall Spanglere9213a72013-01-24 11:19:55 -08001144static int EntryAttributeGetSetTest(void)
1145{
1146 GptData *gpt = GetEmptyGptData();
1147 GptEntry *e = (GptEntry *)(gpt->primary_entries);
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001148 MtdData *mtd = GetEmptyMtdData();
1149 MtdDiskPartition *m = &mtd->primary.partitions[0];
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001150
Randall Spanglere9213a72013-01-24 11:19:55 -08001151 e->attrs.whole = 0x0000000000000000ULL;
1152 SetEntrySuccessful(e, 1);
1153 EXPECT(0x0100000000000000ULL == e->attrs.whole);
1154 EXPECT(1 == GetEntrySuccessful(e));
1155 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
1156 SetEntrySuccessful(e, 0);
1157 EXPECT(0xFEFFFFFFFFFFFFFFULL == e->attrs.whole);
1158 EXPECT(0 == GetEntrySuccessful(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001159
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001160 m->flags = 0;
1161 MtdSetEntrySuccessful(m, 1);
1162 EXPECT(0x00000100 == m->flags);
1163 EXPECT(1 == MtdGetEntrySuccessful(m));
1164 m->flags = ~0;
1165 MtdSetEntrySuccessful(m, 0);
1166 EXPECT(0xFFFFFEFF == m->flags);
1167 EXPECT(0 == MtdGetEntrySuccessful(m));
1168
Randall Spanglere9213a72013-01-24 11:19:55 -08001169 e->attrs.whole = 0x0000000000000000ULL;
1170 SetEntryTries(e, 15);
1171 EXPECT(15 == GetEntryTries(e));
1172 EXPECT(0x00F0000000000000ULL == e->attrs.whole);
1173 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
1174 SetEntryTries(e, 0);
1175 EXPECT(0xFF0FFFFFFFFFFFFFULL == e->attrs.whole);
1176 EXPECT(0 == GetEntryTries(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001177
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001178 m->flags = 0;
1179 MtdSetEntryTries(m, 15);
1180 EXPECT(0x000000F0 == m->flags);
1181 EXPECT(15 == MtdGetEntryTries(m));
1182 m->flags = ~0;
1183 MtdSetEntryTries(m, 0);
1184 EXPECT(0xFFFFFF0F == m->flags);
1185 EXPECT(0 == MtdGetEntryTries(m));
1186
Randall Spanglere9213a72013-01-24 11:19:55 -08001187 e->attrs.whole = 0x0000000000000000ULL;
1188 SetEntryPriority(e, 15);
1189 EXPECT(0x000F000000000000ULL == e->attrs.whole);
1190 EXPECT(15 == GetEntryPriority(e));
1191 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
1192 SetEntryPriority(e, 0);
1193 EXPECT(0xFFF0FFFFFFFFFFFFULL == e->attrs.whole);
1194 EXPECT(0 == GetEntryPriority(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001195
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001196 m->flags = 0;
1197 MtdSetEntryPriority(m, 15);
1198 EXPECT(0x0000000F == m->flags);
1199 EXPECT(15 == MtdGetEntryPriority(m));
1200 m->flags = ~0;
1201 MtdSetEntryPriority(m, 0);
1202 EXPECT(0xFFFFFFF0 == m->flags);
1203 EXPECT(0 == MtdGetEntryPriority(m));
1204
Randall Spanglere9213a72013-01-24 11:19:55 -08001205 e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
1206 EXPECT(1 == GetEntrySuccessful(e));
1207 EXPECT(15 == GetEntryPriority(e));
1208 EXPECT(15 == GetEntryTries(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001209
Randall Spanglere9213a72013-01-24 11:19:55 -08001210 e->attrs.whole = 0x0123000000000000ULL;
1211 EXPECT(1 == GetEntrySuccessful(e));
1212 EXPECT(2 == GetEntryTries(e));
1213 EXPECT(3 == GetEntryPriority(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001214
Randall Spanglere9213a72013-01-24 11:19:55 -08001215 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001216}
1217
Randall Spanglere9213a72013-01-24 11:19:55 -08001218static int EntryTypeTest(void)
1219{
1220 GptData *gpt = GetEmptyGptData();
1221 GptEntry *e = (GptEntry *)(gpt->primary_entries);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001222
Randall Spanglere9213a72013-01-24 11:19:55 -08001223 Memcpy(&e->type, &guid_zero, sizeof(Guid));
1224 EXPECT(1 == IsUnusedEntry(e));
1225 EXPECT(0 == IsKernelEntry(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001226
Randall Spanglere9213a72013-01-24 11:19:55 -08001227 Memcpy(&e->type, &guid_kernel, sizeof(Guid));
1228 EXPECT(0 == IsUnusedEntry(e));
1229 EXPECT(1 == IsKernelEntry(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001230
Randall Spanglere9213a72013-01-24 11:19:55 -08001231 Memcpy(&e->type, &guid_rootfs, sizeof(Guid));
1232 EXPECT(0 == IsUnusedEntry(e));
1233 EXPECT(0 == IsKernelEntry(e));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001234
Randall Spanglere9213a72013-01-24 11:19:55 -08001235 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001236}
1237
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001238/* Make an entry unused by clearing its type. */
Randall Spanglere9213a72013-01-24 11:19:55 -08001239static void FreeEntry(GptEntry *e)
1240{
1241 Memset(&e->type, 0, sizeof(Guid));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001242}
1243
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001244static void MtdFreeEntry(MtdDiskPartition *e)
1245{
1246 MtdSetEntryType(e, MTD_PARTITION_TYPE_UNUSED);
1247}
1248
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001249/* Set up an entry. */
Randall Spanglere9213a72013-01-24 11:19:55 -08001250static void FillEntry(GptEntry *e, int is_kernel,
1251 int priority, int successful, int tries)
1252{
1253 Memcpy(&e->type, (is_kernel ? &guid_kernel : &guid_zero), sizeof(Guid));
1254 SetEntryPriority(e, priority);
1255 SetEntrySuccessful(e, successful);
1256 SetEntryTries(e, tries);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001257}
1258
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001259static void MtdFillEntry(MtdDiskPartition *e, int is_kernel,
1260 int priority, int successful, int tries)
1261{
1262 MtdSetEntryType(e, is_kernel ? MTD_PARTITION_TYPE_CHROMEOS_KERNEL :
1263 MTD_PARTITION_TYPE_CHROMEOS_FIRMWARE);
1264 MtdSetEntryPriority(e, priority);
1265 MtdSetEntrySuccessful(e, successful);
1266 MtdSetEntryTries(e, tries);
1267}
1268
Randall Spanglere9213a72013-01-24 11:19:55 -08001269/*
1270 * Invalidate all kernel entries and expect GptNextKernelEntry() cannot find
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001271 * any usable kernel entry.
1272 */
Randall Spanglere9213a72013-01-24 11:19:55 -08001273static int NoValidKernelEntryTest(void)
1274{
1275 GptData *gpt = GetEmptyGptData();
1276 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001277
Randall Spanglere9213a72013-01-24 11:19:55 -08001278 BuildTestGptData(gpt);
1279 SetEntryPriority(e1 + KERNEL_A, 0);
1280 FreeEntry(e1 + KERNEL_B);
1281 RefreshCrc32(gpt);
1282 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1283 GptNextKernelEntry(gpt, NULL, NULL));
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001284
Randall Spanglere9213a72013-01-24 11:19:55 -08001285 return TEST_OK;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001286}
1287
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001288static int MtdNoValidKernelEntryTest(void)
1289{
1290 MtdData *mtd = GetEmptyMtdData();
1291 MtdDiskPartition *e1 = mtd->primary.partitions;
1292
1293 BuildTestMtdData(mtd);
1294 MtdSetEntryPriority(e1 + KERNEL_A, 0);
1295 MtdFreeEntry(e1 + KERNEL_B);
1296 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1297 MtdNextKernelEntry(mtd, NULL, NULL));
1298
1299 return TEST_OK;
1300}
1301
Randall Spanglere9213a72013-01-24 11:19:55 -08001302static int GetNextNormalTest(void)
1303{
1304 GptData *gpt = GetEmptyGptData();
1305 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
1306 uint64_t start, size;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001307
Randall Spanglere9213a72013-01-24 11:19:55 -08001308 /* Normal case - both kernels successful */
1309 BuildTestGptData(gpt);
1310 FillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
1311 FillEntry(e1 + KERNEL_B, 1, 2, 1, 0);
1312 RefreshCrc32(gpt);
1313 GptInit(gpt);
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001314
Randall Spanglere9213a72013-01-24 11:19:55 -08001315 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1316 EXPECT(KERNEL_A == gpt->current_kernel);
1317 EXPECT(34 == start);
1318 EXPECT(100 == size);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001319
Randall Spanglere9213a72013-01-24 11:19:55 -08001320 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1321 EXPECT(KERNEL_B == gpt->current_kernel);
1322 EXPECT(134 == start);
1323 EXPECT(99 == size);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001324
Randall Spanglere9213a72013-01-24 11:19:55 -08001325 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1326 GptNextKernelEntry(gpt, &start, &size));
1327 EXPECT(-1 == gpt->current_kernel);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001328
Randall Spanglere9213a72013-01-24 11:19:55 -08001329 /* Call as many times as you want; you won't get another kernel... */
1330 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1331 GptNextKernelEntry(gpt, &start, &size));
1332 EXPECT(-1 == gpt->current_kernel);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001333
Randall Spanglere9213a72013-01-24 11:19:55 -08001334 return TEST_OK;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001335}
1336
Randall Spanglere9213a72013-01-24 11:19:55 -08001337static int GetNextPrioTest(void)
1338{
1339 GptData *gpt = GetEmptyGptData();
1340 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
1341 uint64_t start, size;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001342
Randall Spanglere9213a72013-01-24 11:19:55 -08001343 /* Priority 3, 4, 0, 4 - should boot order B, Y, A */
1344 BuildTestGptData(gpt);
1345 FillEntry(e1 + KERNEL_A, 1, 3, 1, 0);
1346 FillEntry(e1 + KERNEL_B, 1, 4, 1, 0);
1347 FillEntry(e1 + KERNEL_X, 1, 0, 1, 0);
1348 FillEntry(e1 + KERNEL_Y, 1, 4, 1, 0);
1349 RefreshCrc32(gpt);
1350 GptInit(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001351
Randall Spanglere9213a72013-01-24 11:19:55 -08001352 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1353 EXPECT(KERNEL_B == gpt->current_kernel);
1354 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1355 EXPECT(KERNEL_Y == gpt->current_kernel);
1356 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1357 EXPECT(KERNEL_A == gpt->current_kernel);
1358 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1359 GptNextKernelEntry(gpt, &start, &size));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001360
Randall Spanglere9213a72013-01-24 11:19:55 -08001361 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001362}
1363
Randall Spanglere9213a72013-01-24 11:19:55 -08001364static int GetNextTriesTest(void)
1365{
1366 GptData *gpt = GetEmptyGptData();
1367 GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
1368 uint64_t start, size;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001369
Randall Spanglere9213a72013-01-24 11:19:55 -08001370 /* Tries=nonzero is attempted just like success, but tries=0 isn't */
1371 BuildTestGptData(gpt);
1372 FillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
1373 FillEntry(e1 + KERNEL_B, 1, 3, 0, 0);
1374 FillEntry(e1 + KERNEL_X, 1, 4, 0, 1);
1375 FillEntry(e1 + KERNEL_Y, 1, 0, 0, 5);
1376 RefreshCrc32(gpt);
1377 GptInit(gpt);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001378
Randall Spanglere9213a72013-01-24 11:19:55 -08001379 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1380 EXPECT(KERNEL_X == gpt->current_kernel);
1381 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1382 EXPECT(KERNEL_A == gpt->current_kernel);
1383 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1384 GptNextKernelEntry(gpt, &start, &size));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001385
Randall Spanglere9213a72013-01-24 11:19:55 -08001386 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001387}
1388
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001389static int MtdGetNextNormalTest(void)
1390{
1391 MtdData *mtd = GetEmptyMtdData();
1392 MtdDiskPartition *e1 = mtd->primary.partitions;
1393 uint64_t start, size;
1394
1395 /* Normal case - both kernels successful */
1396 BuildTestMtdData(mtd);
1397 MtdFillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
1398 MtdFillEntry(e1 + KERNEL_B, 1, 2, 1, 0);
1399 mtd->primary.crc32 = MtdHeaderCrc(&mtd->primary);
1400 MtdInit(mtd);
1401
1402 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1403 EXPECT(KERNEL_A == mtd->current_kernel);
1404 EXPECT(34 == start);
1405 EXPECT(100 == size);
1406
1407 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1408 EXPECT(KERNEL_B == mtd->current_kernel);
1409 EXPECT(134 == start);
1410 EXPECT(99 == size);
1411
1412 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1413 MtdNextKernelEntry(mtd, &start, &size));
1414 EXPECT(-1 == mtd->current_kernel);
1415
1416 /* Call as many times as you want; you won't get another kernel... */
1417 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1418 MtdNextKernelEntry(mtd, &start, &size));
1419 EXPECT(-1 == mtd->current_kernel);
1420
1421 return TEST_OK;
1422}
1423
1424static int MtdGetNextPrioTest(void)
1425{
1426 MtdData *mtd = GetEmptyMtdData();
1427 MtdDiskPartition *e1 = mtd->primary.partitions;
1428 uint64_t start, size;
1429
1430 /* Priority 3, 4, 0, 4 - should boot order B, Y, A */
1431 BuildTestMtdData(mtd);
1432 MtdFillEntry(e1 + KERNEL_A, 1, 3, 1, 0);
1433 MtdFillEntry(e1 + KERNEL_B, 1, 4, 1, 0);
1434 MtdFillEntry(e1 + KERNEL_X, 1, 0, 1, 0);
1435 MtdFillEntry(e1 + KERNEL_Y, 1, 4, 1, 0);
1436 mtd->primary.crc32 = MtdHeaderCrc(&mtd->primary);
1437 MtdInit(mtd);
1438
1439 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1440 EXPECT(KERNEL_B == mtd->current_kernel);
1441 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1442 EXPECT(KERNEL_Y == mtd->current_kernel);
1443 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1444 EXPECT(KERNEL_A == mtd->current_kernel);
1445 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1446 MtdNextKernelEntry(mtd, &start, &size));
1447
1448 return TEST_OK;
1449}
1450
1451static int MtdGetNextTriesTest(void)
1452{
1453 MtdData *mtd = GetEmptyMtdData();
1454 MtdDiskPartition *e1 = mtd->primary.partitions;
1455 uint64_t start, size;
1456
1457 /* Tries=nonzero is attempted just like success, but tries=0 isn't */
1458 BuildTestMtdData(mtd);
1459 MtdFillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
1460 MtdFillEntry(e1 + KERNEL_B, 1, 3, 0, 0);
1461 MtdFillEntry(e1 + KERNEL_X, 1, 4, 0, 1);
1462 MtdFillEntry(e1 + KERNEL_Y, 1, 0, 0, 5);
1463 mtd->primary.crc32 = MtdHeaderCrc(&mtd->primary);
1464 MtdInit(mtd);
1465
1466 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1467 EXPECT(KERNEL_X == mtd->current_kernel);
1468 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1469 EXPECT(KERNEL_A == mtd->current_kernel);
1470 EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
1471 MtdNextKernelEntry(mtd, &start, &size));
1472
1473 return TEST_OK;
1474}
1475
1476static int MtdUpdateTest() {
1477 MtdData *mtd = GetEmptyMtdData();
1478 MtdDiskPartition *e = &mtd->primary.partitions[0];
1479 uint64_t start, size;
1480
1481 BuildTestMtdData(mtd);
1482
1483 /* Tries=nonzero is attempted just like success, but tries=0 isn't */
1484 MtdFillEntry(e + KERNEL_A, 1, 4, 1, 0);
1485 MtdFillEntry(e + KERNEL_B, 1, 3, 0, 2);
1486 MtdFillEntry(e + KERNEL_X, 1, 2, 0, 2);
1487 mtd->primary.crc32 = MtdHeaderCrc(&mtd->primary);
1488 mtd->modified = 0;
1489 EXPECT(GPT_SUCCESS == MtdInit(mtd));
1490
1491 /* Successful kernel */
1492 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1493 EXPECT(KERNEL_A == mtd->current_kernel);
1494 EXPECT(1 == MtdGetEntrySuccessful(e + KERNEL_A));
1495 EXPECT(4 == MtdGetEntryPriority(e + KERNEL_A));
1496 EXPECT(0 == MtdGetEntryTries(e + KERNEL_A));
1497 /* Trying successful kernel changes nothing */
1498 EXPECT(GPT_SUCCESS == MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_TRY));
1499 EXPECT(1 == MtdGetEntrySuccessful(e + KERNEL_A));
1500 EXPECT(4 == MtdGetEntryPriority(e + KERNEL_A));
1501 EXPECT(0 == MtdGetEntryTries(e + KERNEL_A));
1502 EXPECT(0 == mtd->modified);
1503 /* Marking it bad also does not update it. */
1504 EXPECT(GPT_SUCCESS == MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_BAD));
1505 EXPECT(1 == MtdGetEntrySuccessful(e + KERNEL_A));
1506 EXPECT(4 == MtdGetEntryPriority(e + KERNEL_A));
1507 EXPECT(0 == MtdGetEntryTries(e + KERNEL_A));
1508 EXPECT(0 == mtd->modified);
1509
1510 /* Kernel with tries */
1511 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1512 EXPECT(KERNEL_B == mtd->current_kernel);
1513 EXPECT(0 == MtdGetEntrySuccessful(e + KERNEL_B));
1514 EXPECT(3 == MtdGetEntryPriority(e + KERNEL_B));
1515 EXPECT(2 == MtdGetEntryTries(e + KERNEL_B));
1516 /* Marking it bad clears it */
1517 EXPECT(GPT_SUCCESS == MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_BAD));
1518 EXPECT(0 == MtdGetEntrySuccessful(e + KERNEL_B));
1519 EXPECT(0 == MtdGetEntryPriority(e + KERNEL_B));
1520 EXPECT(0 == MtdGetEntryTries(e + KERNEL_B));
1521 /* And that's caused the mtd to need updating */
1522 EXPECT(1 == mtd->modified);
1523
1524 /* Another kernel with tries */
1525 EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
1526 EXPECT(KERNEL_X == mtd->current_kernel);
1527 EXPECT(0 == MtdGetEntrySuccessful(e + KERNEL_X));
1528 EXPECT(2 == MtdGetEntryPriority(e + KERNEL_X));
1529 EXPECT(2 == MtdGetEntryTries(e + KERNEL_X));
1530 /* Trying it uses up a try */
1531 EXPECT(GPT_SUCCESS == MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_TRY));
1532 EXPECT(0 == MtdGetEntrySuccessful(e + KERNEL_X));
1533 EXPECT(2 == MtdGetEntryPriority(e + KERNEL_X));
1534 EXPECT(1 == MtdGetEntryTries(e + KERNEL_X));
1535 /* Trying it again marks it inactive */
1536 EXPECT(GPT_SUCCESS == MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_TRY));
1537 EXPECT(0 == MtdGetEntrySuccessful(e + KERNEL_X));
1538 EXPECT(0 == MtdGetEntryPriority(e + KERNEL_X));
1539 EXPECT(0 == MtdGetEntryTries(e + KERNEL_X));
1540
1541 /* Can't update if entry isn't a kernel, or there isn't an entry */
1542 MtdSetEntryType(e + KERNEL_X, MTD_PARTITION_TYPE_UNUSED);
1543 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1544 MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_BAD));
1545 mtd->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
1546 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1547 MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_BAD));
1548
1549 return TEST_OK;
1550}
1551
Randall Spanglere9213a72013-01-24 11:19:55 -08001552static int GptUpdateTest(void)
1553{
1554 GptData *gpt = GetEmptyGptData();
1555 GptEntry *e = (GptEntry *)(gpt->primary_entries);
1556 GptEntry *e2 = (GptEntry *)(gpt->secondary_entries);
1557 uint64_t start, size;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001558
Randall Spanglere9213a72013-01-24 11:19:55 -08001559 /* Tries=nonzero is attempted just like success, but tries=0 isn't */
1560 BuildTestGptData(gpt);
1561 FillEntry(e + KERNEL_A, 1, 4, 1, 0);
1562 FillEntry(e + KERNEL_B, 1, 3, 0, 2);
1563 FillEntry(e + KERNEL_X, 1, 2, 0, 2);
1564 RefreshCrc32(gpt);
1565 GptInit(gpt);
1566 gpt->modified = 0; /* Nothing modified yet */
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001567
Randall Spanglere9213a72013-01-24 11:19:55 -08001568 /* Successful kernel */
1569 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1570 EXPECT(KERNEL_A == gpt->current_kernel);
1571 EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
1572 EXPECT(4 == GetEntryPriority(e + KERNEL_A));
1573 EXPECT(0 == GetEntryTries(e + KERNEL_A));
1574 EXPECT(1 == GetEntrySuccessful(e2 + KERNEL_A));
1575 EXPECT(4 == GetEntryPriority(e2 + KERNEL_A));
1576 EXPECT(0 == GetEntryTries(e2 + KERNEL_A));
1577 /* Trying successful kernel changes nothing */
1578 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
1579 EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
1580 EXPECT(4 == GetEntryPriority(e + KERNEL_A));
1581 EXPECT(0 == GetEntryTries(e + KERNEL_A));
1582 EXPECT(0 == gpt->modified);
1583 /* Marking it bad also does not update it. */
1584 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
1585 EXPECT(1 == GetEntrySuccessful(e + KERNEL_A));
1586 EXPECT(4 == GetEntryPriority(e + KERNEL_A));
1587 EXPECT(0 == GetEntryTries(e + KERNEL_A));
1588 EXPECT(0 == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001589
Randall Spanglere9213a72013-01-24 11:19:55 -08001590 /* Kernel with tries */
1591 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1592 EXPECT(KERNEL_B == gpt->current_kernel);
1593 EXPECT(0 == GetEntrySuccessful(e + KERNEL_B));
1594 EXPECT(3 == GetEntryPriority(e + KERNEL_B));
1595 EXPECT(2 == GetEntryTries(e + KERNEL_B));
1596 /* Marking it bad clears it */
1597 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
1598 EXPECT(0 == GetEntrySuccessful(e + KERNEL_B));
1599 EXPECT(0 == GetEntryPriority(e + KERNEL_B));
1600 EXPECT(0 == GetEntryTries(e + KERNEL_B));
1601 /* Which affects both copies of the partition entries */
1602 EXPECT(0 == GetEntrySuccessful(e2 + KERNEL_B));
1603 EXPECT(0 == GetEntryPriority(e2 + KERNEL_B));
1604 EXPECT(0 == GetEntryTries(e2 + KERNEL_B));
1605 /* And that's caused the GPT to need updating */
1606 EXPECT(0x0F == gpt->modified);
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001607
Randall Spanglere9213a72013-01-24 11:19:55 -08001608 /* Another kernel with tries */
1609 EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size));
1610 EXPECT(KERNEL_X == gpt->current_kernel);
1611 EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
1612 EXPECT(2 == GetEntryPriority(e + KERNEL_X));
1613 EXPECT(2 == GetEntryTries(e + KERNEL_X));
1614 /* Trying it uses up a try */
1615 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
1616 EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
1617 EXPECT(2 == GetEntryPriority(e + KERNEL_X));
1618 EXPECT(1 == GetEntryTries(e + KERNEL_X));
1619 EXPECT(0 == GetEntrySuccessful(e2 + KERNEL_X));
1620 EXPECT(2 == GetEntryPriority(e2 + KERNEL_X));
1621 EXPECT(1 == GetEntryTries(e2 + KERNEL_X));
1622 /* Trying it again marks it inactive */
1623 EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY));
1624 EXPECT(0 == GetEntrySuccessful(e + KERNEL_X));
1625 EXPECT(0 == GetEntryPriority(e + KERNEL_X));
1626 EXPECT(0 == GetEntryTries(e + KERNEL_X));
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001627
Randall Spangler0bda13f2013-01-24 12:25:26 -08001628 /* Can't update if entry isn't a kernel, or there isn't an entry */
1629 Memcpy(&e[KERNEL_X].type, &guid_rootfs, sizeof(guid_rootfs));
1630 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1631 GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
1632 gpt->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
1633 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1634 GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD));
1635
1636
Randall Spanglere9213a72013-01-24 11:19:55 -08001637 return TEST_OK;
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001638}
1639
Randall Spanglere9213a72013-01-24 11:19:55 -08001640/*
1641 * Give an invalid kernel type, and expect GptUpdateKernelEntry() returns
1642 * GPT_ERROR_INVALID_UPDATE_TYPE.
1643 */
1644static int UpdateInvalidKernelTypeTest(void)
1645{
1646 GptData *gpt = GetEmptyGptData();
Randall Spangler3dcf9dc2010-06-02 12:46:17 -07001647
Randall Spanglere9213a72013-01-24 11:19:55 -08001648 BuildTestGptData(gpt);
1649 /* anything, but not CGPT_KERNEL_ENTRY_NOT_FOUND */
1650 gpt->current_kernel = 0;
1651 /* any invalid update_type value */
1652 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1653 GptUpdateKernelEntry(gpt, 99));
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001654
Randall Spanglere9213a72013-01-24 11:19:55 -08001655 return TEST_OK;
Louis Yung-Chieh Lob17db3c2010-05-05 11:21:08 -07001656}
1657
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001658static int MtdUpdateInvalidKernelTypeTest(void)
1659{
1660 MtdData *mtd = GetEmptyMtdData();
1661
1662 BuildTestMtdData(mtd);
1663 /* anything, but not CGPT_KERNEL_ENTRY_NOT_FOUND */
1664 mtd->current_kernel = 0;
1665 /* any invalid update_type value */
1666 EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
1667 MtdUpdateKernelEntry(mtd, 99));
1668
1669 return TEST_OK;
1670}
1671
Randall Spanglere9213a72013-01-24 11:19:55 -08001672/* Test duplicate UniqueGuids can be detected. */
1673static int DuplicateUniqueGuidTest(void)
1674{
1675 GptData *gpt = GetEmptyGptData();
1676 GptHeader *h = (GptHeader *)gpt->primary_header;
1677 GptEntry *e = (GptEntry *)gpt->primary_entries;
1678 int i, j;
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001679
Randall Spanglere9213a72013-01-24 11:19:55 -08001680 struct {
1681 int duplicate;
1682 struct {
1683 uint64_t starting_lba;
1684 uint64_t ending_lba;
1685 uint32_t type_guid;
1686 uint32_t unique_guid;
1687 } entries[16]; /* enough for testing. */
1688 } cases[] = {
1689 {GPT_SUCCESS, {{100, 109, 1, 1},
1690 {110, 119, 2, 2},
1691 {120, 129, 3, 3},
1692 {130, 139, 4, 4},
1693 }},
1694 {GPT_SUCCESS, {{100, 109, 1, 1},
1695 {110, 119, 1, 2},
1696 {120, 129, 2, 3},
1697 {130, 139, 2, 4},
1698 }},
1699 {GPT_ERROR_DUP_GUID, {{100, 109, 1, 1},
1700 {110, 119, 2, 2},
1701 {120, 129, 3, 1},
1702 {130, 139, 4, 4},
1703 }},
1704 {GPT_ERROR_DUP_GUID, {{100, 109, 1, 1},
1705 {110, 119, 1, 2},
1706 {120, 129, 2, 3},
1707 {130, 139, 2, 2},
1708 }},
1709 };
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001710
Randall Spanglere9213a72013-01-24 11:19:55 -08001711 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
1712 BuildTestGptData(gpt);
1713 ZeroEntries(gpt);
1714 for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) {
1715 if (!cases[i].entries[j].starting_lba)
1716 break;
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001717
Randall Spanglere9213a72013-01-24 11:19:55 -08001718 e[j].starting_lba = cases[i].entries[j].starting_lba;
1719 e[j].ending_lba = cases[i].entries[j].ending_lba;
1720 SetGuid(&e[j].type, cases[i].entries[j].type_guid);
1721 SetGuid(&e[j].unique, cases[i].entries[j].unique_guid);
1722 }
1723 RefreshCrc32(gpt);
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001724
Randall Spanglere9213a72013-01-24 11:19:55 -08001725 EXPECT(cases[i].duplicate == CheckEntries(e, h));
1726 }
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001727
Randall Spanglere9213a72013-01-24 11:19:55 -08001728 return TEST_OK;
Bill Richardsonaa8eda42010-08-27 09:31:26 -07001729}
1730
Randall Spangler0bda13f2013-01-24 12:25:26 -08001731/* Test getting the current kernel GUID */
1732static int GetKernelGuidTest(void)
1733{
1734 GptData *gpt = GetEmptyGptData();
1735 GptEntry *e = (GptEntry *)gpt->primary_entries;
1736 Guid g;
1737
1738 BuildTestGptData(gpt);
1739 gpt->current_kernel = 0;
1740 GetCurrentKernelUniqueGuid(gpt, &g);
1741 EXPECT(!Memcmp(&g, &e[0].unique, sizeof(Guid)));
1742 gpt->current_kernel = 1;
1743 GetCurrentKernelUniqueGuid(gpt, &g);
1744 EXPECT(!Memcmp(&g, &e[1].unique, sizeof(Guid)));
1745
1746 return TEST_OK;
1747}
1748
1749/* Test getting GPT error text strings */
1750static int ErrorTextTest(void)
1751{
1752 int i;
1753
1754 /* Known errors are not unknown */
1755 for (i = 0; i < GPT_ERROR_COUNT; i++) {
1756 EXPECT(GptErrorText(i));
1757 EXPECT(strcmp(GptErrorText(i), "Unknown"));
1758 }
1759
1760 /* But other error values are */
1761 EXPECT(!strcmp(GptErrorText(GPT_ERROR_COUNT), "Unknown"));
1762
1763 return TEST_OK;
1764}
1765
Albert Chaulk534723a2013-03-20 14:46:50 -07001766int nand_read_page(const nand_geom *nand, int page, void *buf, int size) {
1767 uint32_t ofs = page * nand->szofpg;
1768 uint32_t sz = size;
1769 if (ofs + sz > nand_drive_sz) {
1770 return -1;
1771 }
1772 Memcpy(buf, nand_drive + ofs, sz);
1773 return 0;
1774}
1775
1776int nand_write_page(const nand_geom *nand, int page,
1777 const void *buf, int size) {
1778 uint32_t ofs = page * nand->szofpg;
1779 uint32_t sz = size;
1780 uint32_t i;
1781 if (ofs + sz > nand_drive_sz) {
1782 return -1;
1783 }
1784 for (i = 0; i < sz; i++) {
1785 if (nand_drive[ofs + i] != 0xff) {
1786 return -1;
1787 }
1788 }
1789 Memcpy(nand_drive + ofs, buf, sz);
1790 return 0;
1791}
1792
1793int nand_erase_block(const nand_geom *nand, int block) {
1794 uint32_t ofs = block * nand->szofblk;
1795 uint32_t sz = nand->szofblk;
1796 if (ofs + sz > nand_drive_sz) {
1797 return -1;
1798 }
1799 if (!--nand_bad_block_map[block]) {
1800 return -1;
1801 }
1802 Memset(nand_drive + ofs, 0xFF, sz);
1803 return 0;
1804}
1805
1806int nand_is_bad_block(const nand_geom *nand, int block) {
1807 return nand_bad_block_map[block] == 0;
1808}
1809
1810
1811static void nand_make_ramdisk() {
1812 if (nand_drive) {
1813 free(nand_drive);
1814 }
1815 if (nand_bad_block_map) {
1816 free(nand_bad_block_map);
1817 }
1818 nand_drive_sz = 1024 * 1024 * 16;
1819 nand_drive = (uint8_t *)malloc(nand_drive_sz);
1820 nand_bad_block_map = (uint8_t *)malloc(nand_drive_sz / 512);
1821 Memset(nand_drive, 0xff, nand_drive_sz);
1822 Memset(nand_bad_block_map, 0xff, nand_drive_sz / 512);
1823}
1824
1825static int MtdFtsTest() {
1826 int MtdLoad(struct drive *drive, int sector_bytes);
1827 int MtdSave(struct drive *drive);
1828 int FlashGet(const char *key, uint8_t *data, uint32_t *bufsz);
1829 int FlashSet(const char *key, const uint8_t *data, uint32_t bufsz);
1830
1831 int i, j, err;
1832
1833 struct {
1834 int result;
1835 unsigned int offset, size, block_size_bytes, page_size_bytes;
1836 } cases[] = {
1837 { 0, 1, 2, 1024 * 1024, 1024 * 4 },
1838 { 0, 1, 2, 1024 * 1024, 1024 * 16 },
1839
1840 /* Failure cases, non-power-of-2 */
1841 { -ENODEV, 1, 2, 5000000, 1024 * 16 },
1842 { -ENODEV, 1, 2, 1024 * 1024, 65535 },
1843
1844 /* Page > block */
1845 { -ENODEV, 1, 2, 1024 * 16, 1024 * 1024 },
1846 };
1847
1848
1849 /* Check if the FTS store works */
1850 for (i = 0; i < ARRAY_SIZE(cases); i++) {
1851 nand_make_ramdisk();
1852 EXPECT(cases[i].result == flash_ts_init(cases[i].offset, cases[i].size,
1853 cases[i].page_size_bytes,
1854 cases[i].block_size_bytes, 512, 0));
1855
1856 if (cases[i].result == 0) {
1857 /* We should have a working FTS store now */
1858 char buffer[64];
1859 uint8_t blob[256], blob_read[256];
1860 uint32_t sz = sizeof(blob_read);
1861 struct drive drive;
1862
1863 /* Test the low level API */
1864 EXPECT(0 == flash_ts_set("some_key", "some value"));
1865 flash_ts_get("some_key", buffer, sizeof(buffer));
1866 EXPECT(0 == strcmp(buffer, "some value"));
1867
1868 /* Check overwrite */
1869 EXPECT(0 == flash_ts_set("some_key", "some other value"));
1870 flash_ts_get("some_key", buffer, sizeof(buffer));
1871 EXPECT(0 == strcmp(buffer, "some other value"));
1872
1873 /* Check delete */
1874 EXPECT(0 == flash_ts_set("some_key", ""));
1875
1876 /* Verify that re-initialization pulls the right record. */
1877 flash_ts_init(cases[i].offset, cases[i].size, cases[i].page_size_bytes,
1878 cases[i].block_size_bytes, 512, 0);
1879 flash_ts_get("some_key", buffer, sizeof(buffer));
1880 EXPECT(0 == strcmp(buffer, ""));
1881
1882 /* Fill up the disk, eating all erase cycles */
1883 for (j = 0; j < nand_drive_sz / 512; j++) {
1884 nand_bad_block_map[j] = 2;
1885 }
1886 for (j = 0; j < 999999; j++) {
1887 char str[32];
1888 sprintf(str, "%d", j);
1889 err = flash_ts_set("some_new_key", str);
1890 if (err) {
1891 EXPECT(err == -ENOMEM);
1892 break;
1893 }
1894
1895 /* Make sure we can figure out where the latest is. */
1896 flash_ts_init(cases[i].offset, cases[i].size, cases[i].page_size_bytes,
1897 cases[i].block_size_bytes, 512, 0);
1898 flash_ts_get("some_new_key", buffer, sizeof(buffer));
1899 EXPECT(0 == strcmp(buffer, str));
1900 }
1901 EXPECT(j < 999999);
1902
1903 /* We need our drive back. */
1904 nand_make_ramdisk();
1905 flash_ts_init(cases[i].offset, cases[i].size, cases[i].page_size_bytes,
1906 cases[i].block_size_bytes, 512, 0);
1907
1908
1909 for (j = 0; j < 256; j++) {
1910 blob[j] = j;
1911 }
1912
1913 /* Hex conversion / blob storage */
1914 EXPECT(0 == FlashSet("some_blob", blob, sizeof(blob)));
1915 EXPECT(0 == FlashGet("some_blob", blob_read, &sz));
1916 EXPECT(sz == sizeof(blob_read));
1917 EXPECT(0 == Memcmp(blob, blob_read, sizeof(blob)));
1918
1919 BuildTestMtdData(&drive.mtd);
1920 drive.mtd.flash_block_bytes = cases[i].block_size_bytes;
1921 drive.mtd.flash_page_bytes = cases[i].page_size_bytes;
1922 drive.mtd.fts_block_offset = cases[i].offset;
1923 drive.mtd.fts_block_size = cases[i].size;
1924 drive.mtd.sector_bytes = 512;
1925 drive.mtd.drive_sectors = nand_drive_sz / 512;
1926
1927 /* MTD-level API */
1928 EXPECT(0 == MtdSave(&drive));
1929 Memset(&drive.mtd.primary, 0, sizeof(drive.mtd.primary));
1930 EXPECT(0 == MtdLoad(&drive, 512));
1931 }
1932 }
1933
1934 return TEST_OK;
1935}
1936
Randall Spanglere9213a72013-01-24 11:19:55 -08001937int main(int argc, char *argv[])
1938{
1939 int i;
1940 int error_count = 0;
1941 struct {
1942 char *name;
1943 test_func fp;
1944 int retval;
1945 } test_cases[] = {
1946 { TEST_CASE(StructSizeTest), },
1947 { TEST_CASE(TestBuildTestGptData), },
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001948 { TEST_CASE(TestBuildTestMtdData), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001949 { TEST_CASE(ParameterTests), },
1950 { TEST_CASE(HeaderCrcTest), },
Randall Spangler0bda13f2013-01-24 12:25:26 -08001951 { TEST_CASE(HeaderSameTest), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001952 { TEST_CASE(SignatureTest), },
1953 { TEST_CASE(RevisionTest), },
1954 { TEST_CASE(SizeTest), },
1955 { TEST_CASE(CrcFieldTest), },
1956 { TEST_CASE(ReservedFieldsTest), },
1957 { TEST_CASE(SizeOfPartitionEntryTest), },
1958 { TEST_CASE(NumberOfPartitionEntriesTest), },
1959 { TEST_CASE(MyLbaTest), },
1960 { TEST_CASE(FirstUsableLbaAndLastUsableLbaTest), },
1961 { TEST_CASE(EntriesCrcTest), },
1962 { TEST_CASE(ValidEntryTest), },
1963 { TEST_CASE(OverlappedPartitionTest), },
1964 { TEST_CASE(SanityCheckTest), },
1965 { TEST_CASE(NoValidKernelEntryTest), },
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001966 { TEST_CASE(MtdNoValidKernelEntryTest), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001967 { TEST_CASE(EntryAttributeGetSetTest), },
1968 { TEST_CASE(EntryTypeTest), },
1969 { TEST_CASE(GetNextNormalTest), },
1970 { TEST_CASE(GetNextPrioTest), },
1971 { TEST_CASE(GetNextTriesTest), },
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001972 { TEST_CASE(MtdGetNextNormalTest), },
1973 { TEST_CASE(MtdGetNextPrioTest), },
1974 { TEST_CASE(MtdGetNextTriesTest), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001975 { TEST_CASE(GptUpdateTest), },
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001976 { TEST_CASE(MtdUpdateTest), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001977 { TEST_CASE(UpdateInvalidKernelTypeTest), },
Albert Chaulk5c9e4532013-03-20 16:03:49 -07001978 { TEST_CASE(MtdUpdateInvalidKernelTypeTest), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001979 { TEST_CASE(DuplicateUniqueGuidTest), },
1980 { TEST_CASE(TestCrc32TestVectors), },
Randall Spangler0bda13f2013-01-24 12:25:26 -08001981 { TEST_CASE(GetKernelGuidTest), },
1982 { TEST_CASE(ErrorTextTest), },
Albert Chaulk534723a2013-03-20 14:46:50 -07001983 { TEST_CASE(MtdFtsTest), },
Randall Spanglere9213a72013-01-24 11:19:55 -08001984 };
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001985
Randall Spanglere9213a72013-01-24 11:19:55 -08001986 for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
1987 printf("Running %s() ...\n", test_cases[i].name);
1988 test_cases[i].retval = test_cases[i].fp();
1989 if (test_cases[i].retval) {
1990 printf(COL_RED "[ERROR]\n\n" COL_STOP);
1991 ++error_count;
1992 } else {
1993 printf(COL_GREEN "[PASS]\n\n" COL_STOP);
1994 }
1995 }
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001996
Randall Spanglere9213a72013-01-24 11:19:55 -08001997 if (error_count) {
1998 printf("\n------------------------------------------------\n");
1999 printf(COL_RED "The following %d test cases are failed:\n"
2000 COL_STOP, error_count);
2001 for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
2002 if (test_cases[i].retval)
2003 printf(" %s()\n", test_cases[i].name);
2004 }
2005 }
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07002006
Randall Spanglere9213a72013-01-24 11:19:55 -08002007 return error_count ? 1 : 0;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07002008}