diff options
Diffstat (limited to 'common/panic_output.c')
-rw-r--r-- | common/panic_output.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/common/panic_output.c b/common/panic_output.c new file mode 100644 index 0000000000..f77277ab33 --- /dev/null +++ b/common/panic_output.c @@ -0,0 +1,169 @@ +/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "common.h" +#include "console.h" +#include "cpu.h" +#include "host_command.h" +#include "panic.h" +#include "printf.h" +#include "system.h" +#include "task.h" +#include "timer.h" +#include "uart.h" +#include "util.h" + +/* Panic data goes at the end of RAM. */ +static struct panic_data * const pdata_ptr = PANIC_DATA_PTR; + +/** + * Add a character directly to the UART buffer. + * + * @param context Context; ignored. + * @param c Character to write. + * @return 0 if the character was transmitted, 1 if it was dropped. + */ +static int panic_txchar(void *context, int c) +{ + if (c == '\n') + panic_txchar(context, '\r'); + + /* Wait for space in transmit FIFO */ + while (!uart_tx_ready()) + ; + + /* Write the character directly to the transmit FIFO */ + uart_write_char(c); + + return 0; +} + +void panic_puts(const char *outstr) +{ + /* Flush the output buffer */ + uart_flush_output(); + + /* Put all characters in the output buffer */ + while (*outstr) + panic_txchar(NULL, *outstr++); + + /* Flush the transmit FIFO */ + uart_tx_flush(); +} + +void panic_printf(const char *format, ...) +{ + va_list args; + + /* Flush the output buffer */ + uart_flush_output(); + + va_start(args, format); + vfnprintf(panic_txchar, NULL, format, args); + va_end(args); + + /* Flush the transmit FIFO */ + uart_tx_flush(); +} + +/** + * Display a message and reboot + */ +void panic_reboot(void) +{ + panic_puts("\n\nRebooting...\n"); + system_reset(0); +} + +#ifdef CONFIG_DEBUG_ASSERT_REBOOTS +void panic_assert_fail(const char *msg, const char *func, const char *fname, + int linenum) +{ + panic_printf("\nASSERTION FAILURE '%s' in %s() at %s:%d\n", + msg, func, fname, linenum); + + panic_reboot(); +} +#endif + +void panic(const char *msg) +{ + panic_printf("\n** PANIC: %s\n", msg); + panic_reboot(); +} + +struct panic_data *panic_get_data(void) +{ + return pdata_ptr->magic == PANIC_DATA_MAGIC ? pdata_ptr : NULL; +} + +/*****************************************************************************/ +/* Console commands */ + +static int command_crash(int argc, char **argv) +{ + if (argc < 2) + return EC_ERROR_PARAM1; + + if (!strcasecmp(argv[1], "divzero")) { + int a = 1, b = 0; + + cflush(); + ccprintf("%08x", a / b); + } else if (!strcasecmp(argv[1], "unaligned")) { + cflush(); + ccprintf("%08x", *(int *)0xcdef); + } else { + return EC_ERROR_PARAM1; + } + + /* Everything crashes, so shouldn't get back here */ + return EC_ERROR_UNKNOWN; +} +DECLARE_CONSOLE_COMMAND(crash, command_crash, + "[divzero | unaligned]", + "Crash the system (for testing)", + NULL); + +static int command_panicinfo(int argc, char **argv) +{ + if (pdata_ptr->magic == PANIC_DATA_MAGIC) { + ccprintf("Saved panic data:%s\n", + (pdata_ptr->flags & PANIC_DATA_FLAG_OLD_CONSOLE ? + "" : " (NEW)")); + + panic_data_print(pdata_ptr); + + /* Data has now been printed */ + pdata_ptr->flags |= PANIC_DATA_FLAG_OLD_CONSOLE; + } else { + ccprintf("No saved panic data available.\n"); + } + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(panicinfo, command_panicinfo, + NULL, + "Print info from a previous panic", + NULL); + +/*****************************************************************************/ +/* Host commands */ + +int host_command_panic_info(struct host_cmd_handler_args *args) +{ + if (pdata_ptr->magic == PANIC_DATA_MAGIC) { + ASSERT(pdata_ptr->struct_size <= args->response_max); + memcpy(args->response, pdata_ptr, pdata_ptr->struct_size); + args->response_size = pdata_ptr->struct_size; + + /* Data has now been returned */ + pdata_ptr->flags |= PANIC_DATA_FLAG_OLD_HOSTCMD; + } + + return EC_RES_SUCCESS; +} +DECLARE_HOST_COMMAND(EC_CMD_GET_PANIC_INFO, + host_command_panic_info, + EC_VER_MASK(0)); |