[panic] Allow assert/panic to take optional user cpu_state

In places where the "user" state is available, like interrupt handlers,
panic() and kassert() can now take an optional pointer to that user
cpu_state structure, and the panic handler will print that out as well.
This commit is contained in:
Justin C. Miller
2022-01-15 09:33:38 -08:00
parent 421fe33dc0
commit 4d9b33ecd4
8 changed files with 32 additions and 19 deletions

View File

@@ -9,5 +9,5 @@ void const *symbol_table = nullptr;
extern "C" extern "C"
void _PDCLIB_assert(const char *message, const char *function, const char *file, unsigned line) { void _PDCLIB_assert(const char *message, const char *function, const char *file, unsigned line) {
panic::panic(message, function, file, line); panic::panic(message, nullptr, function, file, line);
} }

View File

@@ -16,6 +16,7 @@ extern void const *symbol_table;
__attribute__ ((always_inline)) __attribute__ ((always_inline))
inline void panic( inline void panic(
const char *message = nullptr, const char *message = nullptr,
const cpu_state *user = nullptr,
const char *function = __builtin_FUNCTION(), const char *function = __builtin_FUNCTION(),
const char *file = __builtin_FILE(), const char *file = __builtin_FILE(),
uint64_t line = __builtin_LINE()) uint64_t line = __builtin_LINE())
@@ -28,10 +29,13 @@ inline void panic(
// If we aren't the first CPU to panic, cpu.panic will be null // If we aren't the first CPU to panic, cpu.panic will be null
if (cpu.panic) { if (cpu.panic) {
cpu.panic->symbol_data = symbol_table; cpu.panic->symbol_data = symbol_table;
cpu.panic->user_state = user;
cpu.panic->message = message; cpu.panic->message = message;
cpu.panic->function = function; cpu.panic->function = function;
cpu.panic->file = file; cpu.panic->file = file;
cpu.panic->line = line; cpu.panic->line = line;
cpu.panic->cpus = g_num_cpus; cpu.panic->cpus = g_num_cpus;
*apic_icr = send_nmi_command; *apic_icr = send_nmi_command;
@@ -48,12 +52,13 @@ __attribute__ ((always_inline))
inline void kassert( inline void kassert(
bool check, bool check,
const char *message = nullptr, const char *message = nullptr,
const cpu_state *user = nullptr,
const char *function = __builtin_FUNCTION(), const char *function = __builtin_FUNCTION(),
const char *file = __builtin_FILE(), const char *file = __builtin_FILE(),
uint64_t line = __builtin_LINE()) uint64_t line = __builtin_LINE())
{ {
if (!check) if (!check)
panic::panic(message, function, file, line); panic::panic(message, user, function, file, line);
} }
#define assert(x) kassert((x)) #define assert(x) kassert((x))

View File

@@ -21,11 +21,14 @@ struct cpu_state
/// Kernel-wide panic information /// Kernel-wide panic information
struct panic_data struct panic_data
{ {
void const * symbol_data; void const *symbol_data;
char const * message; cpu_state const *user_state;
char const * function;
char const * file; char const *message;
char const *function;
char const *file;
uint32_t line; uint32_t line;
uint16_t cpus; uint16_t cpus;
}; };

View File

@@ -91,11 +91,11 @@ isr_handler(cpu_state *regs)
asm volatile ("mov %%dr5, %%r13" ::: "r13"); asm volatile ("mov %%dr5, %%r13" ::: "r13");
asm volatile ("mov %%dr6, %%r14" ::: "r14"); asm volatile ("mov %%dr6, %%r14" ::: "r14");
asm volatile ("mov %%dr7, %%r15" ::: "r15"); asm volatile ("mov %%dr7, %%r15" ::: "r15");
kassert(false, "Debug exception"); kassert(false, "Debug exception", regs);
break; break;
case isr::isrDoubleFault: case isr::isrDoubleFault:
kassert(false, "Double fault"); kassert(false, "Double fault", regs);
break; break;
case isr::isrGPFault: case isr::isrGPFault:
@@ -113,7 +113,7 @@ isr_handler(cpu_state *regs)
snprintf(message, sizeof(message), "General Protection Fault, error:%lx%s", snprintf(message, sizeof(message), "General Protection Fault, error:%lx%s",
regs->errorcode, regs->errorcode & 1 ? " external" : ""); regs->errorcode, regs->errorcode & 1 ? " external" : "");
} }
kassert(false, message); kassert(false, message, regs);
break; break;
case isr::isrPageFault: { case isr::isrPageFault: {
@@ -138,7 +138,7 @@ isr_handler(cpu_state *regs)
(regs->errorcode & 0x04) ? " user" : "", (regs->errorcode & 0x04) ? " user" : "",
(regs->errorcode & 0x08) ? " reserved" : "", (regs->errorcode & 0x08) ? " reserved" : "",
(regs->errorcode & 0x10) ? " ip" : ""); (regs->errorcode & 0x10) ? " ip" : "");
kassert(false, message); kassert(false, message, regs);
} }
break; break;
@@ -156,7 +156,7 @@ isr_handler(cpu_state *regs)
default: default:
snprintf(message, sizeof(message), "Unknown interrupt 0x%lx", regs->interrupt); snprintf(message, sizeof(message), "Unknown interrupt 0x%lx", regs->interrupt);
kassert(false, message); kassert(false, message, regs);
} }
// Return the IST for this vector to what it was // Return the IST for this vector to what it was

View File

@@ -113,6 +113,13 @@ print_cpu_state(serial_port &out, const cpu_state &regs)
out.write(clear); out.write(clear);
} }
void
print_user_state(serial_port &out, const cpu_state &regs)
{
out.write("\n\e[1;35m USER:\e[0 ");
print_cpu_state(out, regs);
}
} // namespace panicking } // namespace panicking
// For printf.c // For printf.c

View File

@@ -28,5 +28,6 @@ void print_header(
void print_cpu(serial_port &out, cpu_data &cpu); void print_cpu(serial_port &out, cpu_data &cpu);
void print_callstack(serial_port &out, symbol_table &syms, frame const *fp); void print_callstack(serial_port &out, symbol_table &syms, frame const *fp);
void print_cpu_state(serial_port &out, const cpu_state &regs); void print_cpu_state(serial_port &out, const cpu_state &regs);
void print_user_state(serial_port &out, const cpu_state &regs);
} // namespace panicking } // namespace panicking

View File

@@ -12,7 +12,7 @@ _panic_entry:
push_all push_all
check_swap_gs check_swap_gs
mov r9, rsp mov rdi, rsp
mov rax, [rsp + REGS.rip] mov rax, [rsp + REGS.rip]
push rax push rax

View File

@@ -22,13 +22,7 @@ panicking::symbol_table &syms = __syms_storage.value;
constexpr int order = __ATOMIC_ACQ_REL; constexpr int order = __ATOMIC_ACQ_REL;
extern "C" extern "C"
void panic_handler( void panic_handler(const cpu_state *regs)
const void *symbol_data,
const char *message,
const char *function,
const char *file,
uint64_t line,
const cpu_state *regs)
{ {
cpu_data &cpu = current_cpu(); cpu_data &cpu = current_cpu();
panic_data *panic = cpu.panic; panic_data *panic = cpu.panic;
@@ -57,6 +51,9 @@ void panic_handler(
print_callstack(com1, syms, fp); print_callstack(com1, syms, fp);
print_cpu_state(com1, *regs); print_cpu_state(com1, *regs);
if (panic && panic->user_state)
print_user_state(com1, *panic->user_state);
__atomic_clear(&asserting_locked, order); __atomic_clear(&asserting_locked, order);
// If we're running on the CPU that panicked, tell the // If we're running on the CPU that panicked, tell the