summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjake <jake@FreeBSD.org>2002-01-01 20:56:28 +0000
committerjake <jake@FreeBSD.org>2002-01-01 20:56:28 +0000
commit0c96d7eeb6498a8651b05efb8c969e26f52bca69 (patch)
tree2bd175b358b2539426d5136d20b58ad7dbaf9209
parent42ab31b72dfc0f062385a870460943d5b21017a1 (diff)
downloadFreeBSD-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.h7
-rw-r--r--sys/sparc64/sparc64/exception.S48
-rw-r--r--sys/sparc64/sparc64/exception.s48
-rw-r--r--sys/sparc64/sparc64/machdep.c10
-rw-r--r--sys/sparc64/sparc64/sys_machdep.c64
-rw-r--r--sys/sparc64/sparc64/vm_machdep.c16
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));
OpenPOWER on IntegriCloud