summaryrefslogtreecommitdiff
path: root/sys/src/9/port/devsegment.c
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2015-04-16 00:45:25 +0200
committercinap_lenrek <cinap_lenrek@felloff.net>2015-04-16 00:45:25 +0200
commit46070c3122227f5fc04c9b7a29d0652600fa7074 (patch)
tree82d1d3e022e7fe96baa7834f8a7718c818f39353 /sys/src/9/port/devsegment.c
parent88d7d8428a6cb10b421d5ff900617dad3c290fd1 (diff)
kernel: add segio() function for reading/writing segments
devproc's procctlmemio() did not handle physical segment types correctly, as it assumed it can just kmap() the page in question and write to it. physical segments however need to be mapped uncached but kmap() will always map cached as it assumes normal memory. on some machines with aliasing memory with different cache attributes leads to undefined behaviour! we borrow the code from devsegment and provide a generic segio() function to read and write user segments which handles all the cases without using kmap by just spawning a kproc that attaches the segment that needs to be read from or written to. fault() will setup the right mmu attributes for us. it will also properly flush pages for segments that maintain instruction cache when written. however, tlb's have to be flushed separately. segio() is used for devsegment and devproc now, which also allows for simplification of fixfault() as there is no special error handling case anymore as fixfault() is now called from faulting process *only*. reads from /proc/$pid/mem can now span multiple pages.
Diffstat (limited to 'sys/src/9/port/devsegment.c')
-rw-r--r--sys/src/9/port/devsegment.c169
1 files changed, 5 insertions, 164 deletions
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.