mirror of
https://github.com/genodelabs/genode.git
synced 2025-03-14 08:16:28 +00:00
hw: dump cpu context when kernel faults
* Introduce architecture-specific Cpu::panic routine * Dump stored CPU state in panic routine * Try to backtrace kernel context's stack Fix genodelabs/genode#5425
This commit is contained in:
parent
17d1e41053
commit
31a5597f66
@ -159,11 +159,16 @@ Cpu::Context & Cpu::schedule_next_context(Context &last)
|
||||
}
|
||||
|
||||
|
||||
addr_t Cpu::stack_base()
|
||||
{
|
||||
return Hw::Mm::cpu_local_memory().base +
|
||||
Hw::Mm::CPU_LOCAL_MEMORY_SLOT_SIZE*_id;
|
||||
}
|
||||
|
||||
|
||||
addr_t Cpu::stack_start()
|
||||
{
|
||||
return Abi::stack_align(Hw::Mm::cpu_local_memory().base +
|
||||
(Hw::Mm::CPU_LOCAL_MEMORY_SLOT_SIZE*_id)
|
||||
+ Hw::Mm::KERNEL_STACK_SIZE);
|
||||
return Abi::stack_align(stack_base() + Hw::Mm::KERNEL_STACK_SIZE);
|
||||
}
|
||||
|
||||
|
||||
|
@ -155,6 +155,7 @@ class Kernel::Cpu : public Core::Cpu, private Irq::Pool,
|
||||
Board::Pic & pic() { return _pic; }
|
||||
Timer & timer() { return _timer; }
|
||||
|
||||
addr_t stack_base();
|
||||
addr_t stack_start();
|
||||
|
||||
/**
|
||||
@ -181,6 +182,8 @@ class Kernel::Cpu : public Core::Cpu, private Irq::Pool,
|
||||
_arch_init();
|
||||
_state = RUN;
|
||||
}
|
||||
|
||||
[[noreturn]] void panic(Genode::Cpu_state &state);
|
||||
};
|
||||
|
||||
|
||||
|
@ -72,9 +72,7 @@ void Kernel::Main::_handle_kernel_entry(Genode::Cpu_state *state)
|
||||
if (state) recent.exception(*state);
|
||||
context = &cpu.schedule_next_context(recent);
|
||||
},
|
||||
[&] () {
|
||||
Genode::error("Cpu ", Cpu::executing_id(), " re-entered lock. ",
|
||||
"Kernel exception?!"); });
|
||||
[&] () { _cpu_pool.cpu(Cpu::executing_id()).panic(*state); });
|
||||
|
||||
context->proceed();
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
/* core includes */
|
||||
#include <kernel/cpu.h>
|
||||
#include <kernel/perf_counter.h>
|
||||
#include <hw/memory_consts.h>
|
||||
|
||||
|
||||
void Kernel::Cpu::_arch_init()
|
||||
@ -24,3 +25,55 @@ void Kernel::Cpu::_arch_init()
|
||||
/* enable timer interrupt */
|
||||
_pic.unmask(_timer.interrupt_id(), id());
|
||||
}
|
||||
|
||||
|
||||
[[noreturn]] void Kernel::Cpu::panic(Genode::Cpu_state &state)
|
||||
{
|
||||
using namespace Genode;
|
||||
using Cs = Genode::Cpu_state;
|
||||
|
||||
const char *reason = "unknown";
|
||||
|
||||
switch (state.cpu_exception) {
|
||||
case Cs::PREFETCH_ABORT: [[fallthrough]];
|
||||
case Cs::DATA_ABORT: reason = "page-fault"; break;
|
||||
case Cs::UNDEFINED_INSTRUCTION: reason = "undefined instruction"; break;
|
||||
case Cs::SUPERVISOR_CALL: reason = "system-call"; break;
|
||||
case Cs::FAST_INTERRUPT_REQUEST: [[fallthrough]];
|
||||
case Cs::INTERRUPT_REQUEST: reason = "interrupt "; break;
|
||||
case Cs::RESET : reason = "reset "; break;
|
||||
default: ;
|
||||
};
|
||||
|
||||
log("");
|
||||
log("Kernel panic on CPU ", Cpu::executing_id());
|
||||
log("Exception reason is ", reason);
|
||||
log("");
|
||||
log("Register dump:");
|
||||
log("r0 = ", Hex(state.r0));
|
||||
log("r1 = ", Hex(state.r1));
|
||||
log("r2 = ", Hex(state.r2));
|
||||
log("r3 = ", Hex(state.r3));
|
||||
log("r4 = ", Hex(state.r4));
|
||||
log("r5 = ", Hex(state.r5));
|
||||
log("r6 = ", Hex(state.r6));
|
||||
log("r7 = ", Hex(state.r7));
|
||||
log("r8 = ", Hex(state.r8));
|
||||
log("r9 = ", Hex(state.r9));
|
||||
log("r10 = ", Hex(state.r10));
|
||||
log("r11 = ", Hex(state.r11));
|
||||
log("r12 = ", Hex(state.r12));
|
||||
log("sp = ", Hex(state.sp));
|
||||
log("lr = ", Hex(state.lr));
|
||||
log("ip = ", Hex(state.ip));
|
||||
log("cpsr = ", Hex(state.cpsr));
|
||||
log("");
|
||||
log("Backtrace:");
|
||||
|
||||
Core::Cpu::Context &context = static_cast<Core::Cpu::Context&>(state);
|
||||
Const_byte_range_ptr const stack {
|
||||
(char const*)stack_base(), Hw::Mm::KERNEL_STACK_SIZE };
|
||||
context.for_each_return_address(stack, [&] (void **p) { log(*p); });
|
||||
|
||||
while (true) asm volatile("wfi");
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/cpu.h>
|
||||
#include <hw/memory_consts.h>
|
||||
|
||||
|
||||
void Kernel::Cpu::_arch_init()
|
||||
@ -20,3 +21,55 @@ void Kernel::Cpu::_arch_init()
|
||||
/* enable timer interrupt */
|
||||
_pic.unmask(_timer.interrupt_id(), id());
|
||||
}
|
||||
|
||||
|
||||
[[noreturn]] void Kernel::Cpu::panic(Genode::Cpu_state &state)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
Core::Cpu::Context &context = static_cast<Core::Cpu::Context&>(state);
|
||||
|
||||
const char *reason = "unknown";
|
||||
|
||||
switch (context.exception_type) {
|
||||
case Cpu::SYNC_LEVEL_EL0: [[fallthrough]];
|
||||
case Cpu::SYNC_LEVEL_EL1:
|
||||
using Ec = Cpu::Esr::Ec;
|
||||
switch (Ec::get(state.esr_el1)) {
|
||||
case Ec::INST_ABORT_SAME_LEVEL: [[fallthrough]];
|
||||
case Ec::DATA_ABORT_SAME_LEVEL: [[fallthrough]];
|
||||
case Ec::INST_ABORT_LOW_LEVEL: [[fallthrough]];
|
||||
case Ec::DATA_ABORT_LOW_LEVEL: reason = "page-fault"; break;
|
||||
case Ec::SVC: reason = "system-call"; break;
|
||||
case Ec::SOFTWARE_STEP_LOW_LEVEL: [[fallthrough]];
|
||||
case Ec::BRK: reason = "debug"; break;
|
||||
default: ;
|
||||
}
|
||||
break;
|
||||
case Cpu::IRQ_LEVEL_EL0: [[fallthrough]];
|
||||
case Cpu::IRQ_LEVEL_EL1: [[fallthrough]];
|
||||
case Cpu::FIQ_LEVEL_EL0: [[fallthrough]];
|
||||
case Cpu::FIQ_LEVEL_EL1: reason = "interrupt "; break;
|
||||
case Cpu::RESET: reason = "reset "; break;
|
||||
default: ;
|
||||
};
|
||||
|
||||
log("");
|
||||
log("Kernel panic on CPU ", Cpu::executing_id());
|
||||
log("Exception reason is ", reason);
|
||||
log("");
|
||||
log("Register dump:");
|
||||
for (unsigned i = 0; i < 31; i++)
|
||||
log("r", i, i<10 ? " " : "", " = ", Hex(state.r[i]));
|
||||
log("sp = ", Hex(state.sp));
|
||||
log("ip = ", Hex(state.ip));
|
||||
log("esr_el1 = ", Hex(state.esr_el1));
|
||||
log("");
|
||||
log("Backtrace:");
|
||||
|
||||
Const_byte_range_ptr const stack {
|
||||
(char const*)stack_base(), Hw::Mm::KERNEL_STACK_SIZE };
|
||||
context.for_each_return_address(stack, [&] (void **p) { log(*p); });
|
||||
|
||||
while (true) asm volatile("wfi");
|
||||
}
|
||||
|
@ -14,7 +14,82 @@
|
||||
/* core includes */
|
||||
#include <kernel/cpu.h>
|
||||
#include <hw/memory_map.h>
|
||||
#include <hw/memory_consts.h>
|
||||
|
||||
|
||||
void Kernel::Cpu::_arch_init() {
|
||||
Stvec::write(Hw::Mm::supervisor_exception_vector().base); }
|
||||
|
||||
|
||||
[[noreturn]] void Kernel::Cpu::panic(Genode::Cpu_state &state)
|
||||
{
|
||||
using namespace Genode;
|
||||
using Cs = Genode::Cpu_state;
|
||||
|
||||
Core::Cpu::Context &context = static_cast<Core::Cpu::Context&>(state);
|
||||
|
||||
const char *reason = "unknown";
|
||||
|
||||
if (context.is_irq()) reason = "interrupt";
|
||||
|
||||
switch(state.cpu_exception) {
|
||||
case Cs::ECALL_FROM_SUPERVISOR: [[fallthrough]];
|
||||
case Cs::ECALL_FROM_USER: reason = "system-call"; break;
|
||||
case Cs::INSTRUCTION_PAGE_FAULT: [[fallthrough]];
|
||||
case Cs::STORE_PAGE_FAULT: [[fallthrough]];
|
||||
case Cs::LOAD_PAGE_FAULT: [[fallthrough]];
|
||||
case Cs::INSTRUCTION_ACCESS_FAULT: [[fallthrough]];
|
||||
case Cs::LOAD_ACCESS_FAULT: [[fallthrough]];
|
||||
case Cs::STORE_ACCESS_FAULT: reason = "page-fault"; break;
|
||||
case Cs::INSTRUCTION_ILLEGAL: reason = "undefined-instruction"; break;
|
||||
case Cs::BREAKPOINT: reason = "debug"; break;
|
||||
case Cs::RESET: reason = "reset"; break;
|
||||
default: ;
|
||||
}
|
||||
|
||||
log("");
|
||||
log("Kernel panic on CPU ", Cpu::executing_id());
|
||||
log("Exception reason is ", reason);
|
||||
log("");
|
||||
log("Register dump:");
|
||||
log("ip = ", Hex(state.ip));
|
||||
log("ra = ", Hex(state.ra));
|
||||
log("sp = ", Hex(state.sp));
|
||||
log("gp = ", Hex(state.gp));
|
||||
log("tp = ", Hex(state.tp));
|
||||
log("t0 = ", Hex(state.t0));
|
||||
log("t1 = ", Hex(state.t1));
|
||||
log("t2 = ", Hex(state.t2));
|
||||
log("s0 = ", Hex(state.s0));
|
||||
log("s1 = ", Hex(state.s1));
|
||||
log("a0 = ", Hex(state.a0));
|
||||
log("a1 = ", Hex(state.a1));
|
||||
log("a2 = ", Hex(state.a2));
|
||||
log("a3 = ", Hex(state.a3));
|
||||
log("a4 = ", Hex(state.a4));
|
||||
log("a5 = ", Hex(state.a5));
|
||||
log("a6 = ", Hex(state.a6));
|
||||
log("a7 = ", Hex(state.a7));
|
||||
log("s2 = ", Hex(state.s2));
|
||||
log("s3 = ", Hex(state.s3));
|
||||
log("s4 = ", Hex(state.s4));
|
||||
log("s5 = ", Hex(state.s5));
|
||||
log("s6 = ", Hex(state.s6));
|
||||
log("s7 = ", Hex(state.s7));
|
||||
log("s8 = ", Hex(state.s8));
|
||||
log("s9 = ", Hex(state.s9));
|
||||
log("s10 = ", Hex(state.s10));
|
||||
log("s11 = ", Hex(state.s11));
|
||||
log("t3 = ", Hex(state.t3));
|
||||
log("t4 = ", Hex(state.t4));
|
||||
log("t5 = ", Hex(state.t5));
|
||||
log("t6 = ", Hex(state.t6));
|
||||
log("");
|
||||
log("Backtrace:");
|
||||
|
||||
Const_byte_range_ptr const stack {
|
||||
(char const*)stack_base(), Hw::Mm::KERNEL_STACK_SIZE };
|
||||
context.for_each_return_address(stack, [&] (void **p) { log(*p); });
|
||||
|
||||
while (true) asm volatile("wfi");
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/cpu.h>
|
||||
#include <hw/memory_consts.h>
|
||||
|
||||
|
||||
void Kernel::Cpu::_arch_init()
|
||||
@ -32,3 +33,44 @@ void Kernel::Cpu::_arch_init()
|
||||
/* enable timer interrupt */
|
||||
_pic.unmask(_timer.interrupt_id(), id());
|
||||
}
|
||||
|
||||
|
||||
[[noreturn]] void Kernel::Cpu::panic(Genode::Cpu_state &state)
|
||||
{
|
||||
using namespace Genode;
|
||||
using Cs = Genode::Cpu_state;
|
||||
|
||||
const char *reason = "unknown";
|
||||
|
||||
switch (state.trapno) {
|
||||
case Cs::PAGE_FAULT: reason = "page-fault"; break;
|
||||
case Cs::UNDEFINED_INSTRUCTION: reason = "undefined instruction"; break;
|
||||
case Cs::SUPERVISOR_CALL: reason = "system-call"; break;
|
||||
default:
|
||||
if (state.trapno >= Cs::INTERRUPTS_START &&
|
||||
state.trapno <= Cs::INTERRUPTS_END)
|
||||
reason = "interrupt";
|
||||
};
|
||||
|
||||
log("");
|
||||
log("Kernel panic on CPU ", Cpu::executing_id());
|
||||
log("Exception reason is ", reason, " (trapno=", state.trapno, ")");
|
||||
log("");
|
||||
log("Register dump:");
|
||||
log("ip = ", Hex(state.ip));
|
||||
log("sp = ", Hex(state.sp));
|
||||
log("cs = ", Hex(state.cs));
|
||||
log("ss = ", Hex(state.ss));
|
||||
log("eflags = ", Hex(state.eflags));
|
||||
log("rax = ", Hex(state.rax));
|
||||
log("rbx = ", Hex(state.rbx));
|
||||
log("rcx = ", Hex(state.rcx));
|
||||
log("rdx = ", Hex(state.rdx));
|
||||
log("rdi = ", Hex(state.rdi));
|
||||
log("rsi = ", Hex(state.rsi));
|
||||
log("rbp = ", Hex(state.rbp));
|
||||
log("CR2 = ", Hex(Cpu::Cr2::read()));
|
||||
log("CR3 = ", Hex(Cpu::Cr3::read()));
|
||||
|
||||
while (true) asm volatile("hlt");
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user