aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/tests/mem_tests.c2
-rw-r--r--app/tests/printf_tests.c1
-rw-r--r--include/debug.h8
-rw-r--r--include/lib/console.h12
-rw-r--r--include/platform/debug.h4
-rw-r--r--include/stdio.h1
-rw-r--r--kernel/vm/vm.c2
-rw-r--r--lib/console/console.c112
-rw-r--r--lib/debug/debug.c22
-rw-r--r--platform/debug.c11
-rw-r--r--platform/power.c16
-rw-r--r--platform/stm32f7xx/debug.c9
-rw-r--r--platform/stm32f7xx/include/platform/stm32.h2
-rw-r--r--platform/stm32f7xx/uart.c9
14 files changed, 199 insertions, 12 deletions
diff --git a/app/tests/mem_tests.c b/app/tests/mem_tests.c
index 9c11d6c8..fdd14fe1 100644
--- a/app/tests/mem_tests.c
+++ b/app/tests/mem_tests.c
@@ -28,6 +28,7 @@
#include <arch/ops.h>
#include <lib/console.h>
#include <platform.h>
+#include <debug.h>
#if WITH_KERNEL_VM
#include <kernel/vm.h>
@@ -239,4 +240,3 @@ usage:
STATIC_COMMAND_START
STATIC_COMMAND("mem_test", "test memory", &mem_test)
STATIC_COMMAND_END(mem_tests);
-
diff --git a/app/tests/printf_tests.c b/app/tests/printf_tests.c
index fc2fb1fa..e3b55bff 100644
--- a/app/tests/printf_tests.c
+++ b/app/tests/printf_tests.c
@@ -23,6 +23,7 @@
#include <app/tests.h>
#include <stdio.h>
#include <string.h>
+#include <debug.h>
void printf_tests(void)
{
diff --git a/include/debug.h b/include/debug.h
index b59859dd..797c3b37 100644
--- a/include/debug.h
+++ b/include/debug.h
@@ -28,11 +28,16 @@
#include <compiler.h>
#include <platform/debug.h>
#include <list.h>
+#include <stdio.h>
#if !defined(LK_DEBUGLEVEL)
#define LK_DEBUGLEVEL 0
#endif
+#if !defined(ENABLE_PANIC_SHELL)
+#define ENABLE_PANIC_SHELL 1
+#endif
+
/* debug levels */
#define CRITICAL 0
#define ALWAYS 0
@@ -52,6 +57,9 @@ struct __print_callback {
/* input/output */
int _dprintf(const char *fmt, ...) __PRINTFLIKE(1, 2);
+// Obtain the panic file descriptor.
+FILE get_panic_fd(void);
+
/* dump memory */
void hexdump(const void *ptr, size_t len);
void hexdump8_ex(const void *ptr, size_t len, uint64_t disp_addr_start);
diff --git a/include/lib/console.h b/include/lib/console.h
index 38f32aaa..a00e2adb 100644
--- a/include/lib/console.h
+++ b/include/lib/console.h
@@ -38,11 +38,16 @@ typedef struct {
typedef int (*console_cmd)(int argc, const cmd_args *argv);
+#define CMD_AVAIL_NORMAL (0x1 << 0)
+#define CMD_AVAIL_PANIC (0x1 << 1)
+#define CMD_AVAIL_ALWAYS (CMD_AVAIL_NORMAL | CMD_AVAIL_PANIC)
+
/* a block of commands to register */
typedef struct {
const char *cmd_str;
const char *help_str;
const console_cmd cmd_callback;
+ uint8_t availability_mask;
} cmd;
typedef struct _cmd_block {
@@ -69,7 +74,8 @@ typedef struct _cmd_block {
#define STATIC_COMMAND_END_NAMED(name) }; const cmd_block _cmd_block_##name __SECTION(".commands")= { NULL, sizeof(_cmd_list_##name) / sizeof(_cmd_list_##name[0]), _cmd_list_##name }
#endif
-#define STATIC_COMMAND(command_str, help_str, func) { command_str, help_str, func },
+#define STATIC_COMMAND(command_str, help_str, func) { command_str, help_str, func, CMD_AVAIL_NORMAL },
+#define STATIC_COMMAND_MASKED(command_str, help_str, func, availability_mask) { command_str, help_str, func, availability_mask },
#else
@@ -94,7 +100,9 @@ int console_run_script_locked(const char *string); // special case from inside a
console_cmd console_get_command_handler(const char *command);
void console_abort_script(void);
+/* panic shell api */
+void panic_shell_start(void);
+
extern int lastresult;
#endif
-
diff --git a/include/platform/debug.h b/include/platform/debug.h
index 50791046..8cbf024a 100644
--- a/include/platform/debug.h
+++ b/include/platform/debug.h
@@ -33,6 +33,10 @@ __BEGIN_CDECLS
void platform_dputc(char c);
int platform_dgetc(char *c, bool wait);
+// Should be available even if the system has panicked.
+void platform_pputc(char c);
+int platform_pgetc(char *c, bool wait);
+
__END_CDECLS
#endif
diff --git a/include/stdio.h b/include/stdio.h
index 74601ae9..d1b98c77 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -24,7 +24,6 @@
#define __STDIO_H
#include <compiler.h>
-#include <debug.h>
#include <printf.h>
#include <sys/types.h>
diff --git a/kernel/vm/vm.c b/kernel/vm/vm.c
index 6a223568..a5c7aba6 100644
--- a/kernel/vm/vm.c
+++ b/kernel/vm/vm.c
@@ -29,6 +29,7 @@
#include <lk/init.h>
#include <lib/console.h>
#include <arch/mmu.h>
+#include <debug.h>
#define LOCAL_TRACE 0
@@ -180,4 +181,3 @@ STATIC_COMMAND_END(vm);
LK_INIT_HOOK(vm_preheap, &vm_init_preheap, LK_INIT_LEVEL_HEAP - 1);
LK_INIT_HOOK(vm, &vm_init_postheap, LK_INIT_LEVEL_VM);
-
diff --git a/lib/console/console.c b/lib/console/console.c
index 19b4c107..04aab84c 100644
--- a/lib/console/console.c
+++ b/lib/console/console.c
@@ -41,12 +41,16 @@
#define LINE_LEN 128
+#define PANIC_LINE_LEN 32
+
#define MAX_NUM_ARGS 16
#define HISTORY_LEN 16
#define LOCAL_TRACE 0
+#define WHITESPACE " \t"
+
/* debug buffer */
static char *debug_buffer;
@@ -81,6 +85,7 @@ extern cmd_block __commands_start;
extern cmd_block __commands_end;
static int cmd_help(int argc, const cmd_args *argv);
+static int cmd_help_panic(int argc, const cmd_args *argv);
static int cmd_echo(int argc, const cmd_args *argv);
static int cmd_test(int argc, const cmd_args *argv);
#if CONSOLE_ENABLE_HISTORY
@@ -89,6 +94,7 @@ static int cmd_history(int argc, const cmd_args *argv);
STATIC_COMMAND_START
STATIC_COMMAND("help", "this list", &cmd_help)
+STATIC_COMMAND_MASKED("help", "this list", &cmd_help_panic, CMD_AVAIL_PANIC)
STATIC_COMMAND("echo", NULL, &cmd_echo)
#if LK_DEBUGLEVEL > 1
STATIC_COMMAND("test", "test the command processor", &cmd_test)
@@ -211,7 +217,7 @@ static const char *prev_history(uint *cursor)
}
#endif
-static const cmd *match_command(const char *command)
+static const cmd *match_command(const char *command, const uint8_t availability_mask)
{
cmd_block *block;
size_t i;
@@ -219,6 +225,9 @@ static const cmd *match_command(const char *command)
for (block = command_list; block != NULL; block = block->next) {
const cmd *curr_cmd = block->list;
for (i = 0; i < block->count; i++) {
+ if ((availability_mask & curr_cmd[i].availability_mask) == 0) {
+ continue;
+ }
if (strcmp(command, curr_cmd[i].cmd_str) == 0) {
return &curr_cmd[i];
}
@@ -603,7 +612,7 @@ static status_t command_loop(int (*get_line)(const char **, void *), void *get_l
convert_args(argc, args);
/* try to match the command */
- const cmd *command = match_command(args[0].str);
+ const cmd *command = match_command(args[0].str, CMD_AVAIL_NORMAL);
if (!command) {
if (showprompt)
printf("command not found\n");
@@ -738,7 +747,7 @@ int console_run_script_locked(const char *string)
console_cmd console_get_command_handler(const char *commandstr)
{
- const cmd *command = match_command(commandstr);
+ const cmd *command = match_command(commandstr, CMD_AVAIL_NORMAL);
if (command)
return command->cmd_callback;
@@ -755,9 +764,9 @@ void console_register_commands(cmd_block *block)
command_list = block;
}
-static int cmd_help(int argc, const cmd_args *argv)
-{
+static int cmd_help_impl(uint8_t availability_mask)
+{
printf("command list:\n");
cmd_block *block;
@@ -766,6 +775,10 @@ static int cmd_help(int argc, const cmd_args *argv)
for (block = command_list; block != NULL; block = block->next) {
const cmd *curr_cmd = block->list;
for (i = 0; i < block->count; i++) {
+ if ((availability_mask & curr_cmd[i].availability_mask) == 0) {
+ // Skip commands that aren't available in the current shell.
+ continue;
+ }
if (curr_cmd[i].help_str)
printf("\t%-16s: %s\n", curr_cmd[i].cmd_str, curr_cmd[i].help_str);
}
@@ -774,6 +787,16 @@ static int cmd_help(int argc, const cmd_args *argv)
return 0;
}
+static int cmd_help(int argc, const cmd_args *argv)
+{
+ return cmd_help_impl(CMD_AVAIL_NORMAL);
+}
+
+static int cmd_help_panic(int argc, const cmd_args *argv)
+{
+ return cmd_help_impl(CMD_AVAIL_PANIC);
+}
+
static int cmd_echo(int argc, const cmd_args *argv)
{
if (argc > 1)
@@ -781,6 +804,84 @@ static int cmd_echo(int argc, const cmd_args *argv)
return NO_ERROR;
}
+static void read_line_panic(char* buffer, const size_t len, FILE* panic_fd) {
+ size_t pos = 0;
+
+ for (;;) {
+ int c;
+ if ((c = getc(panic_fd)) < 0) {
+ continue;
+ }
+
+ switch(c) {
+ case '\r':
+ case '\n':
+ fputc('\n', panic_fd);
+ goto done;
+ case 0x7f: // backspace or delete
+ case 0x8:
+ if (pos > 0) {
+ pos--;
+ fputc('\b', stdout);
+ fputc(' ', panic_fd);
+ fputc('\b', stdout); // move to the left one
+ }
+ break;
+ default:
+ buffer[pos++] = c;
+ fputc(c, panic_fd);
+ }
+ if (pos == (len - 1)) {
+ fputs("\nerror: line too long\n", panic_fd);
+ pos = 0;
+ goto done;
+ }
+ }
+done:
+ buffer[pos] = 0;
+}
+
+void panic_shell_start(void)
+{
+ dprintf(INFO, "entering panic shell loop\n");
+ char input_buffer[PANIC_LINE_LEN];
+ cmd_args args[MAX_NUM_ARGS];
+
+ // panic_fd allows us to do I/O using the polling drivers.
+ // These drivers function even if interrupts are disabled.
+ FILE _panic_fd = get_panic_fd();
+ FILE *panic_fd = &_panic_fd;
+
+ for(;;) {
+ fputs("! ", panic_fd);
+ read_line_panic(input_buffer, PANIC_LINE_LEN, panic_fd);
+
+ int argc;
+ char* tok = strtok(input_buffer, WHITESPACE);
+ for (argc = 0; argc < MAX_NUM_ARGS; argc++) {
+ if (tok == NULL) {
+ break;
+ }
+ args[argc].str = tok;
+ tok = strtok(NULL, WHITESPACE);
+ }
+
+ if (argc == 0) {
+ continue;
+ }
+
+ convert_args(argc, args);
+
+ const cmd* command = match_command(args[0].str, CMD_AVAIL_PANIC);
+ if (!command) {
+ fputs("command not found\n", panic_fd);
+ continue;
+ }
+
+ command->cmd_callback(argc, args);
+ }
+}
+
#if LK_DEBUGLEVEL > 1
static int cmd_test(int argc, const cmd_args *argv)
{
@@ -793,4 +894,3 @@ static int cmd_test(int argc, const cmd_args *argv)
return 0;
}
#endif
-
diff --git a/lib/debug/debug.c b/lib/debug/debug.c
index b16f4ea7..160038ab 100644
--- a/lib/debug/debug.c
+++ b/lib/debug/debug.c
@@ -137,6 +137,17 @@ static int __debug_stdio_fgetc(void *ctx)
return (unsigned char)c;
}
+static int __panic_stdio_fgetc(void *ctx)
+{
+ char c;
+ int err;
+
+ err = platform_pgetc(&c, true);
+ if (err < 0)
+ return err;
+ return (unsigned char)c;
+}
+
static int __debug_stdio_vfprintf(void *ctx, const char *fmt, va_list ap)
{
return _dvprintf(fmt, ap);
@@ -158,6 +169,17 @@ FILE __stdio_FILEs[3] = {
};
#undef DEFINE_STDIO_DESC
+FILE get_panic_fd(void)
+{
+ FILE panic_fd;
+ panic_fd.fgetc = __panic_stdio_fgetc;
+
+ panic_fd.fputc = __debug_stdio_fputc;
+ panic_fd.fputs = __debug_stdio_fputs;
+ panic_fd.vfprintf = __debug_stdio_vfprintf;
+ return panic_fd;
+}
+
#if !DISABLE_DEBUG_OUTPUT
static int _dprintf_output_func(const char *str, size_t len, void *state)
diff --git a/platform/debug.c b/platform/debug.c
index b12f15c4..2b2cfdd9 100644
--- a/platform/debug.c
+++ b/platform/debug.c
@@ -21,4 +21,15 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+#include <compiler.h>
+#include <debug.h>
+__WEAK void platform_pputc(char c)
+{
+ return platform_dputc(c);
+}
+
+__WEAK int platform_pgetc(char *c, bool wait)
+{
+ return platform_pgetc(c, wait);
+}
diff --git a/platform/power.c b/platform/power.c
index d4cc8f01..2f111385 100644
--- a/platform/power.c
+++ b/platform/power.c
@@ -26,6 +26,11 @@
#include <platform.h>
#include <platform/debug.h>
#include <kernel/thread.h>
+#include <stdio.h>
+
+#ifdef ENABLE_PANIC_SHELL
+#include <lib/console.h>
+#endif
/*
* default implementations of these routines, if the platform code
@@ -34,6 +39,16 @@
__WEAK void platform_halt(platform_halt_action suggested_action,
platform_halt_reason reason)
{
+#ifdef ENABLE_PANIC_SHELL
+
+ if (reason == HALT_REASON_SW_PANIC) {
+ dprintf(ALWAYS, "CRASH: starting debug shell... (reason = %d)\n", reason);
+ arch_disable_ints();
+ panic_shell_start();
+ }
+
+#endif // ENABLE_PANIC_SHELL
+
dprintf(ALWAYS, "HALT: spinning forever... (reason = %d)\n", reason);
arch_disable_ints();
for(;;);
@@ -63,4 +78,3 @@ STATIC_COMMAND("poweroff", "powerdown", &cmd_poweroff)
STATIC_COMMAND_END(platform_power);
#endif
-
diff --git a/platform/stm32f7xx/debug.c b/platform/stm32f7xx/debug.c
index bb51cc1b..e97157db 100644
--- a/platform/stm32f7xx/debug.c
+++ b/platform/stm32f7xx/debug.c
@@ -30,6 +30,7 @@
#include <dev/uart.h>
#include <target/debugconfig.h>
#include <arch/arm/cm.h>
+#include <platform/stm32.h>
void stm32_debug_early_init(void)
{
@@ -58,3 +59,11 @@ int platform_dgetc(char *c, bool wait)
return 0;
}
+int platform_pgetc(char *c, bool wait)
+{
+ int ret = stm32_uart_getc_poll(DEBUG_UART);
+ if (ret == -1)
+ return -1;
+ *c = ret;
+ return 0;
+}
diff --git a/platform/stm32f7xx/include/platform/stm32.h b/platform/stm32f7xx/include/platform/stm32.h
index 0ac507a0..73c0c025 100644
--- a/platform/stm32f7xx/include/platform/stm32.h
+++ b/platform/stm32f7xx/include/platform/stm32.h
@@ -35,5 +35,7 @@ void stm32_gpio_early_init(void);
void stm32_flash_early_init(void);
void stm32_flash_init(void);
+int stm32_uart_getc_poll(int port);
+
/* unique id of device */
uint32_t stm32_unique_id[3];
diff --git a/platform/stm32f7xx/uart.c b/platform/stm32f7xx/uart.c
index 2db5cc9f..e4de1312 100644
--- a/platform/stm32f7xx/uart.c
+++ b/platform/stm32f7xx/uart.c
@@ -197,6 +197,15 @@ int uart_getc(int port, bool wait)
return c;
}
+int stm32_uart_getc_poll(int port)
+{
+ if ((__HAL_UART_GET_IT(&handle, UART_IT_RXNE) != RESET) && (__HAL_UART_GET_IT_SOURCE(&handle, UART_IT_RXNE) != RESET)) {
+ uint8_t c = (uint8_t)(handle.Instance->RDR & 0xff);
+ return c;
+ }
+ return -1;
+}
+
void uart_flush_tx(int port) {}
void uart_flush_rx(int port) {}