diff options
author | jake <jake@FreeBSD.org> | 2002-01-01 20:56:28 +0000 |
---|---|---|
committer | jake <jake@FreeBSD.org> | 2002-01-01 20:56:28 +0000 |
commit | 0c96d7eeb6498a8651b05efb8c969e26f52bca69 (patch) | |
tree | 2bd175b358b2539426d5136d20b58ad7dbaf9209 | |
parent | 42ab31b72dfc0f062385a870460943d5b21017a1 (diff) | |
download | FreeBSD-src-0c96d7eeb6498a8651b05efb8c969e26f52bca69.zip FreeBSD-src-0c96d7eeb6498a8651b05efb8c969e26f52bca69.tar.gz |
Implement user trap delivery as specified by the sparc abi. This provides
an efficient way for the kernel to bounce certain mundane traps back to
userland for handling there. A user trap handler returns directly to the
trapping user code, rather than going through the kernel again. Only a
handful of instructions are actually executed in kernel mode.
Implement sysarch(SPARC_UTRAP_INSTALL).
Add code to handle sharing of the user trap table across forks and unsharing
at exec.
This can be used to implement efficient tracking of floating point register
usage in userland, fe by a thread library, and to handle alignment fault
fixups and instruction emulation in userland, for which the code may need
to be different for 32bit and 64bit binaries.
-rw-r--r-- | sys/sparc64/include/proc.h | 7 | ||||
-rw-r--r-- | sys/sparc64/sparc64/exception.S | 48 | ||||
-rw-r--r-- | sys/sparc64/sparc64/exception.s | 48 | ||||
-rw-r--r-- | sys/sparc64/sparc64/machdep.c | 10 | ||||
-rw-r--r-- | sys/sparc64/sparc64/sys_machdep.c | 64 | ||||
-rw-r--r-- | sys/sparc64/sparc64/vm_machdep.c | 16 |
6 files changed, 189 insertions, 4 deletions
diff --git a/sys/sparc64/include/proc.h b/sys/sparc64/include/proc.h index e40f9e8..e261b24 100644 --- a/sys/sparc64/include/proc.h +++ b/sys/sparc64/include/proc.h @@ -39,11 +39,18 @@ #define _MACHINE_PROC_H_ #include <machine/tte.h> +#include <machine/utrap.h> + +struct md_utrap { + utrap_entry_t *ut_precise[UT_MAX]; /* must be first */ + int ut_refcnt; +}; struct mdthread { }; struct mdproc { + struct md_utrap *md_utrap; }; #endif /* !_MACHINE_PROC_H_ */ diff --git a/sys/sparc64/sparc64/exception.S b/sys/sparc64/sparc64/exception.S index cb2d272..bc414df 100644 --- a/sys/sparc64/sparc64/exception.S +++ b/sys/sparc64/sparc64/exception.S @@ -2004,7 +2004,53 @@ ENTRY(tl0_trap) #endif and %l5, WSTATE_NORMAL_MASK, %l5 - sllx %l5, WSTATE_OTHER_SHIFT, %l5 + + cmp %o0, UT_MAX + bge,a,pt %xcc, 2f + nop + + ldx [PCPU(CURTHREAD)], %l6 + ldx [%l6 + TD_PROC], %l6 + ldx [%l6 + P_MD + MD_UTRAP], %l6 + brz,pt %l6, 2f + sllx %o0, PTR_SHIFT, %l7 + ldx [%l6 + %l7], %l6 + brz,pt %l6, 2f + andn %l0, TSTATE_CWP_MASK, %l7 + + ldx [PCB_REG + PCB_NSAVED], %g1 + brnz,a,pn %g1, 1f + mov T_SPILL, %o0 + +#if KTR_COMPILE & KTR_TRAP + CATR(KTR_TRAP, "tl0_trap: user trap npc=%#lx" + , %g1, %g2, %g3, 7, 8, 9) + stx %l6, [%g1 + KTR_PARM1] +9: +#endif + + wrpr %l5, %wstate + wrpr %l6, %tnpc + rdpr %cwp, %l6 + wrpr %l6, %l7, %tstate + + mov %l0, %l5 + mov %l1, %l6 + mov %l2, %l7 + + done + +1: +#if KTR_COMPILE & KTR_TRAP + CATR(KTR_TRAP, "tl0_trap: defer user trap npc=%#lx nsaved=%#lx" + , %g1, %g2, %g3, 7, 8, 9) + stx %l6, [%g1 + KTR_PARM1] + ldx [PCB_REG + PCB_NSAVED], %g2 + stx %g2, [%g1 + KTR_PARM2] +9: +#endif + +2: sllx %l5, WSTATE_OTHER_SHIFT, %l5 wrpr %l5, WSTATE_KERNEL, %wstate rdpr %canrestore, %l6 wrpr %l6, 0, %otherwin diff --git a/sys/sparc64/sparc64/exception.s b/sys/sparc64/sparc64/exception.s index cb2d272..bc414df 100644 --- a/sys/sparc64/sparc64/exception.s +++ b/sys/sparc64/sparc64/exception.s @@ -2004,7 +2004,53 @@ ENTRY(tl0_trap) #endif and %l5, WSTATE_NORMAL_MASK, %l5 - sllx %l5, WSTATE_OTHER_SHIFT, %l5 + + cmp %o0, UT_MAX + bge,a,pt %xcc, 2f + nop + + ldx [PCPU(CURTHREAD)], %l6 + ldx [%l6 + TD_PROC], %l6 + ldx [%l6 + P_MD + MD_UTRAP], %l6 + brz,pt %l6, 2f + sllx %o0, PTR_SHIFT, %l7 + ldx [%l6 + %l7], %l6 + brz,pt %l6, 2f + andn %l0, TSTATE_CWP_MASK, %l7 + + ldx [PCB_REG + PCB_NSAVED], %g1 + brnz,a,pn %g1, 1f + mov T_SPILL, %o0 + +#if KTR_COMPILE & KTR_TRAP + CATR(KTR_TRAP, "tl0_trap: user trap npc=%#lx" + , %g1, %g2, %g3, 7, 8, 9) + stx %l6, [%g1 + KTR_PARM1] +9: +#endif + + wrpr %l5, %wstate + wrpr %l6, %tnpc + rdpr %cwp, %l6 + wrpr %l6, %l7, %tstate + + mov %l0, %l5 + mov %l1, %l6 + mov %l2, %l7 + + done + +1: +#if KTR_COMPILE & KTR_TRAP + CATR(KTR_TRAP, "tl0_trap: defer user trap npc=%#lx nsaved=%#lx" + , %g1, %g2, %g3, 7, 8, 9) + stx %l6, [%g1 + KTR_PARM1] + ldx [PCB_REG + PCB_NSAVED], %g2 + stx %g2, [%g1 + KTR_PARM2] +9: +#endif + +2: sllx %l5, WSTATE_OTHER_SHIFT, %l5 wrpr %l5, WSTATE_KERNEL, %wstate rdpr %canrestore, %l6 wrpr %l6, 0, %otherwin diff --git a/sys/sparc64/sparc64/machdep.c b/sys/sparc64/sparc64/machdep.c index daed400..b346360 100644 --- a/sys/sparc64/sparc64/machdep.c +++ b/sys/sparc64/sparc64/machdep.c @@ -50,6 +50,7 @@ #include <sys/ktr.h> #include <sys/linker.h> #include <sys/lock.h> +#include <sys/malloc.h> #include <sys/msgbuf.h> #include <sys/mutex.h> #include <sys/pcpu.h> @@ -603,9 +604,18 @@ void setregs(struct thread *td, u_long entry, u_long stack, u_long ps_strings) { struct trapframe *tf; + struct md_utrap *ut; struct pcb *pcb; u_long sp; + /* XXX no cpu_exec */ + if ((ut = td->td_proc->p_md.md_utrap) != NULL) { + ut->ut_refcnt--; + if (ut->ut_refcnt == 0) + free(ut, M_SUBPROC); + td->td_proc->p_md.md_utrap = NULL; + } + pcb = td->td_pcb; sp = rounddown(stack, 16); tf = td->td_frame; diff --git a/sys/sparc64/sparc64/sys_machdep.c b/sys/sparc64/sparc64/sys_machdep.c index 41fa94f..9025f59 100644 --- a/sys/sparc64/sparc64/sys_machdep.c +++ b/sys/sparc64/sparc64/sys_machdep.c @@ -27,9 +27,16 @@ */ #include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> #include <sys/proc.h> #include <sys/sysproto.h> +#include <machine/utrap.h> +#include <machine/sysarch.h> + +static int sparc_utrap_install(struct thread *td, char *args); + #ifndef _SYS_SYSPROTO_H_ struct sysarch_args { int op; @@ -40,5 +47,60 @@ struct sysarch_args { int sysarch(struct thread *td, struct sysarch_args *uap) { - return (EINVAL); + int error; + + error = 0; + switch (uap->op) { + case SPARC_UTRAP_INSTALL: + error = sparc_utrap_install(td, uap->parms); + break; + default: + error = EINVAL; + break; + } + return (error); +} + +static int +sparc_utrap_install(struct thread *td, char *args) +{ + struct sparc_utrap_install_args uia; + struct sparc_utrap_args ua; + struct md_utrap *ut; + int error; + int i; + + ut = td->td_proc->p_md.md_utrap; + if ((error = copyin(args, &uia, sizeof(uia))) != 0) + return (error); + if (uia.num < 0 || uia.num > UT_MAX || + (uia.handlers == NULL && uia.num > 0)) + return (EINVAL); + for (i = 0; i < uia.num; i++) { + if ((error = copyin(&uia.handlers[i], &ua, sizeof(ua))) != 0) + return (error); + if (ua.type != UTH_NOCHANGE && + (ua.type < 0 || ua.type >= UT_MAX)) + return (EINVAL); + if (ua.old_deferred != NULL) { + if ((error = suword(ua.old_deferred, 0)) != 0) + return (error); + } + if (ua.old_precise != NULL) { + error = suword(ua.old_precise, + ut != NULL ? (long)ut->ut_precise[ua.type] : 0); + if (error != 0) + return (error); + } + if (ua.type != UTH_NOCHANGE) { + if (ut == NULL) { + ut = malloc(sizeof *ut, M_SUBPROC, + M_WAITOK | M_ZERO); + ut->ut_refcnt = 1; + td->td_proc->p_md.md_utrap = ut; + } + ut->ut_precise[ua.type] = ua.new_precise; + } + } + return (0); } diff --git a/sys/sparc64/sparc64/vm_machdep.c b/sys/sparc64/sparc64/vm_machdep.c index b072cf1..32eecea 100644 --- a/sys/sparc64/sparc64/vm_machdep.c +++ b/sys/sparc64/sparc64/vm_machdep.c @@ -45,6 +45,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/malloc.h> #include <sys/proc.h> #include <sys/bio.h> #include <sys/buf.h> @@ -71,6 +72,14 @@ void cpu_exit(struct thread *td) { + struct md_utrap *ut; + + if ((ut = td->td_proc->p_md.md_utrap) != NULL) { + ut->ut_refcnt--; + if (ut->ut_refcnt == 0) + free(ut, M_SUBPROC); + td->td_proc->p_md.md_utrap = NULL; + } } /* @@ -82,6 +91,7 @@ void cpu_fork(struct thread *td1, struct proc *p2, int flags) { struct thread *td2; + struct md_utrap *ut; struct trapframe *tf; struct frame *fp; struct pcb *pcb; @@ -92,6 +102,10 @@ cpu_fork(struct thread *td1, struct proc *p2, int flags) if ((flags & RFPROC) == 0) return; + if ((ut = td1->td_proc->p_md.md_utrap) != NULL) + ut->ut_refcnt++; + p2->p_md.md_utrap = ut; + td2 = &p2->p_thread; /* The pcb must be aligned on a 64-byte boundary. */ pcb = (struct pcb *)((td2->td_kstack + KSTACK_PAGES * PAGE_SIZE - @@ -107,7 +121,7 @@ cpu_fork(struct thread *td1, struct proc *p2, int flags) mtx_unlock_spin(&sched_lock); } /* Make sure the copied windows are spilled. */ - __asm __volatile("flushw"); + __asm __volatile("flushw" : :); /* Copy the pcb (this will copy the windows saved in the pcb, too). */ bcopy(td1->td_pcb, pcb, sizeof(*pcb)); |