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