[panic] Have panics stop all cores

Kernel panics previously only stopped the calling core. This commit
re-implements the panic system to allow us to stop all cores on a panic.

Changes include:

- panic now sends an NMI to all cores. This means we can't control the
  contents of their registers, so panic information has been moved to a
  global struct, and the panicking cpu sets the pointer to that data in
  its cpu_data.
- the panic_handler is now set up with mutexes to print appropriately
  and only initialize objects once.
- copying _current_gsbase into the panic handler, and #including the
  cpprt.cpp file (so that we can define NDEBUG and not have it try to
  link the assert code back in)
- making the symbol data pointer in kargs an actual pointer again, not
  an address - and carrying that through to the panic handler
- the number of cpus is now saved globally in the kernel as g_num_cpus
This commit is contained in:
Justin C. Miller
2022-01-08 01:00:43 -08:00
parent a3fff889d1
commit eeef23c2b7
12 changed files with 134 additions and 30 deletions

View File

@@ -1,16 +1,17 @@
#pragma once
#include <stdint.h>
#include "cpu.h"
namespace panic {
constexpr uint32_t send_nmi_command =
(4 << 8) | // Delivery mode NMI
(1 << 14) | // assert level high
(1 << 18); // destination self
(2 << 18); // destination all
extern uint32_t *apic_icr;
extern uintptr_t symbol_table;
extern void const *symbol_table;
__attribute__ ((always_inline))
inline void panic(
@@ -19,19 +20,23 @@ inline void panic(
const char *file = __builtin_FILE(),
uint64_t line = __builtin_LINE())
{
register uintptr_t syms asm("rdi");
register const char *m asm("rsi");
register const char *fn asm("rdx");
register const char *fi asm("rcx");
register uint64_t l asm("r8");
cpu_data &cpu = current_cpu();
asm volatile ("mov %1, %0" : "=r"(syms) : "r"(symbol_table));
asm volatile ("mov %1, %0" : "=r"(m) : "r"(message));
asm volatile ("mov %1, %0" : "=r"(fn) : "r"(function));
asm volatile ("mov %1, %0" : "=r"(fi) : "r"(file));
asm volatile ("mov %1, %0" : "=r"(l) : "r"(line));
// Grab the global panic block for ourselves
cpu.panic = __atomic_exchange_n(&g_panic_data_p, nullptr, __ATOMIC_ACQ_REL);
// If we aren't the first CPU to panic, cpu.panic will be null
if (cpu.panic) {
cpu.panic->symbol_data = symbol_table;
cpu.panic->message = message;
cpu.panic->function = function;
cpu.panic->file = file;
cpu.panic->line = line;
cpu.panic->cpus = g_num_cpus;
*apic_icr = send_nmi_command;
}
*apic_icr = send_nmi_command;
while (1) asm ("hlt");
}