ref: de463408482b3d1e5c361866ac7500c07c5f4e96
parent: 686f9fa1db8c6f12d86f186cd141485eadaae15e
author: jpathy <[email protected]>
date: Mon Jun 10 14:07:16 EDT 2013
ARM: kernel changes make teg2 procfork() call fpuprocfork() and acid fixes for vfp instruction
--- a/sys/src/9/bcm/mkfile
+++ b/sys/src/9/bcm/mkfile
@@ -1,6 +1,7 @@
CONF=pif
CONFLIST=pif picpuf
-EXTRACOPIES=piestand lookout boundary # bovril
+EXTRACOPIES=
+#EXTRACOPIES=''piestand lookout boundary # bovril
loadaddr=0x80008000
--- a/sys/src/9/bcm/picpuf
+++ b/sys/src/9/bcm/picpuf
@@ -33,6 +33,7 @@
icmp
icmp6
ipmux
+ il
misc
uartmini
--- a/sys/src/9/bcm/pif
+++ b/sys/src/9/bcm/pif
@@ -33,6 +33,7 @@
icmp
icmp6
ipmux
+ il
misc
uartmini
--- a/sys/src/9/teg2/arch.c
+++ b/sys/src/9/teg2/arch.c
@@ -147,6 +147,8 @@
{
p->kentry = up->kentry;
p->pcycles = -p->kentry;
+
+ fpuprocfork(p);
}
void
--- a/sys/src/9/teg2/fns.h
+++ b/sys/src/9/teg2/fns.h
@@ -172,6 +172,7 @@
extern void fpuprocrestore(Proc*);
extern void fpuprocsave(Proc*);
extern void fpusysprocsetup(Proc*);
+extern void fpuprocfork(Proc*);
extern int fpuemu(Ureg*);
/*
--- a/sys/src/9/teg2/softfpu.c
+++ b/sys/src/9/teg2/softfpu.c
@@ -42,25 +42,34 @@
}
void
-fpuprocsave(Proc*)
+fpuprocrestore(Proc*)
{
/*
- * Called from sched() and sleep() via the machine-dependent
- * procsave() routine.
- * About to go in to the scheduler.
- * If the process wasn't using the FPU
- * there's nothing to do.
+ * The process has been rescheduled and is about to run.
+ * Nothing to do here right now. If the process tries to use
+ * the FPU again it will cause a Device Not Available
+ * exception and the state will then be restored.
*/
}
void
-fpuprocrestore(Proc*)
+fpuprocfork(Proc*)
{
/*
- * The process has been rescheduled and is about to run.
- * Nothing to do here right now. If the process tries to use
- * the FPU again it will cause a Device Not Available
- * exception and the state will then be restored.
+ * The current process has been forked, save and copy neccesary
+ * state to child. Nothing to do here, child proc starts with FPinit.
+ */
+}
+
+void
+fpuprocsave(Proc*)
+{
+ /*
+ * Called from sched() and sleep() via the machine-dependent
+ * procsave() routine.
+ * About to go in to the scheduler.
+ * If the process wasn't using the FPU
+ * there's nothing to do.
*/
}
--- a/sys/src/9/teg2/vfp3.c
+++ b/sys/src/9/teg2/vfp3.c
@@ -1,489 +1,1 @@
-/*
- * VFPv2 or VFPv3 floating point unit
- */
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "ureg.h"
-#include "arm.h"
-
-/* subarchitecture code in m->havefp */
-enum {
- VFPv2 = 2,
- VFPv3 = 3,
-};
-
-/* fp control regs. most are read-only */
-enum {
- Fpsid = 0,
- Fpscr = 1, /* rw */
- Mvfr1 = 6,
- Mvfr0 = 7,
- Fpexc = 8, /* rw */
- Fpinst= 9, /* optional, for exceptions */
- Fpinst2=10,
-};
-enum {
- /* Fpexc bits */
- Fpex = 1u << 31,
- Fpenabled = 1 << 30,
- Fpdex = 1 << 29, /* defined synch exception */
-// Fp2v = 1 << 28, /* Fpinst2 reg is valid */
-// Fpvv = 1 << 27, /* if Fpdex, vecitr is valid */
-// Fptfv = 1 << 26, /* trapped fault is valid */
-// Fpvecitr = MASK(3) << 8,
- /* FSR bits appear here */
- Fpmbc = Fpdex, /* bits exception handler must clear */
-
- /* Fpscr bits; see u.h for more */
- Stride = MASK(2) << 20,
- Len = MASK(3) << 16,
- Dn= 1 << 25,
- Fz= 1 << 24,
- /* trap exception enables (not allowed in vfp3) */
- FPIDNRM = 1 << 15, /* input denormal */
- Alltraps = FPIDNRM | FPINEX | FPUNFL | FPOVFL | FPZDIV | FPINVAL,
- /* pending exceptions */
- FPAIDNRM = 1 << 7, /* input denormal */
- Allexc = FPAIDNRM | FPAINEX | FPAUNFL | FPAOVFL | FPAZDIV | FPAINVAL,
- /* condition codes */
- Allcc = MASK(4) << 28,
-};
-enum {
- /* CpCPaccess bits */
- Cpaccnosimd = 1u << 31,
- Cpaccd16 = 1 << 30,
-};
-
-static char *
-subarch(int impl, uint sa)
-{
- static char *armarchs[] = {
- "VFPv1 (unsupported)",
- "VFPv2",
- "VFPv3+ with common VFP subarch v2",
- "VFPv3+ with null subarch",
- "VFPv3+ with common VFP subarch v3",
- };
-
- if (impl != 'A' || sa >= nelem(armarchs))
- return "GOK";
- else
- return armarchs[sa];
-}
-
-static char *
-implement(uchar impl)
-{
- if (impl == 'A')
- return "arm";
- else
- return "unknown";
-}
-
-static int
-havefp(void)
-{
- int gotfp;
- ulong acc, sid;
-
- if (m->havefpvalid)
- return m->havefp;
-
- m->havefp = 0;
- gotfp = 1 << CpFP | 1 << CpDFP;
- cpwrsc(0, CpCONTROL, 0, CpCPaccess, MASK(28));
- acc = cprdsc(0, CpCONTROL, 0, CpCPaccess);
- if ((acc & (MASK(2) << (2*CpFP))) == 0) {
- gotfp &= ~(1 << CpFP);
- print("fpon: no single FP coprocessor\n");
- }
- if ((acc & (MASK(2) << (2*CpDFP))) == 0) {
- gotfp &= ~(1 << CpDFP);
- print("fpon: no double FP coprocessor\n");
- }
- if (!gotfp) {
- print("fpon: no FP coprocessors\n");
- m->havefpvalid = 1;
- return 0;
- }
- m->fpon = 1; /* don't panic */
- sid = fprd(Fpsid);
- m->fpon = 0;
- switch((sid >> 16) & MASK(7)){
- case 0: /* VFPv1 */
- break;
- case 1: /* VFPv2 */
- m->havefp = VFPv2;
- m->fpnregs = 16;
- break;
- default: /* VFPv3 or later */
- m->havefp = VFPv3;
- m->fpnregs = (acc & Cpaccd16) ? 16 : 32;
- break;
- }
- if (m->machno == 0)
- print("fp: %d registers,%s simd\n", m->fpnregs,
- (acc & Cpaccnosimd? " no": ""));
- m->havefpvalid = 1;
- return 1;
-}
-
-/*
- * these can be called to turn the fpu on or off for user procs,
- * not just at system start up or shutdown.
- */
-
-void
-fpoff(void)
-{
- if (m->fpon) {
- fpwr(Fpexc, 0);
- m->fpon = 0;
- }
-}
-
-void
-fpononly(void)
-{
- if (!m->fpon && havefp()) {
- /* enable fp. must be first operation on the FPUs. */
- fpwr(Fpexc, Fpenabled);
- m->fpon = 1;
- }
-}
-
-static void
-fpcfg(void)
-{
- int impl;
- ulong sid;
- static int printed;
-
- /* clear pending exceptions; no traps in vfp3; all v7 ops are scalar */
- m->fpscr = Dn | Fz | FPRNR | (FPINVAL | FPZDIV | FPOVFL) & ~Alltraps;
- fpwr(Fpscr, m->fpscr);
- m->fpconfiged = 1;
-
- if (printed)
- return;
- sid = fprd(Fpsid);
- impl = sid >> 24;
- print("fp: %s arch %s; rev %ld\n", implement(impl),
- subarch(impl, (sid >> 16) & MASK(7)), sid & MASK(4));
- printed = 1;
-}
-
-void
-fpinit(void)
-{
- if (havefp()) {
- fpononly();
- fpcfg();
- }
-}
-
-void
-fpon(void)
-{
- if (havefp()) {
- fpononly();
- if (m->fpconfiged)
- fpwr(Fpscr, (fprd(Fpscr) & Allcc) | m->fpscr);
- else
- fpcfg(); /* 1st time on this fpu; configure it */
- }
-}
-
-void
-fpclear(void)
-{
-// ulong scr;
-
- fpon();
-// scr = fprd(Fpscr);
-// m->fpscr = scr & ~Allexc;
-// fpwr(Fpscr, m->fpscr);
-
- fpwr(Fpexc, fprd(Fpexc) & ~Fpmbc);
-}
-
-
-/*
- * Called when a note is about to be delivered to a
- * user process, usually at the end of a system call.
- * Note handlers are not allowed to use the FPU so
- * the state is marked (after saving if necessary) and
- * checked in the Device Not Available handler.
- */
-void
-fpunotify(Ureg*)
-{
- if(up->fpstate == FPactive){
- fpsave(&up->fpsave);
- up->fpstate = FPinactive;
- }
- up->fpstate |= FPillegal;
-}
-
-/*
- * Called from sysnoted() via the machine-dependent
- * noted() routine.
- * Clear the flag set above in fpunotify().
- */
-void
-fpunoted(void)
-{
- up->fpstate &= ~FPillegal;
-}
-
-/* should only be called if p->fpstate == FPactive */
-void
-fpsave(FPsave *fps)
-{
- int n;
-
- fpon();
- fps->control = fps->status = fprd(Fpscr);
- assert(m->fpnregs);
- for (n = 0; n < m->fpnregs; n++)
- fpsavereg(n, (uvlong *)fps->regs[n]);
- fpoff();
-}
-
-static void
-fprestore(Proc *p)
-{
- int n;
-
- fpon();
- fpwr(Fpscr, p->fpsave.control);
- m->fpscr = fprd(Fpscr) & ~Allcc;
- assert(m->fpnregs);
- for (n = 0; n < m->fpnregs; n++)
- fprestreg(n, *(uvlong *)p->fpsave.regs[n]);
-}
-
-/*
- * Called from sched() and sleep() via the machine-dependent
- * procsave() routine.
- * About to go in to the scheduler.
- * If the process wasn't using the FPU
- * there's nothing to do.
- */
-void
-fpuprocsave(Proc *p)
-{
- if(p->fpstate == FPactive){
- if(p->state == Moribund)
- fpclear();
- else{
- /*
- * Fpsave() stores without handling pending
- * unmasked exeptions. Postnote() can't be called
- * here as sleep() already has up->rlock, so
- * the handling of pending exceptions is delayed
- * until the process runs again and generates an
- * emulation fault to activate the FPU.
- */
- fpsave(&p->fpsave);
- }
- p->fpstate = FPinactive;
- }
-}
-
-/*
- * The process has been rescheduled and is about to run.
- * Nothing to do here right now. If the process tries to use
- * the FPU again it will cause a Device Not Available
- * exception and the state will then be restored.
- */
-void
-fpuprocrestore(Proc *)
-{
-}
-
-/*
- * Disable the FPU.
- * Called from sysexec() via sysprocsetup() to
- * set the FPU for the new process.
- */
-void
-fpusysprocsetup(Proc *p)
-{
- p->fpstate = FPinit;
- fpoff();
-}
-
-static void
-mathnote(void)
-{
- ulong status;
- char *msg, note[ERRMAX];
-
- status = up->fpsave.status;
-
- /*
- * Some attention should probably be paid here to the
- * exception masks and error summary.
- */
- if (status & FPAINEX)
- msg = "inexact";
- else if (status & FPAOVFL)
- msg = "overflow";
- else if (status & FPAUNFL)
- msg = "underflow";
- else if (status & FPAZDIV)
- msg = "divide by zero";
- else if (status & FPAINVAL)
- msg = "bad operation";
- else
- msg = "spurious";
- snprint(note, sizeof note, "sys: fp: %s fppc=%#p status=%#lux",
- msg, up->fpsave.pc, status);
- postnote(up, 1, note, NDebug);
-}
-
-static void
-mathemu(Ureg *)
-{
- switch(up->fpstate){
- case FPemu:
- error("illegal instruction: VFP opcode in emulated mode");
- case FPinit:
- fpinit();
- up->fpstate = FPactive;
- break;
- case FPinactive:
- /*
- * Before restoring the state, check for any pending
- * exceptions. There's no way to restore the state without
- * generating an unmasked exception.
- * More attention should probably be paid here to the
- * exception masks and error summary.
- */
- if(up->fpsave.status & (FPAINEX|FPAUNFL|FPAOVFL|FPAZDIV|FPAINVAL)){
- mathnote();
- break;
- }
- fprestore(up);
- up->fpstate = FPactive;
- break;
- case FPactive:
- error("illegal instruction: bad vfp fpu opcode");
- break;
- }
- fpclear();
-}
-
-void
-fpstuck(uintptr pc)
-{
- if (m->fppc == pc && m->fppid == up->pid) {
- m->fpcnt++;
- if (m->fpcnt > 4)
- panic("fpuemu: cpu%d stuck at pid %ld %s pc %#p "
- "instr %#8.8lux", m->machno, up->pid, up->text,
- pc, *(ulong *)pc);
- } else {
- m->fppid = up->pid;
- m->fppc = pc;
- m->fpcnt = 0;
- }
-}
-
-enum {
- N = 1<<31,
- Z = 1<<30,
- C = 1<<29,
- V = 1<<28,
- REGPC = 15,
-};
-
-static int
-condok(int cc, int c)
-{
- switch(c){
- case 0: /* Z set */
- return cc&Z;
- case 1: /* Z clear */
- return (cc&Z) == 0;
- case 2: /* C set */
- return cc&C;
- case 3: /* C clear */
- return (cc&C) == 0;
- case 4: /* N set */
- return cc&N;
- case 5: /* N clear */
- return (cc&N) == 0;
- case 6: /* V set */
- return cc&V;
- case 7: /* V clear */
- return (cc&V) == 0;
- case 8: /* C set and Z clear */
- return cc&C && (cc&Z) == 0;
- case 9: /* C clear or Z set */
- return (cc&C) == 0 || cc&Z;
- case 10: /* N set and V set, or N clear and V clear */
- return (~cc&(N|V))==0 || (cc&(N|V)) == 0;
- case 11: /* N set and V clear, or N clear and V set */
- return (cc&(N|V))==N || (cc&(N|V))==V;
- case 12: /* Z clear, and either N set and V set or N clear and V clear */
- return (cc&Z) == 0 && ((~cc&(N|V))==0 || (cc&(N|V))==0);
- case 13: /* Z set, or N set and V clear or N clear and V set */
- return (cc&Z) || (cc&(N|V))==N || (cc&(N|V))==V;
- case 14: /* always */
- return 1;
- case 15: /* never (reserved) */
- return 0;
- }
- return 0; /* not reached */
-}
-
-/* only called to deal with user-mode instruction faults */
-int
-fpuemu(Ureg* ureg)
-{
- int s, nfp, cop, op;
- uintptr pc;
-
- if(waserror()){
- postnote(up, 1, up->errstr, NDebug);
- return 1;
- }
-
- if(up->fpstate & FPillegal)
- error("floating point in note handler");
-
- nfp = 0;
- pc = ureg->pc;
- validaddr(pc, 4, 0);
- if(!condok(ureg->psr, *(ulong*)pc >> 28))
- iprint("fpuemu: conditional instr shouldn't have got here\n");
- op = (*(ulong *)pc >> 24) & MASK(4);
- cop = (*(ulong *)pc >> 8) & MASK(4);
- if(m->fpon)
- fpstuck(pc); /* debugging; could move down 1 line */
- if (ISFPAOP(cop, op)) { /* old arm 7500 fpa opcode? */
-// iprint("fpuemu: fpa instr %#8.8lux at %#p\n", *(ulong *)pc, pc);
-// error("illegal instruction: old arm 7500 fpa opcode");
- s = spllo();
- if(waserror()){
- splx(s);
- nexterror();
- }
- nfp = fpiarm(ureg); /* advances pc past emulated instr(s) */
- if (nfp > 1) /* could adjust this threshold */
- m->fppc = m->fpcnt = 0;
- splx(s);
- poperror();
- } else if (ISVFPOP(cop, op)) { /* if vfp, fpu must be off */
- mathemu(ureg); /* enable fpu & retry */
- nfp = 1;
- }
-
- poperror();
- return nfp;
-}
+#include "../bcm/vfp3.c"
--- a/sys/src/libmach/5db.c
+++ b/sys/src/libmach/5db.c
@@ -247,7 +247,7 @@
op = 108;
break;
case 7:
- if(((w >> 19) & 0x1) == 0)
+ if(((w >> 19) & 0x1) == 0){
if(((w >> 17) & 0x1) == 0)
op = 109 + ((w >> 16) & 0x4) +
((w >> 15) & 0x2) +
@@ -254,6 +254,7 @@
((w >> 7) & 0x1);
else if(((w >> 16) & 0x7) == 0x7)
op = 117;
+ }
else
switch((w >> 16) & 0x7){
case 0:
@@ -402,6 +403,16 @@
} else
if(i->op == 11) {
format("MOVW", i, "R%s, SPSR");
+ return;
+ }
+ }
+ if(i->rd == 15) {
+ if(i->op == 120) {
+ format("MOVW", i, "PSR, %x");
+ return;
+ } else
+ if(i->op == 121) {
+ format("MOVW", i, "%x, PSR");
return;
}
}