Date: Wed, 23 Apr 2003 13:56:05 -0700 (PDT) From: Marcel Moolenaar <marcel@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 29537 for review Message-ID: <200304232056.h3NKu5VU060332@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=29537 Change 29537 by marcel@marcel_nfs on 2003/04/23 13:55:54 Get signal delivery working for the "legacy" syscalls. This brings us back online with a world from HEAD and an EPC based kernel. Note that since we have a gateway page, we don't have to copy signal trampoline code onto the stack when we exec. We have the trampoline code in the gateway page now. Not only does this remove the pressure on the size of the trampoline code, it also means we can stop using executable stacks. Some additional work needs to be done to handle the less common cases. This is delayed until the signal delivery for EPC syscalls has been implemented. Both syscall paths will share a lot of code WRT signal delivery, so it's better to have the rudimentary support for the EPC syscalls in place before working on the hairy details. Things that need to be done are: o Save the preserved registers so that we can safely sigreturn from anywhere the process pleases, rather than by returning from the signal handler. Restoring the preserved registers can be tricky as it involves unwinding. o Make sure the kernel backing store doesn't have more than 0x200 bytes worth of dirty registers (including NaT collections). We need to be able to return to the original stack, which means that we need to be able to discard the current register stack. This mimics the problem of exec'ing. See also exec_setregs(). Affected files ... .. //depot/projects/ia64_epc/sys/ia64/ia64/elf_machdep.c#4 edit .. //depot/projects/ia64_epc/sys/ia64/ia64/locore.s#15 edit .. //depot/projects/ia64_epc/sys/ia64/ia64/machdep.c#17 edit .. //depot/projects/ia64_epc/sys/ia64/ia64/syscall.s#10 edit Differences ... ==== //depot/projects/ia64_epc/sys/ia64/ia64/elf_machdep.c#4 (text+ko) ==== @@ -59,8 +59,8 @@ NULL, __elfN(freebsd_fixup), sendsig, - sigcode, - &szsigcode, + NULL, /* sigcode */ + NULL, /* &szsigcode */ NULL, "FreeBSD ELF64", __elfN(coredump), ==== //depot/projects/ia64_epc/sys/ia64/ia64/locore.s#15 (text+ko) ==== @@ -295,84 +295,6 @@ #endif /* !SMP */ -/**************************************************************************/ - -/* - * Signal "trampoline" code. Invoked from RTE setup by sendsig(). - * - * On entry, registers look like: - * - * r14 signal number - * r15 pointer to siginfo_t - * r16 pointer to signal context frame (scp) - * r17 address of handler function descriptor - * r18 address of new backing store (if any) - * sp+16 pointer to sigframe - */ - -ENTRY(sigcode,0) - ld8 r8=[r17],8 // function address - ;; - ld8 gp=[r17] // function's gp value - mov b6=r8 // transfer to a branch register - cover - ;; - add r8=UC_MCONTEXT+MC_SPECIAL_BSPSTORE,r16 // address or mc_ar_bsp - mov r9=ar.bsp // save ar.bsp - ;; - st8 [r8]=r9 - cmp.eq p1,p2=r0,r18 // check for new bs -(p1) br.cond.sptk.few 1f // branch if not switching - flushrs // flush out to old bs - mov ar.rsc=0 // switch off RSE - add r8=UC_MCONTEXT+MC_SPECIAL_RNAT,r16 // address of mc_ar_rnat - ;; - mov r9=ar.rnat // value of ar.rnat after flush - mov ar.bspstore=r18 // point at new bs - ;; - st8 [r8]=r9 // remember ar.rnat - mov ar.rsc=15 // XXX bogus value - check - invala - ;; -1: alloc r5=ar.pfs,0,0,3,0 // register frame for call - ;; - mov out0=r14 // signal number - mov out1=r15 // siginfo - mov out2=r16 // ucontext - mov r4=r16 // save from call - br.call.sptk.few rp=b6 // call the signal handler - ;; - alloc r14=ar.pfs,0,0,0,0 // discard call frame - ;; - flushrs - ;; -(p1) br.cond.sptk.few 2f // note: p1 is preserved - mov ar.rsc=0 - add r8=UC_MCONTEXT+MC_SPECIAL_RNAT,r4 // address of mc_ar_rnat - ;; - ld8 r9=[r8] - ;; - add r8=UC_MCONTEXT+MC_SPECIAL_BSPSTORE,r4 // address of mc_ar_bsp - ;; - ld8 r10=[r8] - ;; - mov ar.bspstore=r10 - ;; - mov ar.rnat=r9 - mov ar.rsc=15 - ;; -2: CALLSYS_NOERROR(sigreturn) // call sigreturn() - alloc r14=ar.pfs,0,0,1,0 ;; - mov out0=ret0 // if that failed, get error code - CALLSYS_NOERROR(exit) // and call exit() with it. -XENTRY(esigcode) - END(sigcode) - - .data - EXPORT(szsigcode) - .quad esigcode-sigcode - .text - /* * Create a default interrupt name table. The first entry (vector 0) is * hardwaired to the clock interrupt. ==== //depot/projects/ia64_epc/sys/ia64/ia64/machdep.c#17 (text+ko) ==== @@ -106,6 +106,8 @@ extern u_int64_t kernel_text[], _end[]; extern u_int64_t ia64_gateway_page[]; +extern u_int64_t break_sigtramp[]; +extern u_int64_t epc_sigtramp[]; FPSWA_INTERFACE *fpswa_interface; @@ -808,35 +810,28 @@ } /* - * Send an interrupt to process. - * - * Stack is set up to allow sigcode stored - * at top to call routine, followed by kcall - * to sigreturn routine below. After sigreturn - * resets the signal mask, the stack, and the - * frame pointer, it returns to the user - * specified pc, psl. + * Send an interrupt (signal) to a process. */ void sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) { struct proc *p; struct thread *td; - struct trapframe *frame; + struct trapframe *tf; struct sigacts *psp; struct sigframe sf, *sfp; mcontext_t *mc; - u_int64_t sbs = 0, sp; - int oonstack, rndfsize; + u_int64_t sbs, sp; + int oonstack; td = curthread; p = td->td_proc; PROC_LOCK_ASSERT(p, MA_OWNED); psp = p->p_sigacts; - frame = td->td_frame; - sp = frame->tf_special.sp; + tf = td->td_frame; + sp = tf->tf_special.sp; oonstack = sigonstack(sp); - rndfsize = ((sizeof(sf) + 15) / 16) * 16; + sbs = 0; /* save user context */ bzero(&sf, sizeof(struct sigframe)); @@ -845,27 +840,7 @@ sf.sf_uc.uc_stack.ss_flags = (p->p_flag & P_ALTSTACK) ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE; - mc = &sf.sf_uc.uc_mcontext; - mc->mc_special = frame->tf_special; - if ((frame->tf_flags & FRAME_SYSCALL) == 0) { - mc->mc_flags |= IA64_MC_FLAGS_SCRATCH_VALID; - mc->mc_scratch = frame->tf_scratch; - mc->mc_scratch_fp = frame->tf_scratch_fp; - /* - * XXX High FP. If the process has never used the high FP, - * mark the high FP as valid (zero defaults). If the process - * did use the high FP, then store them in the PCB if not - * already there (ie get them from the CPU that has them) - * and write them in the context. - */ - } - /* - * XXX preserved registers. We don't have the preserved registers - * in the trapframe. We don't worry about it now. - */ - - /* * Allocate and validate space for the signal handler * context. Note that if the stack is in P0 space, the * call to grow() is a nop, and the useracc() check @@ -874,32 +849,43 @@ */ if ((p->p_flag & P_ALTSTACK) != 0 && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { - sbs = (u_int64_t) p->p_sigstk.ss_sp; - sfp = (struct sigframe *)((caddr_t)p->p_sigstk.ss_sp + - p->p_sigstk.ss_size - rndfsize); - /* Align sp and bsp. */ + sbs = (u_int64_t)p->p_sigstk.ss_sp; sbs = (sbs + 15) & ~15; - sfp = (struct sigframe *)((u_int64_t)sfp & ~15); + sfp = (struct sigframe *)(sbs + p->p_sigstk.ss_size); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) p->p_sigstk.ss_flags |= SS_ONSTACK; #endif } else - sfp = (struct sigframe *)(sp - rndfsize); + sfp = (struct sigframe *)sp; + sfp = (struct sigframe *)((u_int64_t)(sfp - 1) & ~15); + + /* Fill in the siginfo structure for POSIX handlers. */ + if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { + sf.sf_si.si_signo = sig; + sf.sf_si.si_code = code; + sf.sf_si.si_addr = (void*)tf->tf_special.ifa; + code = (u_int64_t)&sfp->sf_si; + } + PROC_UNLOCK(p); -#ifdef DEBUG - if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) - printf("sendsig(%d): sig %d ssp %p usp %p\n", p->p_pid, - sig, &sf, sfp); -#endif + mc = &sf.sf_uc.uc_mcontext; + mc->mc_special = tf->tf_special; + mc->mc_scratch = tf->tf_scratch; + if ((tf->tf_flags & FRAME_SYSCALL) == 0) { + mc->mc_flags |= IA64_MC_FLAGS_SCRATCH_VALID; + mc->mc_scratch_fp = tf->tf_scratch_fp; + /* + * XXX High FP. If the process has never used the high FP, + * mark the high FP as valid (zero defaults). If the process + * did use the high FP, then store them in the PCB if not + * already there (ie get them from the CPU that has them) + * and write them in the context. + */ + } /* Copy the frame out to userland. */ - if (copyout((caddr_t)&sf, (caddr_t)sfp, sizeof(sf)) != 0) { -#ifdef DEBUG - if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) - printf("sendsig(%d): copyout failed on sig %d\n", - p->p_pid, sig); -#endif + if (copyout(&sf, sfp, sizeof(sf)) != 0) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. @@ -908,41 +894,31 @@ sigexit(td, SIGILL); return; } -#ifdef DEBUG - if (sigdebug & SDB_FOLLOW) - printf("sendsig(%d): sig %d sfp %p code %lx\n", p->p_pid, sig, - sfp, code); -#endif - /* Set up the registers to return to sigcode. */ - frame->tf_special.psr &= ~IA64_PSR_RI; - frame->tf_special.iip = PS_STRINGS - (esigcode - sigcode); - frame->tf_special.gp = sig; - PROC_LOCK(p); - if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { - frame->tf_scratch.gr15 = (u_int64_t)&(sfp->sf_si); - - /* Fill in POSIX parts */ - sf.sf_si.si_signo = sig; - sf.sf_si.si_code = code; - sf.sf_si.si_addr = (void*)frame->tf_special.ifa; + if ((tf->tf_flags & FRAME_SYSCALL) == 0) { + tf->tf_special.psr &= ~IA64_PSR_RI; + tf->tf_special.iip = ia64_get_k5() + + ((uint64_t)break_sigtramp - (uint64_t)ia64_gateway_page); } else - frame->tf_scratch.gr15 = code; + tf->tf_special.rp = ia64_get_k5() + + ((uint64_t)epc_sigtramp - (uint64_t)ia64_gateway_page); - frame->tf_special.sp = (u_int64_t)sfp - 16; - frame->tf_scratch.gr14 = sig; - frame->tf_scratch.gr16 = (u_int64_t) &sfp->sf_uc; - frame->tf_scratch.gr17 = (u_int64_t)catcher; - frame->tf_scratch.gr18 = sbs; + /* + * Setup the trapframe to return to the signal trampoline. We pass + * information to the trampoline in the following registers: + * + * gp new backing store or NULL + * r8 signal number + * r9 signal code or siginfo pointer + * r10 signal handler (function descriptor) + */ + tf->tf_special.sp = (u_int64_t)sfp - 16; + tf->tf_special.gp = sbs; + tf->tf_scratch.gr8 = sig; + tf->tf_scratch.gr9 = code; + tf->tf_scratch.gr10 = (u_int64_t)catcher; -#ifdef DEBUG - if (sigdebug & SDB_FOLLOW) - printf("sendsig(%d): pc %lx, catcher %lx\n", p->p_pid, - frame->tf_cr_iip, frame->tf_scratch.gr17); - if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) - printf("sendsig(%d): sig %d returns\n", - p->p_pid, sig); -#endif + PROC_LOCK(p); } /* @@ -963,23 +939,15 @@ } */ *uap) { ucontext_t uc; - struct trapframe *frame; + struct trapframe *tf; struct __mcontext *mc; struct proc *p; struct pcb *pcb; - frame = td->td_frame; + tf = td->td_frame; p = td->td_proc; pcb = td->td_pcb; -#ifdef DEBUG - if (sigdebug & SDB_FOLLOW) - printf("sigreturn: pid %d, scp %p\n", p->p_pid, uap->sigcntxp); -#endif - - /* Throw away the high FP registers. */ - ia64_highfp_drop(td); - /* * Fetch the entire context structure at once for speed. * We don't use a normal argument to simplify RSE handling. @@ -988,37 +956,35 @@ return (EFAULT); /* + * XXX make sure ndirty in the current trapframe is less than + * 0x1f8 so that if we throw away the current register stack, + * we have reached the bottom of the kernel register stack. + * See also exec_setregs. + */ + + /* * Restore the user-supplied information */ mc = &uc.uc_mcontext; - frame->tf_special = mc->mc_special; + tf->tf_special = mc->mc_special; + tf->tf_scratch = mc->mc_scratch; if ((mc->mc_flags & IA64_MC_FLAGS_SCRATCH_VALID) != 0) { - frame->tf_scratch = mc->mc_scratch; - frame->tf_scratch_fp = mc->mc_scratch_fp; + tf->tf_scratch_fp = mc->mc_scratch_fp; + /* XXX high FP. */ } - /* - * XXX preserved registers. - * XXX High FP. - */ - PROC_LOCK(p); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) - if (sigonstack(frame->tf_special.sp)) + if (sigonstack(tf->tf_special.sp)) p->p_sigstk.ss_flags |= SS_ONSTACK; else p->p_sigstk.ss_flags &= ~SS_ONSTACK; #endif - td->td_sigmask = uc.uc_sigmask; SIG_CANTMASK(td->td_sigmask); signotify(td); PROC_UNLOCK(p); -#ifdef DEBUG - if (sigdebug & SDB_FOLLOW) - printf("sigreturn(%d): returns\n", p->p_pid); -#endif return (EJUSTRETURN); } ==== //depot/projects/ia64_epc/sys/ia64/ia64/syscall.s#10 (text+ko) ==== @@ -26,6 +26,7 @@ * $FreeBSD$ */ +#include <sys/syscall.h> #include <machine/asm.h> #include <assym.s> @@ -92,14 +93,80 @@ ;; } +ENTRY(break_sigtramp, 0) +{ .mib + mov ar.rsc=0 + cmp.ne p15,p0=0,gp + cover + ;; +} +{ .mmi + flushrs +(p15) invala + add r16=16+UC_MCONTEXT+MC_SPECIAL,sp + ;; +} +{ .mmi + mov r17=ar.bsp + mov r18=ar.rnat + add r14=40,r16 + ;; +} +{ .mmi + st8 [r14]=r17,64 // bspstore +(p15) mov ar.bspstore=gp + add r15=48,r16 + ;; +} +{ .mmi + st8 [r15]=r18 // rnat + st8 [r14]=r0 // ndirty + nop 0 + ;; +} +{ .mmi + alloc r14=ar.pfs, 0, 0, 3, 0 + mov ar.rsc=15 + mov out0=r8 + ;; +} +{ .mmi + ld8 r16=[r10],8 // function address + ;; + ld8 gp=[r10] // function's gp value + mov b7=r16 + ;; +} +{ .mib + mov out1=r9 + add out2=16,sp + br.call.sptk rp=b7 + ;; +} +{ .mmi + mov r15=SYS_sigreturn + add out0=16,sp + break 0x100000 + ;; +} +{ .mmi + mov r15=SYS_exit + mov out0=ret0 + break 0x100000 + ;; +} +END(break_sigtramp) + +ENTRY(epc_sigtramp, 0) + break 0x80100 + ;; +END(epc_sigtramp) + .align PAGE_SIZE + .section .text.syscall, "ax" - .section .text.syscall, "ax" - .global epc_syscall - .proc epc_syscall - .regstk 8,0,0,0 -epc_syscall: +ENTRY(epc_syscall, 8) { .mmi mov r16=ar.rsc mov ar.rsc=0 @@ -358,4 +425,4 @@ br.ret.sptk b7 ;; } - .endp epc_syscall +END(epc_syscall)
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200304232056.h3NKu5VU060332>