xref: /netbsd/sys/arch/usermode/usermode/trap.c (revision bce879b8)
1 /* $NetBSD: trap.c,v 1.74 2022/05/28 21:14:56 andvar Exp $ */
2 
3 /*-
4  * Copyright (c) 2011 Reinoud Zandijk <reinoud@netbsd.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.74 2022/05/28 21:14:56 andvar Exp $");
31 
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/proc.h>
36 #include <sys/systm.h>
37 #include <sys/userret.h>
38 #include <sys/kauth.h>
39 #include <sys/errno.h>
40 
41 #include <uvm/uvm_extern.h>
42 #include <machine/cpu.h>
43 #include <machine/pcb.h>
44 #include <machine/pmap.h>
45 #include <machine/machdep.h>
46 #include <machine/intr.h>
47 #include <machine/thunk.h>
48 
49 #include "opt_kgdb.h"
50 
51 #ifdef KGDB
52 #include <sys/kgdb.h>
53 #endif
54 
55 /* define maximum signal number */
56 #ifndef NSIG
57 #define NSIG 64
58 #endif
59 
60 /* forwards and externals */
61 void setup_signal_handlers(void);
62 void stop_all_signal_handlers(void);
63 
64 static sigfunc_t pagefault;
65 static sigfunc_t illegal_instruction;
66 static sigfunc_t alarm;
67 static sigfunc_t sigio;
68 static sigfunc_t pass_on;
69 
70 void kgdb_kernel_trap(int signo, vaddr_t pc, vaddr_t va, ucontext_t *ctx);
71 
72 /* raw signal handlers */
73 static char    sig_stack[SIGSTKSZ];
74 static stack_t sigstk;
75 ucontext_t jump_ucp;
76 
77 sigfunc_t *sig_funcs[NSIG];
78 
79 /* segv, bus */
80 extern bool pmap_fault(pmap_t pmap, vaddr_t va, vm_prot_t *atype);
81 
82 /* alarm */
83 void setup_clock_intr(void);
84 extern void clock_intr(void *priv);
85 
86 extern int clock_running;
87 void *alrm_ih;
88 
89 /* sigio handlers */
90 struct intr_handler {
91 	int (*func)(void *);
92 	void *arg;
93 };
94 #define SIGIO_MAX_HANDLERS	8
95 static struct intr_handler sigio_intr_handler[SIGIO_MAX_HANDLERS];
96 
97 /* misc */
98 int astpending = 0;
99 
100 
101 /* XXX why is it here ? */
102 void
startlwp(void * arg)103 startlwp(void *arg)
104 {
105 	/* nothing here */
106 }
107 
108 
109 void
setup_signal_handlers(void)110 setup_signal_handlers(void)
111 {
112 	int i;
113 
114 	/*
115 	 * Set up the alternative signal stack. This prevents signals to be
116 	 * pushed on the NetBSD/usermode userland's stack with all desastrous
117 	 * effects. Especially ld.so and friends have such tiny stacks that
118 	 * its not feasible.
119 	 */
120 	sigstk.ss_sp    = sig_stack;
121 	sigstk.ss_size  = SIGSTKSZ;
122 	sigstk.ss_flags = 0;
123 	if (thunk_sigaltstack(&sigstk, 0) < 0)
124 		panic("can't set alternate stacksize: %d",
125 		    thunk_geterrno());
126 
127 	for (i = 0; i < NSIG; i++)
128 		sig_funcs[i] = NULL;
129 
130 	/* HUP */
131 	/* INT */	/* ttycons ^C */
132 	/* QUIT */
133 	signal_intr_establish(SIGILL, illegal_instruction);
134 	signal_intr_establish(SIGTRAP, pass_on); 	/* special */
135 	/* ABRT */
136 	/* SIGEMT */
137 	signal_intr_establish(SIGFPE, pass_on);
138 	/* KILL */
139 	signal_intr_establish(SIGBUS,  pagefault);
140 	signal_intr_establish(SIGSEGV, pagefault);
141 	/* SYS */
142 	/* PIPE */
143 	signal_intr_establish(SIGALRM, alarm);
144 	/* TERM */
145 	/* URG */
146 	/* STOP */
147 	/* TSTP */	/* ttycons ^Z */
148 	/* CONT */
149 	/* CHLD */
150 	/* GTTIN */
151 	/* TTOU */
152 	signal_intr_establish(SIGIO,   sigio);
153 	/* XCPU */
154 	/* XFSZ */
155 	/* VTALRM */
156 	/* PROF */
157 	/* WINCH */
158 	/* INFO */
159 	/* USR1 */
160 	/* USR2 */
161 	/* PWR */
162 }
163 
164 
165 /* XXX yes this is blunt */
166 void
stop_all_signal_handlers(void)167 stop_all_signal_handlers(void)
168 {
169 	int i;
170 	for (i = 0; i < NSIG; i++)
171 		if (sig_funcs[i])
172 			thunk_sigblock(i);
173 }
174 
175 
176 void
setup_clock_intr(void)177 setup_clock_intr(void)
178 {
179 	/* setup soft interrupt handler */
180 	alrm_ih = softint_establish(SOFTINT_CLOCK,
181 		clock_intr, NULL);
182 }
183 
184 
185 /* ast and userret */
186 static void
ast(struct lwp * l)187 ast(struct lwp *l)
188 {
189 	struct pcb *pcb;
190 
191 	curcpu()->ci_data.cpu_ntrap++;
192 
193 	do {
194 		astpending = 0;
195 		mi_userret(l);
196 	} while (astpending);
197 
198 #if 0
199 	/* profiling */
200 	if (l->l_pflag & LP_OWEUPC) {
201 		l->l_pflag &= ~LP_OWEUPC;
202 		ADDUPROF(l);
203 	}
204 #endif
205 
206 	KASSERT(l == curlwp); KASSERT(l);
207 	pcb = lwp_getpcb(l); KASSERT(pcb);
208 }
209 
210 
211 void
userret(struct lwp * l)212 userret(struct lwp *l)
213 {
214 	/* invoke MI userret code */
215 	mi_userret(l);
216 
217 	ast(l);
218 }
219 
220 
221 #ifdef DEBUG
222 /*
223  * Uncomment the following if you want to receive information about what
224  * triggered the fault. Mainly for debugging and porting purposes
225  */
226 static void
print_mem_access_siginfo(int sig,siginfo_t * info,void * ctx,vaddr_t pc,vaddr_t va,vaddr_t sp)227 print_mem_access_siginfo(int sig, siginfo_t *info, void *ctx,
228 	vaddr_t pc, vaddr_t va, vaddr_t sp)
229 {
230 #if 0
231 	thunk_printf_debug("SIGSEGV or SIGBUS!\n");
232 	thunk_printf_debug("\tsi_signo = %d\n", info->si_signo);
233 	thunk_printf_debug("\tsi_errno = %d\n", info->si_errno);
234 	thunk_printf_debug("\tsi_code  = %d\n", info->si_code);
235 	if (info->si_code == SEGV_MAPERR)
236 		thunk_printf_debug("\t\tSEGV_MAPERR\n");
237 	if (info->si_code == SEGV_ACCERR)
238 		thunk_printf_debug("\t\tSEGV_ACCERR\n");
239 	if (info->si_code == BUS_ADRALN)
240 		thunk_printf_debug("\t\tBUS_ADRALN\n");
241 	if (info->si_code == BUS_ADRERR)
242 		thunk_printf_debug("\t\tBUS_ADRERR\n");
243 	if (info->si_code == BUS_OBJERR)
244 		thunk_printf_debug("\t\tBUS_OBJERR\n");
245 	thunk_printf_debug("\tsi_addr = %p\n", info->si_addr);
246 	thunk_printf_debug("\tsi_trap = %d\n", info->si_trap);
247 #endif
248 
249 #if 0
250 	thunk_printf("memaccess error, pc %p, va %p, sp %p\n",
251 		(void *) pc, (void *) va, (void *) sp);
252 #endif
253 }
254 
255 /*
256  * Uncomment the following if you want to receive information about what
257  * triggered the fault. Mainly for debugging and porting purposes
258  */
259 static void
print_illegal_instruction_siginfo(int sig,siginfo_t * info,void * ctx,vaddr_t pc,vaddr_t va,vaddr_t sp)260 print_illegal_instruction_siginfo(int sig, siginfo_t *info, void *ctx,
261 	vaddr_t pc, vaddr_t va, vaddr_t sp)
262 {
263 #if 0
264 	thunk_printf("SIGILL!\n");
265 	thunk_printf("\tsi_signo = %d\n", info->si_signo);
266 	thunk_printf("\tsi_errno = %d\n", info->si_errno);
267 	thunk_printf("\tsi_code  = %d\n", info->si_code);
268 	if (info->si_code == ILL_ILLOPC)
269 		thunk_printf("\t\tIllegal opcode");
270 	if (info->si_code == ILL_ILLOPN)
271 		thunk_printf("\t\tIllegal operand");
272 	if (info->si_code == ILL_ILLADR)
273 		thunk_printf("\t\tIllegal addressing mode");
274 	if (info->si_code == ILL_ILLTRP)
275 		thunk_printf("\t\tIllegal trap");
276 	if (info->si_code == ILL_PRVOPC)
277 		thunk_printf("\t\tPrivileged opcode");
278 	if (info->si_code == ILL_PRVREG)
279 		thunk_printf("\t\tPrivileged register");
280 	if (info->si_code == ILL_COPROC)
281 		thunk_printf("\t\tCoprocessor error");
282 	if (info->si_code == ILL_BADSTK)
283 		thunk_printf("\t\tInternal stack error");
284 	thunk_printf("\tsi_addr = %p\n", info->si_addr);
285 	thunk_printf("\tsi_trap = %d\n", info->si_trap);
286 
287 	thunk_printf("%p : ", info->si_addr);
288 	for (int i = 0; i < 10; i++)
289 		thunk_printf("%02x ", *((uint8_t *) info->si_addr + i));
290 	thunk_printf("\n");
291 #endif
292 
293 #if 0
294 	thunk_printf("sigill\n");
295 #endif
296 }
297 #else /* DEBUG */
298 #define print_mem_access_siginfo(s, i, c, p, v, sp) {}
299 #define print_illegal_instruction_siginfo(s, i, c, p, v, sp) {}
300 #endif /* DEBUG */
301 
302 
303 static void
handle_signal(int sig,siginfo_t * info,void * ctx)304 handle_signal(int sig, siginfo_t *info, void *ctx)
305 {
306 	sigfunc_t *f;
307 	ucontext_t *ucp = ctx;
308 	struct lwp *l;
309 	struct pcb *pcb;
310 	vaddr_t va, sp, pc, fp;
311 	long from_userland;
312 
313 	if (sig == SIGBUS || sig == SIGSEGV || sig == SIGILL) {
314 		if (info->si_code == SI_NOINFO)
315 			panic("received signal %d with no info",
316 			    info->si_signo);
317 	}
318 
319 	f = sig_funcs[sig];
320 	KASSERT(f);
321 
322 	/* get address of possible faulted memory access and page align it */
323 	va = (vaddr_t) info->si_addr;
324 	va = trunc_page(va);
325 
326 	/* get PC address of possibly faulted instruction */
327 	pc = md_get_pc(ctx);
328 
329 	/*
330 	 * short-cut for SIGTRAP as we have NO indication anything is valid
331 	 */
332 #ifdef KGDB
333 	if (sig == SIGTRAP) {
334 		from_userland = 0;
335 		if (pc < kmem_user_end)
336 			from_userland = 1;
337 		if (!from_userland) {
338 			kgdb_kernel_trap(sig, pc, va, ucp);
339 			return;
340 		}
341 	}
342 #endif
343 
344 	/* get stack pointer for nesting */
345 	sp = md_get_sp(ctx);
346 
347 	if (sig == SIGBUS || sig == SIGSEGV)
348 		print_mem_access_siginfo(sig, info, ctx, pc, va, sp);
349 	if (sig == SIGILL)
350 		print_illegal_instruction_siginfo(sig, info, ctx, pc, va, sp);
351 
352 	/* get thread */
353 	l = curlwp; KASSERT(l);
354 	pcb = lwp_getpcb(l); KASSERT(pcb);
355 
356 	/* currently running on the dedicated signal stack */
357 
358 	/* if we're running on a userland stack, switch to the system stack */
359 	from_userland = 0;
360 	if ((sp < (vaddr_t) pcb->sys_stack) ||
361 	    (sp > (vaddr_t) pcb->sys_stack_top)) {
362 		sp = (vaddr_t) pcb->sys_stack_top - sizeof(register_t);
363 		fp = (vaddr_t) &pcb->pcb_userret_ucp;
364 		if (pc < kmem_user_end)
365 			from_userland = 1;
366 	} else {
367 		/* stack grows down */
368 		fp = sp - sizeof(ucontext_t) - sizeof(register_t); /* slack */
369 		sp = fp - sizeof(register_t);	/* slack */
370 
371 		/* sanity check before copying */
372 		if (fp - 4*PAGE_SIZE < (vaddr_t) pcb->sys_stack)
373 			panic("%s: out of system stack", __func__);
374 	}
375 
376 	memcpy((void *) fp, ucp, sizeof(ucontext_t));
377 	memcpy(&jump_ucp, ucp, sizeof(ucontext_t));
378 
379 	/* create context */
380 	jump_ucp.uc_stack.ss_sp = (void *) pcb->sys_stack;
381 	jump_ucp.uc_stack.ss_size = sp - (vaddr_t) pcb->sys_stack;
382 	jump_ucp.uc_link = (void *) fp;	/* link to old frame on stack */
383 
384 	/* prevent multiple nested SIGIOs */
385 	if (sig == SIGIO)
386 		thunk_sigfillset(&jump_ucp.uc_sigmask);
387 	else
388 		thunk_sigemptyset(&jump_ucp.uc_sigmask);
389 	jump_ucp.uc_flags = _UC_STACK | _UC_CPU | _UC_SIGMASK;
390 
391 	thunk_makecontext(&jump_ucp,
392 			(void (*)(void)) f,
393 		4, info, (void *) from_userland, (void *) pc, (void *) va);
394 
395 	/* switch to the new context on return from signal */
396 	thunk_setcontext(&jump_ucp);
397 //	memcpy(ctx, &pcb->pcb_ucp, sizeof(ucontext_t));
398 }
399 
400 
401 void
signal_intr_establish(int sig,sigfunc_t f)402 signal_intr_establish(int sig, sigfunc_t f)
403 {
404 	static struct sigaction sa;
405 
406 	sig_funcs[sig] = f;
407 
408 	sa.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
409 	sa.sa_sigaction = (void *) handle_signal;
410 	thunk_sigfillset(&sa.sa_mask);
411 	if (thunk_sigaction(sig, &sa, NULL) == -1)
412 		panic("couldn't register SIG%d handler: %d", sig,
413 		    thunk_geterrno());
414 }
415 
416 
417 /*
418  * Context for handing page faults from the sigsegv handler; check if its a
419  * pmap reference fault or let uvm handle it.
420  */
421 static void
pagefault(siginfo_t * info,vaddr_t from_userland,vaddr_t pc,vaddr_t va)422 pagefault(siginfo_t *info, vaddr_t from_userland, vaddr_t pc, vaddr_t va)
423 {
424 	struct proc *p;
425 	struct lwp *l;
426 	struct pcb *pcb;
427 	struct vmspace *vm;
428 	struct vm_map *vm_map;
429 	vm_prot_t atype;
430 	void *onfault;
431 	int from_kernel, lwp_errno, error;
432 	ksiginfo_t ksi;
433 
434 	l = curlwp; KASSERT(l);
435 	pcb = lwp_getpcb(l);
436 	p = l->l_proc;
437 	vm = p->p_vmspace;
438 
439 	lwp_errno = thunk_geterrno();
440 
441 	vm_map = &vm->vm_map;
442 	from_kernel = (pc >= kmem_k_start) && (!from_userland);
443 	if (from_kernel && (va >= VM_MIN_KERNEL_ADDRESS))
444 		vm_map = kernel_map;
445 
446 #if 0
447 	thunk_printf("%s: l %p, pcb %p\n", __func__, l, pcb);
448 	thunk_printf("\tpc %p, va %p\n", (void *) pc, (void *) va);
449 #endif
450 
451 	/* can pmap handle it? on its own? (r/m) emulation */
452 	if (pmap_fault(vm_map->pmap, va, &atype)) {
453 		/* no use doing anything else here */
454 		goto out_quick;
455 	}
456 
457 	/* ask UVM */
458 #if 0
459 thunk_printf("%s: l %p, pcb %p, ", __func__, l, pcb);
460 thunk_printf("pc %p, va %p ", (void *) pc, (void *) va);
461 thunk_printf("derived atype %d\n", atype);
462 #endif
463 	thunk_printf_debug("pmap fault couldn't handle it! : "
464 		"derived atype %d\n", atype);
465 
466 	onfault = pcb->pcb_onfault;
467 	pcb->pcb_onfault = NULL;
468 	error = uvm_fault(vm_map, va, atype);
469 	pcb->pcb_onfault = onfault;
470 
471 	if (vm_map != kernel_map) {
472 		if (error == 0)
473 			uvm_grow(l->l_proc, va);
474 	}
475 	if (error == EACCES)
476 		error = EFAULT;
477 
478 	/* if uvm handled it, return */
479 	if (error == 0) {
480 //		thunk_printf("pagefault leave (uvm)\n");
481 		goto out;
482 	}
483 
484 	/* check if its from copyin/copyout */
485 	if (onfault) {
486 		panic("%s: can't call onfault yet\n", __func__);
487 		/* XXX implement me ? */
488 		/* jump to given onfault */
489 		// tf = &kernel_tf;
490 		// memset(tf, 0, sizeof(struct trapframe));
491 		// tf->tf_pc = onfault;
492 		// tf->tf_io[0] = (rv == EACCES) ? EFAULT : rv;
493 		goto out;
494 	}
495 
496 	if (from_kernel) {
497 		thunk_printf("%s: uvm fault %d, pc %p, va %p, from_kernel %d\n",
498 			__func__, error, (void *) pc, (void *) va, from_kernel);
499 		panic("Unhandled page fault in kernel mode");
500 	}
501 
502 	/* send signal */
503 	/* something got wrong */
504 	thunk_printf_debug("%s: uvm fault %d, pc %p, va %p, from_kernel %d\n",
505 		__func__, error, (void *) pc, (void *) va, from_kernel);
506 
507 	thunk_printf_debug("giving signal to userland\n");
508 
509 	KASSERT(from_userland);
510 	KSI_INIT_TRAP(&ksi);
511 	ksi.ksi_signo = info->si_signo;
512 	ksi.ksi_trap = 0;	/* XXX */
513 	ksi.ksi_code = (error == EPERM) ? SEGV_ACCERR : SEGV_MAPERR;
514 	ksi.ksi_addr = (void *) va;
515 
516 	if (error == ENOMEM) {
517 		printf("UVM: pid %d.%d (%s), uid %d killed: "
518 		    "out of swap\n",
519 		    p->p_pid, l->l_lid, p->p_comm,
520 		    l->l_cred ? kauth_cred_geteuid(l->l_cred) : -1);
521 		ksi.ksi_signo = SIGKILL;
522 	}
523 
524 #if 0
525 	p->p_emul->e_trapsignal(l, &ksi);
526 #else
527 	trapsignal(l, &ksi);
528 #endif
529 
530 //	thunk_printf("pagefault leave\n");
531 out:
532 	if (from_userland)
533 		userret(l);
534 out_quick:
535 	thunk_seterrno(lwp_errno);
536 	pcb->pcb_errno = lwp_errno;
537 }
538 
539 
540 /*
541  * handle an illegal instruction.
542  *
543  * arguments 'pc' and 'va' are ignored here
544  */
545 static void
illegal_instruction(siginfo_t * info,vaddr_t from_userland,vaddr_t pc,vaddr_t va)546 illegal_instruction(siginfo_t *info, vaddr_t from_userland, vaddr_t pc, vaddr_t va)
547 {
548 	struct lwp *l = curlwp;
549 	struct pcb *pcb = lwp_getpcb(l);
550 	ucontext_t *ucp = &pcb->pcb_userret_ucp;
551 	ksiginfo_t ksi;
552 
553 //	thunk_printf("%s: l %p, pcb %p\n", __func__, l, pcb);
554 
555 	KASSERT(from_userland);
556 
557 	/* if its a syscall ... */
558 	if (md_syscall_check_opcode(ucp)) {
559 		syscall();
560 		userret(l);
561 		return;
562 	}
563 
564 	thunk_printf("%s: giving SIGILL (TRAP)\n", __func__);
565 
566 	KASSERT(from_userland);
567 	KSI_INIT_TRAP(&ksi);
568 	ksi.ksi_signo = SIGILL;
569 	ksi.ksi_trap  = 0;	/* XXX */
570 	ksi.ksi_errno = 0; // info->si_errno;
571 	ksi.ksi_code  = 0; // info->si_code;
572 	ksi.ksi_addr  = (void *) md_get_pc(ucp); /* only reliable source */
573 
574 #if 0
575 	p->p_emul->e_trapsignal(l, &ksi);
576 #else
577 	trapsignal(l, &ksi);
578 #endif
579 	userret(l);
580 }
581 
582 
583 /*
584  * handle pass to userland signals
585  *
586  * arguments other than the original siginfo_t are not used
587  */
588 static void
pass_on(siginfo_t * info,vaddr_t from_userland,vaddr_t pc,vaddr_t va)589 pass_on(siginfo_t *info, vaddr_t from_userland, vaddr_t pc, vaddr_t va)
590 {
591 	struct lwp *l = curlwp;
592 	struct pcb *pcb = lwp_getpcb(l);
593 	ucontext_t *ucp = &pcb->pcb_userret_ucp;
594 	ksiginfo_t ksi;
595 
596 	KASSERT(from_userland);
597 	KSI_INIT_TRAP(&ksi);
598 	ksi.ksi_signo = info->si_signo;
599 	ksi.ksi_trap  = 0;	/* XXX ? */
600 	ksi.ksi_errno = info->si_errno;
601 	ksi.ksi_code  = info->si_code;
602 	ksi.ksi_addr  = (void *) md_get_pc(ucp); /* only reliable source */
603 
604 	trapsignal(l, &ksi);
605 	userret(l);
606 }
607 
608 
609 /*
610  * handle alarm, a clock ticker.
611  *
612  * arguments 'pc' and 'va' are ignored here
613  */
614 static void
alarm(siginfo_t * info,vaddr_t from_userland,vaddr_t pc,vaddr_t va)615 alarm(siginfo_t *info, vaddr_t from_userland, vaddr_t pc, vaddr_t va)
616 {
617 	struct lwp *l = curlwp;
618 	struct pcb *pcb = lwp_getpcb(l); KASSERT(pcb);
619 
620 	if (!clock_running)
621 		return;
622 //	thunk_printf("%s: l %p, pcb %p\n", __func__, l, pcb);
623 
624 	softint_schedule(alrm_ih);
625 
626 	KASSERT(l == curlwp);
627 	if (from_userland)
628 		userret(l);
629 }
630 
631 
632 /*
633  * handle sigio, a mux for all io operations.
634  *
635  * arguments 'pc' and 'va' are ignored here
636  */
637 static void
sigio(siginfo_t * info,vaddr_t from_userland,vaddr_t pc,vaddr_t va)638 sigio(siginfo_t *info, vaddr_t from_userland, vaddr_t pc, vaddr_t va)
639 {
640 	struct lwp *l = curlwp;
641 	struct pcb *pcb = lwp_getpcb(l); KASSERT(pcb);
642 	struct intr_handler *sih;
643 	unsigned int n, pass;
644 
645 //	thunk_printf("%s: l %p, pcb %p\n", __func__, l, pcb);
646 	for (pass = 0; pass < 2; pass++) {
647 		for (n = 0; n < SIGIO_MAX_HANDLERS; n++) {
648 			sih = &sigio_intr_handler[n];
649 			if (sih->func)
650 				sih->func(sih->arg);
651 		}
652 	}
653 
654 	KASSERT(l == curlwp);
655 	if (from_userland)
656 		userret(l);		/* or ast? */
657 }
658 
659 
660 /* sigio register function */
661 void *
sigio_intr_establish(int (* func)(void *),void * arg)662 sigio_intr_establish(int (*func)(void *), void *arg)
663 {
664 	struct intr_handler *sih;
665 	unsigned int n;
666 
667 	for (n = 0; n < SIGIO_MAX_HANDLERS; n++) {
668 		sih = &sigio_intr_handler[n];
669 		if (sih->func == NULL) {
670 			sih->func = func;
671 			sih->arg = arg;
672 			return sih;
673 		}
674 	}
675 
676 	panic("increase SIGIO_MAX_HANDLERS");
677 }
678 
679