diff --git a/sys/x86/include/mca.h b/sys/x86/include/mca.h --- a/sys/x86/include/mca.h +++ b/sys/x86/include/mca.h @@ -46,6 +46,11 @@ #ifdef _KERNEL +typedef void (*mca_decode_func)(void*, const struct mca_record*); + +int mca_register_decode_func(mca_decode_func func, void *aux); +int mca_deregister_decode_func(mca_decode_func func); + void cmc_intr(void); void mca_init(void); void mca_intr(void); diff --git a/sys/x86/x86/mca.c b/sys/x86/x86/mca.c --- a/sys/x86/x86/mca.c +++ b/sys/x86/x86/mca.c @@ -99,6 +99,8 @@ static volatile int mca_count; /* Number of records stored. */ static int mca_banks; /* Number of per-CPU register banks. */ static int mca_maxcount = -1; /* Limit on records stored. (-1 = unlimited) */ +static mca_decode_func mca_func; +static void *mca_decode_arg; static SYSCTL_NODE(_hw, OID_AUTO, mca, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Machine Check Architecture"); @@ -421,10 +423,45 @@ return (0); } +int +mca_register_decode_func(mca_decode_func func, void *arg) +{ + int error = 0; + + KASSERT(func != NULL, ("missing decode function")); + + mtx_lock_spin(&mca_lock); + if (mca_func == NULL) { + mca_decode_arg = arg; + atomic_set_ptr((uintptr_t *)&mca_func, (uintptr_t)func); + } else + error = EEXIST; + mtx_unlock_spin(&mca_lock); + + return (error); +} + +int +mca_deregister_decode_func(mca_decode_func func) +{ + int error = 0; + + KASSERT(func != NULL, ("missing decode function")); + + mtx_lock_spin(&mca_lock); + if (!atomic_cmpset_acq_ptr((uintptr_t *)&mca_func, (uintptr_t)func, + (uintptr_t)NULL)) + error = EINVAL; + mtx_unlock_spin(&mca_lock); + + return (error); +} + /* Dump details about a single machine check. */ static void mca_log(const struct mca_record *rec) { + mca_decode_func decode_func; uint16_t mca_error; if (mca_mute(rec)) @@ -613,6 +650,14 @@ } if (rec->mr_status & MC_STATUS_MISCV) printf("MCA: Misc 0x%llx\n", (long long)rec->mr_misc); + + /* + * Pass record to a memory controller driver so that it can + * decode the address. + */ + decode_func = atomic_load_ptr(&mca_func); + if (decode_func != NULL) + decode_func(mca_decode_arg, rec); } static bool