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:
Stefan Kalkowski 2025-01-27 14:22:24 +01:00 committed by Christian Helmuth
parent 17d1e41053
commit 31a5597f66
7 changed files with 235 additions and 6 deletions

View File

@ -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);
}

View File

@ -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);
};

View File

@ -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();
}

View File

@ -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");
}

View File

@ -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");
}

View File

@ -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");
}

View File

@ -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");
}