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