mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-25 02:35:22 +00:00
347 lines
11 KiB
C
347 lines
11 KiB
C
/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "cgpt_test.h"
|
|
#include <string.h>
|
|
#include "cgpt.h"
|
|
#include "gpt.h"
|
|
#include "utility.h"
|
|
|
|
/* Testing partition layout (sector_bytes=512)
|
|
*
|
|
* LBA Size Usage
|
|
* 0 1 PMBR
|
|
* 1 1 primary partition header
|
|
* 2 32 primary partition entries (128B * 128)
|
|
* 34 100 kernel A
|
|
* 134 100 kernel B
|
|
* 234 100 root A
|
|
* 334 100 root B
|
|
* 434 32 secondary partition entries
|
|
* 466 1 secondary partition header
|
|
* 467
|
|
*/
|
|
#define DEFAULT_SECTOR_SIZE 512
|
|
#define MAX_SECTOR_SIZE 4096
|
|
#define DEFAULT_DRIVE_SECTORS 467
|
|
#define PARTITION_ENTRIES_SIZE (16*1024)
|
|
|
|
#define TEST_CASE(func) #func, func
|
|
typedef int (*test_func)(void);
|
|
|
|
/* NOT A REAL CRC32, it is fake before I call real one . FIXME */
|
|
uint32_t CalculateCrc32(const uint8_t *start, size_t len) {
|
|
uint32_t buf = 0;
|
|
int i;
|
|
for (i = 0; i < len; i += 4, len -= 4) {
|
|
buf ^= *(uint32_t*)&start[i];
|
|
}
|
|
if (len >= 3) buf ^= start[i-2] << 16;
|
|
if (len >= 2) buf ^= start[i-3] << 8;
|
|
if (len >= 1) buf ^= start[i-4];
|
|
return buf;
|
|
}
|
|
|
|
/* Given a GptData pointer, first re-calculate entries CRC32 value,
|
|
* then reset header CRC32 value to 0, and calculate header CRC32 value.
|
|
* Both primary and secondary are updated. */
|
|
void RefreshCrc32(struct GptData *gpt) {
|
|
GptHeader *header, *header2;
|
|
GptEntry *entries, *entries2;
|
|
|
|
header = (GptHeader*)gpt->primary_header;
|
|
entries = (GptEntry*)gpt->primary_entries;
|
|
header2 = (GptHeader*)gpt->secondary_header;
|
|
entries2 = (GptEntry*)gpt->secondary_entries;
|
|
|
|
header->entries_crc32 = CalculateCrc32((uint8_t*)entries,
|
|
sizeof(GptEntry));
|
|
header->header_crc32 = 0;
|
|
header->header_crc32 = CalculateCrc32((uint8_t*)header,
|
|
header->size);
|
|
header2->entries_crc32 = CalculateCrc32((uint8_t*)entries2,
|
|
sizeof(GptEntry));
|
|
header2->header_crc32 = 0;
|
|
header2->header_crc32 = CalculateCrc32((uint8_t*)header2,
|
|
header2->size);
|
|
}
|
|
|
|
/* Returns a pointer to a static GptData instance (no free is required).
|
|
* All fields are zero except 4 pointers linking to header and entries.
|
|
* All content of headers and entries are zero. */
|
|
struct GptData* GetAClearGptData() {
|
|
static GptData_t gpt;
|
|
static uint8_t primary_header[MAX_SECTOR_SIZE];
|
|
static uint8_t primary_entries[PARTITION_ENTRIES_SIZE];
|
|
static uint8_t secondary_header[MAX_SECTOR_SIZE];
|
|
static uint8_t secondary_entries[PARTITION_ENTRIES_SIZE];
|
|
|
|
Memset(&gpt, 0, sizeof(gpt));
|
|
Memset(&primary_header, 0, sizeof(primary_header));
|
|
Memset(&primary_entries, 0, sizeof(primary_entries));
|
|
Memset(&secondary_header, 0, sizeof(secondary_header));
|
|
Memset(&secondary_entries, 0, sizeof(secondary_entries));
|
|
|
|
gpt.primary_header = primary_header;
|
|
gpt.primary_entries = primary_entries;
|
|
gpt.secondary_header = secondary_header;
|
|
gpt.secondary_entries = secondary_entries;
|
|
|
|
return &gpt;
|
|
}
|
|
|
|
/* Fills in most of fields and creates the layout described in the top of this
|
|
* file. */
|
|
struct GptData*
|
|
BuildTestGptData(uint32_t sector_bytes) {
|
|
GptData_t *gpt;
|
|
GptHeader *header, *header2;
|
|
GptEntry *entries, *entries2;
|
|
Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
|
|
|
|
gpt = GetAClearGptData();
|
|
gpt->sector_bytes = sector_bytes;
|
|
gpt->drive_sectors = DEFAULT_DRIVE_SECTORS;
|
|
|
|
/* build primary */
|
|
header = (GptHeader*)gpt->primary_header;
|
|
entries = (GptEntry*)gpt->primary_entries;
|
|
Memcpy(header->signature, GPT_HEADER_SIGNATURE, sizeof(GPT_HEADER_SIGNATURE));
|
|
header->revision = GPT_HEADER_REVISION;
|
|
header->size = sizeof(GptHeader) - sizeof(header->padding);
|
|
header->my_lba = 1;
|
|
header->first_usable_lba = 34;
|
|
header->last_usable_lba = DEFAULT_DRIVE_SECTORS - 1 - 32 - 1; /* 433 */
|
|
header->entries_lba = 2;
|
|
header->number_of_entries = 128; /* 512B / 128B * 32sectors = 128 entries */
|
|
header->size_of_entry = 128; /* bytes */
|
|
Memcpy(&entries[0].type, &chromeos_kernel, sizeof(chromeos_kernel));
|
|
entries[0].starting_lba = 34;
|
|
entries[0].ending_lba = 133;
|
|
Memcpy(&entries[1].type, &chromeos_kernel, sizeof(chromeos_kernel));
|
|
entries[1].starting_lba = 134;
|
|
entries[1].ending_lba = 233;
|
|
Memcpy(&entries[2].type, &chromeos_kernel, sizeof(chromeos_kernel));
|
|
entries[2].starting_lba = 234;
|
|
entries[2].ending_lba = 333;
|
|
Memcpy(&entries[3].type, &chromeos_kernel, sizeof(chromeos_kernel));
|
|
entries[3].starting_lba = 334;
|
|
entries[3].ending_lba = 433;
|
|
|
|
/* build secondary */
|
|
header2 = (GptHeader*)gpt->secondary_header;
|
|
entries2 = (GptEntry*)gpt->secondary_entries;
|
|
Memcpy(header2, header, sizeof(header));
|
|
Memcpy(entries2, entries, sizeof(entries));
|
|
header2->my_lba = DEFAULT_DRIVE_SECTORS - 1; /* 466 */
|
|
header2->entries_lba = DEFAULT_DRIVE_SECTORS - 1 - 32; /* 434 */
|
|
|
|
RefreshCrc32(gpt);
|
|
return gpt;
|
|
}
|
|
|
|
/* Dumps memory starting from [vp] with [len] bytes.
|
|
* Prints [memo] if not NULL. Example output:
|
|
*
|
|
* 00 01 02 03 04 05 06 07 - 08 09 0a 0b 0c 0d 0e 0f
|
|
* 10 11 12 13 14 15 16 17 - 18 19 1a 1b 1c 1d 1e 1f
|
|
* ...
|
|
*/
|
|
static void dump(void *vp, int len, char* memo) {
|
|
uint8_t *start = vp;
|
|
int i;
|
|
if (memo) printf("--[%s]----------\n", memo);
|
|
for (i = 0; i < len; ++i) {
|
|
printf("%02x%s", start[i],
|
|
(!(~i & 15) ? "\n" :
|
|
!(~i & 7) ? " - ": " "));
|
|
}
|
|
if (i&15) printf("\n");
|
|
}
|
|
|
|
/* More formatted dump with GptData. */
|
|
void DumpGptData(struct GptData *gpt) {
|
|
printf("DumpGptData(%p)...\n", gpt);
|
|
dump(gpt, sizeof(gpt), NULL);
|
|
dump(gpt->primary_header, sizeof(GptHeader), "Primary header");
|
|
dump(gpt->primary_entries, sizeof(GptEntry) * 8, "Primary entries");
|
|
dump(gpt->secondary_header, sizeof(GptHeader), "Secondary header");
|
|
dump(gpt->secondary_entries, sizeof(GptEntry) * 8,
|
|
"Secondary entries");
|
|
}
|
|
|
|
/* Tests if signature ("EFI PART") is checked. */
|
|
int SignatureTest() {
|
|
int i;
|
|
GptData_t *gpt;
|
|
GptHeader *primary_header, *secondary_header;
|
|
|
|
gpt = BuildTestGptData(DEFAULT_SECTOR_SIZE);
|
|
primary_header = (GptHeader*)gpt->primary_header;
|
|
secondary_header = (GptHeader*)gpt->secondary_header;
|
|
|
|
EXPECT(GPT_SUCCESS == GptInit(gpt));
|
|
|
|
/* change every char in signature of primary. Secondary is still valid. */
|
|
for (i = 0; i < 8; ++i) {
|
|
gpt->primary_header[i] ^= 0xff;
|
|
RefreshCrc32(gpt);
|
|
EXPECT(GPT_SUCCESS == GptInit(gpt));
|
|
gpt->primary_header[i] ^= 0xff;
|
|
RefreshCrc32(gpt);
|
|
}
|
|
|
|
/* change every char in signature of secondary. Primary is still valid. */
|
|
for (i = 0; i < 8; ++i) {
|
|
gpt->secondary_header[i] ^= 0xff;
|
|
RefreshCrc32(gpt);
|
|
EXPECT(GPT_SUCCESS == GptInit(gpt));
|
|
gpt->secondary_header[i] ^= 0xff;
|
|
RefreshCrc32(gpt);
|
|
}
|
|
|
|
/* change every char in signature of primary and secondary. Expect fail. */
|
|
for (i = 0; i < 8; ++i) {
|
|
gpt->primary_header[i] ^= 0xff;
|
|
gpt->secondary_header[i] ^= 0xff;
|
|
RefreshCrc32(gpt);
|
|
EXPECT(GPT_ERROR_INVALID_HEADERS == GptInit(gpt));
|
|
gpt->primary_header[i] ^= 0xff;
|
|
gpt->secondary_header[i] ^= 0xff;
|
|
RefreshCrc32(gpt);
|
|
}
|
|
|
|
return TEST_OK;
|
|
}
|
|
|
|
/* Tests if header CRC in two copies are calculated. */
|
|
int HeaderCrcTest() {
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
/* Tests if myLBA field is checked (1 for primary, last for secondary). */
|
|
int MyLbaTest() {
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
/* Tests if SizeOfPartitionEntry is checked. SizeOfPartitionEntry must be
|
|
* between 128 and 512, and a multiple of 8. */
|
|
int SizeOfPartitionEntryTest() {
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
/* Tests if NumberOfPartitionEntries is checes. NumberOfPartitionEntries must
|
|
* be between 32 and 512, and SizeOfPartitionEntry * NumberOfPartitionEntries
|
|
* must be 16384. */
|
|
int NumberOfPartitionEntriesTest() {
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
/* Tests if PartitionEntryLBA in primary/secondary headers is checked. */
|
|
int PartitionEntryLbaTest() {
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
/* Tests if FirstUsableLBA and LastUsableLBA are checked.
|
|
* FirstUsableLBA must be after the end of the primary GPT table array.
|
|
* LastUsableLBA must be before the start of the secondary GPT table array.
|
|
* FirstUsableLBA <= LastUsableLBA. */
|
|
int FirstUsableLbaAndLastUsableLbaTest() {
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
/* Tests if GptInit() handles non-identical partition entries well.
|
|
* Two copies of partition table entries must be identical. If not, we trust the
|
|
* primary table entries, and mark secondary as modified (see Caller's write-
|
|
* back order below). */
|
|
int IdenticalEntriesTest() {
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
/* Tests if GptInit() handles non-identical headers well.
|
|
* Two partition headers must be identical. If not, we trust the primary
|
|
* partition header, and mark secondary as modified (see Caller's write-back
|
|
* order below). */
|
|
int IdenticalHeaderTest() {
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
/* Tests if PartitionEntryArrayCRC32 is checked.
|
|
* PartitionEntryArrayCRC32 must be calculated over SizeOfPartitionEntry *
|
|
* NumberOfPartitionEntries bytes.
|
|
*/
|
|
int EntriesCrcTest() {
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
/* Tests if partition geometry is checked.
|
|
* All active (non-zero PartitionTypeGUID) partition entries should have:
|
|
* entry.StartingLBA >= header.FirstUsableLBA
|
|
* entry.EndingLBA <= header.LastUsableLBA
|
|
* entry.StartingLBA <= entry.EndingLBA
|
|
*/
|
|
int ValidEntryTest() {
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
/* Tests if overlapped partition tables can be detected. */
|
|
int NoOverlappedPartitionTest() {
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
/* Tests if GptNextKernelEntry() can survive in different corrupt header/entries
|
|
* combinations, like:
|
|
* primary GPT header - valid
|
|
* primary partition table - invalid
|
|
* secondary partition table - valid
|
|
* secondary GPT header - invalid
|
|
*/
|
|
int CorruptCombinationTest() {
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
int i;
|
|
struct {
|
|
char *name;
|
|
test_func fp;
|
|
int retval;
|
|
} test_cases[] = {
|
|
{ TEST_CASE(SignatureTest), },
|
|
#if 0
|
|
{ TEST_CASE(HeaderCrcTest), },
|
|
{ TEST_CASE(MyLbaTest), },
|
|
{ TEST_CASE(SizeOfPartitionEntryTest), },
|
|
{ TEST_CASE(NumberOfPartitionEntriesTest), },
|
|
{ TEST_CASE(PartitionEntryLbaTest), },
|
|
{ TEST_CASE(FirstUsableLbaAndLastUsableLbaTest), },
|
|
{ TEST_CASE(IdenticalEntriesTest), },
|
|
{ TEST_CASE(IdenticalHeaderTest), },
|
|
{ TEST_CASE(EntriesCrcTest), },
|
|
{ TEST_CASE(ValidEntryTest), },
|
|
{ TEST_CASE(NoOverlappedPartitionTest), },
|
|
{ TEST_CASE(CorruptCombinationTest), },
|
|
#endif
|
|
};
|
|
|
|
for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
|
|
printf("Running %s() ...\n", test_cases[i].name);
|
|
test_cases[i].retval = test_cases[i].fp();
|
|
if (test_cases[i].retval)
|
|
printf(COL_RED "[ERROR]" COL_STOP " %s()\n\n", test_cases[i].name);
|
|
else
|
|
printf(COL_GREEN "[PASS]" COL_STOP " %s()\n\n", test_cases[i].name);
|
|
}
|
|
|
|
printf("\n--------------------------------------------------\n");
|
|
printf("The following test cases are failed:\n");
|
|
for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
|
|
if (test_cases[i].retval)
|
|
printf(" %s()\n", test_cases[i].name);
|
|
}
|
|
|
|
return 0;
|
|
}
|