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

+56
View File
@@ -0,0 +1,56 @@
/*
* Copyright (C) 2007-2011 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.
*/
#include <arch.h>
#include <lib/heap.h>
#include <lib/profile.h>
#include <lib/libc.h>
#include <platform.h>
#include <sys.h>
#include <sys/boot.h>
typedef void (* entry_func_t)(void *, int, int, int);
typedef void (* trampoline_func_t)(entry_func_t, void *);
/* quiesce hardware and jump into a new image */
void prepare_and_jump(enum boot_target boot, void *ptr, void *arg)
{
entry_func_t entry = (entry_func_t)(uintptr_t)ptr;
trampoline_func_t trampoline = (trampoline_func_t)platform_get_boot_trampoline();
/* keep alive a little longer */
platform_watchdog_tickle();
/* do whatever prep needs to happen before jumping into something */
platform_bootprep(boot);
/* make sure timers and whatnot aren't running */
platform_quiesce_hardware(boot);
/* verify we haven't had any heap corruption */
heap_verify();
/* make sure interrupts are disabled */
enter_critical_section();
/* Copy profile buffer from SRAM into panic RAM */
PROFILE_HANDOFF();
/* quiesce the cpu, disabling the mmu and caches */
arch_cpu_quiesce();
if (trampoline != NULL)
trampoline(entry, arg);
else
entry(arg, 0, 0, 0);
/* should not get here */
for(;;) ;
}
+187
View File
@@ -0,0 +1,187 @@
/*
* Copyright (C) 2007-2009 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.
*/
#include <debug.h>
#include <list.h>
#include <sys.h>
#include <sys/callout.h>
#include <platform/timer.h>
static struct list_node callout_queue;
static int callout_init(void);
static int _callout_dequeue(struct callout *c);
static void _callout_reset_deadline(void);
static void callout_deadline(void);
static bool ready;
/*
* Initialise the callout system.
*/
static int callout_init(void)
{
list_initialize(&callout_queue);
ready = true;
return 0;
}
/*
* Enqueue (func) to be called after at least (delay) microseconds.
*/
void callout_enqueue(struct callout *c, utime_t delay, callout_func func, void *arg)
{
struct callout *entry;
uint64_t now;
/* if we have not been initialised, do so now */
if (unlikely(!ready))
callout_init();
enter_critical_section();
/* remove it if it's already in a list */
_callout_dequeue(c);
/* convert utime_t delay to absolute clock deadline */
now = timer_get_ticks();
c->sched_ticks = now + timer_usecs_to_ticks(delay);
// printf("callout %p: %lluus at %llu ticks (now %llu)\n", c, delay, c->sched_ticks, now);
c->delay = delay;
c->callback = func;
c->arg = arg;
list_for_every_entry(&callout_queue, entry, struct callout, list) {
/* search through the callout queue, finding the right sorted slot */
if (c->sched_ticks < entry->sched_ticks) {
list_add_before(&entry->list, &c->list);
goto done;
}
}
/* either the queue was empty or our entry is the last */
list_add_tail(&callout_queue, &c->list);
done:
_callout_reset_deadline();
exit_critical_section();
}
/*
* Dequeue the callout (c)
*/
int callout_dequeue(struct callout *c)
{
int err;
enter_critical_section();
err = _callout_dequeue(c);
exit_critical_section();
return err;
}
/*
* Reset the callout (c) to be called after (newdelay) microseconds.
*/
int callout_reset(struct callout *c, utime_t newdelay)
{
int err = 0;
enter_critical_section();
/* remove it if it's already in a list */
_callout_dequeue(c);
if (newdelay != 0)
c->delay = newdelay;
if (c->delay == 0) {
err = -1;
} else {
callout_enqueue(c, c->delay, c->callback, c->arg);
}
exit_critical_section();
return err;
}
/*
* Reset the timer deadline as the queue may have changed.
*/
static void _callout_reset_deadline(void)
{
struct callout *c;
c = list_peek_head_type(&callout_queue, struct callout, list);
if (c == NULL) {
timer_deadline_enter(0, NULL);
} else {
timer_deadline_enter(c->sched_ticks, callout_deadline);
}
}
void callout_reset_deadline(void)
{
enter_critical_section();
_callout_reset_deadline();
exit_critical_section();
}
/*
* Pull callout (c) from the queue (while locked)
*/
static int _callout_dequeue(struct callout *c)
{
if (list_in_list(&c->list)) {
list_delete(&c->list);
_callout_reset_deadline();
return 1;
}
return 0;
}
/*
* Callback from the timer when the deadline expires; call all of the
* pending callouts and reschedule the deadline accordingly.
*
* Note that the timer is allowed to call us early; if we have set a
* deadline beyond its ability to handle we will do no work and just re-schedule.
*/
static void callout_deadline(void)
{
struct callout *c;
uint64_t t;
while ((c = list_peek_head_type(&callout_queue, struct callout, list)) != NULL) {
t = timer_get_ticks();
/* if the event has expired */
if (c->sched_ticks <= t) {
// printf("callout %p: invoked, scheduled %llu now %llu\n", c, c->sched_ticks, t);
/* remove from the list and call out */
list_delete(&c->list);
c->callback(c, c->arg);
} else {
/* callout in the future, schedule callback and we're done */
timer_deadline_enter(c->sched_ticks, callout_deadline);
break;
}
}
}
+202
View File
@@ -0,0 +1,202 @@
/*
* Copyright (C) 2007-2008 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.
*/
#include <arch.h>
#include <sys.h>
#include <sys/task.h>
#include <debug.h>
#include <lib/cbuf.h>
#include <drivers/power.h>
#if WITH_HW_UART
# include <drivers/uart.h>
# if WITH_TARGET_CONFIG
# include <target/uartconfig.h>
# elif WITH_PLATFORM_UARTCONFIG
# include <platform/uartconfig.h>
# endif
#endif
#if APPLICATION_SECUREROM
# define DEBUG_QUEUE_LEN 256
#else
# define DEBUG_QUEUE_LEN 4096
#endif
static struct task_event debug_event;
static struct cbuf *debug_cbuf;
#if WITH_USB_MODE_RECOVERY
// Use USB serial debug, unless there's a dockfifo, because spew from that
// driver will deadlock us.
#if !defined(USE_USB_DEBUG) && !defined(WITH_HW_DOCKFIFO_BULK)
#define USE_USB_DEBUG 1
#endif
#include <drivers/usb/usb_public.h>
#endif // WITH_USB_MODE_RECOVERY
#if WITH_TBT_MODE_RECOVERY
#ifndef USE_TBT_DEBUG
#define USE_TBT_DEBUG 1
#endif
#include <drivers/thunderbolt/thunderboot.h>
#endif // WITH_TBT_MODE_RECOVERY
#if WITH_ARM_DCC
# include <arch/arm/arm.h>
#endif
#if WITH_SHM_CONSOLE
# include <drivers/shmcon.h>
#endif
#if WITH_HW_DOCKFIFO_UART
# include <drivers/dockfifo/dockfifo.h>
#endif
#if WITH_HW_DOCKCHANNEL_UART
# include <drivers/dockchannel/dockchannel.h>
#endif
int debug_getchar(void)
{
ssize_t ret;
char c;
ASSERT(NULL != debug_cbuf);
event_wait(&debug_event);
ret = cbuf_read_char(debug_cbuf, &c);
ASSERT(ret >= 0);
return c;
}
int debug_getchar_nowait(void)
{
ssize_t ret;
char c;
ASSERT(NULL != debug_cbuf);
ret = cbuf_read_char(debug_cbuf, &c);
if (ret < 1) {
return -1;
}
return c;
}
int debug_pushchar(int c)
{
ASSERT(NULL != debug_cbuf);
return cbuf_write_char(debug_cbuf, c);
}
void debug_init(void)
{
debug_cbuf = cbuf_create(DEBUG_QUEUE_LEN, &debug_event);
}
int DebugUartReady = 0;
void debug_enable_uarts(int debug_uarts)
{
DebugUartReady |= debug_uarts;
}
void debug_putchar(int c)
{
#if USE_USB_DEBUG
usb_serial_putchar(c);
#endif
#if USE_TBT_DEBUG
thunderboot_putchar(c);
#endif
#if defined(DEBUG_SERIAL_PORT)
if ((DebugUartReady & kPowerNVRAMiBootDebugIAPSerial) != 0) {
if (c == '\n')
uart_putc(DEBUG_SERIAL_PORT, '\r');
uart_putc(DEBUG_SERIAL_PORT, c);
}
#endif
#if defined(DEBUG_SERIAL_PORT2)
if ((DebugUartReady & kPowerNVRAMiBootDebugAltSerial) != 0) {
if (c == '\n')
uart_putc(DEBUG_SERIAL_PORT2, '\r');
uart_putc(DEBUG_SERIAL_PORT2, c);
}
#endif
#if WITH_ARM_DCC
// always output dcc
arm_write_dcc_char(c);
#endif
#if WITH_SHM_CONSOLE
if ((DebugUartReady & kPowerNVRAMiBootDebugJtag) != 0) {
if (c == '\n')
shmcon_putc(0, '\r');
shmcon_putc(0, c);
}
#endif
#if WITH_HW_DOCKFIFO_UART
if ((DebugUartReady & kPowerNVRAMiBootDebugIAPSerial) != 0) {
if (c == '\n')
dockfifo_uart_putc('\r');
dockfifo_uart_putc(c);
}
#endif
#if WITH_HW_DOCKCHANNEL_UART
if ((DebugUartReady & kPowerNVRAMiBootDebugIAPSerial) != 0) {
if (c == '\n')
dockchannel_uart_putc('\r');
dockchannel_uart_putc(c);
}
#endif
#if WITH_APPLICATION_PUTCHAR
application_putchar(c);
#endif
}
int debug_run_script(const char *addr)
{
char lastchar;
// printf("running script at %p\n", addr);
/* start stuffing data into the input queue at the specified address until we hit an EOF char */
lastchar = 0;
while ((*addr != 0x04) && (*addr != 0)) {
debug_pushchar(*addr);
lastchar = *addr;
addr++;
}
if (lastchar != '\n')
debug_pushchar('\n');
// printf("finished running script (EOF at %p)\n", addr);
return 0;
}
+203
View File
@@ -0,0 +1,203 @@
/*
* 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.
*/
#include <arch.h>
#include <lib/libc.h>
#include <lib/random.h>
#include <platform.h>
#include <sys.h>
#include <sys/boot.h>
#include <debug.h>
#if WITH_CONSISTENT_DBG
#include <drivers/consistent_debug.h>
#endif
#if WITH_HW_TIMER
#include <platform/timer.h>
#endif
/*
* Make the panic info easy to find.
*/
char * gPanicStr; /* pointer to current panic string or NULL if not doing panic */
const char * gPanicFunc; /* pointer to function calling panic */
#if defined(__LP64__)
static char panicBuf[1024]; /* buffer for constructed panic message */
#else
static char panicBuf[512]; /* buffer for constructed panic message */
#endif
static unsigned panicDepth = 0;
static u_int64_t panicStamp;
static const char doublePanic[] = "double panic in ";
void _panic(const char *func, const char *str, ...)
{
va_list ap;
#if WITH_PANIC_HOOKS
void ** cursor;
struct panic_hook * hook;
#endif
/* There are cases where panic can spiral out of control if the task structure
* was demolished. Detect recursion here before doing anything else, and STOP
* (with interrupts known to have been masked). */
if (++panicDepth > 2)
arch_spin();
/* make sure that interrupts are masked and don't get enabled during panic */
enter_critical_section();
if (NULL != gPanicStr) {
/*
* We are already trying to panic, so this is very bad.
* Do our very best to get the 'double panic' string into
* the panic buffer.
*/
memcpy(panicBuf, doublePanic, sizeof(doublePanic));
gPanicFunc = func;
strlcat(panicBuf, func, sizeof(panicBuf));
/* clean the cache so that the panic string is in memory */
platform_cache_operation(CACHE_PANIC | CACHE_CLEAN, 0, 0);
/* and try to print it */
puts("\n\n");
puts(panicBuf);
puts("\n\n");
/* spin here - not safe to do anything else */
arch_spin();
}
#if WITH_HW_TIMER
panicStamp = timer_get_ticks();
#endif
/*
* First pass through the panic path
*/
/* gPanicFunc can be compared with NULL to test whether we are panicking */
gPanicFunc = func;
/* construct the panic string */
gPanicStr = panicBuf;
va_start(ap, str);
vsnprintf(panicBuf, sizeof(panicBuf), str, ap);
va_end(ap);
/* clean the cache so that the panic string is in memory */
platform_cache_operation(CACHE_PANIC | CACHE_CLEAN, 0, 0);
/* emit it */
puts("\npanic: ");
puts(func);
puts(": ");
puts(panicBuf);
puts("\n\n");
#if WITH_CONSISTENT_DBG && (PRODUCT_IBEC || PRODUCT_IBOOT)
consistent_debug_update_ap_cpr(DBG_CPR_STATE_CRASHED, DBG_CPR_AP_PANICKED_IN_IBOOT);
// Register location of panic string
dbg_record_header_t dbghdr;
dbghdr.physaddr = (uintptr_t)(mem_static_map_physical((uintptr_t)panicBuf));
dbghdr.length = sizeof(panicBuf);
dbghdr.record_id = kDbgIdPanicHeaderAP;
consistent_debug_register_header(dbghdr);
#endif
#if WITH_PANIC_HOOKS
/* run the set of panic handlers */
LINKER_SET_FOREACH(cursor, panic_hooks) {
hook = (struct panic_hook *)*cursor;
hook->func(hook->arg);
}
#endif
/* XXX try to drain the console here */
/* clean the cache again to get console output out in case the application is saving it */
platform_cache_operation(CACHE_PANIC | CACHE_CLEAN, 0, 0);
#if !DEBUG_BUILD
platform_reset(true);
#else
halt();
#endif
}
void abort(void)
{
panic("abort");
}
void halt()
{
printf("\nsystem halted, spinning forever...\n");
/* try to quiesce hardware to make JTAG easier */
//prepare_and_jump(BOOT_HALT, (void *)(uintptr_t)&arch_spin, NULL);
arch_spin();
}
#if defined(__SSP_ALL__)
#error "Can't compile stack.c with -fstack-protector-all. That'd emit a stack check fault on sys_init_stack!"
#endif
/*
* Stack overflow testing.
*/
#ifdef __arm64__
#define DEFAULT_STACK_COOKIE 0x4752400444303631ull // 'GRD\0D061'
uint64_t __stack_chk_guard __used = DEFAULT_STACK_COOKIE;
#else
#define DEFAULT_STACK_COOKIE 'GRD\0'
uint32_t __stack_chk_guard __used = DEFAULT_STACK_COOKIE;
#endif
#if WITH_RANDOM
// this needs to be outside of sys_init_stack_cookie to stop -fstack-protector-strong from tripping
static uint8_t stack_chk_guard_zero_byte = 0;
#endif
// WARNING: This function cannot be called by anything that returns "normally"
// without risking a false stack overflow panic.
void sys_init_stack_cookie(void)
{
#if WITH_RANDOM
uint8_t *guard = (uint8_t*)&__stack_chk_guard;
// This is tricky. You can't do anything in this function that would
// cause the compiler to insert its stack validation cookie into
// the stack frame because we're changing the value of the cookie
// that the stack check code checks.
if (random_get_bytes((u_int8_t *)&__stack_chk_guard, sizeof(__stack_chk_guard)) != 0) {
// In case of failure, put back the static cookie just in case.
__stack_chk_guard = DEFAULT_STACK_COOKIE;
}
// Grab a byte of entropy and use that value as an index to stuff a
// zero byte into the cookie to block string functions from reading
// past the cookie.
random_get_bytes(&stack_chk_guard_zero_byte, sizeof(stack_chk_guard_zero_byte));
guard[stack_chk_guard_zero_byte & (sizeof(__stack_chk_guard) - 1)] = 0;
#endif
}
void __noreturn __used
__stack_chk_fail(void)
{
panic("stack corrupted");
}
+66
View File
@@ -0,0 +1,66 @@
/*
* Copyright (C) 2014-2015 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.
*/
#include <debug.h>
#include <sys/hash.h>
#include <sys/menu.h>
#if WITH_SHA2_384
void sha384_calculate(const void *buffer, size_t length, void *result, size_t out_len)
{
RELEASE_ASSERT(out_len >= CCSHA384_OUTPUT_SIZE);
ccdigest(ccsha384_di(), length, buffer, result);
}
#endif
#if !HOST_TEST
void hash_calculate(const void *in_ptr, size_t in_len, void *out_ptr, size_t out_len)
{
RELEASE_ASSERT(out_len >= HASH_OUTPUT_SIZE);
#if WITH_SHA2_384
sha384_calculate(in_ptr, in_len, out_ptr, out_len);
#else // SHA1
sha1_calculate(in_ptr, in_len, out_ptr);
#endif
}
#if WITH_SHA2_384 && WITH_MENU
int do_sha384(int argc, struct cmd_arg *args)
{
u_int8_t hash[CCSHA384_OUTPUT_SIZE];
u_int32_t cnt;
if (argc < 3) {
printf("not enough arguments.\n");
printf("%s <address> <len>\n", args[0].str);
return -1;
}
if (!security_allow_memory((void *)args[1].u, args[2].u)) {
printf("Permission Denied\n");
return -1;
}
sha384_calculate((void *)args[1].u, args[2].u, hash, sizeof(hash));
printf("sha384 of 0x%08lx for 0x%08lx bytes: ", args[1].u, args[2].u);
for (cnt = 0; cnt < CCSHA384_OUTPUT_SIZE; cnt++)
printf("%02x%s", hash[cnt], (cnt != CCSHA384_OUTPUT_SIZE-1) ? ":" : "\n");
return 0;
}
MENU_COMMAND_DEVELOPMENT(sha384, do_sha384, "SHA_384 hash of specified memory address range.", NULL);
#endif // WITH_SHA2_384 && WITH_MENU
#endif // !HOST_TEST */
+95
View File
@@ -0,0 +1,95 @@
/*
* Copyright (C) 2006-2011 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.
*/
#include <debug.h>
#include <arch.h>
#include <compiler.h>
#include <lib/env.h>
#include <lib/heap.h>
#include <lib/mib.h>
#include <lib/random.h>
#include <platform/memmap.h>
#include <sys.h>
#include <sys/task.h>
#include <sys/security.h>
#include <sys/callout.h>
/* these need to be non-static and initialised for applications that patch them */
#define HEAP_SIZE_UNPATCHED ((size_t)-1)
void *heap_base = (void *)-1;
size_t heap_size = HEAP_SIZE_UNPATCHED;
MIB_CONSTANT_PTR(kMIBBuildBanner, kOIDTypeString|kOIDDataIndirect, (void *)&build_banner_string);
MIB_CONSTANT_PTR(kMIBBuildStyle, kOIDTypeString|kOIDDataIndirect, (void *)&build_style_string);
MIB_CONSTANT_PTR(kMIBBuildTag, kOIDTypeString|kOIDDataIndirect, (void *)&build_tag_string);
/* called from each binary's main() routine to initialize basic system services */
void sys_init(void)
{
/*
* Initialise the heap.
*
* If HEAP_END is defined, we assume that we are going to
* configure the heap size using it.
*
* If HEAP_BASE is defined, we respect the definition. Otherwise
* we start the heap at the end of the __DATA segment.
*
* If HEAP_END is not defined, someone may have patched heap_base/
* heap_end, so we check and create a heap with their values if they
* have.
*/
#ifdef HEAP_END
# ifdef HEAP_BASE
/* we have a defined base for the heap */
heap_base = (void *)HEAP_BASE;
# else
/* create the heap at the end of the __DATA segment */
heap_base = __segment_end(__DATA);
# endif
/* compute the heap size*/
heap_size = HEAP_END - (uintptr_t)heap_base;
#endif
/* if we have computed (or had patched in) a heap size, create the heap */
if (heap_size != HEAP_SIZE_UNPATCHED) {
#if WITH_RANDOM
bool random_heap_cookie = mib_get_bool(kMIBTargetRandomHeapCookie);
if (random_heap_cookie) {
uint8_t heap_cookie[HEAP_COOKIE_SIZE];
random_get_bytes_noheap(heap_cookie, sizeof(heap_cookie), heap_base, heap_size);
heap_set_cookie(heap_cookie);
}
#endif
heap_add_chunk(heap_base, heap_size, true);
}
/* initialize security */
#if !WITH_NO_SECURITY
security_init(false);
#endif
#if WITH_ENV
/* populate the environment with some default values */
sys_setup_default_environment();
#endif
/* initialize the tasking system */
task_init();
/* after tasks are initialized, do some more cpu init (if needed) */
arch_cpu_init_posttasks();
/* initialize the debug i/o queue */
debug_init();
}
+61
View File
@@ -0,0 +1,61 @@
/*
* Copyright (C) 2006,2009 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.
*/
#include <arch.h>
#include <stdio.h>
#include <debug.h>
#include <sys.h>
#include <sys/task.h>
#if DEBUG_CRITICAL_SECTIONS
void _enter_critical_section(const char *from)
{
dprintf(DEBUG_SPEW, "enter_critical_section: %s %p %d\n", from, current_task, current_task->irq_disable_count);
#else
void enter_critical_section(void)
{
#endif
RELEASE_ASSERT(current_task->irq_disable_count >= 0);
RELEASE_ASSERT(current_task->irq_disable_count < 1000);
current_task->irq_disable_count++;
if (current_task->irq_disable_count == 1) {
arch_disable_ints();
}
}
#if DEBUG_CRITICAL_SECTIONS
void _exit_critical_section(const char *from)
{
dprintf(DEBUG_SPEW, "exit_critical_section: %s %p %d\n", from, current_task, current_task->irq_disable_count);
#else
void exit_critical_section(void)
{
#endif
RELEASE_ASSERT(current_task->irq_disable_count > 0);
current_task->irq_disable_count--;
if (current_task->irq_disable_count == 0) {
arch_enable_ints();
}
}
/* the following are only used in interrupt handler glue */
void _irq_enter_critical_section(void)
{
RELEASE_ASSERT(current_task->irq_disable_count >= 0);
RELEASE_ASSERT(current_task->irq_disable_count < 1000);
current_task->irq_disable_count += 100;
}
void _irq_exit_critical_section(void)
{
RELEASE_ASSERT(current_task->irq_disable_count >= 100);
current_task->irq_disable_count -= 100;
}
+92
View File
@@ -0,0 +1,92 @@
/*
* Copyright (C) 2009 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.
*/
/*
* Generic memory mapping functions.
*/
#include <sys/types.h>
#include <sys.h>
static struct mem_static_map_entry *
mem_static_find_virtual(uintptr_t addr, ptrdiff_t *offset)
{
struct mem_static_map_entry *mp;
for (mp = mem_static_map_entries; mp->size != 0; mp++) {
/* is this an entry in a cached mapping? */
if ((MAP_NO_ENTRY != mp->cached_base) &&
(addr >= mp->cached_base) &&
(addr <= (mp->cached_base + mp->size - 1))) {
*offset = addr - mp->cached_base;
return(mp);
}
/* is this an entry in an uncached mapping? */
if ((mp->uncached_base != MAP_NO_ENTRY) &&
(addr >= mp->uncached_base) &&
(addr <= (mp->uncached_base + mp->size - 1))) {
*offset = addr - mp->uncached_base;
return(mp);
}
}
return(NULL);
}
static struct mem_static_map_entry *
mem_static_find_physical(uintptr_t addr)
{
struct mem_static_map_entry *mp;
for (mp = mem_static_map_entries; mp->size != 0; mp++) {
/* is this an entry in a physical mapping? */
if ((MAP_NO_ENTRY != mp->physical_base) &&
(addr >= mp->physical_base) &&
(addr <= (mp->physical_base + mp->size - 1)))
return(mp);
}
return(NULL);
}
void *
mem_static_map_cached(uintptr_t ptr)
{
struct mem_static_map_entry *mp;
ptrdiff_t offset;
mp = mem_static_find_virtual(ptr, &offset);
if (NULL != mp)
return((void *)(mp->cached_base + offset));
return(MAP_FAILED);
}
void *
mem_static_map_uncached(uintptr_t ptr)
{
struct mem_static_map_entry *mp;
ptrdiff_t offset;
mp = mem_static_find_virtual(ptr, &offset);
if (NULL != mp)
return((void *)(mp->uncached_base + offset));
return(MAP_FAILED);
}
uintptr_t
mem_static_map_physical(uintptr_t ptr)
{
struct mem_static_map_entry *mp;
ptrdiff_t offset;
mp = mem_static_find_virtual(ptr, &offset);
if (NULL != mp)
return(mp->physical_base + offset);
return(MAP_NO_ENTRY);
}
+502
View File
@@ -0,0 +1,502 @@
/*
* Copyright (C) 2007-2008 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.
*/
#include <stdio.h>
#include <string.h>
#include <debug.h>
#include <sys.h>
#include <sys/menu.h>
#include <sys/task.h>
#include <platform.h>
#include <platform/memmap.h>
#include <drivers/power.h>
#include <lib/env.h>
#if WITH_MENU
#if !WITH_SIMPLE_MENU
// 0x1b 0x5b 0x41 uparrow
// 0x1b 0x5b 0x42 downarrow
// 0x1b 0x5b 0x43 rightarrow
// 0x1b 0x5b 0x44 leftarrow
#define HISTORY_SIZE 16
static char (*history)[256];
static uint32_t curr_history_pos = 0;
#define kTokenBufSize (1024)
#define kMaxMenuArgs 64
utime_t gMenuLastActivityTime;
static char *token_buf;
static char *console_prompt;
struct task_event gMenuTaskReadyEvent = EVENT_STATIC_INIT(gMenuTaskReadyEvent, false, 0);
static char *get_line(const char *prompt, char *buf, int buf_size)
{
int i;
int escape;
uint32_t history_pos = curr_history_pos;
uint32_t saved_history_pos = curr_history_pos;
do_prompt:
puts(prompt);
history[curr_history_pos][0] = 0;
i = 0;
escape = 0;
for (;;) {
char c = getchar();
// printf("c = 0x%x (%c)\n", c, c);
/* Update activity time on any new input. */
gMenuLastActivityTime = system_time();
switch (c) {
case '\n':
escape = 0;
putchar('\n');
if (i != 0) {
buf[i] = 0;
/* save the history, if it's different from the last command */
if (strcmp(buf, history[(curr_history_pos - 1) % HISTORY_SIZE]) != 0) {
strlcpy(history[curr_history_pos], buf, sizeof(history[curr_history_pos]));
curr_history_pos = (curr_history_pos + 1) % HISTORY_SIZE;
}
return buf;
} else {
goto do_prompt;
}
break;
case 0x8: // backspace
case 0x7f: // del
escape = 0;
if (i > 0) {
i--;
putchar(0x8);
putchar(0x20);
putchar(0x8);
}
break;
case 0x1b:
escape = 1;
break;
case 0x5b:
if (escape > 0)
escape = 2;
break;
case 0x41: case 0x42:
if (escape < 2) {
goto regchar;
} else {
// up/down arrow
char *new_history;
if (c == 0x41) {
int temp = history_pos;
history_pos = (history_pos - 1) % HISTORY_SIZE;
if (history_pos == saved_history_pos) {
// printf("%d %d\n", history_pos, saved_history_pos);
// we've wrapped around
history_pos = temp;
break;
}
if (strlen(history[history_pos]) == 0) {
// printf("%p %d, len 0\n", history[history_pos], history_pos);
// we've walked before the start of history
history_pos = temp;
break;
}
} else {
if (history_pos == saved_history_pos)
break; // can't go forward past top of the history
history_pos = (history_pos + 1) % HISTORY_SIZE;
}
new_history = history[history_pos];
/* wipe out the line */
while(i > 0) {
putchar(0x8);
putchar(' ');
putchar(0x8);
i--;
}
/* output the new line */
for (i=0; new_history[i] != 0; i++) {
buf[i] = new_history[i];
putchar(new_history[i]);
}
}
escape = 0;
break;
case 0x43: case 0x44:
if (escape < 2) {
goto regchar;
} else {
// left & right arrow
escape = 0;
}
break;
default:
regchar:
escape = 0;
if (i < (buf_size - 1)) {
buf[i++] = c;
putchar(c);
}
}
}
}
/*
* chop a string into multiple tokens, each pointed to by the tokens array.
* if an unescaped ';' is hit, stop tokenizing and return the remainder of
* the line in *line_remainder. If no ';' is hit, return null in *line_remainder.
*/
static int tokenize(const char *buf, char **tokens, int token_count, const char **line_remainder)
{
bool done;
bool done_after;
int inpos = 0;
int outpos = 0;
int outpos_token_start = 0;
int token = 0;
char last_char = 0;
enum {
INITIAL,
CONSUME_WHITESPACE,
TOKEN_START,
TOKEN,
QUOTED_TOKEN,
FINISH_TOKEN,
#if WITH_ENV
ENV_TOKEN,
FINISH_ENV_TOKEN,
#endif
} state = INITIAL;
*line_remainder = NULL;
done = done_after = false;
while (!done) {
/* end of input buffer, finish off whatever token we're in the middle of and exit */
if ((buf[inpos] == 0) || (outpos >= (kTokenBufSize - 1))) {
done = true;
if (state == TOKEN || state == QUOTED_TOKEN || state == FINISH_TOKEN)
state = FINISH_TOKEN;
#if WITH_ENV
else if (state == ENV_TOKEN)
state = FINISH_ENV_TOKEN;
#endif
else
break;
}
if (done_after)
done = true;
// printf("tok: in %d (%c) out %d tok %d state %d\n",
// inpos, buf[inpos], outpos, token, state);
switch (state) {
case INITIAL:
case CONSUME_WHITESPACE:
/* eat whitespace until we see the start of a token */
if (isspace(buf[inpos])) {
last_char = buf[inpos];
inpos++;
continue;
}
state = TOKEN_START;
break;
case TOKEN_START:
/* start of a token, examine the first character to see if we need to do anything special */
outpos_token_start = outpos;
if (buf[inpos] == '#') {
/* comment, ignore the rest of the line */
last_char = buf[inpos];
done = true;
break;
#if WITH_ENV
} else if (buf[inpos] == '$') {
/* environment variable */
last_char = buf[inpos];
inpos++;
state = ENV_TOKEN;
tokens[token] = &token_buf[outpos];
#endif
} else if (buf[inpos] == ';') {
/* if we hit a unescaped ';', it's the end of the line */
*line_remainder = &buf[inpos+1];
done = true;
break;
} else if (buf[inpos] == '"') {
/* quoted token */
last_char = buf[inpos];
inpos++;
state = QUOTED_TOKEN;
tokens[token] = &token_buf[outpos];
} else {
state = TOKEN;
tokens[token] = &token_buf[outpos];
}
break;
case TOKEN:
/* consume characters until we hit whitespace */
if (isspace(buf[inpos])) {
/* whitespace, null terminate current token and switch to whitespace consume state */
last_char = buf[inpos];
state = FINISH_TOKEN;
break;
} else if (buf[inpos] == ';') {
/* if we hit a unescaped ';', it's the end of the line */
if (last_char != '\\') {
*line_remainder = &buf[inpos+1];
state = FINISH_TOKEN;
done_after = true;
break;
}
}
last_char = buf[inpos];
if (buf[inpos] != '\\')
token_buf[outpos++] = buf[inpos];
inpos++;
break;
case QUOTED_TOKEN:
/* consume characters until we hit terminating quote */
if (buf[inpos] == '"') {
/* terminating quote, null terminate current token and switch to whitespace consume state */
inpos++; // consume the quote
state = FINISH_TOKEN;
break;
}
last_char = buf[inpos];
token_buf[outpos++] = buf[inpos++];
break;
case FINISH_TOKEN:
/* finish whatever token we're dealing with */
token_buf[outpos++] = 0;
if (++token < token_count)
state = CONSUME_WHITESPACE;
else {
*line_remainder = &buf[inpos];
done = true;
}
break;
#if WITH_ENV
case ENV_TOKEN:
/* consume characters until we hit whitespace */
if (isspace(buf[inpos])) {
/* whitespace, we've now got the environment variable we want to read */
last_char = buf[inpos];
state = FINISH_ENV_TOKEN;
break;
}
last_char = buf[inpos];
token_buf[outpos++] = buf[inpos++];
break;
case FINISH_ENV_TOKEN: {
/* the current token now holds the environment variable we want to read */
const char *env;
token_buf[outpos++] = 0;
/* read in the environment variable */
env = env_get(tokens[token]);
if (!env) {
printf("\ncould not read environment var '%s'\n", tokens[token]);
return -1;
}
/* copy the value of the environment variable on top of the current token */
strlcpy(&token_buf[outpos_token_start], env, kTokenBufSize - outpos_token_start);
outpos = outpos_token_start + strlen(token_buf + outpos_token_start) + 1;
if (++token < token_count)
state = CONSUME_WHITESPACE;
else {
*line_remainder = &buf[inpos];
done = true;
}
break;
}
#endif
default:
panic("tokenize: got into an invalid state\n");
}
}
return token;
}
bool process_command_line(char *line, int* ret_val)
{
char *tokens[kMaxMenuArgs];
struct cmd_arg args[kMaxMenuArgs];
int token_count;
int ret = 0;
const struct cmd_menu_item *menu_entry = NULL;
void **menu_cursor;
int argnum;
/* don't allow ourselves to be called before the menu task has started */
if (NULL == token_buf)
return(false);
/* Update activity; we might have come from outside the get_line() loop */
gMenuLastActivityTime = system_time();
while(line) {
memset(tokens, 0, sizeof(tokens));
memset(args, 0, sizeof(args));
token_count = tokenize(line, tokens, sizeof(tokens)/sizeof(char *), (const char **)&line);
if (token_count <= 0)
continue;
// printf("buf %p, line %p\n", buf, line);
// for(i=0; i < token_count; i++)
// printf("\t%d: '%s'\n", i, tokens[i]);
/* if the command starts with '?', only execute it if the last command returned a positive error */
if (tokens[0][0] == '?') {
tokens[0]++;
if (ret < 0)
continue;
}
menu_entry = NULL;
LINKER_SET_FOREACH(menu_cursor, menu) {
menu_entry = (const struct cmd_menu_item *)*menu_cursor;
if (!strcmp(menu_entry->cmd, tokens[0])) {
/* parse the arglist */
for (argnum = 0; argnum < kMaxMenuArgs; argnum++) {
/* are we done? */
if (argnum >= token_count)
break;
args[argnum].n = strtol(tokens[argnum], NULL, 0);
args[argnum].u = strtoul(tokens[argnum], NULL, 0);
args[argnum].h = strtol(tokens[argnum], NULL, 16);
if (!strcmp(tokens[argnum], "true"))
args[argnum].b = true;
else if (!strcmp(tokens[argnum], "false"))
args[argnum].b = false;
else
args[argnum].b = args[argnum].n ? true : false;
args[argnum].str = tokens[argnum];
}
/* call the routine */
ret = menu_entry->func(argnum, args);
if (ret_val)
*ret_val = ret;
#if WITH_ENV
/* stick the result in an environment variable */
env_set_uint("?", ret, 0);
#endif
break;
} else {
menu_entry = NULL;
}
}
}
return (menu_entry == NULL);
}
int menu_task(void *arg)
{
char *buf;
/* allocate the history buffer */
history = calloc(1, HISTORY_SIZE * sizeof(*history));
/* allocate the line buffer */
buf = malloc(512);
/* allocate the token buffer */
token_buf = malloc(kTokenBufSize);
/* signal others waiting for us */
event_signal(&gMenuTaskReadyEvent);
menu_prompt(NULL);
for (;;) {
/* prompt */
puts("\x1b[m");
get_line(console_prompt, buf, 512);
if (process_command_line(buf, NULL)) {
printf("\x1b[1m?SYNTAX ERROR\n");
}
}
return 0;
}
char *menu_prompt(char *new_prompt)
{
char *ret;
ret = console_prompt;
if (NULL != new_prompt) {
console_prompt = new_prompt;
} else {
console_prompt = "] ";
}
return(ret);
}
static int do_help(int argc, struct cmd_arg *args)
{
const struct cmd_menu_item *menu_entry;
void **menu_cursor;
printf("command list:\n");
LINKER_SET_FOREACH(menu_cursor, menu) {
menu_entry = (const struct cmd_menu_item *)*menu_cursor;
if (menu_entry->help)
printf(" %-16.16s %s\n", menu_entry->cmd, menu_entry->help);
}
return 0;
}
MENU_COMMAND_DEVELOPMENT(help, do_help, NULL, NULL);
#if 0
static int do_argtest(int argc, struct cmd_arg *args)
{
int i;
printf("argtest, %d args:\n", argc);
for (i=0; i<argc; i++) {
printf("%d: n %d u %u h %x str %p (%s)\n", i, args[i].n, args[i].u, args[i].h, args[i].str, args[i].str);
}
return 0;
}
MENU_COMMAND_DEBUG(argtest, do_argtest, NULL, NULL);
#endif
#endif /* !WITH_SIMPLE_MENU */
#endif /* WITH_MENU */
+45
View File
@@ -0,0 +1,45 @@
# Copyright (C) 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.
#
# generic sys stuff
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULES += \
lib/cbuf
# Some of these files contain nothing if the corresponding WITH_XXX is not defined:
#
# menu.o WITH_MENU
# simple_menu.o WITH_MENU
ALL_OBJS += \
$(LOCAL_DIR)/boot.o \
$(LOCAL_DIR)/callout.o \
$(LOCAL_DIR)/debug.o \
$(LOCAL_DIR)/halt.o \
$(LOCAL_DIR)/hash.o \
$(LOCAL_DIR)/init.o \
$(LOCAL_DIR)/lock.o \
$(LOCAL_DIR)/mem.o \
$(LOCAL_DIR)/menu.o \
$(LOCAL_DIR)/simple_menu.o \
$(LOCAL_DIR)/task.o \
$(LOCAL_DIR)/time.o
# conditionally include the security module
ifeq (${WITH_NO_SECURITY},true)
OPTIONS += \
WITH_NO_SECURITY=1
else
ALL_OBJS += \
$(LOCAL_DIR)/security.o
endif
+461
View File
@@ -0,0 +1,461 @@
/*
* Copyright (C) 2007-2015 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.
*/
#include <debug.h>
#include <drivers/aes.h>
#include <drivers/sha1.h>
#include <lib/libc.h>
#include <lib/devicetree.h>
#include <lib/ramdisk.h>
#include <platform.h>
#include <platform/memmap.h>
#include <sys/security.h>
#define RELEASE_SECURITY_MODE (kSecurityModeGIDKeyAccess | kSecurityModeUIDKeyAccess | kSecurityModeProdCertAccess | kSecurityStatusSystemTrusted)
#define SECRET_SECURITY_MODE (RELEASE_SECURITY_MODE | kSecurityModeKDPEnabled)
// XXX Remove this once image4 transition for older platforms/targets is complete.
#if !WITH_IMAGE4
#define DEVELOPMENT_SECURITY_MODE (RELEASE_SECURITY_MODE | kSecurityModeExUntrust)
#else
#define DEVELOPMENT_SECURITY_MODE (RELEASE_SECURITY_MODE)
#endif
#define DEBUG_SECURITY_MODE (DEVELOPMENT_SECURITY_MODE | kSecurityModeKDPEnabled | kSecurityModeDebugCmd | kSecurityModeMemAccess | kSecurityModeHWAccess)
#if RELEASE_BUILD
#define DEFAULT_SECURITY_MODE RELEASE_SECURITY_MODE
#endif
#if SECRET_BUILD
#define DEFAULT_SECURITY_MODE SECRET_SECURITY_MODE
#endif
#if DEVELOPMENT_BUILD
#define DEFAULT_SECURITY_MODE DEVELOPMENT_SECURITY_MODE
#endif
#if DEBUG_BUILD
#define DEFAULT_SECURITY_MODE DEBUG_SECURITY_MODE
#endif
#ifndef DEFAULT_SECURITY_MODE
#error Security: Unknown build style
#endif
#define CLEAR_MEM_CHUNK_SIZE (256 * 1024 * 1024)
static security_mode_t security_mode;
static addr_t insecure_memory_start;
static addr_t insecure_memory_end;
#if !DISABLE_CLEAR_MEMORY
static bool secure_memory_cleared;
#endif
#if WITH_IMAGE4
static u_int8_t security_boot_manifest_hash[HASH_OUTPUT_SIZE];
static bool security_environment_consolidated;
#endif // WITH_IMAGE4
static void security_clear_mem_in_chunks(char *dst, size_t count);
int security_init(bool clear_memory)
{
security_mode = DEFAULT_SECURITY_MODE;
if (platform_get_secure_mode()) {
security_mode |= kSecurityStatusSecureBoot;
} else {
#if APPLICATION_SECUREROM
// SecureROM allows untrusted execution if secure_mode is false
security_mode |= kSecurityModeExUntrust;
#endif
}
if (!platform_get_current_production_mode()) {
security_mode |= kSecurityModeDevCertAccess;
security_mode |= kSecurityModeKDPEnabled;
}
if (platform_get_lock_fuses_required()) {
security_mode |= kSecurityOptionLockFuses;
}
insecure_memory_start = -1;
insecure_memory_end = 0;
#if !DISABLE_CLEAR_MEMORY
if (clear_memory) {
/* Break up the memory region into chunks to keep watchdog alive in between the clearings */
security_clear_mem_in_chunks((char *)INSECURE_MEMORY_BASE, INSECURE_MEMORY_SIZE);
#ifdef SECURE_MEMORY_SIZE
if ((SECURE_MEMORY_SIZE != 0) && !secure_memory_cleared) {
/* Break up the memory region into chunks to keep watchdog alive in between the clearings */
security_clear_mem_in_chunks((char *)SECURE_MEMORY_BASE, SECURE_MEMORY_SIZE);
}
#endif
secure_memory_cleared = true;
}
#endif
security_protect_memory((void *)INSECURE_MEMORY_BASE, INSECURE_MEMORY_SIZE, false);
#if WITH_RAMDISK
ramdisk_init();
#endif
#if WITH_DEVICETREE
dt_init();
#endif
return 0;
}
bool security_allow_modes(security_mode_t modes)
{
bool result = (modes & security_mode) == modes;
if (result && ((modes & kSecurityModeExUntrust) != 0))
security_set_untrusted();
return result;
}
bool security_validate_image(security_image_t image_validity)
{
// Check if untrusted is allowed.
if ((image_validity == kSecurityImageUntrusted) && !security_allow_modes(kSecurityModeExUntrust)) {
image_validity = kSecurityImageInvalid;
}
return image_validity != kSecurityImageInvalid;
}
bool security_allow_memory(const void *address, size_t length)
{
addr_t addr = (addr_t)address, last = addr + length;
bool allow = false;
if (security_allow_modes(kSecurityModeMemAccess))
return true;
// Disallow wrap-around
if (last <= addr)
return false;
if ((insecure_memory_start <= addr) && (last <= insecure_memory_end))
allow = true;
return allow;
}
void security_protect_memory(const void *address, size_t length, bool protect)
{
addr_t addr = (addr_t)address, last = addr + length;
if (security_allow_modes(kSecurityModeMemAccess))
return;
if (protect) {
insecure_memory_start = -1;
insecure_memory_end = 0;
} else {
if (addr < insecure_memory_start)
insecure_memory_start = addr;
if (insecure_memory_end < last)
insecure_memory_end = last;
}
}
void security_enable_kdp(void)
{
if ((security_mode & kSecurityModeKDPEnabled) != 0)
return;
security_allow_modes(kSecurityModeExUntrust);
}
void security_set_untrusted(void)
{
security_mode &= ~(kSecurityModeGIDKeyAccess | kSecurityModeUIDKeyAccess | kSecurityStatusSystemTrusted);
security_mode |= kSecurityModeKDPEnabled;
}
void security_set_production_override(bool override)
{
security_mode &= ~kSecurityOptionClearProduction;
if (override)security_mode |= kSecurityOptionClearProduction;
}
bool security_get_production_override(void)
{
return (security_mode & kSecurityOptionClearProduction) != 0;
}
#if WITH_IMAGE4
bool security_get_effective_production_status(bool with_demotion)
{
bool device_production_status = platform_get_current_production_mode();
return (device_production_status ? (device_production_status ^ with_demotion) : false);
}
void security_set_boot_manifest_hash(u_int8_t *boot_manifest_hash)
{
security_mode &= ~kSecurityOptionBootManifestHashValid;
if (boot_manifest_hash == NULL) {
security_mode &= ~kSecurityOptionBootManifestHashValid;
} else {
security_mode |= kSecurityOptionBootManifestHashValid;
memcpy((void *)security_boot_manifest_hash, (const void *)boot_manifest_hash, sizeof(security_boot_manifest_hash));
}
}
bool security_get_boot_manifest_hash(u_int8_t *boot_manifest_hash, u_int32_t hash_length)
{
if (security_mode & kSecurityOptionBootManifestHashValid) {
RELEASE_ASSERT(boot_manifest_hash != NULL);
RELEASE_ASSERT(hash_length == sizeof(security_boot_manifest_hash));
memcpy((void *)boot_manifest_hash, (const void *)security_boot_manifest_hash, hash_length);
return true;
} else {
return false;
}
}
void security_set_mix_n_match_prevention_status(bool mix_n_match_enforced)
{
security_mode &= ~kSecurityOptionMixNMatchPrevented;
if (mix_n_match_enforced)
security_mode |= kSecurityOptionMixNMatchPrevented;
}
bool security_get_mix_n_match_prevention_status(void)
{
return (security_mode & kSecurityOptionMixNMatchPrevented);
}
void security_set_lock_fuses(void)
{
security_mode |= kSecurityOptionLockFuses;
}
bool security_get_lock_fuses(void)
{
return (security_mode & kSecurityOptionLockFuses);
}
bool security_restore_environment(void)
{
uint8_t boot_manifest_hash[HASH_OUTPUT_SIZE];
if (security_environment_consolidated)
return false;
security_set_mix_n_match_prevention_status(platform_get_mix_n_match_prevention_status());
if (platform_get_boot_manifest_hash((u_int8_t *)boot_manifest_hash) == 0)
security_set_boot_manifest_hash((u_int8_t *)boot_manifest_hash);
else
security_set_boot_manifest_hash(NULL);
if (security_get_production_override())
security_set_production_override(false);
if ((security_mode & (kSecurityModeGIDKeyAccess | kSecurityModeUIDKeyAccess | kSecurityStatusSystemTrusted)) == 0)
security_mode |= (kSecurityModeGIDKeyAccess | kSecurityModeUIDKeyAccess | kSecurityStatusSystemTrusted);
return true;
}
bool security_consolidate_environment(void)
{
/* demote production status if requested */
if (security_get_production_override())
platform_demote_production();
/* disable all keys not requested */
if (!security_allow_modes(kSecurityModeGIDKeyAccess))
platform_disable_keys(~0, 0);
if (!security_allow_modes(kSecurityModeUIDKeyAccess))
platform_disable_keys(0, ~0);
/* update next stage boot-manifest-hash, and related flags */
if (security_mode & kSecurityOptionBootManifestHashValid)
platform_set_boot_manifest_hash((u_int8_t *)security_boot_manifest_hash);
else
platform_set_boot_manifest_hash(NULL);
platform_set_mix_n_match_prevention_status(((security_mode & kSecurityOptionMixNMatchPrevented) == kSecurityOptionMixNMatchPrevented));
/* record environment was consolidated atleast once */
security_environment_consolidated = true;
return true;
}
#else // WITH_IMAGE4
bool security_consolidate_environment(void)
{
return false;
}
#endif // WITH_IMAGE4
static const char gSleepToken[] = "iBootSleepValid";
void security_create_sleep_token(addr_t address)
{
uint8_t key_buffer[16];
memcpy((void *)address, gSleepToken, sizeof(gSleepToken));
#if WITH_AES
if (!security_allow_modes(kSecurityModeUIDKeyAccess))
return;
memcpy(key_buffer, gSleepToken, sizeof(gSleepToken));
/* note that we ignore any errors from AES here */
aes_cbc_encrypt(key_buffer, key_buffer, sizeof(key_buffer), AES_KEY_TYPE_UID0, NULL, NULL);
aes_cbc_encrypt((u_int8_t *)address, (u_int8_t *)address, sizeof(gSleepToken), AES_KEY_TYPE_USER, key_buffer, NULL);
#endif
memset(key_buffer, 0, sizeof(key_buffer));
}
bool security_validate_sleep_token(addr_t address)
{
uint8_t key_buffer[16];
uint8_t token_buffer[16];
bool result = false;
#if WITH_AES
if (security_allow_modes(kSecurityModeUIDKeyAccess)) {
memcpy(token_buffer, gSleepToken, sizeof(token_buffer));
memcpy(key_buffer, gSleepToken, sizeof(key_buffer));
/* note that we ignore any errors from AES here */
aes_cbc_encrypt(key_buffer, key_buffer, sizeof(key_buffer), AES_KEY_TYPE_UID0, NULL, NULL);
aes_cbc_encrypt(token_buffer, token_buffer, sizeof(token_buffer), AES_KEY_TYPE_USER, key_buffer, NULL);
if (!memcmp_secure((void *)address, token_buffer, sizeof(token_buffer))) {
result = true;
goto out;
}
}
#endif
if (!memcmp_secure((void *)address, gSleepToken, sizeof(gSleepToken)) && security_allow_modes(kSecurityModeExUntrust)) {
result = true;
goto out;
}
out:
memset(key_buffer, 0, sizeof(key_buffer));
memset(token_buffer, 0, sizeof(token_buffer));
return result;
}
/*
* This function avoids clearing memory in one bzero call, since that might
* take too long such that watchdog fires (if enabled) and causes a full system reset
*/
static void security_clear_mem_in_chunks(char *dst, size_t count)
{
#if APPLICATION_SECUREROM && WITH_DMA_CLEAR
extern void platform_clear_mem_with_dma(char *dst, size_t count);
platform_clear_mem_with_dma(dst, count);
#else // !WITH_DMA_CLEAR || !APPLICATION_SECUREROM
size_t chunk_len;
do {
/* reset watchdog timer in case it's enabled */
platform_watchdog_tickle();
/* Only clear CLEAR_MEM_CHUNK_SIZE bytes at a time */
chunk_len = (count > CLEAR_MEM_CHUNK_SIZE) ? CLEAR_MEM_CHUNK_SIZE : count;
bzero((void *)dst, chunk_len);
dst += chunk_len;
count -= chunk_len;
}while (count > 0);
#endif // WITH_DMA_CLEAR && APPLICATION_SECUREROM
}
#if WITH_SIDP
#if APPLICATION_SECUREROM
void security_sidp_seal_rom_manifest(void)
{
// Is the boot manifest hash valid?
if (security_mode & kSecurityOptionBootManifestHashValid) {
// Copy the manifest hash to a word aligned buffer.
uint32_t manifest_buffer[HASH_OUTPUT_SIZE / sizeof(uint32_t)];
memcpy(manifest_buffer, security_boot_manifest_hash, HASH_OUTPUT_SIZE);
// Copy the manifest hash to ROM seal registers.
platform_sidp_set_rom_manifest(manifest_buffer, HASH_OUTPUT_SIZE);
} else {
// Clear the ROM seal registers.
platform_sidp_set_rom_manifest(NULL, 0);
}
// Lock the ROM seal.
platform_sidp_lock_rom_manifest();
}
#else // !APPLICATION_SECUREROM
void security_sidp_seal_boot_manifest(bool require_unlocked)
{
// The caller must have consolidated the security environment before
// calling this function.
RELEASE_ASSERT(security_environment_consolidated);
// Did a prior boot stage lock the manifest?
if (platform_sidp_boot_manifest_locked()) {
if (require_unlocked) {
panic("Boot manifest already locked");
}
// Yep, nothing to do.
dprintf(DEBUG_INFO, "SiDP boot manifest already locked\n");
return;
}
// Is the boot manifest hash valid?
if (security_mode & kSecurityOptionBootManifestHashValid) {
// Copy the manifest hash to a word aligned buffer.
uint32_t manifest_buffer[HASH_OUTPUT_SIZE / sizeof(uint32_t)];
memcpy(manifest_buffer, security_boot_manifest_hash, HASH_OUTPUT_SIZE);
// Copy the manifest hash to the bootloader seal registers.
platform_sidp_set_boot_manifest(manifest_buffer, HASH_OUTPUT_SIZE);
} else {
// Clear the bootloader seal registers.
platform_sidp_set_boot_manifest(NULL, 0);
}
// Mix-n-match allowed?
if (!security_get_mix_n_match_prevention_status()) {
platform_sidp_set_mix_n_match();
}
// Lock the boot manifest.
platform_sidp_lock_boot_manifest();
}
#endif // APPLICATION_SECUREROM
#endif // WITH_SIDP
+195
View File
@@ -0,0 +1,195 @@
/*
* Copyright (C) 2009 Apple 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.
*/
#include <stdio.h>
#include <string.h>
#include <debug.h>
#include <sys.h>
#include <sys/menu.h>
#include <sys/task.h>
#include <platform.h>
#include <platform/memmap.h>
#include <drivers/power.h>
#include <lib/env.h>
#if WITH_MENU
#if WITH_SIMPLE_MENU
#define kTokenBufSize 128
#define kMaxTokens 8
utime_t gMenuLastActivityTime;
static char *token_buf;
struct task_event gMenuTaskReadyEvent = EVENT_STATIC_INIT(gMenuTaskReadyEvent, false, 0);
/*
* Parse tokens from (buf).
*/
static int
tokenize(const char *buf, char **tokens, int token_count)
{
const char *in;
char *out, *out_limit;
int token;
enum {
WHITESPACE,
TOKEN,
DONE
} state;
in = buf;
out = token_buf;
out_limit = out + kTokenBufSize - 1;
token = 0;
state = WHITESPACE;
for (;;) {
/* state machine */
switch(state) {
case WHITESPACE:
/* if we hit the end of the input, bail now */
if ('\0' == *in) {
state = DONE;
break;
}
/* found a token starting? */
if (!isspace(*in)) {
tokens[token] = out;
state = TOKEN;
break;
}
/* discard and move on */
in++;
break;
case TOKEN:
/* output cursor has reached or exceeded the last safe character */
if (out >= out_limit) {
/* terminate at the last safe character */
*out_limit = '\0';
/* update the token count */
token++;
/* and we are done */
state = DONE;
break;
}
/* input cursor has reached the end of the input or whitespace */
if (('\0' == *in) || isspace(*in)) {
*out++ = '\0';
token++;
/* if the input is exhausted or we have run out of token space */
if (('\0' == *in) || (token >= token_count)) {
state = DONE;
} else {
/* return to discarding whitespace */
state = WHITESPACE;
}
break;
}
/* copy another character */
*out++ = *in++;
break;
case DONE:
return(token);
}
}
}
bool
process_command_line(char *line, int *ret_val)
{
char *tokens[kMaxTokens];
struct cmd_arg args[kMaxTokens];
const struct cmd_menu_item *menu_entry;
void **menu_cursor;
int argnum;
int token_count;
int ret;
/* don't allow ourselves to be called before the menu task has started */
if (NULL == token_buf)
return(true);
/* Update activity; we might have come from outside the get_line() loop */
gMenuLastActivityTime = system_time();
/* tokenize, will never return > kMaxTokens */
token_count = tokenize(line, tokens, kMaxTokens);
if (token_count > 0) {
LINKER_SET_FOREACH(menu_cursor, menu) {
menu_entry = (const struct cmd_menu_item *)*menu_cursor;
if (!strcmp(menu_entry->cmd, tokens[0])) {
/* parse the arglist */
for (argnum = 0; argnum < token_count; argnum++) {
/* are we done? */
if (argnum >= token_count)
break;
args[argnum].n = strtol(tokens[argnum], NULL, 0);
args[argnum].u = strtoul(tokens[argnum], NULL, 0);
args[argnum].h = strtol(tokens[argnum], NULL, 16);
if (!strcmp(tokens[argnum], "true"))
args[argnum].b = true;
else if (!strcmp(tokens[argnum], "false"))
args[argnum].b = false;
else
args[argnum].b = args[argnum].n ? true : false;
args[argnum].str = tokens[argnum];
}
/* call the routine */
ret = menu_entry->func(argnum, args);
if (ret_val)
*ret_val = ret;
#if WITH_ENV
/* stick the result in an environment variable */
env_set_uint("?", ret, 0);
#endif
return(false);
}
}
}
return(true);
}
int menu_task(void *arg)
{
/* allocate the token buffer */
token_buf = malloc(kTokenBufSize);
/* signal others waiting for us */
event_signal(&gMenuTaskReadyEvent);
/* spin throwing away console input */
for (;;) {
/* get an input character */
(void)getchar();
/* Update activity time on any new input. */
gMenuLastActivityTime = system_time();
}
return 0;
}
#endif /* WITH_SIMPLE_MENU */
#endif /* WITH_MENU */
+774
View File
@@ -0,0 +1,774 @@
/*
* Copyright (C) 2007-2009 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.
*/
#include <list.h>
#include <debug.h>
#include <string.h>
#include <arch.h>
#include <platform.h>
#include <lib/heap.h>
#include <lib/mib.h>
#include <lib/random.h>
#include <sys.h>
#include <sys/callout.h>
#include <sys/task.h>
#include <sys/menu.h>
#include <platform/timer.h>
#if !WITH_HW_TIMER
# error Cannot build task subsystem without timer support
#endif
#define DEFAULT_TASK_STACK_MAGIC 'stak'
/* list of all tasks */
static struct list_node task_list = LIST_INITIAL_VALUE(task_list);
static int task_count;
static int max_task_id;
/* global run queue */
static struct list_node run_q = LIST_INITIAL_VALUE(run_q);
static volatile int run_q_len;
/* initial bootstrapping task, partially constructed */
static struct task bootstrap_task = {
.magic = TASK_MAGIC,
.state = TASK_RUNNING,
.irq_disable_count = 1,
.routine = NULL,
.arg = NULL,
.stack_base = NULL,
.stack_len = 0,
.name = "bootstrap",
.magic2 = TASK_MAGIC2,
.task_id = 0,
};
/* idle task */
static int idle_task_routine(void *);
#ifndef IDLE_TASK_SIZE
#define IDLE_TASK_SIZE TASK_STACK_MIN
#endif
static uint8_t idle_task_stack[IDLE_TASK_SIZE] __attribute__ ((aligned(16)));
static struct task idle_task;
static uint64_t idle_ticks = 0ULL;
static uint64_t deep_idle_ticks = 0ULL;
static uint64_t boot_time_ticks;
static uint64_t shallow_idle_cnt = 0ULL;
static uint64_t deep_idle_cnt = 0ULL;
static uint64_t last_yield;
static uint64_t last_switch;
static uint32_t task_stack_magic = DEFAULT_TASK_STACK_MAGIC;
MIB_VARIABLE(kMIBSystemBootTime, kOIDTypeUInt64, boot_time_ticks);
MIB_VARIABLE(kMIBSystemIdleTime, kOIDTypeUInt64, idle_ticks);
static void
uptime_handler(u_int32_t oid __unused, void *arg __unused, void *data)
{
u_int64_t *resptr = (u_int64_t *)data;
u_int64_t now;
now = timer_get_ticks();
*resptr = now - boot_time_ticks;
}
MIB_FUNCTION(kMIBSystemUptime, kOIDTypeUInt64, uptime_handler, NULL);
/* currently running task */
struct task *current_task = &bootstrap_task;
#if defined(__arm__)
static uint32_t nullptr_value;
#endif
static bool deep_idle;
#ifndef DEEP_IDLE_THRESHOLD_US
#define DEEP_IDLE_THRESHOLD_US 1000
#endif
static volatile uint32_t deep_idle_threshold_us = 0; // <rdar://problem/8913103>
static struct task *task_create_etc(struct task *t, const char *name, task_routine routine, void *arg, void *stack, size_t stack_len);
static void insert_run_q_head(struct task *t);
static void insert_run_q_tail(struct task *t);
struct callout deep_idle_callout;
static void deep_idle_timeout(struct callout *co, void *arg)
{
deep_idle = true;
}
static int idle_task_routine(void *arg)
{
u_int64_t idle_enter, idle_leave;
u_int64_t *ticks_accumulator;
for(;;) {
task_yield();
idle_enter = timer_get_ticks();
enter_critical_section();
ticks_accumulator = & idle_ticks;
if (likely(run_q_len == 0)) {
if (deep_idle) {
ticks_accumulator = & deep_idle_ticks;
deep_idle_cnt++;
platform_deep_idle();
deep_idle = false;
} else {
/* Setup the "deep idle" callout and halt ("shallow idle") */
if (deep_idle_threshold_us)
callout_enqueue(&deep_idle_callout, deep_idle_threshold_us, deep_idle_timeout, NULL);
ticks_accumulator = & idle_ticks;
shallow_idle_cnt++;
platform_halt();
}
}
exit_critical_section();
/* We should never be here with interrupts disabled */
RELEASE_ASSERT(0 == current_task->irq_disable_count);
idle_leave = timer_get_ticks();
*ticks_accumulator += idle_leave - idle_enter;
}
return 0;
}
static void task_init_stack_magic_cookie(void)
{
#if WITH_RANDOM
uint8_t *guard = (uint8_t*)&task_stack_magic;
if (random_get_bytes((u_int8_t *)&task_stack_magic, sizeof(task_stack_magic)) != 0) {
// In case of failure, put back the static cookie just in case.
task_stack_magic = DEFAULT_TASK_STACK_MAGIC;
}
guard[task_stack_magic & (sizeof(task_stack_magic) - 1)] = 0;
#endif
}
void task_init(void)
{
dprintf(DEBUG_INFO, "initializing task system\n");
boot_time_ticks = timer_get_ticks();
#if !WITH_NO_RANDOM_STACK_COOKIE
/* initialize the random cookie used for overflow detection */
task_init_stack_magic_cookie();
#endif
/* go back and fill in some more details of the bootstrap task */
wait_queue_init(&bootstrap_task.return_waiters);
/* construct an idle task */
task_create_etc(&idle_task, "idle task", &idle_task_routine, NULL, idle_task_stack, sizeof(idle_task_stack));
idle_task.state = TASK_READY; /* it never gets started properly */
task_count = 2; /* bootstrap task, idle task */
#if defined(__arm__) && !defined(__clang_analyzer__)
nullptr_value = *(volatile uint32_t *)NULL;
#endif
}
struct task *task_get_current_task(void)
{
return(current_task);
}
static struct task *task_create_etc(struct task *t, const char *name, task_routine routine, void *arg, void *stack, size_t stack_len)
{
uint32_t i;
/* clear the storage for the task */
memset(t, 0, sizeof(struct task));
/* set up the new task */
t->magic = TASK_MAGIC;
t->magic2 = TASK_MAGIC2;
t->stack_base = stack;
t->stack_len = stack_len;
strlcpy(t->name, name, sizeof(t->name));
t->routine = routine;
t->arg = arg;
enter_critical_section();
t->task_id = ++max_task_id;
exit_critical_section();
list_clear_node(&t->queue_node);
wait_queue_init(&t->return_waiters);
t->state = TASK_INITIAL;
t->irq_disable_count = 1; /* start off as if we were inside a critical section */
/* fill the stack with 'magic' */
for (i = 0; i < (stack_len / sizeof(uint32_t)); i++)
*((uint32_t *)t->stack_base + i) = task_stack_magic;
arch_task_create(t);
/* add ourselves to the global task list */
list_add_head(&task_list, &t->task_list_node);
task_count++;
return t;
}
struct task *task_create(const char *name, task_routine routine, void *arg, size_t stack_len)
{
struct task *t;
void *stack;
/* stacks must be at least TASK_STACK_MIN bytes */
if (stack_len < TASK_STACK_MIN)
stack_len = TASK_STACK_MIN;
/* it will panic if not to be able to allocate stack */
t = malloc(sizeof(struct task));
/* assumption: malloc always returns cache-line size aligned buffer */
stack = malloc(stack_len);
return task_create_etc(t, name, routine, arg, stack, stack_len);
}
void task_destroy(struct task *t)
{
list_delete(&t->task_list_node);
free(t->stack_base);
free(t);
}
static void insert_run_q_head(struct task *t)
{
ASSERT(t != &idle_task);
ASSERT(run_q_len < task_count);
list_add_head(&run_q, &t->queue_node);
run_q_len++;
}
static void insert_run_q_tail(struct task *t)
{
ASSERT(t != &idle_task);
ASSERT(run_q_len < task_count);
list_add_tail(&run_q, &t->queue_node);
run_q_len++;
}
static struct task *pop_run_q_head(void)
{
struct task *t = list_remove_head_type(&run_q, struct task, queue_node);
if (t) {
ASSERT(run_q_len > 0);
run_q_len--;
}
return t;
}
void task_yield(void)
{
struct task *old_task;
struct task *new_task;
last_yield = timer_get_ticks();
/*
* If the current task is still ready to run and there's no other tasks ready, just
* continue.
* Note that this is simply an optimisation to avoid entering the critical section;
* we will later check again whether the current task is runnable to avoid racing
* with wakeups.
*/
if (likely(run_q_len == 0) && likely(current_task->state == TASK_RUNNING))
return;
/*
* It's not safe to yield in panic context.
*/
ASSERT(NULL == gPanicStr);
/*
* Sanity check the world before we yield from this task.
*
* XXX we could avoid this for the idle task to improve latency for
* tasks made runnable in interrupt context.
*/
if (likely(&bootstrap_task != current_task)) {
#if defined(__arm__) && !defined(__clang_analyzer__)
/* the bootstrap task might yield before calling task_init() */
/* XXX really? */
if (unlikely(nullptr_value != *(volatile uint32_t *)NULL))
panic("reset vector overwritten while executing task '%s' (0x%08x)",
current_task->name, *(volatile uint32_t *)NULL);
#endif
/* we don't know the base of the bootstrap stack, so it has no magic */
if (unlikely(task_stack_magic != *(uint32_t *)current_task->stack_base))
panic("task '%s' has overflowed its stack", current_task->name);
}
enter_critical_section();
/*
* We're headed to another task, so cancel the deep idle callout. Clear the
* flag too, just in case.
*/
callout_dequeue(&deep_idle_callout);
deep_idle = false;
/* if it's blocked or finished, it shouldn't go back to the run queue */
old_task = current_task;
if (old_task->state == TASK_RUNNING) {
old_task->state = TASK_READY;
/* the idle task gets scheduled when the run_q is empty; don't put it in there */
if (old_task != &idle_task)
insert_run_q_tail(old_task);
}
/* find the next task */
new_task = pop_run_q_head();
if (new_task == NULL)
new_task = &idle_task;
#if 0
dprintf(DEBUG_SPEW, "task_yield: switching from task %p (%s) %d %p to task %p (%s) %d %p\n",
old_task, old_task->name, old_task->irq_disable_count, old_task->stack_base,
new_task, new_task->name, new_task->irq_disable_count, new_task->stack_base);
#endif
ASSERT(new_task != old_task);
new_task->state = TASK_RUNNING;
current_task = new_task;
/* XXX we could sanity-check the new task here before switching to it */
arch_task_context_switch(&old_task->arch, &new_task->arch);
last_switch = timer_get_ticks();
exit_critical_section();
}
void task_start(struct task *t)
{
ASSERT(NULL != t);
if (t->state == TASK_INITIAL) {
/* stick it in the run queue */
t->state = TASK_READY;
enter_critical_section();
insert_run_q_tail(t);
exit_critical_section();
}
}
void task_exit(int return_code)
{
/* set our return code and wake anyone waiting on us */
current_task->return_code = return_code;
current_task->state = TASK_FINISHED;
wait_queue_wake_all(&current_task->return_waiters);
task_count--;
task_yield();
/* should never reach here */
panic("task_exit: should not be here\n");
}
int task_wait_on(struct task *t)
{
ASSERT(NULL != t);
if (t->state == TASK_FINISHED)
return t->return_code;
/* block on the task's wait queue and return with it's return code */
// XXX race condition here for someone deleting the finished task before a
// waiter gets to read it's return code
task_block(&t->return_waiters);
ASSERT(t->state == TASK_FINISHED);
return t->return_code;
}
void task_block(struct task_wait_queue *q)
{
/* stick ourselves into the wait queue, set our state to BLOCKED, and yield */
enter_critical_section();
current_task->state = TASK_BLOCKED;
list_add_tail(&q->task_list, &current_task->queue_node);
task_yield();
exit_critical_section();
}
/* happens at interrupt context */
static void task_sleep_callback(struct callout *c, void *_task)
{
struct task *t = (struct task *)_task;
ASSERT(c == &t->sleep_callout);
ASSERT(t->state == TASK_SLEEPING);
t->state = TASK_READY;
insert_run_q_tail(t);
}
void task_sleep(utime_t delay)
{
/* queue our sleep callout and reschedule */
enter_critical_section();
current_task->state = TASK_SLEEPING;
callout_enqueue(&current_task->sleep_callout, delay, &task_sleep_callback, current_task);
task_yield();
exit_critical_section();
}
/* wait queue stuff */
void wait_queue_init(struct task_wait_queue *q)
{
ASSERT(NULL != q);
list_initialize(&q->task_list);
}
void wait_queue_destroy(struct task_wait_queue *q)
{
wait_queue_wake_all(q);
}
int wait_queue_wake_all(struct task_wait_queue *q)
{
struct task *t;
struct task *temp;
int ret = 0;
/* iterate through the wait queue, sticking each of the waiting threads in the run queue */
enter_critical_section();
list_for_every_entry_safe(&q->task_list, t, temp, struct task, queue_node) {
list_delete(&t->queue_node);
ASSERT(t->state == TASK_BLOCKED);
t->state = TASK_READY;
insert_run_q_tail(t);
ret++;
}
exit_critical_section();
return ret;
}
int wait_queue_wake_one(struct task_wait_queue *q)
{
struct task *t;
int ret = 0;
/* pop the head of the wait queue and stick in the run queue */
enter_critical_section();
t = list_remove_head_type(&q->task_list, struct task, queue_node);
if (t) {
ASSERT(t->state == TASK_BLOCKED);
t->state = TASK_READY;
insert_run_q_tail(t);
ret = 1;
}
exit_critical_section();
return ret;
}
/* profile the task manager */
void task_get_statistics(struct idle_statistics *s)
{
u_int64_t now;
enter_critical_section();
now = timer_get_ticks();
s->uptime_ticks = now - boot_time_ticks;
s->ticksHz = timer_get_tick_rate();
s->idle_ticks = idle_ticks;
s->idles = shallow_idle_cnt;
s->deep_idle_ticks = deep_idle_ticks;
s->deep_idles = deep_idle_cnt;
s->threshold_us = deep_idle_threshold_us;
exit_critical_section();
}
void task_set_idle_threshold(u_int32_t us)
{
deep_idle_threshold_us = us;
}
/* event stuff */
void event_init(struct task_event *event, uint32_t flags, bool initial_state)
{
ASSERT(NULL != event);
wait_queue_init(&event->wait);
event->signalled = initial_state;
event->flags = flags;
}
void event_signal(struct task_event *event)
{
enter_critical_section();
event->signalled = true;
if (event->flags & EVENT_FLAG_AUTO_UNSIGNAL) {
/* only allow one task to get through and unsignal */
if (wait_queue_wake_one(&event->wait) > 0) {
event->signalled = false;
}
} else {
wait_queue_wake_all(&event->wait);
}
exit_critical_section();
}
void event_unsignal(struct task_event *event)
{
event->signalled = false;
}
void event_wait(struct task_event *event)
{
enter_critical_section();
if (event->signalled == false) {
/* block on the wait queue */
task_block(&event->wait);
} else {
/* we're the first task here, unsignal the lock */
if (event->flags & EVENT_FLAG_AUTO_UNSIGNAL)
event->signalled = false;
}
exit_critical_section();
}
/* happens at interrupt context */
struct event_wait_callback_info {
struct task_event *event;
struct task *task;
bool timed_out;
};
static void event_wait_callback(struct callout *c, void *_info)
{
struct event_wait_callback_info *info = (struct event_wait_callback_info *)_info;
struct task_wait_queue *q = &info->event->wait;
struct task *task = info->task;
struct task *t, *temp;
/* we may be racing with a legitimate wakeup, in which case we have not timed out */
if (TASK_BLOCKED != task->state)
return;
/* verify that we are blocked on the queue we think we're blocked on */
list_for_every_entry_safe(&q->task_list, t, temp, struct task, queue_node) {
if (t == task) {
list_delete(&t->queue_node);
ASSERT(t->state == TASK_BLOCKED);
t->state = TASK_READY;
insert_run_q_tail(t);
info->timed_out = true;
}
}
}
bool event_wait_timeout(struct task_event *event, utime_t delay)
{
bool ret;
enter_critical_section();
ret = event->signalled;
if (false == ret) {
/* are we allowed to wait? */
if (delay > 0) {
struct event_wait_callback_info info;
info.event = event;
info.task = current_task;
info.timed_out = false;
/* block on the wait queue */
callout_enqueue(&current_task->sleep_callout, delay, event_wait_callback, &info);
task_block(&event->wait);
callout_dequeue(&current_task->sleep_callout);
/* if we didn't time out, the event was signalled and we woke because of it */
if (false == info.timed_out)
ret = true;
}
} else {
/* we're the first task here, unsignal the lock */
if (event->flags & EVENT_FLAG_AUTO_UNSIGNAL)
event->signalled = false;
}
exit_critical_section();
return ret;
}
/* debug stuff */
static const char *task_state_to_string(enum task_state state)
{
switch (state) {
case TASK_INITIAL:
return "initial";
case TASK_READY:
return "ready";
case TASK_RUNNING:
return "running";
case TASK_BLOCKED:
return "blocked";
case TASK_SLEEPING:
return "sleeping";
case TASK_FINISHED:
return "finished";
default:
return "unknown";
}
}
static void dump_task(struct task *t)
{
uint32_t i;
dprintf(DEBUG_CRITICAL, "task %p (%s):\n", t, t->name);
dprintf(DEBUG_CRITICAL, " state %d (%s) interrupts %sabled (%d)\n",
t->state,
task_state_to_string(t->state),
(t->irq_disable_count == 0) ? "en" : "dis",
t->irq_disable_count);
dprintf(DEBUG_CRITICAL, " stack base %p, len 0x%zx, ", t->stack_base, t->stack_len);
if (task_stack_magic != *(uint32_t *)t->stack_base) {
dprintf(DEBUG_CRITICAL, "overflowed\n");
} else {
for (i = 0; i < (t->stack_len / sizeof(uint32_t)); i++)
if (task_stack_magic != *((uint32_t *)t->stack_base + i))
break;
dprintf(DEBUG_CRITICAL, "used 0x%lx\n", t->stack_len - (i * sizeof(uint32_t)));
}
printf(" start routine %p, args %p\n", t->routine, t->arg);
}
static int do_task(int argc, struct cmd_arg *args)
{
if (argc < 2) {
printf("not enough arguments\n");
usage:
printf("usage: \n");
printf("%s list\n", args[0].str);
printf("%s uptime\n", args[0].str);
return -1;
}
if (!strcmp(args[1].str, "list")) {
struct task *t;
list_for_every_entry(&task_list, t, struct task, task_list_node) {
dump_task(t);
}
} else if (!strcmp(args[1].str, "uptime")) {
uint64_t now;
utime_t elapsed, idle, active;
now = timer_get_ticks();
/* convert to microseconds */
elapsed = timer_ticks_to_usecs(now - boot_time_ticks);
idle = timer_ticks_to_usecs(idle_ticks);
active = elapsed - idle;
printf("up %u.%06u idle %u.%06u active %u.%06u\n",
(unsigned)(elapsed / (1000 * 1000)), (unsigned)(elapsed % (1000 * 1000)),
(unsigned)(idle / (1000 * 1000)), (unsigned)(idle % (1000 * 1000)),
(unsigned)(active / (1000 * 1000)), (unsigned)(active % (1000 * 1000)));
} else {
printf("unrecognized subcommand\n");
goto usage;
}
return 0;
}
MENU_COMMAND_DEVELOPMENT(task, do_task, "examine system tasks", NULL);
/*
* Validate that a task pointer points to something that looks like a task.
*/
static bool task_ptr_sanity(struct task *t)
{
if ((u_int32_t)t % 4) {
dprintf(DEBUG_CRITICAL, "task pointer %p bad, task list corrupt\n", t);
return(false);
}
/* add extra bad-address checks here */
if ((TASK_MAGIC != t->magic) || (TASK_MAGIC2 != t->magic2)) {
dprintf(DEBUG_CRITICAL, "task %p (corrupt)\n", t);
return(false);
}
return(true);
}
static void do_task_panic(void *junk)
{
struct task *t;
int tcount;
dprintf(DEBUG_CRITICAL, "current ");
if (task_ptr_sanity(current_task)) {
dump_task(current_task);
arch_backtrace_current_task(current_task->stack_base, current_task->stack_len);
}
tcount = 0;
list_for_every_entry(&task_list, t, struct task, task_list_node) {
if (current_task != t) {
if (!task_ptr_sanity(t))
break;
/* paranoia */
t->name[TASK_NAME_MAX] = 0;
dump_task(t);
arch_backtrace_task(&t->arch, t->stack_base, t->stack_len);
}
/* XXX tasks aren't properly reaped so many tasks exiting will confuse this */
if (tcount++ > (task_count + 2)) {
dprintf(DEBUG_CRITICAL, "too many tasks, task list probably corrupt\n");
break;
}
}
}
PANIC_HOOK(task, do_task_panic, NULL);
+282
View File
@@ -0,0 +1,282 @@
/*
* 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.
*/
#include <unittest.h>
#include <list.h>
void test_list_is_empty(uintptr_t param)
{
struct list_node list = LIST_INITIAL_VALUE(list);
struct list_node list2;
struct list_node item;
struct list_node item2;
TEST_ASSERT(list_is_empty(&list));
list_add_head(&list, &item);
TEST_ASSERT(!list_is_empty(&list));
list_initialize(&list2);
TEST_ASSERT(list_is_empty(&list2));
list_add_head(&list2, &item2);
TEST_ASSERT(!list_is_empty(&list2));
}
void test_list_add_head(uintptr_t param)
{
struct list_node list = LIST_INITIAL_VALUE(list);
struct list_node *iter;
struct list_node item1;
struct list_node item2;
struct list_node item3;
struct list_node* items[] = {&item1, &item2, &item3};
int i;
list_add_head(&list, &item1);
i = 0;
list_for_every(&list, iter) {
TEST_ASSERT_LT(i, 1);
TEST_ASSERT_PTR_EQ(items[1 - (i + 1)], iter);
i++;
}
list_add_head(&list, &item2);
i = 0;
list_for_every(&list, iter) {
TEST_ASSERT_LT(i, 2);
TEST_ASSERT_PTR_EQ(items[2 - (i + 1)], iter);
i++;
}
list_add_head(&list, &item3);
i = 0;
list_for_every(&list, iter) {
TEST_ASSERT_LT(i, 3);
TEST_ASSERT_PTR_EQ(items[3 - (i + 1)], iter);
i++;
}
}
void test_list_add_tail(uintptr_t param)
{
struct list_node list = LIST_INITIAL_VALUE(list);
struct list_node *iter;
struct list_node item1;
struct list_node item2;
struct list_node item3;
struct list_node* items[] = {&item1, &item2, &item3};
int i;
list_add_tail(&list, &item1);
i = 0;
list_for_every(&list, iter) {
TEST_ASSERT_LT(i, 1);
TEST_ASSERT_PTR_EQ(items[i], iter);
i++;
}
list_add_tail(&list, &item2);
i = 0;
list_for_every(&list, iter) {
TEST_ASSERT_LT(i, 2);
TEST_ASSERT_PTR_EQ(items[i], iter);
i++;
}
list_add_tail(&list, &item3);
i = 0;
list_for_every(&list, iter) {
TEST_ASSERT_LT(i, 3);
TEST_ASSERT_PTR_EQ(items[i], iter);
i++;
}
}
void test_list_remove_head(uintptr_t param)
{
struct list_node list = LIST_INITIAL_VALUE(list);
struct list_node *iter;
struct list_node *removed;
struct list_node item1;
struct list_node item2;
struct list_node item3;
struct list_node* items[] = {&item1, &item2, &item3};
int i;
list_add_tail(&list, &item1);
list_add_tail(&list, &item2);
list_add_tail(&list, &item3);
removed = list_remove_head(&list);
TEST_ASSERT_PTR_EQ(removed, &item1);
TEST_ASSERT(!list_in_list(removed));
i = 0;
list_for_every(&list, iter) {
TEST_ASSERT_LT(i, 2);
TEST_ASSERT_PTR_EQ(items[i + 1], iter);
i++;
}
removed = list_remove_head(&list);
TEST_ASSERT_PTR_EQ(removed, &item2);
TEST_ASSERT(!list_in_list(removed));
i = 0;
list_for_every(&list, iter) {
TEST_ASSERT_LT(i, 1);
TEST_ASSERT_PTR_EQ(items[i + 2], iter);
i++;
}
removed = list_remove_head(&list);
TEST_ASSERT_PTR_EQ(removed, &item3);
TEST_ASSERT(!list_in_list(removed));
TEST_ASSERT(list_is_empty(&list));
removed = list_remove_head(&list);
TEST_ASSERT_NULL(removed);
TEST_ASSERT(list_is_empty(&list));
}
void test_list_remove_tail(uintptr_t param)
{
struct list_node list = LIST_INITIAL_VALUE(list);
struct list_node *iter;
struct list_node *removed;
struct list_node item1;
struct list_node item2;
struct list_node item3;
struct list_node* items[] = {&item1, &item2, &item3};
int i;
list_add_tail(&list, &item1);
list_add_tail(&list, &item2);
list_add_tail(&list, &item3);
removed = list_remove_tail(&list);
TEST_ASSERT_PTR_EQ(removed, &item3);
TEST_ASSERT(!list_in_list(removed));
i = 0;
list_for_every(&list, iter) {
TEST_ASSERT_LT(i, 2);
TEST_ASSERT_PTR_EQ(items[i], iter);
i++;
}
removed = list_remove_tail(&list);
TEST_ASSERT_PTR_EQ(removed, &item2);
TEST_ASSERT(!list_in_list(removed));
i = 0;
list_for_every(&list, iter) {
TEST_ASSERT_LT(i, 1);
TEST_ASSERT_PTR_EQ(items[i], iter);
i++;
}
removed = list_remove_tail(&list);
TEST_ASSERT_PTR_EQ(removed, &item1);
TEST_ASSERT(!list_in_list(removed));
TEST_ASSERT(list_is_empty(&list));
removed = list_remove_head(&list);
TEST_ASSERT_NULL(removed);
TEST_ASSERT(list_is_empty(&list));
}
void test_safe_unlink_double_free(uintptr_t param)
{
struct list_node list = LIST_INITIAL_VALUE(list);
struct list_node item1;
struct list_node item2;
list_add_tail(&list, &item1);
list_add_tail(&list, &item2);
list_delete(&item1);
TEST_EXPECT_PANIC();
list_delete(&item1);
TEST_EXPECT_PANICKED();
}
void test_safe_unlink_next_corrupt(uintptr_t param)
{
struct list_node list = LIST_INITIAL_VALUE(list);
struct list_node item1;
struct list_node item2;
list_add_tail(&list, &item1);
list_add_tail(&list, &item2);
item1.next = item1.next->next;
TEST_EXPECT_PANIC();
list_delete(&item1);
TEST_EXPECT_PANICKED();
}
void test_safe_unlink_prev_corrupt(uintptr_t param)
{
struct list_node list = LIST_INITIAL_VALUE(list);
struct list_node item1;
struct list_node item2;
list_add_tail(&list, &item1);
list_add_tail(&list, &item2);
item1.prev = item1.prev->prev;
TEST_EXPECT_PANIC();
list_delete(&item1);
TEST_EXPECT_PANICKED();
}
struct test_suite linked_list_suite = {
.name = "linked_list",
.test_cases = {
{ "list_is_empty", test_list_is_empty, 0, "Tests list_is_empty" },
{ "list_add_head", test_list_add_head, 0, "Tests list_add_head" },
{ "list_add_tail", test_list_add_tail, 0, "Tests list_add_tail" },
{ "list_remove_head", test_list_remove_head, 0, "Tests list_remove_head" },
{ "list_remove_tail", test_list_remove_tail, 0, "Tests list_remove_tail" },
{ "safe_unlink_double_free", test_safe_unlink_double_free, 0, "Tests removing an item twice is detected" },
{ "safe_unlink_next_corrupt", test_safe_unlink_next_corrupt, 0, "Tests corrupting the next pointer is detected" },
{ "safe_unlink_prev_corrupt", test_safe_unlink_prev_corrupt, 0, "Tests corrupting the next pointer is detected" },
TEST_CASE_LAST
}
};
TEST_SUITE(linked_list_suite);
+57
View File
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2014-2015 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.
*/
#include <unittest.h>
#include <corecrypto/ccsha2.h>
#include <string.h>
void sha384_calculate(const void *in_ptr, size_t in_len, void *out_ptr, size_t out_len);
struct sha384_test {
const char *data;
uint32_t len;
uint8_t expected[CCSHA384_OUTPUT_SIZE];
};
static struct sha384_test sha384_tests[] = {
{ "", 0,
{ 0x38, 0xb0, 0x60, 0xa7, 0x51, 0xac, 0x96, 0x38, 0x4c, 0xd9, 0x32, 0x7e, 0xb1, 0xb1, 0xe3, 0x6a, 0x21, 0xfd, 0xb7, 0x11, 0x14, 0xbe, 0x07, 0x43, 0x4c, 0x0c, 0xc7, 0xbf, 0x63, 0xf6, 0xe1, 0xda, 0x27, 0x4e, 0xde, 0xbf, 0xe7, 0x6f, 0x65, 0xfb, 0xd5, 0x1a, 0xd2, 0xf1, 0x48, 0x98, 0xb9, 0x5b} },
{ "abc", 3,
{ 0xcb, 0x00, 0x75, 0x3f, 0x45, 0xa3, 0x5e, 0x8b, 0xb5, 0xa0, 0x3d, 0x69, 0x9a, 0xc6, 0x50, 0x07, 0x27, 0x2c, 0x32, 0xab, 0x0e, 0xde, 0xd1, 0x63, 0x1a, 0x8b, 0x60, 0x5a, 0x43, 0xff, 0x5b, 0xed, 0x80, 0x86, 0x07, 0x2b, 0xa1, 0xe7, 0xcc, 0x23, 0x58, 0xba, 0xec, 0xa1, 0x34, 0xc8, 0x25, 0xa7 } },
{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56,
{ 0x33, 0x91, 0xfd, 0xdd, 0xfc, 0x8d, 0xc7, 0x39, 0x37, 0x07, 0xa6, 0x5b, 0x1b, 0x47, 0x09, 0x39, 0x7c, 0xf8, 0xb1, 0xd1, 0x62, 0xaf, 0x05, 0xab, 0xfe, 0x8f, 0x45, 0x0d, 0xe5, 0xf3, 0x6b, 0xc6, 0xb0, 0x45, 0x5a, 0x85, 0x20, 0xbc, 0x4e, 0x6f, 0x5f, 0xe9, 0x5b, 0x1f, 0xe3, 0xc8, 0x45, 0x2b } },
};
void test_sha384(uintptr_t param)
{
for (unsigned i = 0; i < sizeof sha384_tests / sizeof(sha384_tests[0]); i++) {
struct sha384_test *test = &sha384_tests[i];
uint8_t calculated[CCSHA384_OUTPUT_SIZE];
sha384_calculate((void *)test->data, test->len, (void *)calculated, sizeof(calculated));
TEST_ASSERT_MEM_EQ(calculated, test->expected, sizeof(test->expected));
}
}
struct test_suite sha384_suite = {
.name = "sha384",
.test_cases = {
{ "sha384", test_sha384, 0, "Tests the sha384_calculate function" },
TEST_CASE_LAST
}
};
TEST_SUITE(sha384_suite);
+28
View File
@@ -0,0 +1,28 @@
# 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 := iboot-sys
TEST_OBJS := \
$(LOCAL_DIR)/hash.o
TEST_SUPPORT_OBJS := \
tests/unittest-main.o \
$(LOCAL_DIR)/tests-sha384.o \
$(LOCAL_DIR)/tests-list.o
HOST_SDKROOT_PATH := $(shell xcodebuild -version -sdk macosx.internal Path)
TEST_CFLAGS := \
-DWITH_SHA2_384=1 \
-I$(HOST_SDKROOT_PATH)/usr/local/include
+67
View File
@@ -0,0 +1,67 @@
/*
* Copyright (C) 2007-2009 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.
*/
#include <lib/libc.h> /* for __unused */
#include <sys.h>
#include <platform/timer.h>
#include <drivers/power.h>
#if WITH_HW_TIMER
utime_t system_time(void)
{
return timer_ticks_to_usecs(timer_get_ticks());
}
bool time_has_elapsed(utime_t start_time, utime_t timeout)
{
return ((system_time() - start_time) >= timeout) ? true : false;
}
void spin(utime_t usecs)
{
utime_t t;
t = system_time();
while (system_time() - t < usecs)
;
}
#else
utime_t system_time(void)
{
return 0;
}
bool time_has_elapsed(utime_t start_time __unused, utime_t timeout __unused)
{
return true;
}
void spin(utime_t usecs __unused)
{
}
#endif
#if WITH_HW_POWER
utime_t calendar_time(void)
{
return power_get_calendar_time();
}
#else
utime_t calendar_time(void)
{
return 0;
}
#endif