shithub: riscv

Download patch

ref: 04c3a6f66e3b895a087124ed415f01e23e21ee10
parent: bf2195b88c9c1483d97cb4578f81467cad73c39e
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Mar 27 16:57:01 EDT 2016

zynq: introduce SG_FAULT to prevent access to AXI segment while PL is not ready

access to the axi segment hangs the machine when the fpga
is not programmed yet. to prevent access, we introduce a
new SG_FAULT flag, that when set on the Segment.type or
Physseg.attr, causes the fault handler to immidiately
return with an error (as if the segment would not be mapped).

during programming, we temporarily set the SG_FAULT flag
on the axi physseg, flush all processes tlb's that have
the segment mapped and when programming is done, we clear
the flag again.

--- a/sys/src/9/pc/devlml.c
+++ b/sys/src/9/pc/devlml.c
@@ -179,7 +179,7 @@
 		kstrdup(&segbuf.name, name);
 		segbuf.pa = PADDR(lml->codedata);
 		segbuf.size = Codedatasize;
-		if(addphysseg(&segbuf) == -1){
+		if(addphysseg(&segbuf) == nil){
 			print("lml: physsegment: %s\n", name);
 			return;
 		}
@@ -190,7 +190,7 @@
 		kstrdup(&segbuf.name, name);
 		segbuf.pa = (ulong)regpa;
 		segbuf.size = pcidev->mem[0].size;
-		if(addphysseg(&segbuf) == -1){
+		if(addphysseg(&segbuf) == nil){
 			print("lml: physsegment: %s\n", name);
 			return;
 		}
--- a/sys/src/9/port/devsegment.c
+++ b/sys/src/9/port/devsegment.c
@@ -232,7 +232,7 @@
 	if(TYPE(c) != Qtopdir)
 		error(Eperm);
 
-	if(isphysseg(name))
+	if(findphysseg(name) != nil)
 		error(Eexist);
 
 	if((perm & DMDIR) == 0)
--- a/sys/src/9/port/fault.c
+++ b/sys/src/9/port/fault.c
@@ -10,7 +10,7 @@
 {
 	Segment *s;
 	char *sps;
-	int pnd;
+	int pnd, attr;
 
 	if(up == nil)
 		panic("fault: nil up");
@@ -34,7 +34,10 @@
 			return -1;
 		}
 
-		if(!read && (s->type&SG_RONLY)) {
+		attr = s->type;
+		if((attr & SG_TYPE) == SG_PHYSICAL)
+			attr |= s->pseg->attr;
+		if((attr & SG_FAULT) != 0 || !read && (attr & SG_RONLY) != 0) {
 			qunlock(s);
 			up->psstate = sps;
 			return -1;
@@ -62,15 +65,16 @@
 {
 	char buf[ERRMAX];
 
-	if(c != nil && c->path != nil){
-		snprint(buf, sizeof buf, "%s accessing %s: %s", s, c->path->s, up->errstr);
-		s = buf;
-	}
+	if(c != nil)
+		snprint(buf, sizeof buf, "sys: %s accessing %s: %s", s, chanpath(c), up->errstr);
+	else
+		snprint(buf, sizeof buf, "sys: %s", s);
 	if(up->nerrlab) {
 		if(up->kp == 0)
-			postnote(up, 1, s, NDebug);
+			postnote(up, 1, buf, NDebug);
 		error(s);
 	}
+	pprint("suicide: %s\n", buf);
 	pexit(s, 1);
 }
 
@@ -208,13 +212,12 @@
 		*pte = etp = ptealloc();
 
 	pg = &etp->pages[(soff&(PTEMAPMEM-1))/BY2PG];
-	type = s->type&SG_TYPE;
-
 	if(pg < etp->first)
 		etp->first = pg;
 	if(pg > etp->last)
 		etp->last = pg;
 
+	type = s->type & SG_TYPE;
 	switch(type) {
 	default:
 		panic("fault");
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -377,6 +377,7 @@
 
 	SG_RONLY	= 0040,		/* Segment is read only */
 	SG_CEXEC	= 0100,		/* Detach at exec */
+	SG_FAULT	= 0200,		/* Fault on access */
 };
 
 #define PG_ONSWAP	1
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -1,7 +1,7 @@
 void		_assert(char*);
 void		accounttime(void);
 Timer*		addclock0link(void (*)(void), int);
-int		addphysseg(Physseg*);
+Physseg*	addphysseg(Physseg*);
 void		addbootfile(char*, uchar*, ulong);
 void		addwatchdog(Watchdog*);
 Block*		adjustblock(Block*, int);
@@ -141,7 +141,7 @@
 int		iseve(void);
 int		islo(void);
 Segment*	isoverlap(Proc*, uintptr, uintptr);
-int		isphysseg(char*);
+Physseg*	findphysseg(char*);
 void		ixsummary(void);
 void		kickpager(void);
 void		killbig(char*);
@@ -231,6 +231,7 @@
 void		procdump(void);
 int		procfdprint(Chan*, int, char*, int);
 void		procflushseg(Segment*);
+void		procflushpseg(Physseg*);
 int		procindex(ulong);
 void		procinit0(void);
 ulong		procpagecount(Proc*);
--- a/sys/src/9/port/proc.c
+++ b/sys/src/9/port/proc.c
@@ -1321,35 +1321,30 @@
 }
 
 /*
- *  wait till all processes have flushed their mmu
- *  state about segement s
+ *  wait till all matching processes have flushed their mmu
  */
-void
-procflushseg(Segment *s)
+static void
+procflushmmu(int (*match)(Proc*, void*), void *a)
 {
-	int i, ns, nm, nwait;
+	int i, nm, nwait;
 	Proc *p;
 
 	/*
-	 *  tell all processes with this
-	 *  segment to flush their mmu's
+	 *  tell all matching processes to flush their mmu's
 	 */
 	nwait = 0;
 	for(i=0; i<conf.nproc; i++) {
 		p = &procalloc.arena[i];
-		if(p->state == Dead)
-			continue;
-		for(ns = 0; ns < NSEG; ns++)
-			if(p->seg[ns] == s){
-				p->newtlb = 1;
-				for(nm = 0; nm < conf.nmach; nm++){
-					if(MACHP(nm)->proc == p){
-						MACHP(nm)->flushmmu = 1;
-						nwait++;
-					}
+		if(p->state != Dead && (*match)(p, a)){
+			p->newtlb = 1;
+			for(nm = 0; nm < conf.nmach; nm++){
+				if(MACHP(nm)->proc == p){
+					MACHP(nm)->flushmmu = 1;
+					nwait++;
 				}
-				break;
 			}
+			break;
+		}
 	}
 
 	if(nwait == 0)
@@ -1362,6 +1357,42 @@
 	for(nm = 0; nm < conf.nmach; nm++)
 		while(m->machno != nm && MACHP(nm)->flushmmu)
 			sched();
+}
+
+static int
+matchseg(Proc *p, void *a)
+{
+	int ns;
+
+	for(ns = 0; ns < NSEG; ns++){
+		if(p->seg[ns] == a)
+			return 1;
+	}
+	return 0;
+}
+void
+procflushseg(Segment *s)
+{
+	procflushmmu(matchseg, s);
+}
+
+static int
+matchpseg(Proc *p, void *a)
+{
+	Segment *s;
+	int ns;
+
+	for(ns = 0; ns < NSEG; ns++){
+		s = p->seg[ns];
+		if(s != nil && s->pseg == a)
+			return 1;
+	}
+	return 0;
+}
+void
+procflushpseg(Physseg *ps)
+{
+	procflushmmu(matchpseg, ps);
 }
 
 void
--- a/sys/src/9/port/segment.c
+++ b/sys/src/9/port/segment.c
@@ -551,7 +551,7 @@
 	return nil;
 }
 
-int
+Physseg*
 addphysseg(Physseg* new)
 {
 	Physseg *ps;
@@ -564,34 +564,29 @@
 	for(ps = physseg; ps->name; ps++){
 		if(strcmp(ps->name, new->name) == 0){
 			unlock(&physseglock);
-			return -1;
+			return nil;
 		}
 	}
 	if(ps-physseg >= nelem(physseg)-2){
 		unlock(&physseglock);
-		return -1;
+		return nil;
 	}
 	*ps = *new;
 	unlock(&physseglock);
 
-	return 0;
+	return ps;
 }
 
-int
-isphysseg(char *name)
+Physseg*
+findphysseg(char *name)
 {
 	Physseg *ps;
-	int rv = 0;
 
-	lock(&physseglock);
-	for(ps = physseg; ps->name; ps++){
-		if(strcmp(ps->name, name) == 0){
-			rv = 1;
-			break;
-		}
-	}
-	unlock(&physseglock);
-	return rv;
+	for(ps = physseg; ps->name; ps++)
+		if(strcmp(ps->name, name) == 0)
+			return ps;
+
+	return nil;
 }
 
 uintptr
@@ -654,12 +649,10 @@
 	if(isoverlap(p, va, len) != nil)
 		error(Esoverlap);
 
-	for(ps = physseg; ps->name; ps++)
-		if(strcmp(name, ps->name) == 0)
-			goto found;
+	ps = findphysseg(name);
+	if(ps == nil)
+		error(Ebadarg);
 
-	error(Ebadarg);
-found:
 	if(len > ps->size)
 		error(Enovmem);
 
--- a/sys/src/9/ppc/m8260.c
+++ b/sys/src/9/ppc/m8260.c
@@ -445,7 +445,7 @@
 	kstrdup(&segbuf.name, name);
 	segbuf.pa = start;
 	segbuf.size = length;
-	if (addphysseg(&segbuf) == -1) {
+	if (addphysseg(&segbuf) == nil) {
 		print("addphysseg: %s\n", name);
 		return;
 	}
--- a/sys/src/9/zynq/devarch.c
+++ b/sys/src/9/zynq/devarch.c
@@ -25,14 +25,15 @@
 };
 static int narchdir = Qbase;
 
-int temp = -128;
-ulong *devc;
-int dmadone;
+static int temp = -128;
+static ulong *devc;
+static int dmadone;
 enum { PLBUFSIZ = 8192 };
-uchar *plbuf;
-Rendez plinitr, pldoner, pldmar;
-QLock plrlock, plwlock;
-Ref plwopen;
+static uchar *plbuf;
+static Rendez plinitr, pldoner, pldmar;
+static QLock plrlock, plwlock;
+static Ref plwopen;
+static Physseg *axi;
 
 enum {
 	DEVCTRL = 0,
@@ -164,6 +165,8 @@
 		slcr[0x900/4] = 0xf;
 		slcr[0x240/4] = 0;
 		devc[DEVMASK] |= DONE;
+		if(axi != nil)
+			axi->attr &= ~SG_FAULT;
 		wakeup(&pldoner);
 	}
 	if((fl & DMADONE) != 0){
@@ -187,16 +190,21 @@
 	slcr[FPGA0_CLK_CTRL] = 1<<20 | 10<<8;
 
 	memset(&seg, 0, sizeof seg);
-	seg.attr = SG_PHYSICAL;
+	seg.attr = SG_PHYSICAL | SG_FAULT;
 	seg.name = "axi";
 	seg.pa = 0x40000000;
 	seg.size = 0x8000000;
-	addphysseg(&seg);
+	axi = addphysseg(&seg);
 }
 
 static void
 plconf(void)
 {
+	if(axi != nil){
+		axi->attr |= SG_FAULT;
+		procflushpseg(axi);
+	}
+
 	slcr[0x240/4] = 0xf;
 	slcr[0x900/4] = 0xa;
 	devc[DEVISTS] = DONE|INITPE|DMADONE;