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.
This commit is contained in:
cinap_lenrek 2016-03-27 20:57:01 +02:00
parent bf2195b88c
commit 04c3a6f66e
9 changed files with 100 additions and 63 deletions

View file

@ -179,7 +179,7 @@ lmlreset(void)
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 @@ lmlreset(void)
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;
}

View file

@ -232,7 +232,7 @@ segmentcreate(Chan *c, char *name, int omode, ulong perm)
if(TYPE(c) != Qtopdir)
error(Eperm);
if(isphysseg(name))
if(findphysseg(name) != nil)
error(Eexist);
if((perm & DMDIR) == 0)

View file

@ -10,7 +10,7 @@ fault(uintptr addr, int read)
{
Segment *s;
char *sps;
int pnd;
int pnd, attr;
if(up == nil)
panic("fault: nil up");
@ -34,7 +34,10 @@ fault(uintptr addr, int read)
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 @@ faulterror(char *s, Chan *c)
{
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 @@ fixfault(Segment *s, uintptr addr, int read)
*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");

View file

@ -377,6 +377,7 @@ enum
SG_RONLY = 0040, /* Segment is read only */
SG_CEXEC = 0100, /* Detach at exec */
SG_FAULT = 0200, /* Fault on access */
};
#define PG_ONSWAP 1

View file

@ -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 @@ void isdir(Chan*);
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 procctl(void);
void procdump(void);
int procfdprint(Chan*, int, char*, int);
void procflushseg(Segment*);
void procflushpseg(Physseg*);
int procindex(ulong);
void procinit0(void);
ulong procpagecount(Proc*);

View file

@ -1321,35 +1321,30 @@ procdump(void)
}
/*
* 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)
@ -1364,6 +1359,42 @@ procflushseg(Segment *s)
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
scheddump(void)
{

View file

@ -551,7 +551,7 @@ isoverlap(Proc *p, uintptr va, uintptr len)
return nil;
}
int
Physseg*
addphysseg(Physseg* new)
{
Physseg *ps;
@ -564,34 +564,29 @@ addphysseg(Physseg* new)
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 @@ segattach(Proc *p, ulong attr, char *name, uintptr va, uintptr len)
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);

View file

@ -445,7 +445,7 @@ addseg(char *name, ulong start, ulong length)
kstrdup(&segbuf.name, name);
segbuf.pa = start;
segbuf.size = length;
if (addphysseg(&segbuf) == -1) {
if (addphysseg(&segbuf) == nil) {
print("addphysseg: %s\n", name);
return;
}

View file

@ -25,14 +25,15 @@ static Dirtab archdir[Qmax] = {
};
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 @@ plirq(Ureg *, void *)
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 @@ plinit(void)
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;