/* * Copyright (c) 2017 Actions Semiconductor Co., Ltd * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief Magic System Request Key Hacks * */ #include <kernel.h> #include <drivers/uart.h> #include <soc.h> struct sysrq_key_op { char key; char reserved[3]; void (*handler)(int); char *help_msg; char *action_msg; }; #if CONFIG_KERNEL_SHOW_STACK extern void show_stack(void); static void sysrq_handle_show_stack(int key) { show_stack(); } #endif static void sysrq_handle_change_jtag(int key) { jtag_set(); } #if defined(CONFIG_INIT_STACKS) && defined(CONFIG_THREAD_STACK_INFO) && defined(CONFIG_THREAD_MONITOR) static void sysrq_stack_dump(const struct k_thread *thread, void *user_data) { unsigned int pcnt; size_t unused; size_t size = thread->stack_info.size; const char *tname; int ret; ret = k_thread_stack_space_get(thread, &unused); if (ret) { printk("Unable to determine unused stack size (%d)\n", ret); return; } tname = k_thread_name_get((struct k_thread *)thread); /* Calculate the real size reserved for the stack */ pcnt = ((size - unused) * 100U) / size; printk("%p %-10s (real size %u):\tunused %u\tusage %u / %u (%u %%)\n", thread, tname ? tname : "NA", size, unused, size - unused, size, pcnt); } static void sysrq_handle_stack_dump(int key) { k_thread_foreach(sysrq_stack_dump, NULL); } #endif static const struct sysrq_key_op sysrq_key_table[] = { #ifdef CONFIG_KERNEL_SHOW_STACK { .key = 't', .handler = sysrq_handle_show_stack, .help_msg = "show-thread-states(t)", .action_msg = "Show State:", }, #endif { .key = 'j', .handler = sysrq_handle_change_jtag, .help_msg = "change jtag to grp1 (j)", .action_msg = "jtag:", }, #if defined(CONFIG_INIT_STACKS) && defined(CONFIG_THREAD_STACK_INFO) && defined(CONFIG_THREAD_MONITOR) { .key = 's', .handler = sysrq_handle_stack_dump, .help_msg = "show thread stack usage (s)", .action_msg = "stack usage:", }, #endif }; /* magic sysrq key: CTLR + 'b' 'r' 'e' 'a' 'k' */ static const char sysrq_breakbuf[] = {0x02, 0x12, 0x05, 0x01, 0x0b}; static int sysrq_break_idx; static struct sysrq_key_op* sysrq_get_key_op(char key) { int i, cnt; cnt = ARRAY_SIZE(sysrq_key_table); for (i = 0; i < cnt; i++) { if (key == sysrq_key_table[i].key) { return (struct sysrq_key_op*)&sysrq_key_table[i]; } } return NULL; } static void sysrq_print_help(void) { int i; printk("HELP : quit(q) \n"); for (i = 0; i < ARRAY_SIZE(sysrq_key_table); i++) { printk("%s \n", sysrq_key_table[i].help_msg); } printk("\n"); } extern void printk_dma_switch(int sw_dma); static void handle_sysrq_main(const struct device * port) { struct sysrq_key_op* op_p; char key; #ifdef CONFIG_ACTIONS_PRINTK_DMA printk_dma_switch(0); #endif for(;;) { printk("Wait SYSRQ Key:\n"); sysrq_print_help(); uart_poll_in(port, &key); if (key == 'q') { printk("sysrq: exit\n"); break; } op_p = sysrq_get_key_op(key); if (op_p) { printk("%s\n", op_p->action_msg); op_p->handler(key); } else { sysrq_print_help(); } } #ifdef CONFIG_ACTIONS_PRINTK_DMA printk_dma_switch(1); #endif } void uart_handle_sysrq_char(const struct device * port, char c) { if (c == sysrq_breakbuf[sysrq_break_idx]) { sysrq_break_idx++; if (sysrq_break_idx == sizeof(sysrq_breakbuf)) { sysrq_break_idx = 0; handle_sysrq_main(port); } } else { sysrq_break_idx = 0; } }