// Copyright 2020-2021 Beken // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include "boot.h" #include "arm.h" #include "bk_arch.h" #include "bk_uart.h" #include #include extern uint32_t und_stack_start; extern uint32_t abt_stack_start; extern uint32_t fiq_stack_start; extern uint32_t irq_stack_start; extern uint32_t sys_stack_start; extern uint32_t svc_stack_start; extern void fiq_handler(); extern char __flash_txt_end; extern char _itcmcode_ram_begin, _itcmcode_ram_end; #define STACK_CALLBACK_BUF_SIZE 32 #if STACK_DUMP_MEMORY static void stack_mem_dump(uint32_t stack_top, uint32_t stack_bottom) { uint32_t data = *((uint32_t *) stack_top); uint32_t cnt = 0; os_printf("cur stack_top=%08x, stack end=%08x\n", stack_top, stack_bottom); for (; stack_top < stack_bottom; stack_top += sizeof(size_t)) { data = *((uint32_t *) stack_top); if ((cnt++ % 4) == 0) os_printf("\n%08x: ", stack_top); os_printf("%08x ", data); } os_printf("\n"); } #endif #if !((CONFIG_SOC_BK7231U) || (CONFIG_SOC_BK7251)) static bool addr_is_in_itcm(uint32_t addr) { return ((addr > (uint32_t)&_itcmcode_ram_begin) && (addr < (uint32_t)&_itcmcode_ram_end)); } #endif static bool addr_is_in_flash_txt(uint32_t addr) { return ((addr > (uint32_t)fiq_handler) && (addr < (uint32_t)&__flash_txt_end)); } static bool code_addr_is_valid(uint32_t addr) { #if ((CONFIG_SOC_BK7231U) || (CONFIG_SOC_BK7251)) return (addr_is_in_flash_txt(addr)); #else return (addr_is_in_itcm(addr) || addr_is_in_flash_txt(addr)); #endif } /* The stack is grow from bottom to top * * | | <- minimum_addr = (bottom - stack_size) * | | * | | * | | <- top * | . | * | . | * | . | <- bottom, (big address) * * */ void arch_parse_stack_backtrace(const char *str_type, uint32_t stack_top, uint32_t stack_bottom, uint32_t stack_size, bool thumb_mode) { uint32_t call_stack_buf[STACK_CALLBACK_BUF_SIZE] = {0}; uint32_t stack_minimum = stack_bottom - stack_size; uint32_t pc; int call_stack_index = 0; uint32_t init_stack_top = stack_top; #if STACK_DUMP_MEMORY stack_mem_dump(stack_top, stack_bottom); #endif for (; stack_top < stack_bottom && (call_stack_index < STACK_CALLBACK_BUF_SIZE); stack_top += sizeof(size_t)) { pc = *((uint32_t *) stack_top); /* ARM9 using thumb instruction, so the pc must be an odd number */ if (thumb_mode && (pc & 1) == 0) continue; if (code_addr_is_valid(pc)) { if (pc & 1) pc = pc - 1; call_stack_buf[call_stack_index] = pc; call_stack_index++; } } if (call_stack_index > 0) { int index; os_printf("%-16s [0x%-6x ~ 0x%-6x] 0x%-6x %-4d %-8d ", str_type, stack_minimum, stack_bottom, init_stack_top, stack_size, init_stack_top < stack_minimum); for (index = 0; index < call_stack_index; index++) os_printf("%lx ", call_stack_buf[index]); os_printf("\n"); } else if (init_stack_top < stack_minimum) { os_printf("%-16s [0x%-6x ~ 0x%-6x] 0x%-6x %-4d %-8d ", str_type, stack_minimum, stack_bottom, init_stack_top, stack_size, init_stack_top < stack_minimum); } } void arch_dump_exception_stack(void) { uint32_t stack_bottom; uint32_t sp; sp = *(uint32_t*)(MCU_REG_BACKUP_SP_FIQ); stack_bottom = (uint32_t)&fiq_stack_start; arch_parse_stack_backtrace("fiq", sp, stack_bottom, FIQ_STACK_SIZE, false); sp = *(uint32_t*)(MCU_REG_BACKUP_SP_IRQ); stack_bottom = (uint32_t)&irq_stack_start; arch_parse_stack_backtrace("irq", sp, stack_bottom, IRQ_STACK_SIZE, false); sp = *(uint32_t*)(MCU_REG_BACKUP_SP_UND); stack_bottom = (uint32_t)&und_stack_start; arch_parse_stack_backtrace("und", sp, stack_bottom, UND_STACK_SIZE, false); sp = *(uint32_t*)(MCU_REG_BACKUP_SP_ABT); stack_bottom = (uint32_t)&abt_stack_start; arch_parse_stack_backtrace("abt", sp, stack_bottom, ABT_STACK_SIZE, false); sp = *(uint32_t*)(MCU_REG_BACKUP_SP_SVC); stack_bottom = (uint32_t)&svc_stack_start; arch_parse_stack_backtrace("svc", sp, stack_bottom, SVC_STACK_SIZE, false); sp = *(uint32_t*)(MCU_REG_BACKUP_SP_SYS); stack_bottom = (uint32_t)&sys_stack_start; arch_parse_stack_backtrace("sys", sp, stack_bottom, SYS_STACK_SIZE, false); }