204 lines
5.4 KiB
C
204 lines
5.4 KiB
C
|
/*
|
||
|
* 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");
|
||
|
}
|