1 /* $NetBSD: kern_subr.c,v 1.203 2009/11/05 18:07:19 dyoung Exp $ */ 2 3 /*- 4 * Copyright (c) 1997, 1998, 1999, 2002, 2007, 2008 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 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1982, 1986, 1991, 1993 35 * The Regents of the University of California. All rights reserved. 36 * (c) UNIX System Laboratories, Inc. 37 * All or some portions of this file are derived from material licensed 38 * to the University of California by American Telephone and Telegraph 39 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 40 * the permission of UNIX System Laboratories, Inc. 41 * 42 * Copyright (c) 1992, 1993 43 * The Regents of the University of California. All rights reserved. 44 * 45 * This software was developed by the Computer Systems Engineering group 46 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 47 * contributed to Berkeley. 48 * 49 * All advertising materials mentioning features or use of this software 50 * must display the following acknowledgement: 51 * This product includes software developed by the University of 52 * California, Lawrence Berkeley Laboratory. 53 * 54 * Redistribution and use in source and binary forms, with or without 55 * modification, are permitted provided that the following conditions 56 * are met: 57 * 1. Redistributions of source code must retain the above copyright 58 * notice, this list of conditions and the following disclaimer. 59 * 2. Redistributions in binary form must reproduce the above copyright 60 * notice, this list of conditions and the following disclaimer in the 61 * documentation and/or other materials provided with the distribution. 62 * 3. Neither the name of the University nor the names of its contributors 63 * may be used to endorse or promote products derived from this software 64 * without specific prior written permission. 65 * 66 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 67 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 68 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 69 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 70 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 71 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 72 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 73 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 74 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 75 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 76 * SUCH DAMAGE. 77 * 78 * @(#)kern_subr.c 8.4 (Berkeley) 2/14/95 79 */ 80 81 #include <sys/cdefs.h> 82 __KERNEL_RCSID(0, "$NetBSD: kern_subr.c,v 1.203 2009/11/05 18:07:19 dyoung Exp $"); 83 84 #include "opt_ddb.h" 85 #include "opt_md.h" 86 #include "opt_syscall_debug.h" 87 #include "opt_ktrace.h" 88 #include "opt_ptrace.h" 89 #include "opt_powerhook.h" 90 #include "opt_tftproot.h" 91 92 #include <sys/param.h> 93 #include <sys/systm.h> 94 #include <sys/proc.h> 95 #include <sys/malloc.h> 96 #include <sys/mount.h> 97 #include <sys/device.h> 98 #include <sys/reboot.h> 99 #include <sys/conf.h> 100 #include <sys/disk.h> 101 #include <sys/disklabel.h> 102 #include <sys/queue.h> 103 #include <sys/ktrace.h> 104 #include <sys/ptrace.h> 105 #include <sys/fcntl.h> 106 #include <sys/kauth.h> 107 #include <sys/vnode.h> 108 #include <sys/syscallvar.h> 109 #include <sys/xcall.h> 110 #include <sys/module.h> 111 112 #include <uvm/uvm_extern.h> 113 114 #include <dev/cons.h> 115 116 #include <net/if.h> 117 118 /* XXX these should eventually move to subr_autoconf.c */ 119 static device_t finddevice(const char *); 120 static device_t getdisk(char *, int, int, dev_t *, int); 121 static device_t parsedisk(char *, int, int, dev_t *); 122 static const char *getwedgename(const char *, int); 123 124 /* 125 * A generic linear hook. 126 */ 127 struct hook_desc { 128 LIST_ENTRY(hook_desc) hk_list; 129 void (*hk_fn)(void *); 130 void *hk_arg; 131 }; 132 typedef LIST_HEAD(, hook_desc) hook_list_t; 133 134 #ifdef TFTPROOT 135 int tftproot_dhcpboot(device_t); 136 #endif 137 138 dev_t dumpcdev; /* for savecore */ 139 140 static void * 141 hook_establish(hook_list_t *list, void (*fn)(void *), void *arg) 142 { 143 struct hook_desc *hd; 144 145 hd = malloc(sizeof(*hd), M_DEVBUF, M_NOWAIT); 146 if (hd == NULL) 147 return (NULL); 148 149 hd->hk_fn = fn; 150 hd->hk_arg = arg; 151 LIST_INSERT_HEAD(list, hd, hk_list); 152 153 return (hd); 154 } 155 156 static void 157 hook_disestablish(hook_list_t *list, void *vhook) 158 { 159 #ifdef DIAGNOSTIC 160 struct hook_desc *hd; 161 162 LIST_FOREACH(hd, list, hk_list) { 163 if (hd == vhook) 164 break; 165 } 166 167 if (hd == NULL) 168 panic("hook_disestablish: hook %p not established", vhook); 169 #endif 170 LIST_REMOVE((struct hook_desc *)vhook, hk_list); 171 free(vhook, M_DEVBUF); 172 } 173 174 static void 175 hook_destroy(hook_list_t *list) 176 { 177 struct hook_desc *hd; 178 179 while ((hd = LIST_FIRST(list)) != NULL) { 180 LIST_REMOVE(hd, hk_list); 181 free(hd, M_DEVBUF); 182 } 183 } 184 185 static void 186 hook_proc_run(hook_list_t *list, struct proc *p) 187 { 188 struct hook_desc *hd; 189 190 LIST_FOREACH(hd, list, hk_list) 191 ((void (*)(struct proc *, void *))*hd->hk_fn)(p, hd->hk_arg); 192 } 193 194 /* 195 * "Shutdown hook" types, functions, and variables. 196 * 197 * Should be invoked immediately before the 198 * system is halted or rebooted, i.e. after file systems unmounted, 199 * after crash dump done, etc. 200 * 201 * Each shutdown hook is removed from the list before it's run, so that 202 * it won't be run again. 203 */ 204 205 static hook_list_t shutdownhook_list; 206 207 void * 208 shutdownhook_establish(void (*fn)(void *), void *arg) 209 { 210 return hook_establish(&shutdownhook_list, fn, arg); 211 } 212 213 void 214 shutdownhook_disestablish(void *vhook) 215 { 216 hook_disestablish(&shutdownhook_list, vhook); 217 } 218 219 /* 220 * Run shutdown hooks. Should be invoked immediately before the 221 * system is halted or rebooted, i.e. after file systems unmounted, 222 * after crash dump done, etc. 223 * 224 * Each shutdown hook is removed from the list before it's run, so that 225 * it won't be run again. 226 */ 227 void 228 doshutdownhooks(void) 229 { 230 struct hook_desc *dp; 231 232 while ((dp = LIST_FIRST(&shutdownhook_list)) != NULL) { 233 LIST_REMOVE(dp, hk_list); 234 (*dp->hk_fn)(dp->hk_arg); 235 #if 0 236 /* 237 * Don't bother freeing the hook structure,, since we may 238 * be rebooting because of a memory corruption problem, 239 * and this might only make things worse. It doesn't 240 * matter, anyway, since the system is just about to 241 * reboot. 242 */ 243 free(dp, M_DEVBUF); 244 #endif 245 } 246 } 247 248 /* 249 * "Mountroot hook" types, functions, and variables. 250 */ 251 252 static hook_list_t mountroothook_list; 253 254 void * 255 mountroothook_establish(void (*fn)(device_t), device_t dev) 256 { 257 return hook_establish(&mountroothook_list, (void (*)(void *))fn, dev); 258 } 259 260 void 261 mountroothook_disestablish(void *vhook) 262 { 263 hook_disestablish(&mountroothook_list, vhook); 264 } 265 266 void 267 mountroothook_destroy(void) 268 { 269 hook_destroy(&mountroothook_list); 270 } 271 272 void 273 domountroothook(void) 274 { 275 struct hook_desc *hd; 276 277 LIST_FOREACH(hd, &mountroothook_list, hk_list) { 278 if (hd->hk_arg == (void *)root_device) { 279 (*hd->hk_fn)(hd->hk_arg); 280 return; 281 } 282 } 283 } 284 285 static hook_list_t exechook_list; 286 287 void * 288 exechook_establish(void (*fn)(struct proc *, void *), void *arg) 289 { 290 return hook_establish(&exechook_list, (void (*)(void *))fn, arg); 291 } 292 293 void 294 exechook_disestablish(void *vhook) 295 { 296 hook_disestablish(&exechook_list, vhook); 297 } 298 299 /* 300 * Run exec hooks. 301 */ 302 void 303 doexechooks(struct proc *p) 304 { 305 hook_proc_run(&exechook_list, p); 306 } 307 308 static hook_list_t exithook_list; 309 extern krwlock_t exec_lock; 310 311 void * 312 exithook_establish(void (*fn)(struct proc *, void *), void *arg) 313 { 314 void *rv; 315 316 rw_enter(&exec_lock, RW_WRITER); 317 rv = hook_establish(&exithook_list, (void (*)(void *))fn, arg); 318 rw_exit(&exec_lock); 319 return rv; 320 } 321 322 void 323 exithook_disestablish(void *vhook) 324 { 325 326 rw_enter(&exec_lock, RW_WRITER); 327 hook_disestablish(&exithook_list, vhook); 328 rw_exit(&exec_lock); 329 } 330 331 /* 332 * Run exit hooks. 333 */ 334 void 335 doexithooks(struct proc *p) 336 { 337 hook_proc_run(&exithook_list, p); 338 } 339 340 static hook_list_t forkhook_list; 341 342 void * 343 forkhook_establish(void (*fn)(struct proc *, struct proc *)) 344 { 345 return hook_establish(&forkhook_list, (void (*)(void *))fn, NULL); 346 } 347 348 void 349 forkhook_disestablish(void *vhook) 350 { 351 hook_disestablish(&forkhook_list, vhook); 352 } 353 354 /* 355 * Run fork hooks. 356 */ 357 void 358 doforkhooks(struct proc *p2, struct proc *p1) 359 { 360 struct hook_desc *hd; 361 362 LIST_FOREACH(hd, &forkhook_list, hk_list) { 363 ((void (*)(struct proc *, struct proc *))*hd->hk_fn) 364 (p2, p1); 365 } 366 } 367 368 /* 369 * "Power hook" types, functions, and variables. 370 * The list of power hooks is kept ordered with the last registered hook 371 * first. 372 * When running the hooks on power down the hooks are called in reverse 373 * registration order, when powering up in registration order. 374 */ 375 struct powerhook_desc { 376 CIRCLEQ_ENTRY(powerhook_desc) sfd_list; 377 void (*sfd_fn)(int, void *); 378 void *sfd_arg; 379 char sfd_name[16]; 380 }; 381 382 static CIRCLEQ_HEAD(, powerhook_desc) powerhook_list = 383 CIRCLEQ_HEAD_INITIALIZER(powerhook_list); 384 385 void * 386 powerhook_establish(const char *name, void (*fn)(int, void *), void *arg) 387 { 388 struct powerhook_desc *ndp; 389 390 ndp = (struct powerhook_desc *) 391 malloc(sizeof(*ndp), M_DEVBUF, M_NOWAIT); 392 if (ndp == NULL) 393 return (NULL); 394 395 ndp->sfd_fn = fn; 396 ndp->sfd_arg = arg; 397 strlcpy(ndp->sfd_name, name, sizeof(ndp->sfd_name)); 398 CIRCLEQ_INSERT_HEAD(&powerhook_list, ndp, sfd_list); 399 400 aprint_error("%s: WARNING: powerhook_establish is deprecated\n", name); 401 return (ndp); 402 } 403 404 void 405 powerhook_disestablish(void *vhook) 406 { 407 #ifdef DIAGNOSTIC 408 struct powerhook_desc *dp; 409 410 CIRCLEQ_FOREACH(dp, &powerhook_list, sfd_list) 411 if (dp == vhook) 412 goto found; 413 panic("powerhook_disestablish: hook %p not established", vhook); 414 found: 415 #endif 416 417 CIRCLEQ_REMOVE(&powerhook_list, (struct powerhook_desc *)vhook, 418 sfd_list); 419 free(vhook, M_DEVBUF); 420 } 421 422 /* 423 * Run power hooks. 424 */ 425 void 426 dopowerhooks(int why) 427 { 428 struct powerhook_desc *dp; 429 430 #ifdef POWERHOOK_DEBUG 431 const char *why_name; 432 static const char * pwr_names[] = {PWR_NAMES}; 433 why_name = why < __arraycount(pwr_names) ? pwr_names[why] : "???"; 434 #endif 435 436 if (why == PWR_RESUME || why == PWR_SOFTRESUME) { 437 CIRCLEQ_FOREACH_REVERSE(dp, &powerhook_list, sfd_list) { 438 #ifdef POWERHOOK_DEBUG 439 printf("dopowerhooks %s: %s (%p)\n", why_name, dp->sfd_name, dp); 440 #endif 441 (*dp->sfd_fn)(why, dp->sfd_arg); 442 } 443 } else { 444 CIRCLEQ_FOREACH(dp, &powerhook_list, sfd_list) { 445 #ifdef POWERHOOK_DEBUG 446 printf("dopowerhooks %s: %s (%p)\n", why_name, dp->sfd_name, dp); 447 #endif 448 (*dp->sfd_fn)(why, dp->sfd_arg); 449 } 450 } 451 452 #ifdef POWERHOOK_DEBUG 453 printf("dopowerhooks: %s done\n", why_name); 454 #endif 455 } 456 457 static int 458 isswap(device_t dv) 459 { 460 struct dkwedge_info wi; 461 struct vnode *vn; 462 int error; 463 464 if (device_class(dv) != DV_DISK || !device_is_a(dv, "dk")) 465 return 0; 466 467 if ((vn = opendisk(dv)) == NULL) 468 return 0; 469 470 error = VOP_IOCTL(vn, DIOCGWEDGEINFO, &wi, FREAD, NOCRED); 471 VOP_CLOSE(vn, FREAD, NOCRED); 472 vput(vn); 473 if (error) { 474 #ifdef DEBUG_WEDGE 475 printf("%s: Get wedge info returned %d\n", device_xname(dv), error); 476 #endif 477 return 0; 478 } 479 return strcmp(wi.dkw_ptype, DKW_PTYPE_SWAP) == 0; 480 } 481 482 /* 483 * Determine the root device and, if instructed to, the root file system. 484 */ 485 486 #include "md.h" 487 488 #if NMD > 0 489 extern struct cfdriver md_cd; 490 #ifdef MEMORY_DISK_IS_ROOT 491 int md_is_root = 1; 492 #else 493 int md_is_root = 0; 494 #endif 495 #endif 496 497 /* 498 * The device and wedge that we booted from. If booted_wedge is NULL, 499 * the we might consult booted_partition. 500 */ 501 device_t booted_device; 502 device_t booted_wedge; 503 int booted_partition; 504 505 /* 506 * Use partition letters if it's a disk class but not a wedge. 507 * XXX Check for wedge is kinda gross. 508 */ 509 #define DEV_USES_PARTITIONS(dv) \ 510 (device_class((dv)) == DV_DISK && \ 511 !device_is_a((dv), "dk")) 512 513 void 514 setroot(device_t bootdv, int bootpartition) 515 { 516 device_t dv; 517 deviter_t di; 518 int len, majdev; 519 dev_t nrootdev; 520 dev_t ndumpdev = NODEV; 521 char buf[128]; 522 const char *rootdevname; 523 const char *dumpdevname; 524 device_t rootdv = NULL; /* XXX gcc -Wuninitialized */ 525 device_t dumpdv = NULL; 526 struct ifnet *ifp; 527 const char *deffsname; 528 struct vfsops *vops; 529 530 #ifdef TFTPROOT 531 if (tftproot_dhcpboot(bootdv) != 0) 532 boothowto |= RB_ASKNAME; 533 #endif 534 535 #if NMD > 0 536 if (md_is_root) { 537 /* 538 * XXX there should be "root on md0" in the config file, 539 * but it isn't always 540 */ 541 bootdv = md_cd.cd_devs[0]; 542 bootpartition = 0; 543 } 544 #endif 545 546 /* 547 * If NFS is specified as the file system, and we found 548 * a DV_DISK boot device (or no boot device at all), then 549 * find a reasonable network interface for "rootspec". 550 */ 551 vops = vfs_getopsbyname(MOUNT_NFS); 552 if (vops != NULL && strcmp(rootfstype, MOUNT_NFS) == 0 && 553 rootspec == NULL && 554 (bootdv == NULL || device_class(bootdv) != DV_IFNET)) { 555 IFNET_FOREACH(ifp) { 556 if ((ifp->if_flags & 557 (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0) 558 break; 559 } 560 if (ifp == NULL) { 561 /* 562 * Can't find a suitable interface; ask the 563 * user. 564 */ 565 boothowto |= RB_ASKNAME; 566 } else { 567 /* 568 * Have a suitable interface; behave as if 569 * the user specified this interface. 570 */ 571 rootspec = (const char *)ifp->if_xname; 572 } 573 } 574 if (vops != NULL) 575 vfs_delref(vops); 576 577 /* 578 * If wildcarded root and we the boot device wasn't determined, 579 * ask the user. 580 */ 581 if (rootspec == NULL && bootdv == NULL) 582 boothowto |= RB_ASKNAME; 583 584 top: 585 if (boothowto & RB_ASKNAME) { 586 device_t defdumpdv; 587 588 for (;;) { 589 printf("root device"); 590 if (bootdv != NULL) { 591 printf(" (default %s", device_xname(bootdv)); 592 if (DEV_USES_PARTITIONS(bootdv)) 593 printf("%c", bootpartition + 'a'); 594 printf(")"); 595 } 596 printf(": "); 597 len = cngetsn(buf, sizeof(buf)); 598 if (len == 0 && bootdv != NULL) { 599 strlcpy(buf, device_xname(bootdv), sizeof(buf)); 600 len = strlen(buf); 601 } 602 if (len > 0 && buf[len - 1] == '*') { 603 buf[--len] = '\0'; 604 dv = getdisk(buf, len, 1, &nrootdev, 0); 605 if (dv != NULL) { 606 rootdv = dv; 607 break; 608 } 609 } 610 dv = getdisk(buf, len, bootpartition, &nrootdev, 0); 611 if (dv != NULL) { 612 rootdv = dv; 613 break; 614 } 615 } 616 617 /* 618 * Set up the default dump device. If root is on 619 * a network device, there is no default dump 620 * device, since we don't support dumps to the 621 * network. 622 */ 623 if (DEV_USES_PARTITIONS(rootdv) == 0) 624 defdumpdv = NULL; 625 else 626 defdumpdv = rootdv; 627 628 for (;;) { 629 printf("dump device"); 630 if (defdumpdv != NULL) { 631 /* 632 * Note, we know it's a disk if we get here. 633 */ 634 printf(" (default %sb)", device_xname(defdumpdv)); 635 } 636 printf(": "); 637 len = cngetsn(buf, sizeof(buf)); 638 if (len == 0) { 639 if (defdumpdv != NULL) { 640 ndumpdev = MAKEDISKDEV(major(nrootdev), 641 DISKUNIT(nrootdev), 1); 642 } 643 dumpdv = defdumpdv; 644 break; 645 } 646 if (len == 4 && strcmp(buf, "none") == 0) { 647 dumpdv = NULL; 648 break; 649 } 650 dv = getdisk(buf, len, 1, &ndumpdev, 1); 651 if (dv != NULL) { 652 dumpdv = dv; 653 break; 654 } 655 } 656 657 rootdev = nrootdev; 658 dumpdev = ndumpdev; 659 660 for (vops = LIST_FIRST(&vfs_list); vops != NULL; 661 vops = LIST_NEXT(vops, vfs_list)) { 662 if (vops->vfs_mountroot != NULL && 663 strcmp(rootfstype, vops->vfs_name) == 0) 664 break; 665 } 666 667 if (vops == NULL) { 668 deffsname = "generic"; 669 } else 670 deffsname = vops->vfs_name; 671 672 for (;;) { 673 printf("file system (default %s): ", deffsname); 674 len = cngetsn(buf, sizeof(buf)); 675 if (len == 0) { 676 if (strcmp(deffsname, "generic") == 0) 677 rootfstype = ROOT_FSTYPE_ANY; 678 break; 679 } 680 if (len == 4 && strcmp(buf, "halt") == 0) 681 cpu_reboot(RB_HALT, NULL); 682 else if (len == 6 && strcmp(buf, "reboot") == 0) 683 cpu_reboot(0, NULL); 684 #if defined(DDB) 685 else if (len == 3 && strcmp(buf, "ddb") == 0) { 686 console_debugger(); 687 } 688 #endif 689 else if (len == 7 && strcmp(buf, "generic") == 0) { 690 rootfstype = ROOT_FSTYPE_ANY; 691 break; 692 } 693 vops = vfs_getopsbyname(buf); 694 if (vops == NULL || vops->vfs_mountroot == NULL) { 695 printf("use one of: generic"); 696 for (vops = LIST_FIRST(&vfs_list); 697 vops != NULL; 698 vops = LIST_NEXT(vops, vfs_list)) { 699 if (vops->vfs_mountroot != NULL) 700 printf(" %s", vops->vfs_name); 701 } 702 if (vops != NULL) 703 vfs_delref(vops); 704 #if defined(DDB) 705 printf(" ddb"); 706 #endif 707 printf(" halt reboot\n"); 708 } else { 709 /* 710 * XXX If *vops gets freed between here and 711 * the call to mountroot(), rootfstype will 712 * point to something unexpected. But in 713 * this case the system will fail anyway. 714 */ 715 rootfstype = vops->vfs_name; 716 vfs_delref(vops); 717 break; 718 } 719 } 720 721 } else if (rootspec == NULL) { 722 /* 723 * Wildcarded root; use the boot device. 724 */ 725 rootdv = bootdv; 726 727 if (bootdv) 728 majdev = devsw_name2blk(device_xname(bootdv), NULL, 0); 729 else 730 majdev = -1; 731 if (majdev >= 0) { 732 /* 733 * Root is on a disk. `bootpartition' is root, 734 * unless the device does not use partitions. 735 */ 736 if (DEV_USES_PARTITIONS(bootdv)) 737 rootdev = MAKEDISKDEV(majdev, 738 device_unit(bootdv), 739 bootpartition); 740 else 741 rootdev = makedev(majdev, device_unit(bootdv)); 742 } 743 } else { 744 745 /* 746 * `root on <dev> ...' 747 */ 748 749 /* 750 * If it's a network interface, we can bail out 751 * early. 752 */ 753 dv = finddevice(rootspec); 754 if (dv != NULL && device_class(dv) == DV_IFNET) { 755 rootdv = dv; 756 goto haveroot; 757 } 758 759 if (rootdev == NODEV && 760 device_class(dv) == DV_DISK && device_is_a(dv, "dk") && 761 (majdev = devsw_name2blk(device_xname(dv), NULL, 0)) >= 0) 762 rootdev = makedev(majdev, device_unit(dv)); 763 764 rootdevname = devsw_blk2name(major(rootdev)); 765 if (rootdevname == NULL) { 766 printf("unknown device major 0x%llx\n", 767 (unsigned long long)rootdev); 768 boothowto |= RB_ASKNAME; 769 goto top; 770 } 771 memset(buf, 0, sizeof(buf)); 772 snprintf(buf, sizeof(buf), "%s%llu", rootdevname, 773 (unsigned long long)DISKUNIT(rootdev)); 774 775 rootdv = finddevice(buf); 776 if (rootdv == NULL) { 777 printf("device %s (0x%llx) not configured\n", 778 buf, (unsigned long long)rootdev); 779 boothowto |= RB_ASKNAME; 780 goto top; 781 } 782 } 783 784 haveroot: 785 786 root_device = rootdv; 787 788 switch (device_class(rootdv)) { 789 case DV_IFNET: 790 case DV_DISK: 791 aprint_normal("root on %s", device_xname(rootdv)); 792 if (DEV_USES_PARTITIONS(rootdv)) 793 aprint_normal("%c", (int)DISKPART(rootdev) + 'a'); 794 break; 795 796 default: 797 printf("can't determine root device\n"); 798 boothowto |= RB_ASKNAME; 799 goto top; 800 } 801 802 /* 803 * Now configure the dump device. 804 * 805 * If we haven't figured out the dump device, do so, with 806 * the following rules: 807 * 808 * (a) We already know dumpdv in the RB_ASKNAME case. 809 * 810 * (b) If dumpspec is set, try to use it. If the device 811 * is not available, punt. 812 * 813 * (c) If dumpspec is not set, the dump device is 814 * wildcarded or unspecified. If the root device 815 * is DV_IFNET, punt. Otherwise, use partition b 816 * of the root device. 817 */ 818 819 if (boothowto & RB_ASKNAME) { /* (a) */ 820 if (dumpdv == NULL) 821 goto nodumpdev; 822 } else if (dumpspec != NULL) { /* (b) */ 823 if (strcmp(dumpspec, "none") == 0 || dumpdev == NODEV) { 824 /* 825 * Operator doesn't want a dump device. 826 * Or looks like they tried to pick a network 827 * device. Oops. 828 */ 829 goto nodumpdev; 830 } 831 832 dumpdevname = devsw_blk2name(major(dumpdev)); 833 if (dumpdevname == NULL) 834 goto nodumpdev; 835 memset(buf, 0, sizeof(buf)); 836 snprintf(buf, sizeof(buf), "%s%llu", dumpdevname, 837 (unsigned long long)DISKUNIT(dumpdev)); 838 839 dumpdv = finddevice(buf); 840 if (dumpdv == NULL) { 841 /* 842 * Device not configured. 843 */ 844 goto nodumpdev; 845 } 846 } else { /* (c) */ 847 if (DEV_USES_PARTITIONS(rootdv) == 0) { 848 for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST); 849 dv != NULL; 850 dv = deviter_next(&di)) 851 if (isswap(dv)) 852 break; 853 deviter_release(&di); 854 if (dv == NULL) 855 goto nodumpdev; 856 857 majdev = devsw_name2blk(device_xname(dv), NULL, 0); 858 if (majdev < 0) 859 goto nodumpdev; 860 dumpdv = dv; 861 dumpdev = makedev(majdev, device_unit(dumpdv)); 862 } else { 863 dumpdv = rootdv; 864 dumpdev = MAKEDISKDEV(major(rootdev), 865 device_unit(dumpdv), 1); 866 } 867 } 868 869 dumpcdev = devsw_blk2chr(dumpdev); 870 aprint_normal(" dumps on %s", device_xname(dumpdv)); 871 if (DEV_USES_PARTITIONS(dumpdv)) 872 aprint_normal("%c", (int)DISKPART(dumpdev) + 'a'); 873 aprint_normal("\n"); 874 return; 875 876 nodumpdev: 877 dumpdev = NODEV; 878 dumpcdev = NODEV; 879 aprint_normal("\n"); 880 } 881 882 static device_t 883 finddevice(const char *name) 884 { 885 const char *wname; 886 887 if ((wname = getwedgename(name, strlen(name))) != NULL) 888 return dkwedge_find_by_wname(wname); 889 890 return device_find_by_xname(name); 891 } 892 893 static device_t 894 getdisk(char *str, int len, int defpart, dev_t *devp, int isdump) 895 { 896 device_t dv; 897 deviter_t di; 898 899 if ((dv = parsedisk(str, len, defpart, devp)) == NULL) { 900 printf("use one of:"); 901 for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST); dv != NULL; 902 dv = deviter_next(&di)) { 903 if (DEV_USES_PARTITIONS(dv)) 904 printf(" %s[a-%c]", device_xname(dv), 905 'a' + MAXPARTITIONS - 1); 906 else if (device_class(dv) == DV_DISK) 907 printf(" %s", device_xname(dv)); 908 if (isdump == 0 && device_class(dv) == DV_IFNET) 909 printf(" %s", device_xname(dv)); 910 } 911 deviter_release(&di); 912 dkwedge_print_wnames(); 913 if (isdump) 914 printf(" none"); 915 #if defined(DDB) 916 printf(" ddb"); 917 #endif 918 printf(" halt reboot\n"); 919 } 920 return dv; 921 } 922 923 static const char * 924 getwedgename(const char *name, int namelen) 925 { 926 const char *wpfx = "wedge:"; 927 const int wpfxlen = strlen(wpfx); 928 929 if (namelen < wpfxlen || strncmp(name, wpfx, wpfxlen) != 0) 930 return NULL; 931 932 return name + wpfxlen; 933 } 934 935 static device_t 936 parsedisk(char *str, int len, int defpart, dev_t *devp) 937 { 938 device_t dv; 939 const char *wname; 940 char *cp, c; 941 int majdev, part; 942 if (len == 0) 943 return (NULL); 944 945 if (len == 4 && strcmp(str, "halt") == 0) 946 cpu_reboot(RB_HALT, NULL); 947 else if (len == 6 && strcmp(str, "reboot") == 0) 948 cpu_reboot(0, NULL); 949 #if defined(DDB) 950 else if (len == 3 && strcmp(str, "ddb") == 0) 951 console_debugger(); 952 #endif 953 954 cp = str + len - 1; 955 c = *cp; 956 957 if ((wname = getwedgename(str, len)) != NULL) { 958 if ((dv = dkwedge_find_by_wname(wname)) == NULL) 959 return NULL; 960 part = defpart; 961 goto gotdisk; 962 } else if (c >= 'a' && c <= ('a' + MAXPARTITIONS - 1)) { 963 part = c - 'a'; 964 *cp = '\0'; 965 } else 966 part = defpart; 967 968 dv = finddevice(str); 969 if (dv != NULL) { 970 if (device_class(dv) == DV_DISK) { 971 gotdisk: 972 majdev = devsw_name2blk(device_xname(dv), NULL, 0); 973 if (majdev < 0) 974 panic("parsedisk"); 975 if (DEV_USES_PARTITIONS(dv)) 976 *devp = MAKEDISKDEV(majdev, device_unit(dv), 977 part); 978 else 979 *devp = makedev(majdev, device_unit(dv)); 980 } 981 982 if (device_class(dv) == DV_IFNET) 983 *devp = NODEV; 984 } 985 986 *cp = c; 987 return (dv); 988 } 989 990 /* 991 * Return true if system call tracing is enabled for the specified process. 992 */ 993 bool 994 trace_is_enabled(struct proc *p) 995 { 996 #ifdef SYSCALL_DEBUG 997 return (true); 998 #endif 999 #ifdef KTRACE 1000 if (ISSET(p->p_traceflag, (KTRFAC_SYSCALL | KTRFAC_SYSRET))) 1001 return (true); 1002 #endif 1003 #ifdef PTRACE 1004 if (ISSET(p->p_slflag, PSL_SYSCALL)) 1005 return (true); 1006 #endif 1007 1008 return (false); 1009 } 1010 1011 /* 1012 * Start trace of particular system call. If process is being traced, 1013 * this routine is called by MD syscall dispatch code just before 1014 * a system call is actually executed. 1015 */ 1016 int 1017 trace_enter(register_t code, const register_t *args, int narg) 1018 { 1019 #ifdef SYSCALL_DEBUG 1020 scdebug_call(code, args); 1021 #endif /* SYSCALL_DEBUG */ 1022 1023 ktrsyscall(code, args, narg); 1024 1025 #ifdef PTRACE 1026 if ((curlwp->l_proc->p_slflag & (PSL_SYSCALL|PSL_TRACED)) == 1027 (PSL_SYSCALL|PSL_TRACED)) 1028 process_stoptrace(); 1029 #endif 1030 return 0; 1031 } 1032 1033 /* 1034 * End trace of particular system call. If process is being traced, 1035 * this routine is called by MD syscall dispatch code just after 1036 * a system call finishes. 1037 * MD caller guarantees the passed 'code' is within the supported 1038 * system call number range for emulation the process runs under. 1039 */ 1040 void 1041 trace_exit(register_t code, register_t rval[], int error) 1042 { 1043 #ifdef SYSCALL_DEBUG 1044 scdebug_ret(code, error, rval); 1045 #endif /* SYSCALL_DEBUG */ 1046 1047 ktrsysret(code, error, rval); 1048 1049 #ifdef PTRACE 1050 if ((curlwp->l_proc->p_slflag & (PSL_SYSCALL|PSL_TRACED)) == 1051 (PSL_SYSCALL|PSL_TRACED)) 1052 process_stoptrace(); 1053 #endif 1054 } 1055 1056 int 1057 syscall_establish(const struct emul *em, const struct syscall_package *sp) 1058 { 1059 struct sysent *sy; 1060 int i; 1061 1062 KASSERT(mutex_owned(&module_lock)); 1063 1064 if (em == NULL) { 1065 em = &emul_netbsd; 1066 } 1067 sy = em->e_sysent; 1068 1069 /* 1070 * Ensure that all preconditions are valid, since this is 1071 * an all or nothing deal. Once a system call is entered, 1072 * it can become busy and we could be unable to remove it 1073 * on error. 1074 */ 1075 for (i = 0; sp[i].sp_call != NULL; i++) { 1076 if (sy[sp[i].sp_code].sy_call != sys_nomodule) { 1077 #ifdef DIAGNOSTIC 1078 printf("syscall %d is busy\n", sp[i].sp_code); 1079 #endif 1080 return EBUSY; 1081 } 1082 } 1083 /* Everything looks good, patch them in. */ 1084 for (i = 0; sp[i].sp_call != NULL; i++) { 1085 sy[sp[i].sp_code].sy_call = sp[i].sp_call; 1086 } 1087 1088 return 0; 1089 } 1090 1091 int 1092 syscall_disestablish(const struct emul *em, const struct syscall_package *sp) 1093 { 1094 struct sysent *sy; 1095 uint64_t where; 1096 lwp_t *l; 1097 int i; 1098 1099 KASSERT(mutex_owned(&module_lock)); 1100 1101 if (em == NULL) { 1102 em = &emul_netbsd; 1103 } 1104 sy = em->e_sysent; 1105 1106 /* 1107 * First, patch the system calls to sys_nomodule to gate further 1108 * activity. 1109 */ 1110 for (i = 0; sp[i].sp_call != NULL; i++) { 1111 KASSERT(sy[sp[i].sp_code].sy_call == sp[i].sp_call); 1112 sy[sp[i].sp_code].sy_call = sys_nomodule; 1113 } 1114 1115 /* 1116 * Run a cross call to cycle through all CPUs. This does two 1117 * things: lock activity provides a barrier and makes our update 1118 * of sy_call visible to all CPUs, and upon return we can be sure 1119 * that we see pertinent values of l_sysent posted by remote CPUs. 1120 */ 1121 where = xc_broadcast(0, (xcfunc_t)nullop, NULL, NULL); 1122 xc_wait(where); 1123 1124 /* 1125 * Now it's safe to check l_sysent. Run through all LWPs and see 1126 * if anyone is still using the system call. 1127 */ 1128 for (i = 0; sp[i].sp_call != NULL; i++) { 1129 mutex_enter(proc_lock); 1130 LIST_FOREACH(l, &alllwp, l_list) { 1131 if (l->l_sysent == &sy[sp[i].sp_code]) { 1132 break; 1133 } 1134 } 1135 mutex_exit(proc_lock); 1136 if (l == NULL) { 1137 continue; 1138 } 1139 /* 1140 * We lose: one or more calls are still in use. Put back 1141 * the old entrypoints and act like nothing happened. 1142 * When we drop module_lock, any system calls held in 1143 * sys_nomodule() will be restarted. 1144 */ 1145 for (i = 0; sp[i].sp_call != NULL; i++) { 1146 sy[sp[i].sp_code].sy_call = sp[i].sp_call; 1147 } 1148 return EBUSY; 1149 } 1150 1151 return 0; 1152 } 1153