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;