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