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