1 /* $OpenBSD: kern_subr.c,v 1.29 2004/11/28 02:11:33 deraadt Exp $ */ 2 /* $NetBSD: kern_subr.c,v 1.15 1996/04/09 17:21:56 ragge Exp $ */ 3 4 /* 5 * Copyright (c) 1982, 1986, 1991, 1993 6 * The Regents of the University of California. All rights reserved. 7 * (c) UNIX System Laboratories, Inc. 8 * All or some portions of this file are derived from material licensed 9 * to the University of California by American Telephone and Telegraph 10 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 11 * the permission of UNIX System Laboratories, Inc. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * @(#)kern_subr.c 8.3 (Berkeley) 1/21/94 38 */ 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/proc.h> 43 #include <sys/sched.h> 44 #include <sys/malloc.h> 45 #include <sys/queue.h> 46 #include <sys/kernel.h> 47 #include <sys/resourcevar.h> 48 49 int 50 uiomove(cp, n, uio) 51 register void *cp; 52 register int n; 53 register struct uio *uio; 54 { 55 register struct iovec *iov; 56 u_int cnt; 57 int error = 0; 58 struct proc *p; 59 60 p = uio->uio_procp; 61 62 #ifdef DIAGNOSTIC 63 if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE) 64 panic("uiomove: mode"); 65 if (uio->uio_segflg == UIO_USERSPACE && p != curproc) 66 panic("uiomove: proc"); 67 #endif 68 while (n > 0 && uio->uio_resid) { 69 iov = uio->uio_iov; 70 cnt = iov->iov_len; 71 if (cnt == 0) { 72 uio->uio_iov++; 73 uio->uio_iovcnt--; 74 continue; 75 } 76 if (cnt > n) 77 cnt = n; 78 switch (uio->uio_segflg) { 79 80 case UIO_USERSPACE: 81 #ifdef __HAVE_CPUINFO 82 if (curcpu()->ci_schedstate.spc_schedflags & 83 SPCF_SHOULDYIELD) 84 #else 85 if (p->p_schedflags & PSCHED_SHOULDYIELD) 86 #endif 87 preempt(NULL); 88 if (uio->uio_rw == UIO_READ) 89 error = copyout(cp, iov->iov_base, cnt); 90 else 91 error = copyin(iov->iov_base, cp, cnt); 92 if (error) 93 return (error); 94 break; 95 96 case UIO_SYSSPACE: 97 if (uio->uio_rw == UIO_READ) 98 error = kcopy(cp, iov->iov_base, cnt); 99 else 100 error = kcopy(iov->iov_base, cp, cnt); 101 if (error) 102 return(error); 103 } 104 iov->iov_base = (caddr_t)iov->iov_base + cnt; 105 iov->iov_len -= cnt; 106 uio->uio_resid -= cnt; 107 uio->uio_offset += cnt; 108 cp = (caddr_t)cp + cnt; 109 n -= cnt; 110 } 111 return (error); 112 } 113 114 /* 115 * Give next character to user as result of read. 116 */ 117 int 118 ureadc(c, uio) 119 register int c; 120 register struct uio *uio; 121 { 122 register struct iovec *iov; 123 124 if (uio->uio_resid == 0) 125 #ifdef DIAGNOSTIC 126 panic("ureadc: zero resid"); 127 #else 128 return (EINVAL); 129 #endif 130 again: 131 if (uio->uio_iovcnt <= 0) 132 #ifdef DIAGNOSTIC 133 panic("ureadc: non-positive iovcnt"); 134 #else 135 return (EINVAL); 136 #endif 137 iov = uio->uio_iov; 138 if (iov->iov_len <= 0) { 139 uio->uio_iovcnt--; 140 uio->uio_iov++; 141 goto again; 142 } 143 switch (uio->uio_segflg) { 144 145 case UIO_USERSPACE: 146 { 147 char tmp = c; 148 149 if (copyout(&tmp, iov->iov_base, sizeof(char)) != 0) 150 return (EFAULT); 151 } 152 break; 153 154 case UIO_SYSSPACE: 155 *(char *)iov->iov_base = c; 156 break; 157 } 158 iov->iov_base = (caddr_t)iov->iov_base + 1; 159 iov->iov_len--; 160 uio->uio_resid--; 161 uio->uio_offset++; 162 return (0); 163 } 164 165 /* 166 * General routine to allocate a hash table. 167 */ 168 void * 169 hashinit(elements, type, flags, hashmask) 170 int elements, type, flags; 171 u_long *hashmask; 172 { 173 u_long hashsize, i; 174 LIST_HEAD(generic, generic) *hashtbl; 175 176 if (elements <= 0) 177 panic("hashinit: bad cnt"); 178 for (hashsize = 1; hashsize < elements; hashsize <<= 1) 179 continue; 180 hashtbl = malloc(hashsize * sizeof(*hashtbl), type, flags); 181 if (hashtbl == NULL) 182 return NULL; 183 for (i = 0; i < hashsize; i++) 184 LIST_INIT(&hashtbl[i]); 185 *hashmask = hashsize - 1; 186 return (hashtbl); 187 } 188 189 /* 190 * "Shutdown/startup hook" types, functions, and variables. 191 */ 192 193 struct hook_desc_head startuphook_list = 194 TAILQ_HEAD_INITIALIZER(startuphook_list); 195 struct hook_desc_head shutdownhook_list = 196 TAILQ_HEAD_INITIALIZER(shutdownhook_list); 197 struct hook_desc_head mountroothook_list = 198 TAILQ_HEAD_INITIALIZER(mountroothook_list); 199 200 void * 201 hook_establish(head, tail, fn, arg) 202 struct hook_desc_head *head; 203 int tail; 204 void (*fn)(void *); 205 void *arg; 206 { 207 struct hook_desc *hdp; 208 209 hdp = (struct hook_desc *)malloc(sizeof (*hdp), M_DEVBUF, M_NOWAIT); 210 if (hdp == NULL) 211 return (NULL); 212 213 hdp->hd_fn = fn; 214 hdp->hd_arg = arg; 215 if (tail) 216 TAILQ_INSERT_TAIL(head, hdp, hd_list); 217 else 218 TAILQ_INSERT_HEAD(head, hdp, hd_list); 219 220 return (hdp); 221 } 222 223 void 224 hook_disestablish(head, vhook) 225 struct hook_desc_head *head; 226 void *vhook; 227 { 228 struct hook_desc *hdp; 229 230 #ifdef DIAGNOSTIC 231 for (hdp = TAILQ_FIRST(head); hdp != NULL; 232 hdp = TAILQ_NEXT(hdp, hd_list)) 233 if (hdp == vhook) 234 break; 235 if (hdp == NULL) 236 panic("hook_disestablish: hook not established"); 237 #endif 238 hdp = vhook; 239 TAILQ_REMOVE(head, hdp, hd_list); 240 free(hdp, M_DEVBUF); 241 } 242 243 /* 244 * Run hooks. Startup hooks are invoked right after scheduler_start but 245 * before root is mounted. Shutdown hooks are invoked immediately before the 246 * system is halted or rebooted, i.e. after file systems unmounted, 247 * after crash dump done, etc. 248 */ 249 void 250 dohooks(struct hook_desc_head *head, int flags) 251 { 252 struct hook_desc *hdp; 253 254 if ((flags & HOOK_REMOVE) == 0) { 255 TAILQ_FOREACH(hdp, head, hd_list) { 256 (*hdp->hd_fn)(hdp->hd_arg); 257 } 258 } else { 259 while ((hdp = TAILQ_FIRST(head)) != NULL) { 260 TAILQ_REMOVE(head, hdp, hd_list); 261 (*hdp->hd_fn)(hdp->hd_arg); 262 if ((flags & HOOK_FREE) != 0) 263 free(hdp, M_DEVBUF); 264 } 265 } 266 } 267 268 /* 269 * "Power hook" types, functions, and variables. 270 */ 271 272 struct powerhook_desc { 273 CIRCLEQ_ENTRY(powerhook_desc) sfd_list; 274 void (*sfd_fn)(int, void *); 275 void *sfd_arg; 276 }; 277 278 CIRCLEQ_HEAD(, powerhook_desc) powerhook_list = 279 CIRCLEQ_HEAD_INITIALIZER(powerhook_list); 280 281 void * 282 powerhook_establish(fn, arg) 283 void (*fn)(int, void *); 284 void *arg; 285 { 286 struct powerhook_desc *ndp; 287 288 ndp = (struct powerhook_desc *) 289 malloc(sizeof(*ndp), M_DEVBUF, M_NOWAIT); 290 if (ndp == NULL) 291 return NULL; 292 293 ndp->sfd_fn = fn; 294 ndp->sfd_arg = arg; 295 CIRCLEQ_INSERT_HEAD(&powerhook_list, ndp, sfd_list); 296 297 return (ndp); 298 } 299 300 void 301 powerhook_disestablish(vhook) 302 void *vhook; 303 { 304 #ifdef DIAGNOSTIC 305 struct powerhook_desc *dp; 306 307 CIRCLEQ_FOREACH(dp, &powerhook_list, sfd_list) 308 if (dp == vhook) 309 break; 310 if (dp == NULL) 311 panic("powerhook_disestablish: hook not established"); 312 #endif 313 314 CIRCLEQ_REMOVE(&powerhook_list, (struct powerhook_desc *)vhook, 315 sfd_list); 316 free(vhook, M_DEVBUF); 317 } 318 319 /* 320 * Run power hooks. 321 */ 322 void 323 dopowerhooks(why) 324 int why; 325 { 326 struct powerhook_desc *dp; 327 int s; 328 329 s = splhigh(); 330 if (why == PWR_RESUME) { 331 CIRCLEQ_FOREACH_REVERSE(dp, &powerhook_list, sfd_list) { 332 (*dp->sfd_fn)(why, dp->sfd_arg); 333 } 334 } else { 335 CIRCLEQ_FOREACH(dp, &powerhook_list, sfd_list) { 336 (*dp->sfd_fn)(why, dp->sfd_arg); 337 } 338 } 339 splx(s); 340 } 341