Home | History | Annotate | Line # | Download | only in usermode
      1 /* $NetBSD: trap.c,v 1.74 2022/05/28 21:14:56 andvar Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2011 Reinoud Zandijk <reinoud (at) 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
    103 startlwp(void *arg)
    104 {
    105 	/* nothing here */
    106 }
    107 
    108 
    109 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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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 *
    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