No empty .Rs/.Re
[netbsd-mini2440.git] / sys / kern / kern_subr.c
bloba5b8f33718fe0e3703ab120f07df705c42e492bf
1 /* $NetBSD: kern_subr.c,v 1.202 2009/11/04 16:54:00 pooka Exp $ */
3 /*-
4 * Copyright (c) 1997, 1998, 1999, 2002, 2007, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
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.
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.
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.
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.
42 * Copyright (c) 1992, 1993
43 * The Regents of the University of California. All rights reserved.
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.
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.
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.
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.
78 * @(#)kern_subr.c 8.4 (Berkeley) 2/14/95
81 #include <sys/cdefs.h>
82 __KERNEL_RCSID(0, "$NetBSD: kern_subr.c,v 1.202 2009/11/04 16:54:00 pooka Exp $");
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"
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>
112 #include <uvm/uvm_extern.h>
114 #include <dev/cons.h>
116 #include <net/if.h>
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);
125 * A generic linear hook.
127 struct hook_desc {
128 LIST_ENTRY(hook_desc) hk_list;
129 void (*hk_fn)(void *);
130 void *hk_arg;
132 typedef LIST_HEAD(, hook_desc) hook_list_t;
134 #ifdef TFTPROOT
135 int tftproot_dhcpboot(device_t);
136 #endif
138 dev_t dumpcdev; /* for savecore */
140 static void *
141 hook_establish(hook_list_t *list, void (*fn)(void *), void *arg)
143 struct hook_desc *hd;
145 hd = malloc(sizeof(*hd), M_DEVBUF, M_NOWAIT);
146 if (hd == NULL)
147 return (NULL);
149 hd->hk_fn = fn;
150 hd->hk_arg = arg;
151 LIST_INSERT_HEAD(list, hd, hk_list);
153 return (hd);
156 static void
157 hook_disestablish(hook_list_t *list, void *vhook)
159 #ifdef DIAGNOSTIC
160 struct hook_desc *hd;
162 LIST_FOREACH(hd, list, hk_list) {
163 if (hd == vhook)
164 break;
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);
174 static void
175 hook_destroy(hook_list_t *list)
177 struct hook_desc *hd;
179 while ((hd = LIST_FIRST(list)) != NULL) {
180 LIST_REMOVE(hd, hk_list);
181 free(hd, M_DEVBUF);
185 static void
186 hook_proc_run(hook_list_t *list, struct proc *p)
188 struct hook_desc *hd;
190 LIST_FOREACH(hd, list, hk_list)
191 ((void (*)(struct proc *, void *))*hd->hk_fn)(p, hd->hk_arg);
195 * "Shutdown hook" types, functions, and variables.
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.
201 * Each shutdown hook is removed from the list before it's run, so that
202 * it won't be run again.
205 static hook_list_t shutdownhook_list;
207 void *
208 shutdownhook_establish(void (*fn)(void *), void *arg)
210 return hook_establish(&shutdownhook_list, fn, arg);
213 void
214 shutdownhook_disestablish(void *vhook)
216 hook_disestablish(&shutdownhook_list, vhook);
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.
224 * Each shutdown hook is removed from the list before it's run, so that
225 * it won't be run again.
227 void
228 doshutdownhooks(void)
230 struct hook_desc *dp;
232 while ((dp = LIST_FIRST(&shutdownhook_list)) != NULL) {
233 LIST_REMOVE(dp, hk_list);
234 (*dp->hk_fn)(dp->hk_arg);
235 #if 0
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.
243 free(dp, M_DEVBUF);
244 #endif
249 * "Mountroot hook" types, functions, and variables.
252 static hook_list_t mountroothook_list;
254 void *
255 mountroothook_establish(void (*fn)(device_t), device_t dev)
257 return hook_establish(&mountroothook_list, (void (*)(void *))fn, dev);
260 void
261 mountroothook_disestablish(void *vhook)
263 hook_disestablish(&mountroothook_list, vhook);
266 void
267 mountroothook_destroy(void)
269 hook_destroy(&mountroothook_list);
272 void
273 domountroothook(void)
275 struct hook_desc *hd;
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;
285 static hook_list_t exechook_list;
287 void *
288 exechook_establish(void (*fn)(struct proc *, void *), void *arg)
290 return hook_establish(&exechook_list, (void (*)(void *))fn, arg);
293 void
294 exechook_disestablish(void *vhook)
296 hook_disestablish(&exechook_list, vhook);
300 * Run exec hooks.
302 void
303 doexechooks(struct proc *p)
305 hook_proc_run(&exechook_list, p);
308 static hook_list_t exithook_list;
309 extern krwlock_t exec_lock;
311 void *
312 exithook_establish(void (*fn)(struct proc *, void *), void *arg)
314 void *rv;
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;
322 void
323 exithook_disestablish(void *vhook)
326 rw_enter(&exec_lock, RW_WRITER);
327 hook_disestablish(&exithook_list, vhook);
328 rw_exit(&exec_lock);
332 * Run exit hooks.
334 void
335 doexithooks(struct proc *p)
337 hook_proc_run(&exithook_list, p);
340 static hook_list_t forkhook_list;
342 void *
343 forkhook_establish(void (*fn)(struct proc *, struct proc *))
345 return hook_establish(&forkhook_list, (void (*)(void *))fn, NULL);
348 void
349 forkhook_disestablish(void *vhook)
351 hook_disestablish(&forkhook_list, vhook);
355 * Run fork hooks.
357 void
358 doforkhooks(struct proc *p2, struct proc *p1)
360 struct hook_desc *hd;
362 LIST_FOREACH(hd, &forkhook_list, hk_list) {
363 ((void (*)(struct proc *, struct proc *))*hd->hk_fn)
364 (p2, p1);
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.
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];
382 static CIRCLEQ_HEAD(, powerhook_desc) powerhook_list =
383 CIRCLEQ_HEAD_INITIALIZER(powerhook_list);
385 void *
386 powerhook_establish(const char *name, void (*fn)(int, void *), void *arg)
388 struct powerhook_desc *ndp;
390 ndp = (struct powerhook_desc *)
391 malloc(sizeof(*ndp), M_DEVBUF, M_NOWAIT);
392 if (ndp == NULL)
393 return (NULL);
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);
400 aprint_error("%s: WARNING: powerhook_establish is deprecated\n", name);
401 return (ndp);
404 void
405 powerhook_disestablish(void *vhook)
407 #ifdef DIAGNOSTIC
408 struct powerhook_desc *dp;
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
417 CIRCLEQ_REMOVE(&powerhook_list, (struct powerhook_desc *)vhook,
418 sfd_list);
419 free(vhook, M_DEVBUF);
423 * Run power hooks.
425 void
426 dopowerhooks(int why)
428 struct powerhook_desc *dp;
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
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);
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);
452 #ifdef POWERHOOK_DEBUG
453 printf("dopowerhooks: %s done\n", why_name);
454 #endif
457 static int
458 isswap(device_t dv)
460 struct dkwedge_info wi;
461 struct vnode *vn;
462 int error;
464 if (device_class(dv) != DV_DISK || !device_is_a(dv, "dk"))
465 return 0;
467 if ((vn = opendisk(dv)) == NULL)
468 return 0;
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;
479 return strcmp(wi.dkw_ptype, DKW_PTYPE_SWAP) == 0;
483 * Determine the root device and, if instructed to, the root file system.
486 #include "md.h"
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
498 * The device and wedge that we booted from. If booted_wedge is NULL,
499 * the we might consult booted_partition.
501 device_t booted_device;
502 device_t booted_wedge;
503 int booted_partition;
506 * Use partition letters if it's a disk class but not a wedge.
507 * XXX Check for wedge is kinda gross.
509 #define DEV_USES_PARTITIONS(dv) \
510 (device_class((dv)) == DV_DISK && \
511 !device_is_a((dv), "dk"))
513 void
514 setroot(device_t bootdv, int bootpartition)
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;
530 #ifdef TFTPROOT
531 if (tftproot_dhcpboot(bootdv) != 0)
532 boothowto |= RB_ASKNAME;
533 #endif
535 #if NMD > 0
536 if (md_is_root) {
538 * XXX there should be "root on md0" in the config file,
539 * but it isn't always
541 bootdv = md_cd.cd_devs[0];
542 bootpartition = 0;
544 #endif
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".
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;
560 if (ifp == NULL) {
562 * Can't find a suitable interface; ask the
563 * user.
565 boothowto |= RB_ASKNAME;
566 } else {
568 * Have a suitable interface; behave as if
569 * the user specified this interface.
571 rootspec = (const char *)ifp->if_xname;
574 if (vops != NULL)
575 vfs_delref(vops);
578 * If wildcarded root and we the boot device wasn't determined,
579 * ask the user.
581 if (rootspec == NULL && bootdv == NULL)
582 boothowto |= RB_ASKNAME;
584 top:
585 if (boothowto & RB_ASKNAME) {
586 device_t defdumpdv;
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(")");
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);
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;
610 dv = getdisk(buf, len, bootpartition, &nrootdev, 0);
611 if (dv != NULL) {
612 rootdv = dv;
613 break;
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.
623 if (DEV_USES_PARTITIONS(rootdv) == 0)
624 defdumpdv = NULL;
625 else
626 defdumpdv = rootdv;
628 for (;;) {
629 printf("dump device");
630 if (defdumpdv != NULL) {
632 * Note, we know it's a disk if we get here.
634 printf(" (default %sb)", device_xname(defdumpdv));
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);
643 dumpdv = defdumpdv;
644 break;
646 if (len == 4 && strcmp(buf, "none") == 0) {
647 dumpdv = NULL;
648 break;
650 dv = getdisk(buf, len, 1, &ndumpdev, 1);
651 if (dv != NULL) {
652 dumpdv = dv;
653 break;
657 rootdev = nrootdev;
658 dumpdev = ndumpdev;
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;
667 if (vops == NULL) {
668 deffsname = "generic";
669 } else
670 deffsname = vops->vfs_name;
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;
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();
688 #endif
689 else if (len == 7 && strcmp(buf, "generic") == 0) {
690 rootfstype = ROOT_FSTYPE_ANY;
691 break;
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);
702 if (vops != NULL)
703 vfs_delref(vops);
704 #if defined(DDB)
705 printf(" ddb");
706 #endif
707 printf(" halt reboot\n");
708 } else {
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.
715 rootfstype = vops->vfs_name;
716 vfs_delref(vops);
717 break;
721 } else if (rootspec == NULL) {
723 * Wildcarded root; use the boot device.
725 rootdv = bootdv;
727 if (bootdv)
728 majdev = devsw_name2blk(device_xname(bootdv), NULL, 0);
729 else
730 majdev = -1;
731 if (majdev >= 0) {
733 * Root is on a disk. `bootpartition' is root,
734 * unless the device does not use partitions.
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));
743 } else {
746 * `root on <dev> ...'
750 * If it's a network interface, we can bail out
751 * early.
753 dv = finddevice(rootspec);
754 if (dv != NULL && device_class(dv) == DV_IFNET) {
755 rootdv = dv;
756 goto haveroot;
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));
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;
771 memset(buf, 0, sizeof(buf));
772 snprintf(buf, sizeof(buf), "%s%llu", rootdevname,
773 (unsigned long long)DISKUNIT(rootdev));
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;
784 haveroot:
786 root_device = rootdv;
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;
796 default:
797 printf("can't determine root device\n");
798 boothowto |= RB_ASKNAME;
799 goto top;
803 * Now configure the dump device.
805 * If we haven't figured out the dump device, do so, with
806 * the following rules:
808 * (a) We already know dumpdv in the RB_ASKNAME case.
810 * (b) If dumpspec is set, try to use it. If the device
811 * is not available, punt.
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.
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) {
825 * Operator doesn't want a dump device.
826 * Or looks like they tried to pick a network
827 * device. Oops.
829 goto nodumpdev;
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));
839 dumpdv = finddevice(buf);
840 if (dumpdv == NULL) {
842 * Device not configured.
844 goto nodumpdev;
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;
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);
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;
876 nodumpdev:
877 dumpdev = NODEV;
878 dumpcdev = NODEV;
879 aprint_normal("\n");
882 static device_t
883 finddevice(const char *name)
885 const char *wname;
887 if ((wname = getwedgename(name, strlen(name))) != NULL)
888 return dkwedge_find_by_wname(wname);
890 return device_find_by_xname(name);
893 static device_t
894 getdisk(char *str, int len, int defpart, dev_t *devp, int isdump)
896 device_t dv;
897 deviter_t di;
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));
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");
920 return dv;
923 static const char *
924 getwedgename(const char *name, int namelen)
926 const char *wpfx = "wedge:";
927 const int wpfxlen = strlen(wpfx);
929 if (namelen < wpfxlen || strncmp(name, wpfx, wpfxlen) != 0)
930 return NULL;
932 return name + wpfxlen;
935 static device_t
936 parsedisk(char *str, int len, int defpart, dev_t *devp)
938 device_t dv;
939 const char *wname;
940 char *cp, c;
941 int majdev, part;
942 if (len == 0)
943 return (NULL);
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
954 cp = str + len - 1;
955 c = *cp;
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;
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));
982 if (device_class(dv) == DV_IFNET)
983 *devp = NODEV;
986 *cp = c;
987 return (dv);
991 * Return true if system call tracing is enabled for the specified process.
993 bool
994 trace_is_enabled(struct proc *p)
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
1008 return (false);
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.
1017 trace_enter(register_t code, const register_t *args, int narg)
1019 #ifdef SYSCALL_DEBUG
1020 scdebug_call(code, args);
1021 #endif /* SYSCALL_DEBUG */
1023 ktrsyscall(code, args, narg);
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;
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.
1040 void
1041 trace_exit(register_t code, register_t rval[], int error)
1043 #ifdef SYSCALL_DEBUG
1044 scdebug_ret(code, error, rval);
1045 #endif /* SYSCALL_DEBUG */
1047 ktrsysret(code, error, rval);
1049 #ifdef PTRACE
1050 if ((curlwp->l_proc->p_slflag & (PSL_SYSCALL|PSL_TRACED)) ==
1051 (PSL_SYSCALL|PSL_TRACED))
1052 process_stoptrace();
1053 #endif
1057 syscall_establish(const struct emul *em, const struct syscall_package *sp)
1059 struct sysent *sy;
1060 int i;
1062 KASSERT(mutex_owned(&module_lock));
1064 if (em == NULL) {
1065 em = &emul_netbsd;
1067 sy = em->e_sysent;
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.
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;
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;
1088 return 0;
1092 syscall_disestablish(const struct emul *em, const struct syscall_package *sp)
1094 struct sysent *sy;
1095 uint64_t where;
1096 lwp_t *l;
1097 int i;
1099 KASSERT(mutex_owned(&module_lock));
1101 if (em == NULL) {
1102 em = &emul_netbsd;
1104 sy = em->e_sysent;
1107 * First, patch the system calls to sys_nomodule to gate further
1108 * activity.
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;
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.
1121 where = xc_broadcast(0, (xcfunc_t)nullop, NULL, NULL);
1122 xc_wait(where);
1125 * Now it's safe to check l_sysent. Run through all LWPs and see
1126 * if anyone is still using the system call.
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;
1135 mutex_exit(proc_lock);
1136 if (l == NULL) {
1137 continue;
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.
1145 for (i = 0; sp[i].sp_call != NULL; i++) {
1146 sy[sp[i].sp_code].sy_call = sp[i].sp_call;
1148 return EBUSY;
1151 return 0;