blob: a451838109c229db3c33dec0d68c818f3728af5f [file] [log] [blame]
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07006#include "cgpt_test.h"
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -07007#include <string.h>
8#include "cgpt.h"
9#include "gpt.h"
10#include "utility.h"
11
12/* Testing partition layout (sector_bytes=512)
13 *
14 * LBA Size Usage
15 * 0 1 PMBR
16 * 1 1 primary partition header
17 * 2 32 primary partition entries (128B * 128)
18 * 34 100 kernel A
19 * 134 100 kernel B
20 * 234 100 root A
21 * 334 100 root B
22 * 434 32 secondary partition entries
23 * 466 1 secondary partition header
24 * 467
25 */
26#define DEFAULT_SECTOR_SIZE 512
27#define MAX_SECTOR_SIZE 4096
28#define DEFAULT_DRIVE_SECTORS 467
29#define PARTITION_ENTRIES_SIZE (16*1024)
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -070030
31#define TEST_CASE(func) #func, func
32typedef int (*test_func)(void);
33
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070034/* NOT A REAL CRC32, it is fake before I call real one . FIXME */
35uint32_t CalculateCrc32(const uint8_t *start, size_t len) {
36 uint32_t buf = 0;
37 int i;
38 for (i = 0; i < len; i += 4, len -= 4) {
39 buf ^= *(uint32_t*)&start[i];
40 }
41 if (len >= 3) buf ^= start[i-2] << 16;
42 if (len >= 2) buf ^= start[i-3] << 8;
43 if (len >= 1) buf ^= start[i-4];
44 return buf;
45}
46
47/* Given a GptData pointer, first re-calculate entries CRC32 value,
48 * then reset header CRC32 value to 0, and calculate header CRC32 value.
49 * Both primary and secondary are updated. */
50void RefreshCrc32(struct GptData *gpt) {
51 GptHeader *header, *header2;
52 GptEntry *entries, *entries2;
53
54 header = (GptHeader*)gpt->primary_header;
55 entries = (GptEntry*)gpt->primary_entries;
56 header2 = (GptHeader*)gpt->secondary_header;
57 entries2 = (GptEntry*)gpt->secondary_entries;
58
59 header->entries_crc32 = CalculateCrc32((uint8_t*)entries,
60 sizeof(GptEntry));
61 header->header_crc32 = 0;
62 header->header_crc32 = CalculateCrc32((uint8_t*)header,
63 header->size);
64 header2->entries_crc32 = CalculateCrc32((uint8_t*)entries2,
65 sizeof(GptEntry));
66 header2->header_crc32 = 0;
67 header2->header_crc32 = CalculateCrc32((uint8_t*)header2,
68 header2->size);
69}
70
71/* Returns a pointer to a static GptData instance (no free is required).
72 * All fields are zero except 4 pointers linking to header and entries.
73 * All content of headers and entries are zero. */
74struct GptData* GetAClearGptData() {
75 static GptData_t gpt;
76 static uint8_t primary_header[MAX_SECTOR_SIZE];
77 static uint8_t primary_entries[PARTITION_ENTRIES_SIZE];
78 static uint8_t secondary_header[MAX_SECTOR_SIZE];
79 static uint8_t secondary_entries[PARTITION_ENTRIES_SIZE];
80
81 Memset(&gpt, 0, sizeof(gpt));
82 Memset(&primary_header, 0, sizeof(primary_header));
83 Memset(&primary_entries, 0, sizeof(primary_entries));
84 Memset(&secondary_header, 0, sizeof(secondary_header));
85 Memset(&secondary_entries, 0, sizeof(secondary_entries));
86
87 gpt.primary_header = primary_header;
88 gpt.primary_entries = primary_entries;
89 gpt.secondary_header = secondary_header;
90 gpt.secondary_entries = secondary_entries;
91
92 return &gpt;
93}
94
95/* Fills in most of fields and creates the layout described in the top of this
96 * file. */
97struct GptData*
98BuildTestGptData(uint32_t sector_bytes) {
99 GptData_t *gpt;
100 GptHeader *header, *header2;
101 GptEntry *entries, *entries2;
102 Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
103
104 gpt = GetAClearGptData();
105 gpt->sector_bytes = sector_bytes;
106 gpt->drive_sectors = DEFAULT_DRIVE_SECTORS;
107
108 /* build primary */
109 header = (GptHeader*)gpt->primary_header;
110 entries = (GptEntry*)gpt->primary_entries;
111 Memcpy(header->signature, GPT_HEADER_SIGNATURE, sizeof(GPT_HEADER_SIGNATURE));
112 header->revision = GPT_HEADER_REVISION;
113 header->size = sizeof(GptHeader) - sizeof(header->padding);
114 header->my_lba = 1;
115 header->first_usable_lba = 34;
116 header->last_usable_lba = DEFAULT_DRIVE_SECTORS - 1 - 32 - 1; /* 433 */
117 header->entries_lba = 2;
118 header->number_of_entries = 128; /* 512B / 128B * 32sectors = 128 entries */
119 header->size_of_entry = 128; /* bytes */
120 Memcpy(&entries[0].type, &chromeos_kernel, sizeof(chromeos_kernel));
121 entries[0].starting_lba = 34;
122 entries[0].ending_lba = 133;
123 Memcpy(&entries[1].type, &chromeos_kernel, sizeof(chromeos_kernel));
124 entries[1].starting_lba = 134;
125 entries[1].ending_lba = 233;
126 Memcpy(&entries[2].type, &chromeos_kernel, sizeof(chromeos_kernel));
127 entries[2].starting_lba = 234;
128 entries[2].ending_lba = 333;
129 Memcpy(&entries[3].type, &chromeos_kernel, sizeof(chromeos_kernel));
130 entries[3].starting_lba = 334;
131 entries[3].ending_lba = 433;
132
133 /* build secondary */
134 header2 = (GptHeader*)gpt->secondary_header;
135 entries2 = (GptEntry*)gpt->secondary_entries;
136 Memcpy(header2, header, sizeof(header));
137 Memcpy(entries2, entries, sizeof(entries));
138 header2->my_lba = DEFAULT_DRIVE_SECTORS - 1; /* 466 */
139 header2->entries_lba = DEFAULT_DRIVE_SECTORS - 1 - 32; /* 434 */
140
141 RefreshCrc32(gpt);
142 return gpt;
143}
144
145/* Dumps memory starting from [vp] with [len] bytes.
146 * Prints [memo] if not NULL. Example output:
147 *
148 * 00 01 02 03 04 05 06 07 - 08 09 0a 0b 0c 0d 0e 0f
149 * 10 11 12 13 14 15 16 17 - 18 19 1a 1b 1c 1d 1e 1f
150 * ...
151 */
152static void dump(void *vp, int len, char* memo) {
153 uint8_t *start = vp;
154 int i;
155 if (memo) printf("--[%s]----------\n", memo);
156 for (i = 0; i < len; ++i) {
157 printf("%02x%s", start[i],
158 (!(~i & 15) ? "\n" :
159 !(~i & 7) ? " - ": " "));
160 }
161 if (i&15) printf("\n");
162}
163
164/* More formatted dump with GptData. */
165void DumpGptData(struct GptData *gpt) {
166 printf("DumpGptData(%p)...\n", gpt);
167 dump(gpt, sizeof(gpt), NULL);
168 dump(gpt->primary_header, sizeof(GptHeader), "Primary header");
169 dump(gpt->primary_entries, sizeof(GptEntry) * 8, "Primary entries");
170 dump(gpt->secondary_header, sizeof(GptHeader), "Secondary header");
171 dump(gpt->secondary_entries, sizeof(GptEntry) * 8,
172 "Secondary entries");
173}
174
175/* Tests if signature ("EFI PART") is checked. */
176int SignatureTest() {
177 int i;
178 GptData_t *gpt;
179 GptHeader *primary_header, *secondary_header;
180
181 gpt = BuildTestGptData(DEFAULT_SECTOR_SIZE);
182 primary_header = (GptHeader*)gpt->primary_header;
183 secondary_header = (GptHeader*)gpt->secondary_header;
184
185 EXPECT(GPT_SUCCESS == GptInit(gpt));
186
187 /* change every char in signature of primary. Secondary is still valid. */
188 for (i = 0; i < 8; ++i) {
189 gpt->primary_header[i] ^= 0xff;
190 RefreshCrc32(gpt);
191 EXPECT(GPT_SUCCESS == GptInit(gpt));
192 gpt->primary_header[i] ^= 0xff;
193 RefreshCrc32(gpt);
194 }
195
196 /* change every char in signature of secondary. Primary is still valid. */
197 for (i = 0; i < 8; ++i) {
198 gpt->secondary_header[i] ^= 0xff;
199 RefreshCrc32(gpt);
200 EXPECT(GPT_SUCCESS == GptInit(gpt));
201 gpt->secondary_header[i] ^= 0xff;
202 RefreshCrc32(gpt);
203 }
204
205 /* change every char in signature of primary and secondary. Expect fail. */
206 for (i = 0; i < 8; ++i) {
207 gpt->primary_header[i] ^= 0xff;
208 gpt->secondary_header[i] ^= 0xff;
209 RefreshCrc32(gpt);
210 EXPECT(GPT_ERROR_INVALID_HEADERS == GptInit(gpt));
211 gpt->primary_header[i] ^= 0xff;
212 gpt->secondary_header[i] ^= 0xff;
213 RefreshCrc32(gpt);
214 }
215
216 return TEST_OK;
217}
218
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700219/* Tests if header CRC in two copies are calculated. */
220int HeaderCrcTest() {
221 return TEST_FAIL;
222}
223
224/* Tests if myLBA field is checked (1 for primary, last for secondary). */
225int MyLbaTest() {
226 return TEST_FAIL;
227}
228
229/* Tests if SizeOfPartitionEntry is checked. SizeOfPartitionEntry must be
230 * between 128 and 512, and a multiple of 8. */
231int SizeOfPartitionEntryTest() {
232 return TEST_FAIL;
233}
234
235/* Tests if NumberOfPartitionEntries is checes. NumberOfPartitionEntries must
236 * be between 32 and 512, and SizeOfPartitionEntry * NumberOfPartitionEntries
237 * must be 16384. */
238int NumberOfPartitionEntriesTest() {
239 return TEST_FAIL;
240}
241
242/* Tests if PartitionEntryLBA in primary/secondary headers is checked. */
243int PartitionEntryLbaTest() {
244 return TEST_FAIL;
245}
246
247/* Tests if FirstUsableLBA and LastUsableLBA are checked.
248 * FirstUsableLBA must be after the end of the primary GPT table array.
249 * LastUsableLBA must be before the start of the secondary GPT table array.
250 * FirstUsableLBA <= LastUsableLBA. */
251int FirstUsableLbaAndLastUsableLbaTest() {
252 return TEST_FAIL;
253}
254
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700255/* Tests if GptInit() handles non-identical partition entries well.
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700256 * Two copies of partition table entries must be identical. If not, we trust the
257 * primary table entries, and mark secondary as modified (see Caller's write-
258 * back order below). */
259int IdenticalEntriesTest() {
260 return TEST_FAIL;
261}
262
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700263/* Tests if GptInit() handles non-identical headers well.
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700264 * Two partition headers must be identical. If not, we trust the primary
265 * partition header, and mark secondary as modified (see Caller's write-back
266 * order below). */
267int IdenticalHeaderTest() {
268 return TEST_FAIL;
269}
270
271/* Tests if PartitionEntryArrayCRC32 is checked.
272 * PartitionEntryArrayCRC32 must be calculated over SizeOfPartitionEntry *
273 * NumberOfPartitionEntries bytes.
274 */
275int EntriesCrcTest() {
276 return TEST_FAIL;
277}
278
279/* Tests if partition geometry is checked.
280 * All active (non-zero PartitionTypeGUID) partition entries should have:
281 * entry.StartingLBA >= header.FirstUsableLBA
282 * entry.EndingLBA <= header.LastUsableLBA
283 * entry.StartingLBA <= entry.EndingLBA
284 */
285int ValidEntryTest() {
286 return TEST_FAIL;
287}
288
289/* Tests if overlapped partition tables can be detected. */
290int NoOverlappedPartitionTest() {
291 return TEST_FAIL;
292}
293
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700294/* Tests if GptNextKernelEntry() can survive in different corrupt header/entries
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700295 * combinations, like:
296 * primary GPT header - valid
297 * primary partition table - invalid
298 * secondary partition table - valid
299 * secondary GPT header - invalid
300 */
301int CorruptCombinationTest() {
302 return TEST_FAIL;
303}
304
305int main(int argc, char *argv[]) {
306 int i;
307 struct {
308 char *name;
309 test_func fp;
310 int retval;
311 } test_cases[] = {
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700312 { TEST_CASE(SignatureTest), },
313#if 0
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700314 { TEST_CASE(HeaderCrcTest), },
315 { TEST_CASE(MyLbaTest), },
316 { TEST_CASE(SizeOfPartitionEntryTest), },
317 { TEST_CASE(NumberOfPartitionEntriesTest), },
318 { TEST_CASE(PartitionEntryLbaTest), },
319 { TEST_CASE(FirstUsableLbaAndLastUsableLbaTest), },
320 { TEST_CASE(IdenticalEntriesTest), },
321 { TEST_CASE(IdenticalHeaderTest), },
322 { TEST_CASE(EntriesCrcTest), },
323 { TEST_CASE(ValidEntryTest), },
324 { TEST_CASE(NoOverlappedPartitionTest), },
325 { TEST_CASE(CorruptCombinationTest), },
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700326#endif
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700327 };
328
329 for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
330 printf("Running %s() ...\n", test_cases[i].name);
331 test_cases[i].retval = test_cases[i].fp();
332 if (test_cases[i].retval)
333 printf(COL_RED "[ERROR]" COL_STOP " %s()\n\n", test_cases[i].name);
334 else
335 printf(COL_GREEN "[PASS]" COL_STOP " %s()\n\n", test_cases[i].name);
336 }
337
338 printf("\n--------------------------------------------------\n");
339 printf("The following test cases are failed:\n");
340 for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
341 if (test_cases[i].retval)
342 printf(" %s()\n", test_cases[i].name);
343 }
344
345 return 0;
346}