summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/src/9/port/devproc.c163
-rw-r--r--sys/src/9/port/devsegment.c169
-rw-r--r--sys/src/9/port/fault.c22
-rw-r--r--sys/src/9/port/portdat.h17
-rw-r--r--sys/src/9/port/portfns.h3
-rw-r--r--sys/src/9/port/segment.c182
6 files changed, 262 insertions, 294 deletions
diff --git a/sys/src/9/port/devproc.c b/sys/src/9/port/devproc.c
index 97a2dba5f..5e1beddbc 100644
--- a/sys/src/9/port/devproc.c
+++ b/sys/src/9/port/devproc.c
@@ -152,7 +152,7 @@ static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", "Fixed"
#define NOTEID(q) ((q).vers)
void procctlreq(Proc*, char*, int);
-int procctlmemio(Proc*, uintptr, int, void*, int);
+long procctlmemio(Chan*, Proc*, uintptr, void*, long, int);
Chan* proctext(Chan*, Proc*);
int procstopped(void*);
ulong procpagecount(Proc *);
@@ -511,13 +511,28 @@ procwstat(Chan *c, uchar *db, int n)
static void
procclose(Chan *c)
{
- if(QID(c->qid) == Qtrace && (c->flag & COPEN) != 0){
+ Segio *sio;
+
+ if((c->flag & COPEN) == 0)
+ return;
+
+ switch(QID(c->qid)){
+ case Qtrace:
lock(&tlock);
if(topens > 0)
topens--;
if(topens == 0)
proctrace = nil;
unlock(&tlock);
+ return;
+ case Qmem:
+ sio = c->aux;
+ if(sio != nil){
+ c->aux = nil;
+ segio(sio, nil, nil, 0, 0, 0);
+ free(sio);
+ }
+ return;
}
}
@@ -774,7 +789,7 @@ procread(Chan *c, void *va, long n, vlong off)
case Qmem:
addr = off2addr(off);
if(addr < KZERO)
- return procctlmemio(p, addr, n, va, 1);
+ return procctlmemio(c, p, addr, va, n, 1);
if(!iseve())
error(Eperm);
@@ -1051,7 +1066,7 @@ procwrite(Chan *c, void *va, long n, vlong off)
case Qmem:
if(p->state != Stopped)
error(Ebadctl);
- n = procctlmemio(p, off2addr(off), n, va, 0);
+ n = procctlmemio(c, p, off2addr(off), va, n, 0);
break;
case Qregs:
@@ -1163,9 +1178,6 @@ proctext(Chan *c, Proc *p)
unlock(i);
nexterror();
}
-
- if(i->s != s)
- error(Eprocdied);
tc = i->c;
if(tc == nil)
@@ -1476,127 +1488,58 @@ procstopped(void *a)
return ((Proc*)a)->state == Stopped;
}
-int
-procctlmemio(Proc *p, uintptr offset, int n, void *va, int read)
+long
+procctlmemio(Chan *c, Proc *p, uintptr offset, void *a, long n, int read)
{
- KMap *k;
- Pte *pte;
- Page *pg;
+ Segio *sio;
Segment *s;
- uintptr soff;
- char *a, *b;
- int i, l;
-
- /* Only one page at a time */
- l = BY2PG - (offset&(BY2PG-1));
- if(n > l)
- n = l;
-
- /*
- * Make temporary copy to avoid fault while we have
- * segment locked as we would deadlock when trying
- * to read the calling procs memory.
- */
- a = malloc(n);
- if(a == nil)
- error(Enomem);
+ int i;
+
+ s = seg(p, offset, 0);
+ if(s == nil)
+ error(Ebadarg);
+ eqlock(&p->seglock);
if(waserror()) {
- free(a);
+ qunlock(&p->seglock);
nexterror();
}
-
- if(!read)
- memmove(a, va, n); /* can fault */
-
- for(;;) {
- s = seg(p, offset, 0);
- if(s == nil)
- error(Ebadarg);
-
- eqlock(&p->seglock);
- if(waserror()) {
- qunlock(&p->seglock);
- nexterror();
- }
-
- for(i = 0; i < NSEG; i++) {
- if(p->seg[i] == s)
- break;
- }
- if(i == NSEG)
- error(Egreg); /* segment gone */
-
- eqlock(s);
- if(waserror()){
- qunlock(s);
- nexterror();
- }
- if(!read && (s->type&SG_TYPE) == SG_TEXT) {
- s = txt2data(s);
- p->seg[i] = s;
- }
- incref(s);
- qunlock(&p->seglock);
- poperror();
- poperror();
- /* segment s still locked, fixfault() unlocks */
- if(waserror()){
- putseg(s);
- nexterror();
- }
- if(fixfault(s, offset, read, 0) == 0)
+ sio = c->aux;
+ if(sio == nil){
+ sio = smalloc(sizeof(Segio));
+ c->aux = sio;
+ }
+ for(i = 0; i < NSEG; i++) {
+ if(p->seg[i] == s)
break;
- putseg(s);
- poperror();
}
-
- /*
- * Only access the page while segment is locked
- * as the proc could segfree or relocate the pte
- * concurrently.
- */
+ if(i == NSEG)
+ error(Egreg); /* segment gone */
eqlock(s);
if(waserror()){
qunlock(s);
nexterror();
}
- if(offset+n >= s->top)
- n = s->top-offset;
- soff = offset-s->base;
- pte = s->map[soff/PTEMAPMEM];
- if(pte == nil)
- error(Egreg); /* page gone, should retry? */
- pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG];
- if(pagedout(pg))
- error(Egreg); /* page gone, should retry? */
-
- /* Map and copy the page */
- k = kmap(pg);
- b = (char*)VA(k);
- b += offset&(BY2PG-1);
- if(read)
- memmove(a, b, n);
- else
- memmove(b, a, n);
- kunmap(k);
-
- if(!read){
- /* Ensure the process sees text page changes */
- if(s->flushme)
- pg->txtflush = ~0;
- p->newtlb = 1;
+ if(!read && (s->type&SG_TYPE) == SG_TEXT) {
+ s = txt2data(s);
+ p->seg[i] = s;
}
-
+ offset -= s->base;
+ incref(s); /* for us while we copy */
qunlock(s);
poperror();
- putseg(s);
+ qunlock(&p->seglock);
poperror();
- if(read)
- memmove(va, a, n); /* can fault */
-
- free(a);
+ if(waserror()) {
+ putseg(s);
+ nexterror();
+ }
+ n = segio(sio, s, a, n, offset, read);
+ putseg(s);
poperror();
+ if(!read)
+ p->newtlb = 1;
+
return n;
}
diff --git a/sys/src/9/port/devsegment.c b/sys/src/9/port/devsegment.c
index 2acaa0d76..07b0fca9c 100644
--- a/sys/src/9/port/devsegment.c
+++ b/sys/src/9/port/devsegment.c
@@ -11,13 +11,6 @@ enum
Qsegdir,
Qctl,
Qdata,
-
- /* commands to kproc */
- Cnone=0,
- Cread,
- Cwrite,
- Cstart,
- Cdie,
};
#define TYPE(x) (int)( (c)->qid.path & 0x7 )
@@ -28,23 +21,13 @@ typedef struct Globalseg Globalseg;
struct Globalseg
{
Ref;
- Segment *s;
char *name;
char *uid;
vlong length;
long perm;
- /* kproc to do reading and writing */
- QLock l; /* sync kproc access */
- Rendez cmdwait; /* where kproc waits */
- Rendez replywait; /* where requestor waits */
- Proc *kproc;
- char *data;
- char *addr;
- int dlen;
- int cmd;
- char err[64];
+ Segio;
};
static Globalseg *globalseg[100];
@@ -53,9 +36,7 @@ static Lock globalseglock;
Segment* (*_globalsegattach)(Proc*, char*);
static Segment* globalsegattach(Proc *p, char *name);
-static int cmddone(void*);
-static void segmentkproc(void*);
-static void docmd(Globalseg *g, int cmd);
+
static Segment* fixedseg(uintptr va, ulong len);
/*
@@ -87,8 +68,7 @@ putgseg(Globalseg *g)
return;
if(g->s != nil)
putseg(g->s);
- if(g->kproc)
- docmd(g, Cdie);
+ segio(g, nil, nil, 0, 0, 0);
free(g->name);
free(g->uid);
free(g);
@@ -191,14 +171,6 @@ segmentstat(Chan *c, uchar *db, int n)
return devstat(c, db, n, 0, 0, segmentgen);
}
-static int
-cmddone(void *arg)
-{
- Globalseg *g = arg;
-
- return g->cmd == Cnone;
-}
-
static Chan*
segmentopen(Chan *c, int omode)
{
@@ -230,20 +202,6 @@ segmentopen(Chan *c, int omode)
devpermcheck(g->uid, g->perm, omode);
if(g->s == nil)
error("segment not yet allocated");
- if(g->kproc == nil){
- eqlock(&g->l);
- if(waserror()){
- qunlock(&g->l);
- nexterror();
- }
- if(g->kproc == nil){
- g->cmd = Cnone;
- kproc(g->name, segmentkproc, g);
- docmd(g, Cstart);
- }
- qunlock(&g->l);
- poperror();
- }
c->aux = g;
poperror();
c->flag |= COPEN;
@@ -316,57 +274,6 @@ segmentcreate(Chan *c, char *name, int omode, ulong perm)
}
static long
-segmentio(Globalseg *g, void *a, long n, vlong off, int wr)
-{
- uintptr m;
- void *b;
-
- m = g->s->top - g->s->base;
- if(off < 0 || off >= m){
- if(wr)
- error(Ebadarg);
- return 0;
- }
- if(off+n > m){
- if(wr)
- error(Ebadarg);
- n = m - off;
- }
-
- if((uintptr)a > KZERO)
- b = a;
- else {
- b = smalloc(n);
- if(waserror()){
- free(b);
- nexterror();
- }
- if(wr)
- memmove(b, a, n);
- }
-
- eqlock(&g->l);
- if(waserror()){
- qunlock(&g->l);
- nexterror();
- }
- g->addr = (char*)g->s->base + off;
- g->data = b;
- g->dlen = n;
- docmd(g, wr ? Cwrite : Cread);
- qunlock(&g->l);
- poperror();
-
- if(a != b){
- if(!wr)
- memmove(a, b, n);
- free(b);
- poperror();
- }
- return n;
-}
-
-static long
segmentread(Chan *c, void *a, long n, vlong voff)
{
Globalseg *g;
@@ -387,7 +294,7 @@ segmentread(Chan *c, void *a, long n, vlong voff)
snprint(buf, sizeof(buf), "va %#p %#p\n", g->s->base, g->s->top-g->s->base);
return readstr(voff, a, n, buf);
case Qdata:
- return segmentio(g, a, n, voff, 0);
+ return segio(g, g->s, a, n, voff, 1);
default:
panic("segmentread");
}
@@ -430,7 +337,7 @@ segmentwrite(Chan *c, void *a, long n, vlong voff)
error(Ebadctl);
break;
case Qdata:
- return segmentio(g, a, n, voff, 1);
+ return segio(g, g->s, a, n, voff, 0);
default:
panic("segmentwrite");
}
@@ -520,72 +427,6 @@ globalsegattach(Proc *p, char *name)
return s;
}
-static void
-docmd(Globalseg *g, int cmd)
-{
- g->err[0] = 0;
- g->cmd = cmd;
- wakeup(&g->cmdwait);
- sleep(&g->replywait, cmddone, g);
- if(g->err[0])
- error(g->err);
-}
-
-static int
-cmdready(void *arg)
-{
- Globalseg *g = arg;
-
- return g->cmd != Cnone;
-}
-
-static void
-segmentkproc(void *arg)
-{
- Globalseg *g = arg;
- int done;
- int sno;
-
- for(sno = 0; sno < NSEG; sno++)
- if(up->seg[sno] == nil && sno != ESEG)
- break;
- if(sno == NSEG)
- panic("segmentkproc");
- g->kproc = up;
-
- incref(g->s);
- up->seg[sno] = g->s;
-
- while(waserror())
- ;
- for(done = 0; !done;){
- sleep(&g->cmdwait, cmdready, g);
- if(waserror()){
- strncpy(g->err, up->errstr, sizeof(g->err)-1);
- g->err[sizeof(g->err)-1] = 0;
- } else {
- switch(g->cmd){
- case Cstart:
- break;
- case Cdie:
- done = 1;
- break;
- case Cread:
- memmove(g->data, g->addr, g->dlen);
- break;
- case Cwrite:
- memmove(g->addr, g->data, g->dlen);
- break;
- }
- poperror();
- }
- g->cmd = Cnone;
- wakeup(&g->replywait);
- }
-
- pexit("done", 1);
-}
-
/*
* allocate a fixed segment with sequential run of of adjacent
* user memory pages.
diff --git a/sys/src/9/port/fault.c b/sys/src/9/port/fault.c
index 966c2992d..123ae4e80 100644
--- a/sys/src/9/port/fault.c
+++ b/sys/src/9/port/fault.c
@@ -40,7 +40,7 @@ fault(uintptr addr, int read)
return -1;
}
- if(fixfault(s, addr, read, 1) == 0)
+ if(fixfault(s, addr, read) == 0)
break;
splhi();
@@ -58,7 +58,7 @@ fault(uintptr addr, int read)
}
static void
-faulterror(char *s, Chan *c, int isfatal)
+faulterror(char *s, Chan *c)
{
char buf[ERRMAX];
@@ -67,15 +67,14 @@ faulterror(char *s, Chan *c, int isfatal)
s = buf;
}
if(up->nerrlab) {
- if(isfatal)
- postnote(up, 1, s, NDebug);
+ postnote(up, 1, s, NDebug);
error(s);
}
pexit(s, 1);
}
static void
-pio(Segment *s, uintptr addr, uintptr soff, Page **p, int isfatal)
+pio(Segment *s, uintptr addr, uintptr soff, Page **p)
{
Page *new;
KMap *k;
@@ -120,11 +119,11 @@ retry:
k = kmap(new);
kaddr = (char*)VA(k);
while(waserror()) {
- if(isfatal && strcmp(up->errstr, Eintr) == 0)
+ if(strcmp(up->errstr, Eintr) == 0)
continue;
kunmap(k);
putpage(new);
- faulterror(Eioload, c, isfatal);
+ faulterror(Eioload, c);
}
n = devtab[c->type]->read(c, kaddr, ask, daddr);
if(n != ask)
@@ -194,7 +193,7 @@ void (*checkaddr)(uintptr, Segment *, Page *);
uintptr addr2check;
int
-fixfault(Segment *s, uintptr addr, int read, int doputmmu)
+fixfault(Segment *s, uintptr addr, int read)
{
int type;
Pte **pte, *etp;
@@ -222,7 +221,7 @@ fixfault(Segment *s, uintptr addr, int read, int doputmmu)
case SG_TEXT: /* Demand load */
if(pagedout(*pg))
- pio(s, addr, soff, pg, doputmmu);
+ pio(s, addr, soff, pg);
mmuphys = PPN((*pg)->pa) | PTERONLY|PTEVALID;
(*pg)->modref = PG_REF;
@@ -242,7 +241,7 @@ fixfault(Segment *s, uintptr addr, int read, int doputmmu)
case SG_DATA:
common: /* Demand load/pagein/copy on write */
if(pagedout(*pg))
- pio(s, addr, soff, pg, doputmmu);
+ pio(s, addr, soff, pg);
/*
* It's only possible to copy on write if
@@ -288,8 +287,7 @@ fixfault(Segment *s, uintptr addr, int read, int doputmmu)
}
qunlock(s);
- if(doputmmu)
- putmmu(addr, mmuphys, *pg);
+ putmmu(addr, mmuphys, *pg);
return 0;
}
diff --git a/sys/src/9/port/portdat.h b/sys/src/9/port/portdat.h
index 495baac93..f2d0a1223 100644
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -39,6 +39,7 @@ typedef struct RWlock RWlock;
typedef struct Sargs Sargs;
typedef struct Schedq Schedq;
typedef struct Segment Segment;
+typedef struct Segio Segio;
typedef struct Sema Sema;
typedef struct Timer Timer;
typedef struct Timers Timers;
@@ -392,6 +393,22 @@ struct Segment
ulong mark; /* portcountrefs */
};
+struct Segio
+{
+ QLock;
+ Rendez cmdwait;
+ Rendez replywait;
+
+ Proc *p; /* segmentio kproc */
+ Segment *s;
+
+ char *data;
+ char *addr;
+ int dlen;
+ int cmd;
+ char err[64];
+};
+
enum
{
RENDLOG = 5,
diff --git a/sys/src/9/port/portfns.h b/sys/src/9/port/portfns.h
index 8b1675816..12032e174 100644
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -107,7 +107,7 @@ int fault(uintptr, int);
void fdclose(int, int);
Chan* fdtochan(int, int, int, int);
int findmount(Chan**, Mhead**, int, int, Qid);
-int fixfault(Segment*, uintptr, int, int);
+int fixfault(Segment*, uintptr, int);
void flushmmu(void);
void forceclosefgrp(void);
void forkchild(Proc*, Ureg*);
@@ -304,6 +304,7 @@ void (*screenputs)(char*, int);
long seconds(void);
uintptr segattach(Proc*, ulong, char *, uintptr, uintptr);
void segclock(uintptr);
+long segio(Segio*, Segment*, void*, long, vlong, int);
void segpage(Segment*, Page*);
int setcolor(ulong, ulong, ulong, ulong);
void setkernur(Ureg*, Proc*);
diff --git a/sys/src/9/port/segment.c b/sys/src/9/port/segment.c
index 7adc005ea..ad3cc0a92 100644
--- a/sys/src/9/port/segment.c
+++ b/sys/src/9/port/segment.c
@@ -670,18 +670,16 @@ found:
return va;
}
-uintptr
-syssegflush(va_list list)
+static void
+segflush(void *va, uintptr len)
{
- uintptr from, to, off, len;
+ uintptr from, to, off;
Segment *s;
Pte *pte;
Page **pg, **pe;
- from = va_arg(list, uintptr);
- to = va_arg(list, ulong);
- to += from;
-
+ from = (uintptr)va;
+ to = from + len;
to = PGROUND(to);
from &= ~(BY2PG-1);
if(to < from)
@@ -717,6 +715,17 @@ syssegflush(va_list list)
qunlock(s);
}
+}
+
+uintptr
+syssegflush(va_list list)
+{
+ void *va;
+ ulong len;
+
+ va = va_arg(list, void*);
+ len = va_arg(list, ulong);
+ segflush(va, len);
flushmmu();
return 0;
}
@@ -767,3 +776,162 @@ data2txt(Segment *s)
ps->flushme = 1;
return ps;
}
+
+
+enum {
+ /* commands to segmentioproc */
+ Cnone=0,
+ Cread,
+ Cwrite,
+ Cdie,
+};
+
+static int
+cmddone(void *arg)
+{
+ Segio *sio = arg;
+
+ return sio->cmd == Cnone;
+}
+
+static void
+docmd(Segio *sio, int cmd)
+{
+ sio->err[0] = 0;
+ sio->cmd = cmd;
+ wakeup(&sio->cmdwait);
+ sleep(&sio->replywait, cmddone, sio);
+ if(sio->err[0])
+ error(sio->err);
+}
+
+static int
+cmdready(void *arg)
+{
+ Segio *sio = arg;
+
+ return sio->cmd != Cnone;
+}
+
+static void
+segmentioproc(void *arg)
+{
+ Segio *sio = arg;
+ int done;
+ int sno;
+
+ for(sno = 0; sno < NSEG; sno++)
+ if(up->seg[sno] == nil && sno != ESEG)
+ break;
+ if(sno == NSEG)
+ panic("segmentkproc");
+
+ sio->p = up;
+ incref(sio->s);
+ up->seg[sno] = sio->s;
+
+ cclose(up->dot);
+ up->dot = up->slash;
+ incref(up->dot);
+
+ while(waserror())
+ ;
+ for(done = 0; !done;){
+ sleep(&sio->cmdwait, cmdready, sio);
+ if(waserror()){
+ strncpy(sio->err, up->errstr, sizeof(sio->err)-1);
+ sio->err[sizeof(sio->err)-1] = 0;
+ } else {
+ if(sio->s != nil && up->seg[sno] != sio->s){
+ putseg(up->seg[sno]);
+ incref(sio->s);
+ up->seg[sno] = sio->s;
+ flushmmu();
+ }
+ switch(sio->cmd){
+ case Cread:
+ memmove(sio->data, sio->addr, sio->dlen);
+ break;
+ case Cwrite:
+ memmove(sio->addr, sio->data, sio->dlen);
+ if(sio->s->flushme)
+ segflush(sio->addr, sio->dlen);
+ break;
+ case Cdie:
+ done = 1;
+ break;
+ }
+ poperror();
+ }
+ sio->cmd = Cnone;
+ wakeup(&sio->replywait);
+ }
+
+ pexit("done", 1);
+}
+
+long
+segio(Segio *sio, Segment *s, void *a, long n, vlong off, int read)
+{
+ uintptr m;
+ void *b;
+
+ b = a;
+ if(s != nil){
+ m = s->top - s->base;
+ if(off < 0 || off >= m){
+ if(!read)
+ error(Ebadarg);
+ return 0;
+ }
+ if(off+n > m){
+ if(!read)
+ error(Ebadarg);
+ n = m - off;
+ }
+
+ if((uintptr)a < KZERO) {
+ b = smalloc(n);
+ if(waserror()){
+ free(b);
+ nexterror();
+ }
+ if(!read)
+ memmove(b, a, n);
+ }
+ }
+
+ eqlock(sio);
+ if(waserror()){
+ qunlock(sio);
+ nexterror();
+ }
+ sio->s = s;
+ if(s == nil){
+ if(sio->p != nil){
+ docmd(sio, Cdie);
+ sio->p = nil;
+ }
+ qunlock(sio);
+ poperror();
+ return 0;
+ }
+ if(sio->p == nil){
+ sio->cmd = Cnone;
+ kproc("segmentio", segmentioproc, sio);
+ }
+ sio->addr = (char*)s->base + off;
+ sio->data = b;
+ sio->dlen = n;
+ docmd(sio, read ? Cread : Cwrite);
+ qunlock(sio);
+ poperror();
+
+ if(a != b){
+ if(read)
+ memmove(a, b, n);
+ free(b);
+ poperror();
+ }
+ return n;
+}