diff --git a/sys/arm64/arm64/exception.S b/sys/arm64/arm64/exception.S --- a/sys/arm64/arm64/exception.S +++ b/sys/arm64/arm64/exception.S @@ -264,9 +264,10 @@ save_registers 0 KMSAN_ENTER mov x0, sp -1: bl do_serror - b 1b + bl do_serror KMSAN_LEAVE + restore_registers 0 + ERET END(handle_serror) ENTRY(handle_empty_exception) diff --git a/sys/arm64/arm64/trap.c b/sys/arm64/arm64/trap.c --- a/sys/arm64/arm64/trap.c +++ b/sys/arm64/arm64/trap.c @@ -33,10 +33,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #ifdef KDB @@ -51,6 +53,7 @@ #include #include +#include #include #include #include @@ -73,6 +76,17 @@ #include #endif +/* SError handler list. */ +struct serror_handler { + serror_handler_func_t handler; + void *arg; + STAILQ_ENTRY(serror_handler) link; +}; +STAILQ_HEAD(, serror_handler) serror_handlers = + STAILQ_HEAD_INITIALIZER(serror_handlers); + +MALLOC_DEFINE(M_SERROR, "SError handlers", "Lists for SError handlers"); + /* Called from exception.S */ void do_el1h_sync(struct thread *, struct trapframe *); void do_el0_sync(struct thread *, struct trapframe *); @@ -741,13 +755,37 @@ ("Kernel VFP state in use when entering userspace")); } +int +register_serror_handler(serror_handler_func_t handler, void *arg) +{ + struct serror_handler *sh; + + if (!cold) + return (EINVAL); + sh = malloc(sizeof(struct serror_handler), M_SERROR, M_WAITOK); + sh->handler = handler; + sh->arg = arg; + STAILQ_INSERT_TAIL(&serror_handlers, sh, link); + + return (0); +} + /* * TODO: We will need to handle these later when we support ARMv8.2 RAS. */ void do_serror(struct trapframe *frame) { + struct serror_handler *handler; uint64_t esr, far; + int error; + + STAILQ_FOREACH(handler, &serror_handlers, link) { + error = handler->handler(handler->arg); + /* A handled SError, no need to panic */ + if (error == 0) + return; + } kasan_mark(frame, sizeof(*frame), sizeof(*frame), 0); kmsan_mark(frame, sizeof(*frame), KMSAN_STATE_INITED); diff --git a/sys/arm64/include/machdep.h b/sys/arm64/include/machdep.h --- a/sys/arm64/include/machdep.h +++ b/sys/arm64/include/machdep.h @@ -44,6 +44,8 @@ ARM64_BUS_ACPI, }; +typedef int (*serror_handler_func_t)(void *); + extern enum arm64_bus arm64_bus_method; void dbg_init(void); @@ -51,6 +53,7 @@ bool in_vhe(void); void initarm(struct arm64_bootparams *); vm_offset_t parse_boot_param(struct arm64_bootparams *abp); +int register_serror_handler(serror_handler_func_t, void *); #ifdef FDT void parse_fdt_bootargs(void); #endif