summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/files.sparc641
-rw-r--r--sys/sparc64/include/asi.h11
-rw-r--r--sys/sparc64/include/globaldata.h1
-rw-r--r--sys/sparc64/include/pcb.h5
-rw-r--r--sys/sparc64/include/pcpu.h1
-rw-r--r--sys/sparc64/include/pstate.h13
-rw-r--r--sys/sparc64/sparc64/exception.S1
-rw-r--r--sys/sparc64/sparc64/exception.s1
-rw-r--r--sys/sparc64/sparc64/genassym.c29
-rw-r--r--sys/sparc64/sparc64/locore.S2
-rw-r--r--sys/sparc64/sparc64/locore.s2
-rw-r--r--sys/sparc64/sparc64/machdep.c16
-rw-r--r--sys/sparc64/sparc64/pmap.c6
-rw-r--r--sys/sparc64/sparc64/swtch.S89
-rw-r--r--sys/sparc64/sparc64/swtch.s89
-rw-r--r--sys/sparc64/sparc64/trap.c38
-rw-r--r--sys/sparc64/sparc64/vm_machdep.c7
17 files changed, 276 insertions, 36 deletions
diff --git a/sys/conf/files.sparc64 b/sys/conf/files.sparc64
index ee8c88f..3938690 100644
--- a/sys/conf/files.sparc64
+++ b/sys/conf/files.sparc64
@@ -20,6 +20,7 @@ sparc64/sparc64/elf_machdep.c standard
# now normal.
# sparc64/sparc64/locore.s standard
sparc64/sparc64/exception.s standard
+sparc64/sparc64/fp.c standard
sparc64/sparc64/machdep.c standard
sparc64/sparc64/pmap.c standard
sparc64/sparc64/procfs_machdep.c standard
diff --git a/sys/sparc64/include/asi.h b/sys/sparc64/include/asi.h
index 34f146d..ee7588d 100644
--- a/sys/sparc64/include/asi.h
+++ b/sys/sparc64/include/asi.h
@@ -90,4 +90,15 @@
#define ASI_DTLB_TAG_READ_REG 0x5e
#define ASI_DMMU_DEMAP 0x5f
+#define ASI_BLK_AUIP 0x70
+#define ASI_BLK_AIUS 0x71
+#define ASI_BLK_AIUPL 0x78
+#define ASI_BLK_AIUSL 0x79
+#define ASI_BLK_COMMIT_S 0xe0
+#define ASI_BLK_COMMIT_P 0xe1
+#define ASI_BLK_P 0xf0
+#define ASI_BLK_S 0xf1
+#define ASI_BLK_PL 0xf8
+#define ASI_BLK_SL 0xf9
+
#endif /* !_MACHINE_ASI_H_ */
diff --git a/sys/sparc64/include/globaldata.h b/sys/sparc64/include/globaldata.h
index 7af3375..20fe891 100644
--- a/sys/sparc64/include/globaldata.h
+++ b/sys/sparc64/include/globaldata.h
@@ -37,7 +37,6 @@ struct globaldata {
SLIST_ENTRY(globaldata) gd_allcpu;
struct pcb *gd_curpcb;
struct proc *gd_curproc;
- struct proc *gd_fpcurproc;
struct proc *gd_idleproc;
u_int gd_cpuid;
u_int gd_other_cpus;
diff --git a/sys/sparc64/include/pcb.h b/sys/sparc64/include/pcb.h
index d5ad7eb..d5dd720 100644
--- a/sys/sparc64/include/pcb.h
+++ b/sys/sparc64/include/pcb.h
@@ -29,7 +29,12 @@
#ifndef _MACHINE_PCB_H_
#define _MACHINE_PCB_H_
+#include <machine/fp.h>
+#include <machine/pstate.h>
+
+/* NOTE: pcb_fpstate must be aligned on a 64 byte boundary. */
struct pcb {
+ struct fpstate pcb_fpstate;
u_long pcb_fp;
u_long pcb_pc;
caddr_t pcb_onfault;
diff --git a/sys/sparc64/include/pcpu.h b/sys/sparc64/include/pcpu.h
index 7af3375..20fe891 100644
--- a/sys/sparc64/include/pcpu.h
+++ b/sys/sparc64/include/pcpu.h
@@ -37,7 +37,6 @@ struct globaldata {
SLIST_ENTRY(globaldata) gd_allcpu;
struct pcb *gd_curpcb;
struct proc *gd_curproc;
- struct proc *gd_fpcurproc;
struct proc *gd_idleproc;
u_int gd_cpuid;
u_int gd_other_cpus;
diff --git a/sys/sparc64/include/pstate.h b/sys/sparc64/include/pstate.h
index 8ff55f3..07301eb 100644
--- a/sys/sparc64/include/pstate.h
+++ b/sys/sparc64/include/pstate.h
@@ -47,6 +47,19 @@
#define PSTATE_MG (1<<10)
#define PSTATE_IG (1<<11)
+#define TSTATE_PSTATE_SHIFT 8
+#define TSTATE_PSTATE(x) ((x) << TSTATE_PSTATE_SHIFT)
+#define TSTATE_AG TSTATE_PSTATE(PSTATE_AG)
+#define TSTATE_IE TSTATE_PSTATE(PSTATE_IE)
+#define TSTATE_PRIV TSTATE_PSTATE(PSTATE_PRIV)
+#define TSTATE_AM TSTATE_PSTATE(PSTATE_AM)
+#define TSTATE_PEF TSTATE_PSTATE(PSTATE_PEF)
+#define TSTATE_RED TSTATE_PSTATE(PSTATE_RED)
+#define TSTATE_TLE TSTATE_PSTATE(PSTATE_TLE)
+#define TSTATE_CLE TSTATE_PSTATE(PSTATE_CLE)
+#define TSTATE_MG TSTATE_PSTATE(PSTATE_MG)
+#define TSTATE_IG TSTATE_PSTATE(PSTATE_IG)
+
#define VER_MANUF_SHIFT (48)
#define VER_IMPL_SHIFT (32)
#define VER_MASK_SHIFT (24)
diff --git a/sys/sparc64/sparc64/exception.S b/sys/sparc64/sparc64/exception.S
index 9abc581..3eee42c 100644
--- a/sys/sparc64/sparc64/exception.S
+++ b/sys/sparc64/sparc64/exception.S
@@ -536,6 +536,7 @@ tl1_breakpoint:
tl1_reserved 128 ! 0x380-0x3ff reserved
ENTRY(tl0_trap)
+ /* In every trap from tl0, we need to set PSTATE.PEF. */
illtrap
END(tl0_trap)
diff --git a/sys/sparc64/sparc64/exception.s b/sys/sparc64/sparc64/exception.s
index 9abc581..3eee42c 100644
--- a/sys/sparc64/sparc64/exception.s
+++ b/sys/sparc64/sparc64/exception.s
@@ -536,6 +536,7 @@ tl1_breakpoint:
tl1_reserved 128 ! 0x380-0x3ff reserved
ENTRY(tl0_trap)
+ /* In every trap from tl0, we need to set PSTATE.PEF. */
illtrap
END(tl0_trap)
diff --git a/sys/sparc64/sparc64/genassym.c b/sys/sparc64/sparc64/genassym.c
index ba956f8..cc7eeb4 100644
--- a/sys/sparc64/sparc64/genassym.c
+++ b/sys/sparc64/sparc64/genassym.c
@@ -40,6 +40,7 @@
#include <machine/asi.h>
#include <machine/vmparam.h>
#include <machine/cpufunc.h>
+#include <machine/fp.h>
#include <machine/frame.h>
#include <machine/globals.h>
#include <machine/pcb.h>
@@ -50,6 +51,13 @@
#include <machine/tlb.h>
#include <machine/tsb.h>
+/*
+ * XXX: gas, as of version 2.11.2, does not know this ASI (and some other
+ * UltraSparc specific ones). This definition will probably get us into trouble
+ * as soon as they are added.
+ */
+ASSYM(ASI_BLK_S, ASI_BLK_S);
+
ASSYM(EFAULT, EFAULT);
ASSYM(ENAMETOOLONG, ENAMETOOLONG);
@@ -63,6 +71,17 @@ ASSYM(PSTATE_PEF, PSTATE_PEF);
ASSYM(PSTATE_MG, PSTATE_MG);
ASSYM(PSTATE_IG, PSTATE_IG);
+ASSYM(TSTATE_AG, TSTATE_AG);
+ASSYM(TSTATE_IE, TSTATE_IE);
+ASSYM(TSTATE_PRIV, TSTATE_PRIV);
+ASSYM(TSTATE_PEF, TSTATE_PEF);
+ASSYM(TSTATE_MG, TSTATE_MG);
+ASSYM(TSTATE_IG, TSTATE_IG);
+
+ASSYM(FPRS_DL, FPRS_DL);
+ASSYM(FPRS_DU, FPRS_DU);
+ASSYM(FPRS_FEF, FPRS_FEF);
+
ASSYM(TTE_SHIFT, TTE_SHIFT);
ASSYM(STTE_SHIFT, STTE_SHIFT);
ASSYM(TSB_PRIMARY_BUCKET_SHIFT, TSB_PRIMARY_BUCKET_SHIFT);
@@ -97,7 +116,6 @@ ASSYM(TT_CTX_SHIFT, TT_CTX_SHIFT);
ASSYM(GD_CURPROC, offsetof(struct globaldata, gd_curproc));
ASSYM(GD_CURPCB, offsetof(struct globaldata, gd_curpcb));
-ASSYM(GD_FPCURPROC, offsetof(struct globaldata, gd_fpcurproc));
ASSYM(JB_FP, offsetof(struct _jmp_buf, _jb[_JB_FP]));
ASSYM(JB_PC, offsetof(struct _jmp_buf, _jb[_JB_PC]));
@@ -105,11 +123,20 @@ ASSYM(JB_SP, offsetof(struct _jmp_buf, _jb[_JB_SP]));
ASSYM(P_ADDR, offsetof(struct proc, p_addr));
ASSYM(P_VMSPACE, offsetof(struct proc, p_vmspace));
+ASSYM(P_FRAME, offsetof(struct proc, p_frame));
+ASSYM(PCB_FPSTATE, offsetof(struct pcb, pcb_fpstate));
ASSYM(PCB_FP, offsetof(struct pcb, pcb_fp));
ASSYM(PCB_PC, offsetof(struct pcb, pcb_pc));
ASSYM(PCB_ONFAULT, offsetof(struct pcb, pcb_onfault));
+ASSYM(FP_FB0, offsetof(struct fpstate, fp_fb[0]));
+ASSYM(FP_FB1, offsetof(struct fpstate, fp_fb[1]));
+ASSYM(FP_FB2, offsetof(struct fpstate, fp_fb[2]));
+ASSYM(FP_FB3, offsetof(struct fpstate, fp_fb[3]));
+ASSYM(FP_FSR, offsetof(struct fpstate, fp_fsr));
+ASSYM(FP_FPRS, offsetof(struct fpstate, fp_fprs));
+
ASSYM(F_L0, offsetof(struct frame, f_local[0]));
ASSYM(F_L1, offsetof(struct frame, f_local[1]));
ASSYM(F_L2, offsetof(struct frame, f_local[2]));
diff --git a/sys/sparc64/sparc64/locore.S b/sys/sparc64/sparc64/locore.S
index cdde7b9..2d809e5 100644
--- a/sys/sparc64/sparc64/locore.S
+++ b/sys/sparc64/sparc64/locore.S
@@ -34,7 +34,7 @@
* void _start(struct bootinfo *bi, u_long ofw_vec)
*/
ENTRY(_start)
- wrpr %g0, PSTATE_IE|PSTATE_PRIV, %pstate
+ wrpr %g0, PSTATE_IE | PSTATE_PRIV | PSTATE_PEF, %pstate
mov %o0, %g1
mov %o1, %g2
flushw
diff --git a/sys/sparc64/sparc64/locore.s b/sys/sparc64/sparc64/locore.s
index cdde7b9..2d809e5 100644
--- a/sys/sparc64/sparc64/locore.s
+++ b/sys/sparc64/sparc64/locore.s
@@ -34,7 +34,7 @@
* void _start(struct bootinfo *bi, u_long ofw_vec)
*/
ENTRY(_start)
- wrpr %g0, PSTATE_IE|PSTATE_PRIV, %pstate
+ wrpr %g0, PSTATE_IE | PSTATE_PRIV | PSTATE_PEF, %pstate
mov %o0, %g1
mov %o1, %g2
flushw
diff --git a/sys/sparc64/sparc64/machdep.c b/sys/sparc64/sparc64/machdep.c
index d831b40..faacd0d 100644
--- a/sys/sparc64/sparc64/machdep.c
+++ b/sys/sparc64/sparc64/machdep.c
@@ -80,7 +80,12 @@ struct mtx Giant;
struct mtx sched_lock;
struct globaldata __globaldata;
-char user0[UPAGES * PAGE_SIZE];
+/*
+ * This needs not be aligned as the other user areas, provided that process 0
+ * does not have an fp state (which it doesn't normally).
+ * This constraint is only here for debugging.
+ */
+char user0[UPAGES * PAGE_SIZE] __attribute__ ((aligned (64)));
struct user *proc0paddr;
vm_offset_t clean_sva;
@@ -303,6 +308,7 @@ sparc64_init(struct bootinfo *bi, ofw_vec_t *vec)
proc0.p_addr = (struct user *)user0;
tf = (struct trapframe *)(user0 + UPAGES * PAGE_SIZE - sizeof(*tf));
proc0.p_frame = tf;
+ tf->tf_tstate = 0;
/*
* Initialize the per-cpu pointer so we can set curproc.
@@ -389,6 +395,14 @@ ptrace_single_step(struct proc *p)
void
setregs(struct proc *p, u_long entry, u_long stack, u_long ps_strings)
{
+ struct pcb *pcb;
+
+ pcb = &p->p_addr->u_pcb;
+ mtx_lock_spin(&sched_lock);
+ fp_init_pcb(pcb);
+ /* XXX */
+ p->p_frame->tf_tstate &= ~TSTATE_PEF;
+ mtx_unlock_spin(&sched_lock);
TODO;
}
diff --git a/sys/sparc64/sparc64/pmap.c b/sys/sparc64/sparc64/pmap.c
index b46b0be..d34114a 100644
--- a/sys/sparc64/sparc64/pmap.c
+++ b/sys/sparc64/sparc64/pmap.c
@@ -257,6 +257,12 @@ pmap_bootstrap(vm_offset_t skpa, vm_offset_t ekva)
virtual_avail += PAGE_SIZE;
CADDR2 = virtual_avail;
virtual_avail += PAGE_SIZE;
+
+ /*
+ * Set the secondary context to be the kernel context (needed for
+ * fp block operations in the kernel).
+ */
+ stxa(AA_DMMU_SCXR, ASI_DMMU, TLB_CTX_KERNEL);
}
/*
diff --git a/sys/sparc64/sparc64/swtch.S b/sys/sparc64/sparc64/swtch.S
index e437522..f9445c4 100644
--- a/sys/sparc64/sparc64/swtch.S
+++ b/sys/sparc64/sparc64/swtch.S
@@ -30,17 +30,57 @@
#include "assym.s"
+/*
+ * Save and restore FPU state. This is done at switch time.
+ * We could use FPRS_DL and FPRS_DU; however, it is accessible to non-privileged
+ * software, so it is avoided for compatabilities sake.
+ * savefp clobbers %fprs.
+ */
+ .macro savefp state, tmp
+ rd %fprs, \tmp
+ stx \tmp, [\state + FP_FPRS]
+ or \tmp, FPRS_FEF, \tmp
+ wr \tmp, 0, %fprs
+ stx %fsr, [\state + FP_FSR]
+ rd %asi, \tmp
+ wr %g0, ASI_BLK_S, %asi
+ stda %f0, [\state + FP_FB0] %asi
+ stda %f16, [\state + FP_FB1] %asi
+ stda %f32, [\state + FP_FB2] %asi
+ stda %f48, [\state + FP_FB3] %asi
+ wr \tmp, 0, %asi
+ membar #Sync
+ .endm
+
+ .macro restrfp state, tmp
+ rd %fprs, \tmp
+ or \tmp, FPRS_FEF, \tmp
+ wr \tmp, 0, %fprs
+ rd %asi, \tmp
+ wr %g0, ASI_BLK_S, %asi
+ ldda [\state + FP_FB0] %asi, %f0
+ ldda [\state + FP_FB1] %asi, %f16
+ ldda [\state + FP_FB2] %asi, %f32
+ ldda [\state + FP_FB3] %asi, %f48
+ wr \tmp, 0, %asi
+ membar #Sync
+ ldx [\state + FP_FSR], %fsr
+ ldx [\state + FP_FPRS], \tmp
+ wr \tmp, 0, %fprs
+ .endm
+
ENTRY(cpu_switch)
save %sp, -CCFSZ, %sp
call chooseproc
ldx [PCPU(CURPROC)], %l0
cmp %l0, %o0
- be,pn %xcc, 2f
- ldx [PCPU(FPCURPROC)], %l2
- cmp %l0, %l2
- bne,pt %xcc, 1f
+ be,pn %xcc, 3f
+ ldx [%l0 + P_FRAME], %l2
+ ldx [%l2 + TF_TSTATE], %l2
+ andcc %l2, TSTATE_PEF, %l2
+ be,pt %xcc, 1f
ldx [PCPU(CURPCB)], %l1
- PANIC("cpu_switch: fpcurproc", %i0)
+ savefp %l1 + PCB_FPSTATE, %l3
1: flushw
wrpr %g0, 0, %cleanwin
stx %fp, [%l1 + PCB_FP]
@@ -48,22 +88,43 @@ ENTRY(cpu_switch)
ldx [%o0 + P_ADDR], %o1
ldx [%o1 + U_PCB + PCB_FP], %fp
ldx [%o1 + U_PCB + PCB_PC], %i7
- stx %o0, [PCPU(CURPROC)]
- stx %o1, [PCPU(CURPCB)]
+ ldx [%o0 + P_FRAME], %l2
+ ldx [%l2 + TF_TSTATE], %l2
+ andcc %l2, TSTATE_PEF, %l2
+ be,pt %xcc, 2f
+ stx %o0, [PCPU(CURPROC)]
+ restrfp %o1 + U_PCB + PCB_FPSTATE, %l4
+2: stx %o1, [PCPU(CURPCB)]
sub %fp, CCFSZ, %sp
-2: ret
+3: ret
restore
END(cpu_switch)
ENTRY(savectx)
save %sp, -CCFSZ, %sp
flushw
- ldx [PCPU(FPCURPROC)], %l0
- brz,pt %l0, 1f
- nop
- illtrap
-1: stx %fp, [%i0 + PCB_FP]
- stx %i7, [%i0 + PCB_PC]
+ ldx [PCPU(CURPROC)], %l0
+ ldx [%l0 + P_FRAME], %l0
+ ldx [%l0 + TF_TSTATE], %l0
+ andcc %l0, TSTATE_PEF, %l0
+ be,pt %xcc, 1f
+ stx %fp, [%i0 + PCB_FP]
+ add %i0, PCB_FPSTATE, %o0
+ call savefpctx
+1: stx %i7, [%i0 + PCB_PC]
ret
restore %g0, 0, %o0
END(savectx)
+
+ENTRY(savefpctx)
+ rd %fprs, %o2
+ savefp %o0, %o1
+ retl
+ wr %o2, 0, %fprs
+END(savefpctx)
+
+ENTRY(restorefpctx)
+ restrfp %o0, %o1
+ retl
+ nop
+END(restorefpctx)
diff --git a/sys/sparc64/sparc64/swtch.s b/sys/sparc64/sparc64/swtch.s
index e437522..f9445c4 100644
--- a/sys/sparc64/sparc64/swtch.s
+++ b/sys/sparc64/sparc64/swtch.s
@@ -30,17 +30,57 @@
#include "assym.s"
+/*
+ * Save and restore FPU state. This is done at switch time.
+ * We could use FPRS_DL and FPRS_DU; however, it is accessible to non-privileged
+ * software, so it is avoided for compatabilities sake.
+ * savefp clobbers %fprs.
+ */
+ .macro savefp state, tmp
+ rd %fprs, \tmp
+ stx \tmp, [\state + FP_FPRS]
+ or \tmp, FPRS_FEF, \tmp
+ wr \tmp, 0, %fprs
+ stx %fsr, [\state + FP_FSR]
+ rd %asi, \tmp
+ wr %g0, ASI_BLK_S, %asi
+ stda %f0, [\state + FP_FB0] %asi
+ stda %f16, [\state + FP_FB1] %asi
+ stda %f32, [\state + FP_FB2] %asi
+ stda %f48, [\state + FP_FB3] %asi
+ wr \tmp, 0, %asi
+ membar #Sync
+ .endm
+
+ .macro restrfp state, tmp
+ rd %fprs, \tmp
+ or \tmp, FPRS_FEF, \tmp
+ wr \tmp, 0, %fprs
+ rd %asi, \tmp
+ wr %g0, ASI_BLK_S, %asi
+ ldda [\state + FP_FB0] %asi, %f0
+ ldda [\state + FP_FB1] %asi, %f16
+ ldda [\state + FP_FB2] %asi, %f32
+ ldda [\state + FP_FB3] %asi, %f48
+ wr \tmp, 0, %asi
+ membar #Sync
+ ldx [\state + FP_FSR], %fsr
+ ldx [\state + FP_FPRS], \tmp
+ wr \tmp, 0, %fprs
+ .endm
+
ENTRY(cpu_switch)
save %sp, -CCFSZ, %sp
call chooseproc
ldx [PCPU(CURPROC)], %l0
cmp %l0, %o0
- be,pn %xcc, 2f
- ldx [PCPU(FPCURPROC)], %l2
- cmp %l0, %l2
- bne,pt %xcc, 1f
+ be,pn %xcc, 3f
+ ldx [%l0 + P_FRAME], %l2
+ ldx [%l2 + TF_TSTATE], %l2
+ andcc %l2, TSTATE_PEF, %l2
+ be,pt %xcc, 1f
ldx [PCPU(CURPCB)], %l1
- PANIC("cpu_switch: fpcurproc", %i0)
+ savefp %l1 + PCB_FPSTATE, %l3
1: flushw
wrpr %g0, 0, %cleanwin
stx %fp, [%l1 + PCB_FP]
@@ -48,22 +88,43 @@ ENTRY(cpu_switch)
ldx [%o0 + P_ADDR], %o1
ldx [%o1 + U_PCB + PCB_FP], %fp
ldx [%o1 + U_PCB + PCB_PC], %i7
- stx %o0, [PCPU(CURPROC)]
- stx %o1, [PCPU(CURPCB)]
+ ldx [%o0 + P_FRAME], %l2
+ ldx [%l2 + TF_TSTATE], %l2
+ andcc %l2, TSTATE_PEF, %l2
+ be,pt %xcc, 2f
+ stx %o0, [PCPU(CURPROC)]
+ restrfp %o1 + U_PCB + PCB_FPSTATE, %l4
+2: stx %o1, [PCPU(CURPCB)]
sub %fp, CCFSZ, %sp
-2: ret
+3: ret
restore
END(cpu_switch)
ENTRY(savectx)
save %sp, -CCFSZ, %sp
flushw
- ldx [PCPU(FPCURPROC)], %l0
- brz,pt %l0, 1f
- nop
- illtrap
-1: stx %fp, [%i0 + PCB_FP]
- stx %i7, [%i0 + PCB_PC]
+ ldx [PCPU(CURPROC)], %l0
+ ldx [%l0 + P_FRAME], %l0
+ ldx [%l0 + TF_TSTATE], %l0
+ andcc %l0, TSTATE_PEF, %l0
+ be,pt %xcc, 1f
+ stx %fp, [%i0 + PCB_FP]
+ add %i0, PCB_FPSTATE, %o0
+ call savefpctx
+1: stx %i7, [%i0 + PCB_PC]
ret
restore %g0, 0, %o0
END(savectx)
+
+ENTRY(savefpctx)
+ rd %fprs, %o2
+ savefp %o0, %o1
+ retl
+ wr %o2, 0, %fprs
+END(savefpctx)
+
+ENTRY(restorefpctx)
+ restrfp %o0, %o1
+ retl
+ nop
+END(restorefpctx)
diff --git a/sys/sparc64/sparc64/trap.c b/sys/sparc64/sparc64/trap.c
index 7aec69b..40548d9 100644
--- a/sys/sparc64/sparc64/trap.c
+++ b/sys/sparc64/sparc64/trap.c
@@ -29,9 +29,12 @@
#include "opt_ddb.h"
#include <sys/param.h>
+#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/systm.h>
#include <sys/proc.h>
+#include <sys/sysent.h>
+#include <sys/user.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
@@ -39,6 +42,7 @@
#include <vm/vm_page.h>
#include <machine/frame.h>
+#include <machine/pcb.h>
#include <machine/pv.h>
#include <machine/trap.h>
#include <machine/tte.h>
@@ -84,8 +88,27 @@ const char *trap_msg[] = {
void
trap(struct trapframe *tf)
{
+ u_quad_t sticks;
+ struct proc *p;
+ int ucode;
+ int sig;
+
+ p = curproc;
+ ucode = tf->tf_type; /* XXX */
+
+ mtx_lock_spin(&sched_lock);
+ sticks = p->p_sticks;
+ mtx_unlock_spin(&sched_lock);
switch (tf->tf_type) {
+ case T_FP_DISABLED:
+ if (fp_enable_proc(p))
+ goto user;
+ else {
+ sig = SIGFPE;
+ goto trapsig;
+ }
+ break;
#ifdef DDB
case T_BREAKPOINT | T_KERNEL:
if (kdb_trap(tf) != 0)
@@ -96,4 +119,19 @@ trap(struct trapframe *tf)
break;
}
panic("trap: %s", trap_msg[tf->tf_type & ~T_KERNEL]);
+
+trapsig:
+ mtx_lock(&Giant);
+ /* Translate fault for emulators. */
+ if (p->p_sysent->sv_transtrap != NULL)
+ sig = (p->p_sysent->sv_transtrap)(sig, tf->tf_type);
+
+ trapsignal(p, sig, ucode);
+ mtx_unlock(&Giant);
+user:
+ userret(p, tf, sticks);
+ if (mtx_owned(&Giant))
+ mtx_unlock(&Giant);
+out:
+ return;
}
diff --git a/sys/sparc64/sparc64/vm_machdep.c b/sys/sparc64/sparc64/vm_machdep.c
index b14c9a4..ed9b6b1 100644
--- a/sys/sparc64/sparc64/vm_machdep.c
+++ b/sys/sparc64/sparc64/vm_machdep.c
@@ -58,10 +58,13 @@ cpu_fork(struct proc *p1, struct proc *p2, int flags)
if ((flags & RFPROC) == 0)
return;
- if (PCPU_GET(fpcurproc) == p1)
- panic("cpu_fork: save fp state\n");
pcb = &p2->p_addr->u_pcb;
+ if ((p1->p_frame->tf_tstate & TSTATE_PEF) != 0) {
+ mtx_lock_spin(&sched_lock);
+ savefpctx(&p1->p_addr->u_pcb.pcb_fpstate);
+ mtx_unlock_spin(&sched_lock);
+ }
bcopy(&p1->p_addr->u_pcb, pcb, sizeof(*pcb));
tf = (struct trapframe *)((caddr_t)pcb + UPAGES * PAGE_SIZE) - 1;
OpenPOWER on IntegriCloud