x86: consolidate some fatal error code
Some code for unwinding stacks and z_x86_fatal_error() now in a common C file, suitable for both modes. Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
parent
64f6e2ac6b
commit
9fb89ccf32
5 changed files with 172 additions and 135 deletions
|
@ -10,6 +10,7 @@ endif ()
|
|||
zephyr_library_sources(cpuhalt.c)
|
||||
zephyr_library_sources(memmap.c)
|
||||
zephyr_library_sources(prep_c.c)
|
||||
zephyr_library_sources(fatal.c)
|
||||
|
||||
zephyr_library_sources_if_kconfig(pcie.c)
|
||||
zephyr_library_sources_if_kconfig(reboot_rst_cnt.c)
|
||||
|
|
147
arch/x86/core/fatal.c
Normal file
147
arch/x86/core/fatal.c
Normal file
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Intel Corporation
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <kernel.h>
|
||||
#include <ksched.h>
|
||||
#include <kernel_structs.h>
|
||||
#include <kernel_internal.h>
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_DECLARE(os);
|
||||
|
||||
#ifdef CONFIG_THREAD_STACK_INFO
|
||||
bool z_x86_check_stack_bounds(uintptr_t addr, size_t size, u16_t cs)
|
||||
{
|
||||
uintptr_t start, end;
|
||||
|
||||
if (z_arch_is_in_isr()) {
|
||||
/* We were servicing an interrupt */
|
||||
start = (uintptr_t)Z_ARCH_THREAD_STACK_BUFFER(_interrupt_stack);
|
||||
end = start + CONFIG_ISR_STACK_SIZE;
|
||||
} else if ((cs & 0x3U) != 0U ||
|
||||
(_current->base.user_options & K_USER) == 0) {
|
||||
/* Thread was in user mode, or is not a user mode thread.
|
||||
* The normal stack buffer is what we will check.
|
||||
*/
|
||||
start = _current->stack_info.start;
|
||||
end = STACK_ROUND_DOWN(_current->stack_info.start +
|
||||
_current->stack_info.size);
|
||||
} else {
|
||||
/* User thread was doing a syscall, check kernel stack bounds */
|
||||
start = _current->stack_info.start - MMU_PAGE_SIZE;
|
||||
end = _current->stack_info.start;
|
||||
}
|
||||
|
||||
return (addr <= start) || (addr + size > end);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_EXCEPTION_STACK_TRACE)
|
||||
struct stack_frame {
|
||||
uintptr_t next;
|
||||
uintptr_t ret_addr;
|
||||
#ifndef CONFIG_X86_64
|
||||
uintptr_t args;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define MAX_STACK_FRAMES 8
|
||||
|
||||
static void unwind_stack(uintptr_t base_ptr, u16_t cs)
|
||||
{
|
||||
struct stack_frame *frame;
|
||||
int i;
|
||||
|
||||
if (base_ptr == 0U) {
|
||||
LOG_ERR("NULL base ptr");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_STACK_FRAMES; i++) {
|
||||
if (base_ptr % sizeof(base_ptr) != 0U) {
|
||||
LOG_ERR("unaligned frame ptr");
|
||||
return;
|
||||
}
|
||||
|
||||
frame = (struct stack_frame *)base_ptr;
|
||||
if (frame == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_THREAD_STACK_INFO
|
||||
/* Ensure the stack frame is within the faulting context's
|
||||
* stack buffer
|
||||
*/
|
||||
if (z_x86_check_stack_bounds((uintptr_t)frame,
|
||||
sizeof(*frame), cs)) {
|
||||
LOG_ERR(" corrupted? (bp=%p)", frame);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (frame->ret_addr == 0U) {
|
||||
break;
|
||||
}
|
||||
#ifdef CONFIG_X86_64
|
||||
LOG_ERR(" 0x%016lx", frame->ret_addr);
|
||||
#else
|
||||
LOG_ERR(" 0x%08lx (0x%lx)", frame->ret_addr, frame->args);
|
||||
#endif
|
||||
base_ptr = frame->next;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_EXCEPTION_STACK_TRACE */
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
static void dump_regs(const z_arch_esf_t *esf)
|
||||
{
|
||||
LOG_ERR("RAX: 0x%016lx RBX: 0x%016lx RCX: 0x%016lx RDX: 0x%016lx",
|
||||
esf->rax, esf->rbx, esf->rcx, esf->rdx);
|
||||
LOG_ERR("RSI: 0x%016lx RDI: 0x%016lx RBP: 0x%016lx RSP: 0x%016lx",
|
||||
esf->rsi, esf->rdi, esf->rbp, esf->rsp);
|
||||
LOG_ERR(" R8: 0x%016lx R9: 0x%016lx R10: 0x%016lx R11: 0x%016lx",
|
||||
esf->r8, esf->r9, esf->r10, esf->r11);
|
||||
LOG_ERR("R12: 0x%016lx R13: 0x%016lx R14: 0x%016lx R15: 0x%016lx",
|
||||
esf->r12, esf->r13, esf->r14, esf->r15);
|
||||
LOG_ERR("RSP: 0x%016lx RFLAGS: 0x%016lx CS: 0x%04lx CR3: %p", esf->rsp,
|
||||
esf->rflags, esf->cs & 0xFFFFU, z_x86_page_tables_get());
|
||||
|
||||
#ifdef CONFIG_EXCEPTION_STACK_TRACE
|
||||
LOG_ERR("call trace:");
|
||||
#endif
|
||||
LOG_ERR("RIP: 0x%016lx", esf->rip);
|
||||
#ifdef CONFIG_EXCEPTION_STACK_TRACE
|
||||
unwind_stack(esf->rbp, esf->cs);
|
||||
#endif
|
||||
}
|
||||
#else /* 32-bit */
|
||||
static void dump_regs(const z_arch_esf_t *esf)
|
||||
{
|
||||
LOG_ERR("EAX: 0x%08x, EBX: 0x%08x, ECX: 0x%08x, EDX: 0x%08x",
|
||||
esf->eax, esf->ebx, esf->ecx, esf->edx);
|
||||
LOG_ERR("ESI: 0x%08x, EDI: 0x%08x, EBP: 0x%08x, ESP: 0x%08x",
|
||||
esf->esi, esf->edi, esf->ebp, esf->esp);
|
||||
LOG_ERR("EFLAGS: 0x%08x CS: 0x%04x CR3: %p", esf->eflags,
|
||||
esf->cs & 0xFFFFU, z_x86_page_tables_get());
|
||||
|
||||
#ifdef CONFIG_EXCEPTION_STACK_TRACE
|
||||
LOG_ERR("call trace:");
|
||||
#endif
|
||||
LOG_ERR("EIP: 0x%08x", esf->eip);
|
||||
#ifdef CONFIG_EXCEPTION_STACK_TRACE
|
||||
unwind_stack(esf->ebp, esf->cs);
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_X86_64 */
|
||||
|
||||
FUNC_NORETURN void z_x86_fatal_error(unsigned int reason,
|
||||
const z_arch_esf_t *esf)
|
||||
{
|
||||
if (esf != NULL) {
|
||||
dump_regs(esf);
|
||||
}
|
||||
|
||||
z_fatal_error(reason, esf);
|
||||
CODE_UNREACHABLE;
|
||||
}
|
|
@ -21,93 +21,6 @@ LOG_MODULE_DECLARE(os);
|
|||
|
||||
__weak void z_debug_fatal_hook(const z_arch_esf_t *esf) { ARG_UNUSED(esf); }
|
||||
|
||||
#ifdef CONFIG_THREAD_STACK_INFO
|
||||
/**
|
||||
* @brief Check if a memory address range falls within the stack
|
||||
*
|
||||
* Given a memory address range, ensure that it falls within the bounds
|
||||
* of the faulting context's stack.
|
||||
*
|
||||
* @param addr Starting address
|
||||
* @param size Size of the region, or 0 if we just want to see if addr is
|
||||
* in bounds
|
||||
* @param cs Code segment of faulting context
|
||||
* @return true if addr/size region is not within the thread stack
|
||||
*/
|
||||
static bool check_stack_bounds(u32_t addr, size_t size, u16_t cs)
|
||||
{
|
||||
u32_t start, end;
|
||||
|
||||
if (z_arch_is_in_isr()) {
|
||||
/* We were servicing an interrupt */
|
||||
start = (u32_t)Z_ARCH_THREAD_STACK_BUFFER(_interrupt_stack);
|
||||
end = start + CONFIG_ISR_STACK_SIZE;
|
||||
} else if ((cs & 0x3U) != 0U ||
|
||||
(_current->base.user_options & K_USER) == 0) {
|
||||
/* Thread was in user mode, or is not a user mode thread.
|
||||
* The normal stack buffer is what we will check.
|
||||
*/
|
||||
start = _current->stack_info.start;
|
||||
end = STACK_ROUND_DOWN(_current->stack_info.start +
|
||||
_current->stack_info.size);
|
||||
} else {
|
||||
/* User thread was doing a syscall, check kernel stack bounds */
|
||||
start = _current->stack_info.start - MMU_PAGE_SIZE;
|
||||
end = _current->stack_info.start;
|
||||
}
|
||||
|
||||
return (addr <= start) || (addr + size > end);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_EXCEPTION_STACK_TRACE)
|
||||
struct stack_frame {
|
||||
u32_t next;
|
||||
u32_t ret_addr;
|
||||
u32_t args;
|
||||
};
|
||||
|
||||
#define MAX_STACK_FRAMES 8
|
||||
|
||||
static void unwind_stack(u32_t base_ptr, u16_t cs)
|
||||
{
|
||||
struct stack_frame *frame;
|
||||
int i;
|
||||
|
||||
if (base_ptr == 0U) {
|
||||
LOG_ERR("NULL base ptr");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_STACK_FRAMES; i++) {
|
||||
if (base_ptr % sizeof(base_ptr) != 0U) {
|
||||
LOG_ERR("unaligned frame ptr");
|
||||
return;
|
||||
}
|
||||
|
||||
frame = (struct stack_frame *)base_ptr;
|
||||
if (frame == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_THREAD_STACK_INFO
|
||||
/* Ensure the stack frame is within the faulting context's
|
||||
* stack buffer
|
||||
*/
|
||||
if (check_stack_bounds((u32_t)frame, sizeof(*frame), cs)) {
|
||||
LOG_ERR(" corrupted? (bp=%p)", frame);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (frame->ret_addr == 0U) {
|
||||
break;
|
||||
}
|
||||
LOG_ERR(" 0x%08x (0x%x)", frame->ret_addr, frame->args);
|
||||
base_ptr = frame->next;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_EXCEPTION_STACK_TRACE */
|
||||
|
||||
#ifdef CONFIG_BOARD_QEMU_X86
|
||||
FUNC_NORETURN void z_arch_system_halt(unsigned int reason)
|
||||
|
@ -122,29 +35,6 @@ FUNC_NORETURN void z_arch_system_halt(unsigned int reason)
|
|||
}
|
||||
#endif
|
||||
|
||||
FUNC_NORETURN void z_x86_fatal_error(unsigned int reason, const z_arch_esf_t *esf)
|
||||
{
|
||||
if (esf != NULL) {
|
||||
LOG_ERR("eax: 0x%08x, ebx: 0x%08x, ecx: 0x%08x, edx: 0x%08x",
|
||||
esf->eax, esf->ebx, esf->ecx, esf->edx);
|
||||
LOG_ERR("esi: 0x%08x, edi: 0x%08x, ebp: 0x%08x, esp: 0x%08x",
|
||||
esf->esi, esf->edi, esf->ebp, esf->esp);
|
||||
LOG_ERR("eflags: 0x%08x cs: 0x%04x cr3: %p", esf->eflags,
|
||||
esf->cs & 0xFFFFU, z_x86_page_tables_get());
|
||||
|
||||
#ifdef CONFIG_EXCEPTION_STACK_TRACE
|
||||
LOG_ERR("call trace:");
|
||||
#endif
|
||||
LOG_ERR("eip: 0x%08x", esf->eip);
|
||||
#ifdef CONFIG_EXCEPTION_STACK_TRACE
|
||||
unwind_stack(esf->ebp, esf->cs);
|
||||
#endif
|
||||
}
|
||||
|
||||
z_fatal_error(reason, esf);
|
||||
CODE_UNREACHABLE;
|
||||
}
|
||||
|
||||
void z_x86_spurious_irq(const z_arch_esf_t *esf)
|
||||
{
|
||||
int vector = z_irq_controller_isr_vector_get();
|
||||
|
@ -348,7 +238,7 @@ void page_fault_handler(z_arch_esf_t *esf)
|
|||
dump_page_fault(esf);
|
||||
#endif
|
||||
#ifdef CONFIG_THREAD_STACK_INFO
|
||||
if (check_stack_bounds(esf->esp, 0, esf->cs)) {
|
||||
if (z_x86_check_stack_bounds(esf->esp, 0, esf->cs)) {
|
||||
z_x86_fatal_error(K_ERR_STACK_CHK_FAIL, esf);
|
||||
}
|
||||
#endif
|
||||
|
@ -407,7 +297,7 @@ static __used void df_handler_bottom(void)
|
|||
|
||||
LOG_ERR("Double Fault");
|
||||
#ifdef CONFIG_THREAD_STACK_INFO
|
||||
if (check_stack_bounds(_df_esf.esp, 0, _df_esf.cs)) {
|
||||
if (z_x86_check_stack_bounds(_df_esf.esp, 0, _df_esf.cs)) {
|
||||
reason = K_ERR_STACK_CHK_FAIL;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -10,28 +10,6 @@
|
|||
#include <logging/log.h>
|
||||
LOG_MODULE_DECLARE(os);
|
||||
|
||||
void z_x86_fatal_error(unsigned int reason, const z_arch_esf_t *esf)
|
||||
{
|
||||
if (esf != NULL) {
|
||||
LOG_ERR("RIP: 0x%016lx RSP: 0x%016lx RFLAGS: 0x%016lx",
|
||||
esf->rip, esf->rsp, esf->rflags);
|
||||
|
||||
LOG_ERR("RAX: 0x%016lx RBX: 0x%016lx RCX: 0x%016lx RDX: 0x%016lx",
|
||||
esf->rax, esf->rbx, esf->rcx, esf->rdx);
|
||||
|
||||
LOG_ERR("RSI: 0x%016lx RDI: 0x%016lx RBP: 0x%016lx RSP: 0x%016lx",
|
||||
esf->rsi, esf->rdi, esf->rbp, esf->rsp);
|
||||
|
||||
LOG_ERR(" R8: 0x%016lx R9: 0x%016lx R10: 0x%016lx R11: 0x%016lx",
|
||||
esf->r8, esf->r9, esf->r10, esf->r11);
|
||||
|
||||
LOG_ERR("R12: 0x%016lx R13: 0x%016lx R14: 0x%016lx R15: 0x%016lx",
|
||||
esf->r12, esf->r13, esf->r14, esf->r15);
|
||||
}
|
||||
|
||||
z_fatal_error(reason, esf);
|
||||
}
|
||||
|
||||
void z_x86_exception(const z_arch_esf_t *esf)
|
||||
{
|
||||
LOG_ERR("** CPU Exception %ld (code %ld/0x%lx) **",
|
||||
|
|
|
@ -47,6 +47,27 @@ void z_x86_early_serial_init(void);
|
|||
void z_x86_paging_init(void);
|
||||
#endif /* CONFIG_X86_MMU */
|
||||
|
||||
#endif
|
||||
/* Called upon unrecoverable error; dump registers and transfer control to
|
||||
* kernel via z_fatal_error()
|
||||
*/
|
||||
FUNC_NORETURN void z_x86_fatal_error(unsigned int reason,
|
||||
const z_arch_esf_t *esf);
|
||||
|
||||
#ifdef CONFIG_THREAD_STACK_INFO
|
||||
/**
|
||||
* @brief Check if a memory address range falls within the stack
|
||||
*
|
||||
* Given a memory address range, ensure that it falls within the bounds
|
||||
* of the faulting context's stack.
|
||||
*
|
||||
* @param addr Starting address
|
||||
* @param size Size of the region, or 0 if we just want to see if addr is
|
||||
* in bounds
|
||||
* @param cs Code segment of faulting context
|
||||
* @return true if addr/size region is not within the thread stack
|
||||
*/
|
||||
bool z_x86_check_stack_bounds(uintptr_t addr, size_t size, u16_t cs);
|
||||
#endif /* CONFIG_THREAD_STACK_INFO */
|
||||
#endif /* !_ASMLANGUAGE */
|
||||
|
||||
#endif /* ZEPHYR_ARCH_X86_INCLUDE_KERNEL_ARCH_FUNC_H_ */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue