first and last commit

This commit is contained in:
Chris Nutter committed 2023-07-08 13:03:17 -07:00
commit 1bf4efd552
2612 files changed
+636500

No files matched your search

+27
View File
@@ -0,0 +1,27 @@
# Copyright (C) 2014 Apple Inc. All rights reserved.
#
# This document is the property of Apple Inc.
# It is considered confidential and proprietary.
#
# This document may not be reproduced or transmitted in any form,
# in whole or in part, without the express written permission of
# Apple Inc.
#
LIBSYSCFG_DIR := $(GET_LOCAL_DIR)
LIBSYSCFG_BUILD := $(call TOLIBDIR,$(LIBSYSCFG_DIR)/LIBSYSCFG.a)
COMMONLIBS += LIBSYSCFG
# Only process the remainder of the makefile if we are building libraries
#
ifeq ($(MAKEPHASE),libraries)
LIBSYSCFG_OBJS := $(LIBSYSCFG_DIR)/syscfg.o
LIBSYSCFG_OBJS := $(call TOLIBOBJDIR,$(LIBSYSCFG_OBJS))
ALL_DEPS += $(LIBSYSCFG_OBJS:%o=%d)
$(LIBSYSCFG_BUILD): $(LIBSYSCFG_OBJS)
endif
+13
View File
@@ -0,0 +1,13 @@
# Copyright (C) 2007, 2011, 2014 Apple Inc. All rights reserved.
# Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
#
# This document is the property of Apple Inc.
# It is considered confidential and proprietary.
#
# This document may not be reproduced or transmitted in any form,
# in whole or in part, without the express written permission of
# Apple Inc.
#
OPTIONS += WITH_SYSCFG=1
LIBRARY_MODULES += lib/syscfg
+342
View File
@@ -0,0 +1,342 @@
/*
* Copyright (C) 2007-2012, 2014 Apple Inc. All rights reserved.
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
*
* This document is the property of Apple Computer, Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Computer, Inc.
*/
/*
* Support for detecting and reading the iPod-style SysCfg data
*/
#include <debug.h>
#include <stdlib.h>
#include <string.h>
#include <lib/syscfg.h>
#include <lib/blockdev.h>
#include <sys/menu.h>
static u_int32_t syscfgKeyCount;
static uint8_t *syscfgData;
static size_t syscfgDataLength;
struct syscfgHeader {
u_int32_t shMagic;
#define kSysCfgHeaderMagic 'SCfg'
u_int32_t shSize;
u_int32_t shMaxSize;
u_int32_t shVersion;
u_int32_t shBigEndian;
u_int32_t shKeyCount;
};
void syscfg_reinit(void)
{
free(syscfgData);
syscfgDataLength = 0;
syscfgData = NULL;
syscfgKeyCount = 0;
}
int
do_syscfg(int argc, struct cmd_arg *args)
{
struct syscfgHeader hdr;
struct syscfgMemEntry entry;
int index, curArg;
size_t size, i, j;
char *sfx;
bool isExt;
size_t lowExt;
size_t highExt;
size_t extSize = 0;
uint8_t *buffer;
bool showExt = false;
if (NULL == syscfgData) {
printf("syscfg is not initialized!\n");
return(0);
}
if (syscfgDataLength < sizeof(struct syscfgHeader))
return (0);
memcpy(&hdr, syscfgData, sizeof(struct syscfgHeader));
printf("version 0x%08x with %d entries\n\n", hdr.shVersion, hdr.shKeyCount);
lowExt = hdr.shMaxSize;
highExt = hdr.shSize;
for (index = 0; ; index++) {
if (!syscfgFindByIndex(index, &entry))
break;
if (argc > 1) {
/* When parameters are present, always show in extended mode */
showExt = true;
/* If the first parameter is ext, assume match in all cases by skipping the match block */
if(strcmp("ext", args[1].str) != 0) {
/* Scan the list of arguments looking for a match */
for (curArg = 1; curArg < argc; curArg ++) {
if (((entry.seTag >> 24) & 0xFF) == args[curArg].str[0] &&
((entry.seTag >> 16) & 0xFF) == args[curArg].str[1] &&
((entry.seTag >> 8) & 0xFF) == args[curArg].str[2] &&
((entry.seTag >> 0) & 0xFF) == args[curArg].str[3])
break;
}
if (curArg == argc) continue;
}
}
sfx = "";
/* Is this a standard entry or an Offset entry? */
if (entry.seDataOffset != 0) {
size = entry.seDataSize;
if (size > sizeof(entry.seData)) {
/* The Size of the entry is too big for the structure
* Should it be truncated? */
if (!showExt) {
size = sizeof(entry.seData);
sfx = "...";
}
}
if (entry.seDataOffset + entry.seDataSize > hdr.shMaxSize) {
printf("entry->seDataOffset not within syscfgData");
return(0);
}
/* Allocate the requested space aligned on 16 bytes to zero
* pad the display. */
buffer = calloc(1, (size + 15) & ~15);
memcpy(buffer, syscfgData + entry.seDataOffset, size);
// Calculate the extents of the offset section
if (entry.seDataOffset < lowExt) {
lowExt = entry.seDataOffset;
}
if ((entry.seDataOffset + entry.seDataSize) > highExt) {
highExt = entry.seDataOffset + entry.seDataSize;
}
isExt = true;
} else {
/* allocate enough space to mirror the entrys buffer */
size = sizeof(entry.seData);
buffer = malloc(sizeof(entry.seData));
memcpy(buffer, entry.seData, size);
isExt = false;
}
printf("0x%08x '%c%c%c%c' %4dB %c ",
entry.seTag,
(entry.seTag >> 24) & 0xff,
(entry.seTag >> 16) & 0xff,
(entry.seTag >> 8) & 0xff,
entry.seTag & 0xff,
entry.seDataSize,
isExt ? '*' : ' ');
/* Format the data in nice columns */
for (i = 0; i < size; i += 16 ) {
printf("%*s", (i >= 16) ? 28 : 0, "");
/* Starting at the offset, display the data values up to 4 per line. */
for (j = i; j < (i + 16); j += 4) {
printf("0x%08x ", *((u_int32_t *)&buffer[j]));
}
printf("%s\n", sfx);
}
free(buffer);
}
printf("\n");
printf("header @ 0-%zu", sizeof(struct syscfgHeader) - 1);
printf("; entries @ %zu-%d", sizeof(struct syscfgHeader), hdr.shSize - 1);
if (lowExt < highExt) {
extSize = highExt - lowExt;
printf("; extra data @ %zu-%zu", lowExt, highExt - 1);
}
printf("; using %zu of %d bytes\n", hdr.shSize + extSize, hdr.shMaxSize);
return(0);
}
bool
syscfgInitWithBdev(const char *bdevName)
{
int result;
struct blockdev *candidate;
struct syscfgHeader hdr;
if (syscfgData != NULL)
return(false);
/* look for the suggested bdev */
if ((candidate = lookup_blockdev(bdevName)) == NULL) {
dprintf(DEBUG_INFO, "syscfg: can't find bdev \"%s\"\n", bdevName);
return(false);
}
/* Make sure it's big enough */
if (candidate->total_len <= kSysCfgBdevOffset + sizeof(hdr)) {
dprintf(DEBUG_INFO, "syscfg: bdev size 0x%llx too small\n", candidate->total_len);
return (false);
}
/* look for the header */
if (blockdev_read(candidate, &hdr, kSysCfgBdevOffset, sizeof(hdr)) < (int)sizeof(hdr)) {
dprintf(DEBUG_INFO, "syscfg: bdev read fail\n");
return(false);
}
if (hdr.shMagic != kSysCfgHeaderMagic) {
dprintf(DEBUG_INFO, "syscfg: bad magic\n");
return(false);
}
dprintf(DEBUG_CRITICAL, "syscfg: version 0x%08x with %d entries using %d of %d bytes\n",
hdr.shVersion, hdr.shKeyCount, hdr.shSize, hdr.shMaxSize);
/* If there is a syscfg there will also be diag info... protect them. */
blockdev_set_protection(candidate, 0x2000, 0x6000);
syscfgDataLength = candidate->total_len - kSysCfgBdevOffset;
if (hdr.shSize < syscfgDataLength)
syscfgDataLength = hdr.shMaxSize;
syscfgData = malloc(syscfgDataLength);
result = blockdev_read(candidate, syscfgData, kSysCfgBdevOffset, syscfgDataLength);
if (result < 0 || (size_t)result < syscfgDataLength) {
dprintf(DEBUG_INFO, "syscfg: bdev read fail (%d)\n", result);
syscfg_reinit();
return false;
}
syscfgKeyCount = hdr.shKeyCount;
return(true);
}
void *
syscfgGetData(struct syscfgMemEntry *entry)
{
/* Handle data stored externally from the entry */
if (entry->seDataOffset != 0) {
if (entry->seDataOffset > syscfgDataLength)
return NULL;
if (entry->seDataOffset + entry->seDataSize > syscfgDataLength)
return NULL;
return syscfgData + entry->seDataOffset;
} else {
return entry->seData;
}
}
uint32_t
syscfgGetSize(struct syscfgMemEntry *entry)
{
return entry->seDataSize;
}
int
syscfgCopyDataForTag(u_int32_t tag, u_int8_t *buffer, size_t size)
{
bool result;
struct syscfgMemEntry entry;
void *data;
result = syscfgFindByTag(tag, &entry);
if (!result)
return(-1);
if (size > entry.seDataSize)
size = entry.seDataSize;
data = syscfgGetData(&entry);
if (data == NULL)
return(-1);
memcpy(buffer, data, size);
// XXX check what to do with the assert that was removed from here
return size;
}
bool
syscfgFindByTag(u_int32_t tag, struct syscfgMemEntry *entry)
{
static struct syscfgMemEntry temp;
bool result;
u_int32_t index;
for (index = 0; index < syscfgKeyCount; index++) {
result = syscfgFindByIndex(index, &temp);
if (result && (temp.seTag == tag)) {
memcpy(entry, &temp, sizeof(*entry));
return true;
}
}
return false;
}
bool
syscfgFindByIndex(u_int32_t index, struct syscfgMemEntry *result)
{
struct syscfgEntry entry;
struct syscfgEntryCNTB *entryCNTB;
if (index >= syscfgKeyCount)
return false;
size_t offset = sizeof(struct syscfgHeader) + index * sizeof(struct syscfgEntry);
if (offset >= syscfgDataLength || offset + sizeof(struct syscfgEntry) >= syscfgDataLength)
return false;
memcpy(&entry, syscfgData + offset, sizeof(entry));
if (entry.seTag == 'CNTB') {
entryCNTB = (struct syscfgEntryCNTB *)&entry;
result->seTag = entryCNTB->seRealTag;
memset(result->seData, 0, sizeof(result->seData));
result->seDataSize = entryCNTB->seDataSize;
result->seDataOffset = entryCNTB->seDataOffset;
} else {
result->seTag = entry.seTag;
memcpy(result->seData, entry.seData, sizeof(result->seData));
result->seDataSize = sizeof(result->seData);
result->seDataOffset = 0;
}
return true;
}
bool
syscfg_find_tag(uint32_t tag, void **data_out, uint32_t *size_out)
{
static struct syscfgMemEntry result;
if (syscfgFindByTag(tag, &result)) {
if (data_out) {
*data_out = syscfgGetData(&result);
}
if (size_out) {
*size_out = syscfgGetSize(&result);
}
return true;
} else {
return false;
}
}
+252
View File
@@ -0,0 +1,252 @@
#include <unittest.h>
#include <lib/blockdev.h>
#include <lib/syscfg.h>
#include <stdlib.h>
#include <string.h>
#define TEST_SYSCFG_BLOCKDEV_SIZE 0x8000
extern void syscfg_reinit(void);
const uint32_t test_syscfg_data1[] =
{
'SCfg', // magic
0x1000, // size
0x1000, // max size
0x0, // version
0x0, // big endian (NOT)
9, // key count
'Ent0', // key
0x0, 0x0, 0x0, 0x0, // data
'Ent1', // key
0x1, 0x1, 0x1, 0x1, // data
'Ent2', // key
0x200, 0x200, // data
0x200, 0x200,
'Ent3', // key
0x30000, 0x30000, // data
0x30000, 0x30000,
'Ent4', // key
0x4000000, 0x4000000, // data
0x4000000, 0x4000000,
'CNTB', 'Ent5',
4, 0x180, 0, // size 4 offset 0x100
'CNTB', 'Ent6',
8, 0x184, 0, // size 4 offset 0x100
'CNTB', 'Ent7',
1, 0x18c, 0, // size 1 offset 0x104
'CNTB', 'Ent8',
32, 0x190, 0, // size 1 offset 0x104
// padding, delete an entry here whenever adding an entry above
0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0,
// CNTB block data starts at 0x100
0xabcd1234, // for 'Ent5'
0x11111111, // for 'Ent6'
0x22222222, // .
0xDDDDDDAA, // for 'Ent7', only 'AA' part is actually valid
0x12345678, // for 'Ent8'
0x23456789, // .
0x3456789a, // .
0x456789ab, // .
0x567891bc, // .
0x6789abcd, // .
0x789abcde, // .
0x89abcdef, // .
};
const uint32_t test_syscfg_data3[] =
{
'SCfg', // magic
0x100, // size
0x100, // max size
0x0, // version
0x0, // big endian (NOT)
4, // key count
'CNTB', 'Ent1',
8, 0xf8, 0, // pointer is right at end of advertised size, but ok
'CNTB', 'Ent2',
4, 0x200, 0, // pointer is past advertised size
'CNTB', 'Ent3',
2, 0xff, 0, // pointer plus size puts over the end
'CNTB', 'Ent4',
32, 0x8000, 0, // pointer is past end of bdev
// actual CNTB block data is just padded out with zeroes
};
// XXX add test with malformed data advertising way too big size
void test_setup_backing(void *backing, const void *data, size_t data_size)
{
TEST_ASSERT_NOT_NULL(backing);
memset(backing, 0, TEST_SYSCFG_BLOCKDEV_SIZE);
memcpy((uint8_t *)backing + 0x4000, data, data_size);
}
void test_syscfg1(uintptr_t param)
{
struct blockdev *bdev;
void *backing = malloc(TEST_SYSCFG_BLOCKDEV_SIZE);
bdev = create_mem_blockdev("syscfg_bdev1", backing, TEST_SYSCFG_BLOCKDEV_SIZE, 0x1000);
TEST_ASSERT_NOT_NULL(bdev);
register_blockdev(bdev);
// Initializing with wrong name should result in failure
TEST_ASSERT_EQ(syscfgInitWithBdev("wrong"), false);
// and then a subsequent read should fail
{
uint8_t resultData[16];
TEST_ASSERT_EQ(syscfgCopyDataForTag('Ent0', resultData, sizeof(resultData)), -1);
}
// Initializing with empty syscfg should result in failure
memset(backing, 0, TEST_SYSCFG_BLOCKDEV_SIZE);
TEST_ASSERT_EQ(syscfgInitWithBdev("syscfg_bdev1"), false);
// and then a subsequent read should fail
{
uint8_t resultData[16];
TEST_ASSERT_EQ(syscfgCopyDataForTag('Ent0', resultData, sizeof(resultData)), -1);
}
test_setup_backing(backing, test_syscfg_data1, sizeof(test_syscfg_data1));
// initializing with a valid syscfg should work
TEST_ASSERT_EQ(syscfgInitWithBdev("syscfg_bdev1"), true);
{
uint8_t resultData[16];
// looking for a non-existant tag should return failure
TEST_ASSERT_EQ(syscfgCopyDataForTag('EntX', resultData, sizeof(resultData)), -1);
// looking for ones that exist should work
TEST_ASSERT_EQ(syscfgCopyDataForTag('Ent0', resultData, sizeof(resultData)), sizeof(resultData));
TEST_ASSERT_MEM_EQ(resultData, TEST_ARRAY(uint32_t, 0, 0, 0, 0), sizeof(resultData));
TEST_ASSERT_EQ(syscfgCopyDataForTag('Ent1', resultData, sizeof(resultData)), sizeof(resultData));
TEST_ASSERT_MEM_EQ(resultData, TEST_ARRAY(uint32_t, 1, 1, 1, 1), sizeof(resultData));
TEST_ASSERT_EQ(syscfgCopyDataForTag('Ent2', resultData, sizeof(resultData)), sizeof(resultData));
TEST_ASSERT_MEM_EQ(resultData, TEST_ARRAY(uint32_t, 0x200, 0x200, 0x200, 0x200), sizeof(resultData));
TEST_ASSERT_EQ(syscfgCopyDataForTag('Ent3', resultData, sizeof(resultData)), sizeof(resultData));
TEST_ASSERT_MEM_EQ(resultData, TEST_ARRAY(uint32_t, 0x30000, 0x30000, 0x30000, 0x30000), sizeof(resultData));
TEST_ASSERT_EQ(syscfgCopyDataForTag('Ent4', resultData, sizeof(resultData)), sizeof(resultData));
TEST_ASSERT_MEM_EQ(resultData, TEST_ARRAY(uint32_t, 0x4000000, 0x4000000, 0x4000000, 0x4000000), sizeof(resultData));
// Requesting an amount smaller than the entry size results in just that amount
memset(resultData, 0xff, sizeof(resultData));
TEST_ASSERT_EQ(syscfgCopyDataForTag('Ent1', resultData, 4), 4);
TEST_ASSERT_MEM_EQ(resultData, TEST_ARRAY(uint32_t, 1, 0xffffffff, 0xffffffff, 0xffffffff), sizeof(resultData));
}
{
uint8_t resultData[32];
// Requesting an amount bigger than the entry size results in a short read
memset(resultData, 0xff, sizeof(resultData));
TEST_ASSERT_EQ(syscfgCopyDataForTag('Ent1', resultData, sizeof(resultData)), 16);
TEST_ASSERT_MEM_EQ(resultData, TEST_ARRAY(uint32_t, 1, 1, 1, 1), 16);
TEST_ASSERT_MEM_EQ(resultData + 16, TEST_ARRAY(uint32_t, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff), 16);
}
{
uint8_t resultData[4];
// Reading from a CNTB-style entry should work and return the size given in the entry
memset(resultData, 0xff, sizeof(resultData));
TEST_ASSERT_EQ(syscfgCopyDataForTag('Ent5', resultData, sizeof(resultData)), sizeof(resultData));
TEST_ASSERT_MEM_EQ(resultData, TEST_ARRAY(uint32_t, 0xabcd1234), sizeof(resultData));
}
{
uint8_t resultData[8];
// Short reads from CNTB blocks should still result in the short size being returned
memset(resultData, 0xff, sizeof(resultData));
TEST_ASSERT_EQ(syscfgCopyDataForTag('Ent6', resultData, 4), 4);
TEST_ASSERT_MEM_EQ(resultData, TEST_ARRAY(uint32_t, 0x11111111, 0xffffffff), sizeof(resultData));
}
}
void test_syscfg2(uintptr_t param)
{
struct blockdev *bdev;
void *backing = malloc(TEST_SYSCFG_BLOCKDEV_SIZE);
test_setup_backing(backing, test_syscfg_data1, sizeof(test_syscfg_data1));
// bdev has the right data in it, but that data is past the end of its advertised length
bdev = create_mem_blockdev("syscfg_bdev2", backing, 0x4000, 0x1000);
register_blockdev(bdev);
TEST_ASSERT_EQ(syscfgInitWithBdev("syscfg_bdev2"), false);
}
void test_syscfg3(uintptr_t param)
{
struct blockdev *bdev;
uint8_t resultData[8];
void *backing = malloc(TEST_SYSCFG_BLOCKDEV_SIZE);
test_setup_backing(backing, test_syscfg_data3, sizeof(test_syscfg_data3));
bdev = create_mem_blockdev("syscfg_bdev3", backing, TEST_SYSCFG_BLOCKDEV_SIZE, 0x1000);
register_blockdev(bdev);
TEST_ASSERT_EQ(syscfgInitWithBdev("syscfg_bdev3"), true);
TEST_ASSERT_EQ(syscfgCopyDataForTag('Ent1', resultData, 8), 8);
TEST_ASSERT_EQ(syscfgCopyDataForTag('Ent2', resultData, 8), -1);
TEST_ASSERT_EQ(syscfgCopyDataForTag('Ent3', resultData, 8), -1);
TEST_ASSERT_EQ(syscfgCopyDataForTag('Ent4', resultData, 8), -1);
}
// XXX add a test for syscfg_find_tag
static struct test_suite syscfg_test_suite = {
.name = "syscfg",
.description = "tests the syscfg library",
.setup_function = syscfg_reinit,
.test_cases = {
{ "syscfg", test_syscfg1, 0 },
{ "syscfg", test_syscfg2, 0 },
{ "syscfg", test_syscfg3, 0 },
TEST_CASE_LAST
}
};
TEST_SUITE(syscfg_test_suite);
+26
View File
@@ -0,0 +1,26 @@
# Copyright (C) 2014 Apple Inc. All rights reserved.
#
# This document is the property of Apple Inc.
# It is considered confidential and proprietary.
#
# This document may not be reproduced or transmitted in any form,
# in whole or in part, without the express written permission of
# Apple Inc.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
TEST_NAME := syscfg
TEST_OBJS := \
$(LOCAL_DIR)/syscfg.o \
lib/blockdev/blockdev.o \
lib/blockdev/mem_blockdev.o \
lib/libc/log2.o
TEST_SUPPORT_OBJS := \
tests/unittest-main.o \
$(LOCAL_DIR)/tests.o
TEST_CFLAGS := \
-DCPU_CACHELINE_SIZE=32