1 /* $Id: nmi.c,v 1.2 2009/02/24 10:37:27 yamt Exp $ */ 2 3 /*- 4 * Copyright (c)2009 YAMAMOTO Takashi, 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: nmi.c,v 1.2 2009/02/24 10:37:27 yamt Exp $"); 31 32 /* 33 * nmi dispatcher. 34 * 35 * XXX no need to be nmi-specific. 36 * actual assumptions are: 37 * - dispatch() is called with preemption disabled. 38 * - handlers never block. 39 * - establish() and disestablish() are called within a thread context. 40 * (thus can block) 41 */ 42 43 #include <sys/param.h> 44 #include <sys/kernel.h> 45 #include <sys/systm.h> 46 #include <sys/atomic.h> 47 #include <sys/kmem.h> 48 #include <sys/mutex.h> 49 #include <sys/xcall.h> 50 51 #include <x86/nmi.h> 52 53 struct nmi_handler { 54 int (*n_func)(const struct trapframe *, void *); 55 void *n_arg; 56 struct nmi_handler *n_next; 57 }; 58 59 static kmutex_t nmi_list_lock; /* serialize establish and disestablish */ 60 static nmi_handler_t *nmi_handlers; /* list of handlers */ 61 62 /* 63 * nmi_establish: establish an nmi handler 64 * 65 * => can block. 66 * => returns an opaque handle. 67 */ 68 69 nmi_handler_t * 70 nmi_establish(int (*func)(const struct trapframe *, void *), void *arg) 71 { 72 struct nmi_handler *n; 73 74 n = kmem_alloc(sizeof(*n), KM_SLEEP); 75 if (n == NULL) { 76 return NULL; 77 } 78 n->n_func = func; 79 n->n_arg = arg; 80 81 /* 82 * put it into the list. 83 */ 84 85 mutex_enter(&nmi_list_lock); 86 n->n_next = nmi_handlers; 87 membar_producer(); /* n->n_next should be visible before nmi_handlers */ 88 nmi_handlers = n; /* atomic store */ 89 mutex_exit(&nmi_list_lock); 90 91 return n; 92 } 93 94 /* 95 * nmi_disestablish: disestablish an nmi handler. 96 * 97 * => can block. 98 * => take an opaque handle. it must be one returned by nmi_establish. 99 */ 100 101 void 102 nmi_disestablish(nmi_handler_t *handle) 103 { 104 nmi_handler_t *n; 105 nmi_handler_t **pp; 106 107 KASSERT(handle != NULL); 108 109 /* 110 * remove the handler from the list. 111 */ 112 113 mutex_enter(&nmi_list_lock); 114 for (pp = &nmi_handlers, n = *pp; n != NULL; n = *pp) { 115 if (n == handle) { 116 break; 117 } 118 pp = &n->n_next; 119 } 120 #if defined(DIAGNOSTIC) 121 if (n == NULL) { 122 mutex_exit(&nmi_list_lock); 123 panic("%s: invalid handle %p", __func__, handle); 124 } 125 #endif /* defined(DIAGNOSTIC) */ 126 *pp = n->n_next; /* atomic store */ 127 mutex_exit(&nmi_list_lock); /* mutex_exit implies a store fence */ 128 129 /* 130 * before freeing 'n', ensure that no other cpus are 131 * in the middle of nmi_dispatch. 132 */ 133 134 if (mp_online) { 135 uint64_t h; 136 137 h = xc_broadcast(0, (xcfunc_t)nullop, NULL, NULL); 138 xc_wait(h); 139 } 140 141 kmem_free(n, sizeof(*n)); 142 } 143 144 /* 145 * nmi_dispatch: dispatch an nmi. 146 * 147 * => called by interrupts, thus preempt disabled. 148 */ 149 150 int 151 nmi_dispatch(const struct trapframe *tf) 152 { 153 const struct nmi_handler *n; 154 int handled = 0; 155 156 for (n = nmi_handlers; /* atomic load */ 157 n != NULL; 158 n = n->n_next) { /* atomic load */ 159 handled |= (*n->n_func)(tf, n->n_arg); 160 } 161 return handled; 162 } 163 164 void 165 nmi_init(void) 166 { 167 168 mutex_init(&nmi_list_lock, MUTEX_DEFAULT, IPL_NONE); 169 } 170