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