shithub: riscv

Download patch

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;
 		}
 	}