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:
parent
bf2195b88c
commit
04c3a6f66e
9 changed files with 100 additions and 63 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue