FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_subr.c
1 /* $NetBSD: kern_subr.c,v 1.150.2.1 2007/05/13 10:28:37 jdc Exp $ */
2
3 /*-
4 * Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center, and by Luke Mewburn.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 /*
41 * Copyright (c) 1982, 1986, 1991, 1993
42 * The Regents of the University of California. All rights reserved.
43 * (c) UNIX System Laboratories, Inc.
44 * All or some portions of this file are derived from material licensed
45 * to the University of California by American Telephone and Telegraph
46 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
47 * the permission of UNIX System Laboratories, Inc.
48 *
49 * Copyright (c) 1992, 1993
50 * The Regents of the University of California. All rights reserved.
51 *
52 * This software was developed by the Computer Systems Engineering group
53 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
54 * contributed to Berkeley.
55 *
56 * All advertising materials mentioning features or use of this software
57 * must display the following acknowledgement:
58 * This product includes software developed by the University of
59 * California, Lawrence Berkeley Laboratory.
60 *
61 * Redistribution and use in source and binary forms, with or without
62 * modification, are permitted provided that the following conditions
63 * are met:
64 * 1. Redistributions of source code must retain the above copyright
65 * notice, this list of conditions and the following disclaimer.
66 * 2. Redistributions in binary form must reproduce the above copyright
67 * notice, this list of conditions and the following disclaimer in the
68 * documentation and/or other materials provided with the distribution.
69 * 3. Neither the name of the University nor the names of its contributors
70 * may be used to endorse or promote products derived from this software
71 * without specific prior written permission.
72 *
73 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
74 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
75 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
76 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
77 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
78 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
79 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
80 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
81 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
82 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
83 * SUCH DAMAGE.
84 *
85 * @(#)kern_subr.c 8.4 (Berkeley) 2/14/95
86 */
87
88 #include <sys/cdefs.h>
89 __KERNEL_RCSID(0, "$NetBSD: kern_subr.c,v 1.150.2.1 2007/05/13 10:28:37 jdc Exp $");
90
91 #include "opt_ddb.h"
92 #include "opt_md.h"
93 #include "opt_syscall_debug.h"
94 #include "opt_ktrace.h"
95 #include "opt_ptrace.h"
96 #include "opt_systrace.h"
97 #include "opt_powerhook.h"
98 #include "opt_tftproot.h"
99
100 #include <sys/param.h>
101 #include <sys/systm.h>
102 #include <sys/proc.h>
103 #include <sys/malloc.h>
104 #include <sys/mount.h>
105 #include <sys/device.h>
106 #include <sys/reboot.h>
107 #include <sys/conf.h>
108 #include <sys/disklabel.h>
109 #include <sys/queue.h>
110 #include <sys/systrace.h>
111 #include <sys/ktrace.h>
112 #include <sys/ptrace.h>
113 #include <sys/fcntl.h>
114
115 #include <uvm/uvm_extern.h>
116
117 #include <dev/cons.h>
118
119 #include <net/if.h>
120
121 /* XXX these should eventually move to subr_autoconf.c */
122 static struct device *finddevice(const char *);
123 static struct device *getdisk(char *, int, int, dev_t *, int);
124 static struct device *parsedisk(char *, int, int, dev_t *);
125
126 /*
127 * A generic linear hook.
128 */
129 struct hook_desc {
130 LIST_ENTRY(hook_desc) hk_list;
131 void (*hk_fn)(void *);
132 void *hk_arg;
133 };
134 typedef LIST_HEAD(, hook_desc) hook_list_t;
135
136 MALLOC_DEFINE(M_IOV, "iov", "large iov's");
137
138 #ifdef TFTPROOT
139 int tftproot_dhcpboot(struct device *);
140 #endif
141
142 void
143 uio_setup_sysspace(struct uio *uio)
144 {
145
146 uio->uio_vmspace = vmspace_kernel();
147 }
148
149 int
150 uiomove(void *buf, size_t n, struct uio *uio)
151 {
152 struct vmspace *vm = uio->uio_vmspace;
153 struct iovec *iov;
154 u_int cnt;
155 int error = 0;
156 char *cp = buf;
157 int hold_count;
158
159 hold_count = KERNEL_LOCK_RELEASE_ALL();
160
161 ASSERT_SLEEPABLE(NULL, "uiomove");
162
163 #ifdef DIAGNOSTIC
164 if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE)
165 panic("uiomove: mode");
166 #endif
167 while (n > 0 && uio->uio_resid) {
168 iov = uio->uio_iov;
169 cnt = iov->iov_len;
170 if (cnt == 0) {
171 KASSERT(uio->uio_iovcnt > 0);
172 uio->uio_iov++;
173 uio->uio_iovcnt--;
174 continue;
175 }
176 if (cnt > n)
177 cnt = n;
178 if (!VMSPACE_IS_KERNEL_P(vm)) {
179 if (curcpu()->ci_schedstate.spc_flags &
180 SPCF_SHOULDYIELD)
181 preempt(1);
182 }
183
184 if (uio->uio_rw == UIO_READ) {
185 error = copyout_vmspace(vm, cp, iov->iov_base,
186 cnt);
187 } else {
188 error = copyin_vmspace(vm, iov->iov_base, cp,
189 cnt);
190 }
191 if (error) {
192 break;
193 }
194 iov->iov_base = (caddr_t)iov->iov_base + cnt;
195 iov->iov_len -= cnt;
196 uio->uio_resid -= cnt;
197 uio->uio_offset += cnt;
198 cp += cnt;
199 KDASSERT(cnt <= n);
200 n -= cnt;
201 }
202 KERNEL_LOCK_ACQUIRE_COUNT(hold_count);
203 return (error);
204 }
205
206 /*
207 * Wrapper for uiomove() that validates the arguments against a known-good
208 * kernel buffer.
209 */
210 int
211 uiomove_frombuf(void *buf, size_t buflen, struct uio *uio)
212 {
213 size_t offset;
214
215 if (uio->uio_offset < 0 || /* uio->uio_resid < 0 || */
216 (offset = uio->uio_offset) != uio->uio_offset)
217 return (EINVAL);
218 if (offset >= buflen)
219 return (0);
220 return (uiomove((char *)buf + offset, buflen - offset, uio));
221 }
222
223 /*
224 * Give next character to user as result of read.
225 */
226 int
227 ureadc(int c, struct uio *uio)
228 {
229 struct iovec *iov;
230
231 if (uio->uio_resid <= 0)
232 panic("ureadc: non-positive resid");
233 again:
234 if (uio->uio_iovcnt <= 0)
235 panic("ureadc: non-positive iovcnt");
236 iov = uio->uio_iov;
237 if (iov->iov_len <= 0) {
238 uio->uio_iovcnt--;
239 uio->uio_iov++;
240 goto again;
241 }
242 if (!VMSPACE_IS_KERNEL_P(uio->uio_vmspace)) {
243 if (subyte(iov->iov_base, c) < 0)
244 return (EFAULT);
245 } else {
246 *(char *)iov->iov_base = c;
247 }
248 iov->iov_base = (caddr_t)iov->iov_base + 1;
249 iov->iov_len--;
250 uio->uio_resid--;
251 uio->uio_offset++;
252 return (0);
253 }
254
255 /*
256 * Like copyin(), but operates on an arbitrary vmspace.
257 */
258 int
259 copyin_vmspace(struct vmspace *vm, const void *uaddr, void *kaddr, size_t len)
260 {
261 struct iovec iov;
262 struct uio uio;
263 int error;
264
265 if (len == 0)
266 return (0);
267
268 if (VMSPACE_IS_KERNEL_P(vm)) {
269 return kcopy(uaddr, kaddr, len);
270 }
271 if (__predict_true(vm == curproc->p_vmspace)) {
272 return copyin(uaddr, kaddr, len);
273 }
274
275 iov.iov_base = kaddr;
276 iov.iov_len = len;
277 uio.uio_iov = &iov;
278 uio.uio_iovcnt = 1;
279 uio.uio_offset = (off_t)(intptr_t)uaddr;
280 uio.uio_resid = len;
281 uio.uio_rw = UIO_READ;
282 UIO_SETUP_SYSSPACE(&uio);
283 error = uvm_io(&vm->vm_map, &uio);
284
285 return (error);
286 }
287
288 /*
289 * Like copyout(), but operates on an arbitrary vmspace.
290 */
291 int
292 copyout_vmspace(struct vmspace *vm, const void *kaddr, void *uaddr, size_t len)
293 {
294 struct iovec iov;
295 struct uio uio;
296 int error;
297
298 if (len == 0)
299 return (0);
300
301 if (VMSPACE_IS_KERNEL_P(vm)) {
302 return kcopy(kaddr, uaddr, len);
303 }
304 if (__predict_true(vm == curproc->p_vmspace)) {
305 return copyout(kaddr, uaddr, len);
306 }
307
308 iov.iov_base = __UNCONST(kaddr); /* XXXUNCONST cast away const */
309 iov.iov_len = len;
310 uio.uio_iov = &iov;
311 uio.uio_iovcnt = 1;
312 uio.uio_offset = (off_t)(intptr_t)uaddr;
313 uio.uio_resid = len;
314 uio.uio_rw = UIO_WRITE;
315 UIO_SETUP_SYSSPACE(&uio);
316 error = uvm_io(&vm->vm_map, &uio);
317
318 return (error);
319 }
320
321 /*
322 * Like copyin(), but operates on an arbitrary process.
323 */
324 int
325 copyin_proc(struct proc *p, const void *uaddr, void *kaddr, size_t len)
326 {
327 struct vmspace *vm;
328 int error;
329
330 error = proc_vmspace_getref(p, &vm);
331 if (error) {
332 return error;
333 }
334 error = copyin_vmspace(vm, uaddr, kaddr, len);
335 uvmspace_free(vm);
336
337 return error;
338 }
339
340 /*
341 * Like copyout(), but operates on an arbitrary process.
342 */
343 int
344 copyout_proc(struct proc *p, const void *kaddr, void *uaddr, size_t len)
345 {
346 struct vmspace *vm;
347 int error;
348
349 error = proc_vmspace_getref(p, &vm);
350 if (error) {
351 return error;
352 }
353 error = copyout_vmspace(vm, kaddr, uaddr, len);
354 uvmspace_free(vm);
355
356 return error;
357 }
358
359 /*
360 * Like copyin(), except it operates on kernel addresses when the FKIOCTL
361 * flag is passed in `ioctlflags' from the ioctl call.
362 */
363 int
364 ioctl_copyin(int ioctlflags, const void *src, void *dst, size_t len)
365 {
366 if (ioctlflags & FKIOCTL)
367 return kcopy(src, dst, len);
368 return copyin(src, dst, len);
369 }
370
371 /*
372 * Like copyout(), except it operates on kernel addresses when the FKIOCTL
373 * flag is passed in `ioctlflags' from the ioctl call.
374 */
375 int
376 ioctl_copyout(int ioctlflags, const void *src, void *dst, size_t len)
377 {
378 if (ioctlflags & FKIOCTL)
379 return kcopy(src, dst, len);
380 return copyout(src, dst, len);
381 }
382
383 /*
384 * General routine to allocate a hash table.
385 * Allocate enough memory to hold at least `elements' list-head pointers.
386 * Return a pointer to the allocated space and set *hashmask to a pattern
387 * suitable for masking a value to use as an index into the returned array.
388 */
389 void *
390 hashinit(u_int elements, enum hashtype htype, struct malloc_type *mtype,
391 int mflags, u_long *hashmask)
392 {
393 u_long hashsize, i;
394 LIST_HEAD(, generic) *hashtbl_list;
395 TAILQ_HEAD(, generic) *hashtbl_tailq;
396 size_t esize;
397 void *p;
398
399 if (elements == 0)
400 panic("hashinit: bad cnt");
401 for (hashsize = 1; hashsize < elements; hashsize <<= 1)
402 continue;
403
404 switch (htype) {
405 case HASH_LIST:
406 esize = sizeof(*hashtbl_list);
407 break;
408 case HASH_TAILQ:
409 esize = sizeof(*hashtbl_tailq);
410 break;
411 default:
412 #ifdef DIAGNOSTIC
413 panic("hashinit: invalid table type");
414 #else
415 return NULL;
416 #endif
417 }
418
419 if ((p = malloc(hashsize * esize, mtype, mflags)) == NULL)
420 return (NULL);
421
422 switch (htype) {
423 case HASH_LIST:
424 hashtbl_list = p;
425 for (i = 0; i < hashsize; i++)
426 LIST_INIT(&hashtbl_list[i]);
427 break;
428 case HASH_TAILQ:
429 hashtbl_tailq = p;
430 for (i = 0; i < hashsize; i++)
431 TAILQ_INIT(&hashtbl_tailq[i]);
432 break;
433 }
434 *hashmask = hashsize - 1;
435 return (p);
436 }
437
438 /*
439 * Free memory from hash table previosly allocated via hashinit().
440 */
441 void
442 hashdone(void *hashtbl, struct malloc_type *mtype)
443 {
444
445 free(hashtbl, mtype);
446 }
447
448
449 static void *
450 hook_establish(hook_list_t *list, void (*fn)(void *), void *arg)
451 {
452 struct hook_desc *hd;
453
454 hd = malloc(sizeof(*hd), M_DEVBUF, M_NOWAIT);
455 if (hd == NULL)
456 return (NULL);
457
458 hd->hk_fn = fn;
459 hd->hk_arg = arg;
460 LIST_INSERT_HEAD(list, hd, hk_list);
461
462 return (hd);
463 }
464
465 static void
466 hook_disestablish(hook_list_t *list, void *vhook)
467 {
468 #ifdef DIAGNOSTIC
469 struct hook_desc *hd;
470
471 LIST_FOREACH(hd, list, hk_list) {
472 if (hd == vhook)
473 break;
474 }
475
476 if (hd == NULL)
477 panic("hook_disestablish: hook %p not established", vhook);
478 #endif
479 LIST_REMOVE((struct hook_desc *)vhook, hk_list);
480 free(vhook, M_DEVBUF);
481 }
482
483 static void
484 hook_destroy(hook_list_t *list)
485 {
486 struct hook_desc *hd;
487
488 while ((hd = LIST_FIRST(list)) != NULL) {
489 LIST_REMOVE(hd, hk_list);
490 free(hd, M_DEVBUF);
491 }
492 }
493
494 static void
495 hook_proc_run(hook_list_t *list, struct proc *p)
496 {
497 struct hook_desc *hd;
498
499 for (hd = LIST_FIRST(list); hd != NULL; hd = LIST_NEXT(hd, hk_list)) {
500 ((void (*)(struct proc *, void *))*hd->hk_fn)(p,
501 hd->hk_arg);
502 }
503 }
504
505 /*
506 * "Shutdown hook" types, functions, and variables.
507 *
508 * Should be invoked immediately before the
509 * system is halted or rebooted, i.e. after file systems unmounted,
510 * after crash dump done, etc.
511 *
512 * Each shutdown hook is removed from the list before it's run, so that
513 * it won't be run again.
514 */
515
516 static hook_list_t shutdownhook_list;
517
518 void *
519 shutdownhook_establish(void (*fn)(void *), void *arg)
520 {
521 return hook_establish(&shutdownhook_list, fn, arg);
522 }
523
524 void
525 shutdownhook_disestablish(void *vhook)
526 {
527 hook_disestablish(&shutdownhook_list, vhook);
528 }
529
530 /*
531 * Run shutdown hooks. Should be invoked immediately before the
532 * system is halted or rebooted, i.e. after file systems unmounted,
533 * after crash dump done, etc.
534 *
535 * Each shutdown hook is removed from the list before it's run, so that
536 * it won't be run again.
537 */
538 void
539 doshutdownhooks(void)
540 {
541 struct hook_desc *dp;
542
543 while ((dp = LIST_FIRST(&shutdownhook_list)) != NULL) {
544 LIST_REMOVE(dp, hk_list);
545 (*dp->hk_fn)(dp->hk_arg);
546 #if 0
547 /*
548 * Don't bother freeing the hook structure,, since we may
549 * be rebooting because of a memory corruption problem,
550 * and this might only make things worse. It doesn't
551 * matter, anyway, since the system is just about to
552 * reboot.
553 */
554 free(dp, M_DEVBUF);
555 #endif
556 }
557 }
558
559 /*
560 * "Mountroot hook" types, functions, and variables.
561 */
562
563 static hook_list_t mountroothook_list;
564
565 void *
566 mountroothook_establish(void (*fn)(struct device *), struct device *dev)
567 {
568 return hook_establish(&mountroothook_list, (void (*)(void *))fn, dev);
569 }
570
571 void
572 mountroothook_disestablish(void *vhook)
573 {
574 hook_disestablish(&mountroothook_list, vhook);
575 }
576
577 void
578 mountroothook_destroy(void)
579 {
580 hook_destroy(&mountroothook_list);
581 }
582
583 void
584 domountroothook(void)
585 {
586 struct hook_desc *hd;
587
588 LIST_FOREACH(hd, &mountroothook_list, hk_list) {
589 if (hd->hk_arg == (void *)root_device) {
590 (*hd->hk_fn)(hd->hk_arg);
591 return;
592 }
593 }
594 }
595
596 static hook_list_t exechook_list;
597
598 void *
599 exechook_establish(void (*fn)(struct proc *, void *), void *arg)
600 {
601 return hook_establish(&exechook_list, (void (*)(void *))fn, arg);
602 }
603
604 void
605 exechook_disestablish(void *vhook)
606 {
607 hook_disestablish(&exechook_list, vhook);
608 }
609
610 /*
611 * Run exec hooks.
612 */
613 void
614 doexechooks(struct proc *p)
615 {
616 hook_proc_run(&exechook_list, p);
617 }
618
619 static hook_list_t exithook_list;
620
621 void *
622 exithook_establish(void (*fn)(struct proc *, void *), void *arg)
623 {
624 return hook_establish(&exithook_list, (void (*)(void *))fn, arg);
625 }
626
627 void
628 exithook_disestablish(void *vhook)
629 {
630 hook_disestablish(&exithook_list, vhook);
631 }
632
633 /*
634 * Run exit hooks.
635 */
636 void
637 doexithooks(struct proc *p)
638 {
639 hook_proc_run(&exithook_list, p);
640 }
641
642 static hook_list_t forkhook_list;
643
644 void *
645 forkhook_establish(void (*fn)(struct proc *, struct proc *))
646 {
647 return hook_establish(&forkhook_list, (void (*)(void *))fn, NULL);
648 }
649
650 void
651 forkhook_disestablish(void *vhook)
652 {
653 hook_disestablish(&forkhook_list, vhook);
654 }
655
656 /*
657 * Run fork hooks.
658 */
659 void
660 doforkhooks(struct proc *p2, struct proc *p1)
661 {
662 struct hook_desc *hd;
663
664 LIST_FOREACH(hd, &forkhook_list, hk_list) {
665 ((void (*)(struct proc *, struct proc *))*hd->hk_fn)
666 (p2, p1);
667 }
668 }
669
670 /*
671 * "Power hook" types, functions, and variables.
672 * The list of power hooks is kept ordered with the last registered hook
673 * first.
674 * When running the hooks on power down the hooks are called in reverse
675 * registration order, when powering up in registration order.
676 */
677 struct powerhook_desc {
678 CIRCLEQ_ENTRY(powerhook_desc) sfd_list;
679 void (*sfd_fn)(int, void *);
680 void *sfd_arg;
681 char sfd_name[16];
682 };
683
684 static CIRCLEQ_HEAD(, powerhook_desc) powerhook_list =
685 CIRCLEQ_HEAD_INITIALIZER(powerhook_list);
686
687 void *
688 powerhook_establish(const char *name, void (*fn)(int, void *), void *arg)
689 {
690 struct powerhook_desc *ndp;
691
692 ndp = (struct powerhook_desc *)
693 malloc(sizeof(*ndp), M_DEVBUF, M_NOWAIT);
694 if (ndp == NULL)
695 return (NULL);
696
697 ndp->sfd_fn = fn;
698 ndp->sfd_arg = arg;
699 strlcpy(ndp->sfd_name, name, sizeof(ndp->sfd_name));
700 CIRCLEQ_INSERT_HEAD(&powerhook_list, ndp, sfd_list);
701
702 return (ndp);
703 }
704
705 void
706 powerhook_disestablish(void *vhook)
707 {
708 #ifdef DIAGNOSTIC
709 struct powerhook_desc *dp;
710
711 CIRCLEQ_FOREACH(dp, &powerhook_list, sfd_list)
712 if (dp == vhook)
713 goto found;
714 panic("powerhook_disestablish: hook %p not established", vhook);
715 found:
716 #endif
717
718 CIRCLEQ_REMOVE(&powerhook_list, (struct powerhook_desc *)vhook,
719 sfd_list);
720 free(vhook, M_DEVBUF);
721 }
722
723 /*
724 * Run power hooks.
725 */
726 void
727 dopowerhooks(int why)
728 {
729 struct powerhook_desc *dp;
730
731 #ifdef POWERHOOK_DEBUG
732 printf("dopowerhooks ");
733 switch (why) {
734 case PWR_RESUME:
735 printf("resume");
736 break;
737 case PWR_SOFTRESUME:
738 printf("softresume");
739 break;
740 case PWR_SUSPEND:
741 printf("suspend");
742 break;
743 case PWR_SOFTSUSPEND:
744 printf("softsuspend");
745 break;
746 case PWR_STANDBY:
747 printf("standby");
748 break;
749 }
750 printf(":");
751 #endif
752
753 if (why == PWR_RESUME || why == PWR_SOFTRESUME) {
754 CIRCLEQ_FOREACH_REVERSE(dp, &powerhook_list, sfd_list) {
755 #ifdef POWERHOOK_DEBUG
756 printf(" %s", dp->sfd_name);
757 #endif
758 (*dp->sfd_fn)(why, dp->sfd_arg);
759 }
760 } else {
761 CIRCLEQ_FOREACH(dp, &powerhook_list, sfd_list) {
762 #ifdef POWERHOOK_DEBUG
763 printf(" %s", dp->sfd_name);
764 #endif
765 (*dp->sfd_fn)(why, dp->sfd_arg);
766 }
767 }
768
769 #ifdef POWERHOOK_DEBUG
770 printf(".\n");
771 #endif
772 }
773
774 /*
775 * Determine the root device and, if instructed to, the root file system.
776 */
777
778 #include "md.h"
779 #if NMD == 0
780 #undef MEMORY_DISK_HOOKS
781 #endif
782
783 #ifdef MEMORY_DISK_HOOKS
784 static struct device fakemdrootdev[NMD];
785 extern struct cfdriver md_cd;
786 #endif
787
788 #ifdef MEMORY_DISK_IS_ROOT
789 #define BOOT_FROM_MEMORY_HOOKS 1
790 #endif
791
792 /*
793 * The device and wedge that we booted from. If booted_wedge is NULL,
794 * the we might consult booted_partition.
795 */
796 struct device *booted_device;
797 struct device *booted_wedge;
798 int booted_partition;
799
800 /*
801 * Use partition letters if it's a disk class but not a wedge.
802 * XXX Check for wedge is kinda gross.
803 */
804 #define DEV_USES_PARTITIONS(dv) \
805 (device_class((dv)) == DV_DISK && \
806 !device_is_a((dv), "dk"))
807
808 void
809 setroot(struct device *bootdv, int bootpartition)
810 {
811 struct device *dv;
812 int len;
813 #ifdef MEMORY_DISK_HOOKS
814 int i;
815 #endif
816 dev_t nrootdev;
817 dev_t ndumpdev = NODEV;
818 char buf[128];
819 const char *rootdevname;
820 const char *dumpdevname;
821 struct device *rootdv = NULL; /* XXX gcc -Wuninitialized */
822 struct device *dumpdv = NULL;
823 struct ifnet *ifp;
824 const char *deffsname;
825 struct vfsops *vops;
826
827 #ifdef TFTPROOT
828 if (tftproot_dhcpboot(bootdv) != 0)
829 boothowto |= RB_ASKNAME;
830 #endif
831
832 #ifdef MEMORY_DISK_HOOKS
833 for (i = 0; i < NMD; i++) {
834 fakemdrootdev[i].dv_class = DV_DISK;
835 fakemdrootdev[i].dv_cfdata = NULL;
836 fakemdrootdev[i].dv_cfdriver = &md_cd;
837 fakemdrootdev[i].dv_unit = i;
838 fakemdrootdev[i].dv_parent = NULL;
839 snprintf(fakemdrootdev[i].dv_xname,
840 sizeof(fakemdrootdev[i].dv_xname), "md%d", i);
841 }
842 #endif /* MEMORY_DISK_HOOKS */
843
844 #ifdef MEMORY_DISK_IS_ROOT
845 bootdv = &fakemdrootdev[0];
846 bootpartition = 0;
847 #endif
848
849 /*
850 * If NFS is specified as the file system, and we found
851 * a DV_DISK boot device (or no boot device at all), then
852 * find a reasonable network interface for "rootspec".
853 */
854 vops = vfs_getopsbyname("nfs");
855 if (vops != NULL && vops->vfs_mountroot == mountroot &&
856 rootspec == NULL &&
857 (bootdv == NULL || device_class(bootdv) != DV_IFNET)) {
858 IFNET_FOREACH(ifp) {
859 if ((ifp->if_flags &
860 (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
861 break;
862 }
863 if (ifp == NULL) {
864 /*
865 * Can't find a suitable interface; ask the
866 * user.
867 */
868 boothowto |= RB_ASKNAME;
869 } else {
870 /*
871 * Have a suitable interface; behave as if
872 * the user specified this interface.
873 */
874 rootspec = (const char *)ifp->if_xname;
875 }
876 }
877
878 /*
879 * If wildcarded root and we the boot device wasn't determined,
880 * ask the user.
881 */
882 if (rootspec == NULL && bootdv == NULL)
883 boothowto |= RB_ASKNAME;
884
885 top:
886 if (boothowto & RB_ASKNAME) {
887 struct device *defdumpdv;
888
889 for (;;) {
890 printf("root device");
891 if (bootdv != NULL) {
892 printf(" (default %s", bootdv->dv_xname);
893 if (DEV_USES_PARTITIONS(bootdv))
894 printf("%c", bootpartition + 'a');
895 printf(")");
896 }
897 printf(": ");
898 len = cngetsn(buf, sizeof(buf));
899 if (len == 0 && bootdv != NULL) {
900 strlcpy(buf, bootdv->dv_xname, sizeof(buf));
901 len = strlen(buf);
902 }
903 if (len > 0 && buf[len - 1] == '*') {
904 buf[--len] = '\0';
905 dv = getdisk(buf, len, 1, &nrootdev, 0);
906 if (dv != NULL) {
907 rootdv = dv;
908 break;
909 }
910 }
911 dv = getdisk(buf, len, bootpartition, &nrootdev, 0);
912 if (dv != NULL) {
913 rootdv = dv;
914 break;
915 }
916 }
917
918 /*
919 * Set up the default dump device. If root is on
920 * a network device, there is no default dump
921 * device, since we don't support dumps to the
922 * network.
923 */
924 if (DEV_USES_PARTITIONS(rootdv) == 0)
925 defdumpdv = NULL;
926 else
927 defdumpdv = rootdv;
928
929 for (;;) {
930 printf("dump device");
931 if (defdumpdv != NULL) {
932 /*
933 * Note, we know it's a disk if we get here.
934 */
935 printf(" (default %sb)", defdumpdv->dv_xname);
936 }
937 printf(": ");
938 len = cngetsn(buf, sizeof(buf));
939 if (len == 0) {
940 if (defdumpdv != NULL) {
941 ndumpdev = MAKEDISKDEV(major(nrootdev),
942 DISKUNIT(nrootdev), 1);
943 }
944 dumpdv = defdumpdv;
945 break;
946 }
947 if (len == 4 && strcmp(buf, "none") == 0) {
948 dumpdv = NULL;
949 break;
950 }
951 dv = getdisk(buf, len, 1, &ndumpdev, 1);
952 if (dv != NULL) {
953 dumpdv = dv;
954 break;
955 }
956 }
957
958 rootdev = nrootdev;
959 dumpdev = ndumpdev;
960
961 for (vops = LIST_FIRST(&vfs_list); vops != NULL;
962 vops = LIST_NEXT(vops, vfs_list)) {
963 if (vops->vfs_mountroot != NULL &&
964 vops->vfs_mountroot == mountroot)
965 break;
966 }
967
968 if (vops == NULL) {
969 mountroot = NULL;
970 deffsname = "generic";
971 } else
972 deffsname = vops->vfs_name;
973
974 for (;;) {
975 printf("file system (default %s): ", deffsname);
976 len = cngetsn(buf, sizeof(buf));
977 if (len == 0)
978 break;
979 if (len == 4 && strcmp(buf, "halt") == 0)
980 cpu_reboot(RB_HALT, NULL);
981 else if (len == 6 && strcmp(buf, "reboot") == 0)
982 cpu_reboot(0, NULL);
983 #if defined(DDB)
984 else if (len == 3 && strcmp(buf, "ddb") == 0) {
985 console_debugger();
986 }
987 #endif
988 else if (len == 7 && strcmp(buf, "generic") == 0) {
989 mountroot = NULL;
990 break;
991 }
992 vops = vfs_getopsbyname(buf);
993 if (vops == NULL || vops->vfs_mountroot == NULL) {
994 printf("use one of: generic");
995 for (vops = LIST_FIRST(&vfs_list);
996 vops != NULL;
997 vops = LIST_NEXT(vops, vfs_list)) {
998 if (vops->vfs_mountroot != NULL)
999 printf(" %s", vops->vfs_name);
1000 }
1001 #if defined(DDB)
1002 printf(" ddb");
1003 #endif
1004 printf(" halt reboot\n");
1005 } else {
1006 mountroot = vops->vfs_mountroot;
1007 break;
1008 }
1009 }
1010
1011 } else if (rootspec == NULL) {
1012 int majdev;
1013
1014 /*
1015 * Wildcarded root; use the boot device.
1016 */
1017 rootdv = bootdv;
1018
1019 majdev = devsw_name2blk(bootdv->dv_xname, NULL, 0);
1020 if (majdev >= 0) {
1021 /*
1022 * Root is on a disk. `bootpartition' is root,
1023 * unless the device does not use partitions.
1024 */
1025 if (DEV_USES_PARTITIONS(bootdv))
1026 rootdev = MAKEDISKDEV(majdev,
1027 device_unit(bootdv),
1028 bootpartition);
1029 else
1030 rootdev = makedev(majdev, device_unit(bootdv));
1031 }
1032 } else {
1033
1034 /*
1035 * `root on <dev> ...'
1036 */
1037
1038 /*
1039 * If it's a network interface, we can bail out
1040 * early.
1041 */
1042 dv = finddevice(rootspec);
1043 if (dv != NULL && device_class(dv) == DV_IFNET) {
1044 rootdv = dv;
1045 goto haveroot;
1046 }
1047
1048 rootdevname = devsw_blk2name(major(rootdev));
1049 if (rootdevname == NULL) {
1050 printf("unknown device major 0x%x\n", rootdev);
1051 boothowto |= RB_ASKNAME;
1052 goto top;
1053 }
1054 memset(buf, 0, sizeof(buf));
1055 snprintf(buf, sizeof(buf), "%s%d", rootdevname,
1056 DISKUNIT(rootdev));
1057
1058 rootdv = finddevice(buf);
1059 if (rootdv == NULL) {
1060 printf("device %s (0x%x) not configured\n",
1061 buf, rootdev);
1062 boothowto |= RB_ASKNAME;
1063 goto top;
1064 }
1065 }
1066
1067 haveroot:
1068
1069 root_device = rootdv;
1070
1071 switch (device_class(rootdv)) {
1072 case DV_IFNET:
1073 case DV_DISK:
1074 aprint_normal("root on %s", rootdv->dv_xname);
1075 if (DEV_USES_PARTITIONS(rootdv))
1076 aprint_normal("%c", DISKPART(rootdev) + 'a');
1077 break;
1078
1079 default:
1080 printf("can't determine root device\n");
1081 boothowto |= RB_ASKNAME;
1082 goto top;
1083 }
1084
1085 /*
1086 * Now configure the dump device.
1087 *
1088 * If we haven't figured out the dump device, do so, with
1089 * the following rules:
1090 *
1091 * (a) We already know dumpdv in the RB_ASKNAME case.
1092 *
1093 * (b) If dumpspec is set, try to use it. If the device
1094 * is not available, punt.
1095 *
1096 * (c) If dumpspec is not set, the dump device is
1097 * wildcarded or unspecified. If the root device
1098 * is DV_IFNET, punt. Otherwise, use partition b
1099 * of the root device.
1100 */
1101
1102 if (boothowto & RB_ASKNAME) { /* (a) */
1103 if (dumpdv == NULL)
1104 goto nodumpdev;
1105 } else if (dumpspec != NULL) { /* (b) */
1106 if (strcmp(dumpspec, "none") == 0 || dumpdev == NODEV) {
1107 /*
1108 * Operator doesn't want a dump device.
1109 * Or looks like they tried to pick a network
1110 * device. Oops.
1111 */
1112 goto nodumpdev;
1113 }
1114
1115 dumpdevname = devsw_blk2name(major(dumpdev));
1116 if (dumpdevname == NULL)
1117 goto nodumpdev;
1118 memset(buf, 0, sizeof(buf));
1119 snprintf(buf, sizeof(buf), "%s%d", dumpdevname,
1120 DISKUNIT(dumpdev));
1121
1122 dumpdv = finddevice(buf);
1123 if (dumpdv == NULL) {
1124 /*
1125 * Device not configured.
1126 */
1127 goto nodumpdev;
1128 }
1129 } else { /* (c) */
1130 if (DEV_USES_PARTITIONS(rootdv) == 0)
1131 goto nodumpdev;
1132 else {
1133 dumpdv = rootdv;
1134 dumpdev = MAKEDISKDEV(major(rootdev),
1135 device_unit(dumpdv), 1);
1136 }
1137 }
1138
1139 aprint_normal(" dumps on %s", dumpdv->dv_xname);
1140 if (DEV_USES_PARTITIONS(dumpdv))
1141 aprint_normal("%c", DISKPART(dumpdev) + 'a');
1142 aprint_normal("\n");
1143 return;
1144
1145 nodumpdev:
1146 dumpdev = NODEV;
1147 aprint_normal("\n");
1148 }
1149
1150 static struct device *
1151 finddevice(const char *name)
1152 {
1153 struct device *dv;
1154 #if defined(BOOT_FROM_MEMORY_HOOKS)
1155 int j;
1156 #endif /* BOOT_FROM_MEMORY_HOOKS */
1157
1158 #ifdef BOOT_FROM_MEMORY_HOOKS
1159 for (j = 0; j < NMD; j++) {
1160 if (strcmp(name, fakemdrootdev[j].dv_xname) == 0) {
1161 dv = &fakemdrootdev[j];
1162 return (dv);
1163 }
1164 }
1165 #endif /* BOOT_FROM_MEMORY_HOOKS */
1166
1167 for (dv = TAILQ_FIRST(&alldevs); dv != NULL;
1168 dv = TAILQ_NEXT(dv, dv_list))
1169 if (strcmp(dv->dv_xname, name) == 0)
1170 break;
1171 return (dv);
1172 }
1173
1174 static struct device *
1175 getdisk(char *str, int len, int defpart, dev_t *devp, int isdump)
1176 {
1177 struct device *dv;
1178 #ifdef MEMORY_DISK_HOOKS
1179 int i;
1180 #endif
1181
1182 if ((dv = parsedisk(str, len, defpart, devp)) == NULL) {
1183 printf("use one of:");
1184 #ifdef MEMORY_DISK_HOOKS
1185 if (isdump == 0)
1186 for (i = 0; i < NMD; i++)
1187 printf(" %s[a-%c]", fakemdrootdev[i].dv_xname,
1188 'a' + MAXPARTITIONS - 1);
1189 #endif
1190 TAILQ_FOREACH(dv, &alldevs, dv_list) {
1191 if (DEV_USES_PARTITIONS(dv))
1192 printf(" %s[a-%c]", dv->dv_xname,
1193 'a' + MAXPARTITIONS - 1);
1194 else if (device_class(dv) == DV_DISK)
1195 printf(" %s", dv->dv_xname);
1196 if (isdump == 0 && device_class(dv) == DV_IFNET)
1197 printf(" %s", dv->dv_xname);
1198 }
1199 if (isdump)
1200 printf(" none");
1201 #if defined(DDB)
1202 printf(" ddb");
1203 #endif
1204 printf(" halt reboot\n");
1205 }
1206 return (dv);
1207 }
1208
1209 static struct device *
1210 parsedisk(char *str, int len, int defpart, dev_t *devp)
1211 {
1212 struct device *dv;
1213 char *cp, c;
1214 int majdev, part;
1215 #ifdef MEMORY_DISK_HOOKS
1216 int i;
1217 #endif
1218 if (len == 0)
1219 return (NULL);
1220
1221 if (len == 4 && strcmp(str, "halt") == 0)
1222 cpu_reboot(RB_HALT, NULL);
1223 else if (len == 6 && strcmp(str, "reboot") == 0)
1224 cpu_reboot(0, NULL);
1225 #if defined(DDB)
1226 else if (len == 3 && strcmp(str, "ddb") == 0)
1227 console_debugger();
1228 #endif
1229
1230 cp = str + len - 1;
1231 c = *cp;
1232 if (c >= 'a' && c <= ('a' + MAXPARTITIONS - 1)) {
1233 part = c - 'a';
1234 *cp = '\0';
1235 } else
1236 part = defpart;
1237
1238 #ifdef MEMORY_DISK_HOOKS
1239 for (i = 0; i < NMD; i++)
1240 if (strcmp(str, fakemdrootdev[i].dv_xname) == 0) {
1241 dv = &fakemdrootdev[i];
1242 goto gotdisk;
1243 }
1244 #endif
1245
1246 dv = finddevice(str);
1247 if (dv != NULL) {
1248 if (device_class(dv) == DV_DISK) {
1249 #ifdef MEMORY_DISK_HOOKS
1250 gotdisk:
1251 #endif
1252 majdev = devsw_name2blk(dv->dv_xname, NULL, 0);
1253 if (majdev < 0)
1254 panic("parsedisk");
1255 if (DEV_USES_PARTITIONS(dv))
1256 *devp = MAKEDISKDEV(majdev, device_unit(dv),
1257 part);
1258 else
1259 *devp = makedev(majdev, device_unit(dv));
1260 }
1261
1262 if (device_class(dv) == DV_IFNET)
1263 *devp = NODEV;
1264 }
1265
1266 *cp = c;
1267 return (dv);
1268 }
1269
1270 /*
1271 * snprintf() `bytes' into `buf', reformatting it so that the number,
1272 * plus a possible `x' + suffix extension) fits into len bytes (including
1273 * the terminating NUL).
1274 * Returns the number of bytes stored in buf, or -1 if there was a problem.
1275 * E.g, given a len of 9 and a suffix of `B':
1276 * bytes result
1277 * ----- ------
1278 * 99999 `99999 B'
1279 * 100000 `97 kB'
1280 * 66715648 `65152 kB'
1281 * 252215296 `240 MB'
1282 */
1283 int
1284 humanize_number(char *buf, size_t len, uint64_t bytes, const char *suffix,
1285 int divisor)
1286 {
1287 /* prefixes are: (none), kilo, Mega, Giga, Tera, Peta, Exa */
1288 const char *prefixes;
1289 int r;
1290 uint64_t umax;
1291 size_t i, suffixlen;
1292
1293 if (buf == NULL || suffix == NULL)
1294 return (-1);
1295 if (len > 0)
1296 buf[0] = '\0';
1297 suffixlen = strlen(suffix);
1298 /* check if enough room for `x y' + suffix + `\0' */
1299 if (len < 4 + suffixlen)
1300 return (-1);
1301
1302 if (divisor == 1024) {
1303 /*
1304 * binary multiplies
1305 * XXX IEC 60027-2 recommends Ki, Mi, Gi...
1306 */
1307 prefixes = " KMGTPE";
1308 } else
1309 prefixes = " kMGTPE"; /* SI for decimal multiplies */
1310
1311 umax = 1;
1312 for (i = 0; i < len - suffixlen - 3; i++)
1313 umax *= 10;
1314 for (i = 0; bytes >= umax && prefixes[i + 1]; i++)
1315 bytes /= divisor;
1316
1317 r = snprintf(buf, len, "%qu%s%c%s", (unsigned long long)bytes,
1318 i == 0 ? "" : " ", prefixes[i], suffix);
1319
1320 return (r);
1321 }
1322
1323 int
1324 format_bytes(char *buf, size_t len, uint64_t bytes)
1325 {
1326 int rv;
1327 size_t nlen;
1328
1329 rv = humanize_number(buf, len, bytes, "B", 1024);
1330 if (rv != -1) {
1331 /* nuke the trailing ` B' if it exists */
1332 nlen = strlen(buf) - 2;
1333 if (strcmp(&buf[nlen], " B") == 0)
1334 buf[nlen] = '\0';
1335 }
1336 return (rv);
1337 }
1338
1339 /*
1340 * Return TRUE if system call tracing is enabled for the specified process.
1341 */
1342 boolean_t
1343 trace_is_enabled(struct proc *p)
1344 {
1345 #ifdef SYSCALL_DEBUG
1346 return (TRUE);
1347 #endif
1348 #ifdef KTRACE
1349 if (ISSET(p->p_traceflag, (KTRFAC_SYSCALL | KTRFAC_SYSRET)))
1350 return (TRUE);
1351 #endif
1352 #ifdef SYSTRACE
1353 if (ISSET(p->p_flag, P_SYSTRACE))
1354 return (TRUE);
1355 #endif
1356 #ifdef PTRACE
1357 if (ISSET(p->p_flag, P_SYSCALL))
1358 return (TRUE);
1359 #endif
1360
1361 return (FALSE);
1362 }
1363
1364 /*
1365 * Start trace of particular system call. If process is being traced,
1366 * this routine is called by MD syscall dispatch code just before
1367 * a system call is actually executed.
1368 * MD caller guarantees the passed 'code' is within the supported
1369 * system call number range for emulation the process runs under.
1370 */
1371 int
1372 trace_enter(struct lwp *l, register_t code,
1373 register_t realcode, const struct sysent *callp, void *args)
1374 {
1375 struct proc *p = l->l_proc;
1376
1377
1378 #if defined(SYSCALL_DEBUG) || defined(KTRACE) || defined(PTRACE) || defined(SYSTRACE)
1379 #ifdef SYSCALL_DEBUG
1380 scdebug_call(l, code, args);
1381 #endif /* SYSCALL_DEBUG */
1382
1383 #ifdef KTRACE
1384 if (KTRPOINT(p, KTR_SYSCALL))
1385 ktrsyscall(l, code, realcode, callp, args);
1386 #endif /* KTRACE */
1387
1388 #ifdef PTRACE
1389 if ((p->p_flag & (P_SYSCALL|P_TRACED)) == (P_SYSCALL|P_TRACED))
1390 process_stoptrace(l);
1391 #endif
1392
1393 #ifdef SYSTRACE
1394 if (ISSET(p->p_flag, P_SYSTRACE))
1395 return systrace_enter(l, code, args);
1396 #endif
1397 #endif /* SYSCALL_DEBUG || {K,P,SYS}TRACE */
1398 return 0;
1399 }
1400
1401 /*
1402 * End trace of particular system call. If process is being traced,
1403 * this routine is called by MD syscall dispatch code just after
1404 * a system call finishes.
1405 * MD caller guarantees the passed 'code' is within the supported
1406 * system call number range for emulation the process runs under.
1407 */
1408 void
1409 trace_exit(struct lwp *l, register_t code, void *args, register_t rval[],
1410 int error)
1411 {
1412 struct proc *p = l->l_proc;
1413
1414 #if defined(SYSCALL_DEBUG) || defined(KTRACE) || defined(PTRACE) || defined(SYSTRACE)
1415 #ifdef SYSCALL_DEBUG
1416 scdebug_ret(l, code, error, rval);
1417 #endif /* SYSCALL_DEBUG */
1418
1419 #ifdef KTRACE
1420 if (KTRPOINT(p, KTR_SYSRET)) {
1421 KERNEL_PROC_LOCK(l);
1422 ktrsysret(l, code, error, rval);
1423 KERNEL_PROC_UNLOCK(l);
1424 }
1425 #endif /* KTRACE */
1426
1427 #ifdef PTRACE
1428 if ((p->p_flag & (P_SYSCALL|P_TRACED)) == (P_SYSCALL|P_TRACED))
1429 process_stoptrace(l);
1430 #endif
1431
1432 #ifdef SYSTRACE
1433 if (ISSET(p->p_flag, P_SYSTRACE)) {
1434 KERNEL_PROC_LOCK(l);
1435 systrace_exit(l, code, args, rval, error);
1436 KERNEL_PROC_UNLOCK(l);
1437 }
1438 #endif
1439 #endif /* SYSCALL_DEBUG || {K,P,SYS}TRACE */
1440 }
Cache object: 6baa8f5d76b68fa7e8eaea216883b574
|