diff options
Diffstat (limited to 'emu/Plan9')
| -rw-r--r-- | emu/Plan9/asm-386.s | 33 | ||||
| -rw-r--r-- | emu/Plan9/asm-mips.s | 24 | ||||
| -rw-r--r-- | emu/Plan9/asm-power.s | 28 | ||||
| -rw-r--r-- | emu/Plan9/asm-sparc.s | 22 | ||||
| -rw-r--r-- | emu/Plan9/cmd.c | 189 | ||||
| -rw-r--r-- | emu/Plan9/devfs.c | 365 | ||||
| -rw-r--r-- | emu/Plan9/devsrv9.c | 395 | ||||
| -rw-r--r-- | emu/Plan9/emu | 109 | ||||
| -rw-r--r-- | emu/Plan9/emusig | 95 | ||||
| -rw-r--r-- | emu/Plan9/mkfile | 45 | ||||
| -rw-r--r-- | emu/Plan9/os.c | 422 | ||||
| -rw-r--r-- | emu/Plan9/win.c | 564 |
12 files changed, 2291 insertions, 0 deletions
diff --git a/emu/Plan9/asm-386.s b/emu/Plan9/asm-386.s new file mode 100644 index 00000000..b8193f71 --- /dev/null +++ b/emu/Plan9/asm-386.s @@ -0,0 +1,33 @@ + +TEXT tramp(SB),$0 + MOVL nsp+0(FP), BX /* new stack */ + MOVL fn+4(FP), CX /* func to exec */ + MOVL arg+8(FP),DX + + LEAL -8(BX), SP /* new stack */ + PUSHL DX + CALL *CX + POPL AX + + PUSHL $0 + CALL _exits(SB) + POPL AX + RET + +TEXT vstack(SB),$0 + MOVL arg+0(FP), AX + MOVL ustack(SB), SP + PUSHL AX + CALL exectramp(SB) + POPL AX /* dammit ken! */ + RET + +TEXT FPsave(SB), 1, $0 + MOVL fpu+0(FP), AX + FSTENV 0(AX) + RET + +TEXT FPrestore(SB), 1, $0 + MOVL fpu+0(FP), AX + FLDENV 0(AX) + RET diff --git a/emu/Plan9/asm-mips.s b/emu/Plan9/asm-mips.s new file mode 100644 index 00000000..b03f8209 --- /dev/null +++ b/emu/Plan9/asm-mips.s @@ -0,0 +1,24 @@ + + TEXT tramp(SB), 1, $0 + ADDU $-8, R1, R3 /* new stack */ + MOVW 4(FP), R2 /* func to exec */ + MOVW 8(FP), R1 /* arg to reg */ + MOVW R3, R29 /* new stack */ + JAL (R2) + MOVW R0, R1 + JMP _exits(SB) + + TEXT vstack(SB), 1, $0 /* Passes &targ through R1 */ + MOVW ustack(SB), R29 + JMP exectramp(SB) + RET + + TEXT FPsave(SB), 1, $0 + MOVW FCR31, R2 + MOVW R2, 0(R1) + RET + + TEXT FPrestore(SB), 1, $0 + MOVW 0(R1), R2 + MOVW R2, FCR31 + RET diff --git a/emu/Plan9/asm-power.s b/emu/Plan9/asm-power.s new file mode 100644 index 00000000..ff1c57f2 --- /dev/null +++ b/emu/Plan9/asm-power.s @@ -0,0 +1,28 @@ + TEXT tramp(SB), 1, $0 + ADD $-8, R3, R4 /* new stack */ + MOVW 4(FP), R5 /* func to exec */ + MOVW R5, LR + MOVW 8(FP), R3 /* arg to reg */ + MOVW R4, R1 /* new stack */ + BL (LR) + MOVW R0, R3 + MOVW $_exits(SB), R4 + MOVW R4, LR + BR (LR) + + TEXT vstack(SB), 1, $0 /* Passes &targ through R3 */ + MOVW ustack(SB), R1 + MOVW $exectramp(SB), R4 + MOVW R4, CTR + BR (CTR) + RETURN + + TEXT FPsave(SB), 1, $0 + MOVFL FPSCR, F0 + FMOVD F0, 0(R3) + RETURN + + TEXT FPrestore(SB), 1, $0 + FMOVD 0(R3), F0 + MOVFL F0, FPSCR + RETURN diff --git a/emu/Plan9/asm-sparc.s b/emu/Plan9/asm-sparc.s new file mode 100644 index 00000000..f68fd02d --- /dev/null +++ b/emu/Plan9/asm-sparc.s @@ -0,0 +1,22 @@ + TEXT tramp(SB), 1, $0 + ADD $-8, R7, R3 /* new stack */ + MOVW 4(FP), R4 /* func to exec */ + MOVW 8(FP), R7 /* arg to reg */ + MOVW R3, R1 /* new stack */ + JMPL (R4) + MOVW R0, R7 + JMPL _exits(SB) /* Leaks the stack in R29 */ + + TEXT vstack(SB), 1, $0 /* Passes &targ through R7 */ + MOVW ustack(SB), R1 + MOVW $exectramp(SB), R3 + JMP (R3) + RETURN + + TEXT FPsave(SB), 1, $0 + MOVW FSR, 0(R7) + RETURN + + TEXT FPrestore(SB), 1, $0 + MOVW 0(R7), FSR + RETURN diff --git a/emu/Plan9/cmd.c b/emu/Plan9/cmd.c new file mode 100644 index 00000000..8d311f2a --- /dev/null +++ b/emu/Plan9/cmd.c @@ -0,0 +1,189 @@ +#include "dat.h" +#include "fns.h" +#include "error.h" + +extern void vstack(void*); + +/* + * all this is for the benefit of devcmd. + * i hope it's grateful. + */ + +typedef struct Targ Targ; +struct Targ +{ + int fd[3]; /* standard input, output and error */ + int wfd; + int* spin; + char** args; + char* dir; + int pid; + int nice; +}; + +/* + * called by vstack once it has moved to + * the unshared stack in the new process. + */ +void +exectramp(Targ *t) +{ + int *fd, i, nfd; + char filename[128], err[ERRMAX], status[2*ERRMAX]; + + t->pid = getpid(); + *t->spin = 0; /* allow parent to proceed: can't just rendezvous: see below */ + fd = t->fd; + + snprint(filename, sizeof(filename), "#d/%d", t->wfd); + t->wfd = open(filename, OWRITE|OCEXEC); + /* if it failed, we'll manage */ + + nfd = MAXNFD; /* TO DO: should read from /fd */ + for(i = 0; i < nfd; i++) + if(i != fd[0] && i != fd[1] && i != fd[2] && i != t->wfd) + close(i); + + if(fd[0] != 0){ + dup(fd[0], 0); + close(fd[0]); + } + if(fd[1] != 1){ + dup(fd[1], 1); + close(fd[1]); + } + if(fd[2] != 2){ + dup(fd[2], 2); + close(fd[2]); + } + + if(t->dir != nil && chdir(t->dir) < 0){ + if(t->wfd > 0) + fprint(t->wfd, "chdir: %s: %r", t->dir); + _exits("bad dir"); + } + if(t->nice) + oslopri(); + + exec(t->args[0], t->args); + err[0] = 0; + errstr(err, sizeof(err)); + if(t->args[0][0] != '/' && t->args[0][0] != '#' && + strncmp(t->args[0], "../", 3) != 0 && strncmp(t->args[0], "./", 2) != 0 && + strlen(t->args[0])+5 < sizeof(filename)){ + snprint(filename, sizeof(filename), "/bin/%s", t->args[0]); + exec(filename, t->args); + errstr(err, sizeof(err)); + } + snprint(status, sizeof(status), "%s: can't exec: %s", t->args[0], err); + if(t->wfd > 0) + write(t->wfd, status, strlen(status)); + _exits(status); +} + +void* +oscmd(char **args, int nice, char *dir, int *fd) +{ + Targ *t; + int spin, *spinptr, fd0[2], fd1[2], fd2[2], wfd[2], n; + Dir *d; + + up->genbuf[0] = 0; + t = mallocz(sizeof(*t), 1); + if(t == nil) + return nil; + t->args = args; + t->dir = dir; + t->nice = nice; + fd0[0] = fd0[1] = -1; + fd1[0] = fd1[1] = -1; + fd2[0] = fd2[1] = -1; + wfd[0] = wfd[1] = -1; + if(dir != nil){ + d = dirstat(dir); + if(d == nil) + goto Error; + free(d); + } + if(pipe(fd0) < 0 || pipe(fd1) < 0 || pipe(fd2) < 0 || pipe(wfd) < 0) + goto Error; + + spinptr = &spin; + spin = 1; + + t->fd[0] = fd0[0]; + t->fd[1] = fd1[1]; + t->fd[2] = fd2[1]; + t->wfd = wfd[1]; + t->spin = spinptr; + switch(rfork(RFPROC|RFMEM|RFREND|RFNOTEG|RFFDG|RFNAMEG|RFENVG)) { + case -1: + goto Error; + case 0: + /* if child returns first from rfork, its call to vstack replaces ... */ + vstack(t); + /* ... parent's return address from rfork and parent returns here */ + default: + /* if parent returns first from rfork, it comes here */ + /* can't call anything: on shared stack until child releases spin in exectramp */ + while(*spinptr) + ; + break; + } + + close(fd0[0]); + close(fd1[1]); + close(fd2[1]); + close(wfd[1]); + + n = read(wfd[0], up->genbuf, sizeof(up->genbuf)-1); + close(wfd[0]); + if(n > 0){ + close(fd0[1]); + close(fd1[0]); + close(fd2[0]); + up->genbuf[n] = 0; + errstr(up->genbuf, sizeof(up->genbuf)); + free(t); + return nil; + } + + fd[0] = fd0[1]; + fd[1] = fd1[0]; + fd[2] = fd2[0]; + return t; + +Error: + errstr(up->genbuf, sizeof(up->genbuf)); /* save the message before close */ + close(fd0[0]); + close(fd0[1]); + close(fd1[0]); + close(fd1[1]); + close(fd2[0]); + close(fd2[1]); + close(wfd[0]); + close(wfd[1]); + free(t); + errstr(up->genbuf, sizeof(up->genbuf)); + return nil; +} + +int +oscmdkill(void *a) +{ + Targ *t = a; + + return postnote(PNGROUP, t->pid, "kill"); +} + +int +oscmdwait(void*, char *buf, int n) +{ + return await(buf, n); +} + +void +oscmdfree(void *a) +{ + free(a); +} diff --git a/emu/Plan9/devfs.c b/emu/Plan9/devfs.c new file mode 100644 index 00000000..d0db522d --- /dev/null +++ b/emu/Plan9/devfs.c @@ -0,0 +1,365 @@ +/* + * Plan 9 file system interface + */ +#include "dat.h" +#include "fns.h" +#include "error.h" + +typedef struct Fsinfo Fsinfo; +struct Fsinfo +{ + int fd; + QLock; /* serialise access to offset */ + ulong offset; /* offset used only for directory reads */ + Cname* name; /* Plan 9's name for file */ + Qid rootqid; /* Plan 9's qid for Inferno's root */ + char* root; /* prefix to strip from all names in diagnostics */ +}; +#define FS(c) ((Fsinfo*)((c)->aux)) + +char rootdir[MAXROOT] = ROOT; + +static void +fserr(Fsinfo *f) +{ + int n; + char *p; + + oserrstr(up->env->errstr, ERRMAX); + if(f != nil && *up->env->errstr == '\'' && (n = strlen(f->root)) > 1){ + /* don't reveal full names */ + if(strncmp(up->env->errstr+1, f->root, n-1) == 0){ + p = up->env->errstr+1+n; + memmove(up->env->errstr+1, p, strlen(p)+1); + } + } + error(up->env->errstr); +} + +static void +fsfree(Chan *c) +{ + cnameclose(FS(c)->name); + free(c->aux); +} + +Chan* +fsattach(char *spec) +{ + Chan *c; + Dir *d; + char *root; + Qid rootqid; + static int devno; + static Lock l; + + if(!emptystr(spec)){ + if(strcmp(spec, "*") != 0) + error(Ebadspec); + root = "/"; + }else + root = rootdir; + + d = dirstat(root); + if(d == nil) + fserr(nil); + rootqid = d->qid; + free(d); + + c = devattach('U', spec); + lock(&l); + c->dev = devno++; + c->qid = rootqid; + unlock(&l); + c->aux = smalloc(sizeof(Fsinfo)); + FS(c)->name = newcname(root); + FS(c)->rootqid = rootqid; + FS(c)->fd = -1; + FS(c)->root = root; + + return c; +} + +Walkqid* +fswalk(Chan *c, Chan *nc, char **name, int nname) +{ + int j, alloc; + Walkqid *wq; + Dir *dir; + char *n; + Cname *current, *next; + Qid rootqid; + + if(nname > 0) + isdir(c); /* do we need this? */ + + alloc = 0; + current = nil; + wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); + if(waserror()){ + if(alloc && wq->clone!=nil) + cclose(wq->clone); + cnameclose(current); + free(wq); + return nil; + } + if(nc == nil){ + nc = devclone(c); + nc->type = 0; + alloc = 1; + } + wq->clone = nc; + + rootqid = FS(c)->rootqid; + current = FS(c)->name; + if(current != nil) + incref(¤t->r); + for(j=0; j<nname; j++){ + if(!(nc->qid.type&QTDIR)){ + if(j==0) + error(Enotdir); + break; + } + n = name[j]; + if(strcmp(n, ".") != 0 && !(isdotdot(n) && nc->qid.path == rootqid.path)){ /* TO DO: underlying qids aliased */ + //print("** ufs walk '%s' -> %s\n", current->s, n); + next = current; + incref(&next->r); + next = addelem(current, n); + dir = dirstat(next->s); + if(dir == nil){ + cnameclose(next); + if(j == 0) + error(Enonexist); + strcpy(up->env->errstr, Enonexist); + break; + } + nc->qid = dir->qid; + free(dir); + cnameclose(current); + current = next; + } + wq->qid[wq->nqid++] = nc->qid; + } +// print("** ufs walk '%s'\n", current->s); + + poperror(); + if(wq->nqid < nname){ + cnameclose(current); + if(alloc) + cclose(wq->clone); + wq->clone = nil; + }else if(wq->clone){ + /* now attach to our device */ + nc->aux = smalloc(sizeof(Fsinfo)); + nc->type = c->type; + FS(nc)->rootqid = FS(c)->rootqid; + FS(nc)->name = current; + FS(nc)->fd = -1; + FS(nc)->root = FS(c)->root; + }else + panic("fswalk: can't happen"); + return wq; +} + +int +fsstat(Chan *c, uchar *dp, int n) +{ + if(FS(c)->fd >= 0) + n = fstat(FS(c)->fd, dp, n); + else + n = stat(FS(c)->name->s, dp, n); + if(n < 0) + fserr(FS(c)); + /* TO DO: change name to / if rootqid */ + return n; +} + +Chan* +fsopen(Chan *c, int mode) +{ + osenter(); + FS(c)->fd = open(FS(c)->name->s, mode); + osleave(); + if(FS(c)->fd < 0) + fserr(FS(c)); + c->mode = openmode(mode); + c->offset = 0; + FS(c)->offset = 0; + c->flag |= COPEN; + return c; +} + +void +fscreate(Chan *c, char *name, int mode, ulong perm) +{ + Dir *d; + Cname *n; + + if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) + error(Efilename); + n = addelem(newcname(FS(c)->name->s), name); + osenter(); + FS(c)->fd = create(n->s, mode, perm); + osleave(); + if(FS(c)->fd < 0) { + cnameclose(n); + fserr(FS(c)); + } + d = dirfstat(FS(c)->fd); + if(d == nil) { + cnameclose(n); + close(FS(c)->fd); + FS(c)->fd = -1; + fserr(FS(c)); + } + c->qid = d->qid; + free(d); + + cnameclose(FS(c)->name); + FS(c)->name = n; + + c->mode = openmode(mode); + c->offset = 0; + FS(c)->offset = 0; + c->flag |= COPEN; +} + +void +fsclose(Chan *c) +{ + if(c->flag & COPEN){ + osenter(); + close(FS(c)->fd); + osleave(); + } + /* don't need to check for CRCLOSE, because Plan 9 itself implements ORCLOSE */ + fsfree(c); +} + +static long +fsdirread(Chan *c, void *va, long count, vlong offset) +{ + long n, r; + static char slop[16384]; + + if(FS(c)->offset != offset){ + seek(FS(c)->fd, 0, 0); + for(n=0; n<offset;) { + r = offset - n; + if(r > sizeof(slop)) + r = sizeof(slop); + osenter(); + r = read(FS(c)->fd, slop, r); + osleave(); + if(r <= 0){ + FS(c)->offset = n; + return 0; + } + n += r; + } + FS(c)->offset = offset; + } + osenter(); + r = read(FS(c)->fd, va, count); + osleave(); + if(r < 0) + return r; + FS(c)->offset = offset+r; + return r; +} + +long +fsread(Chan *c, void *va, long n, vlong offset) +{ + int r; + + if(c->qid.type & QTDIR){ /* need to maintain offset only for directories */ + qlock(FS(c)); + if(waserror()){ + qunlock(FS(c)); + nexterror(); + } + r = fsdirread(c, va, n, offset); + poperror(); + qunlock(FS(c)); + }else{ + osenter(); + r = pread(FS(c)->fd, va, n, offset); + osleave(); + } + if(r < 0) + fserr(FS(c)); + return r; +} + +long +fswrite(Chan *c, void *va, long n, vlong offset) +{ + int r; + + osenter(); + r = pwrite(FS(c)->fd, va, n, offset); + osleave(); + if(r < 0) + fserr(FS(c)); + return r; +} + +void +fsremove(Chan *c) +{ + int r; + + if(waserror()){ + fsfree(c); + nexterror(); + } + osenter(); + r = remove(FS(c)->name->s); + osleave(); + if(r < 0) + fserr(FS(c)); + poperror(); + fsfree(c); +} + +int +fswstat(Chan *c, uchar *dp, int n) +{ + osenter(); + if(FS(c)->fd >= 0) + n = fwstat(FS(c)->fd, dp, n); + else + n = wstat(FS(c)->name->s, dp, n); + osleave(); + if(n < 0) + fserr(FS(c)); + return n; +} + +void +setid(char *name, int owner) +{ + if(!owner || iseve()) + kstrdup(&up->env->user, name); +} + +Dev fsdevtab = { + 'U', + "fs", + + devinit, + fsattach, + fswalk, + fsstat, + fsopen, + fscreate, + fsclose, + fsread, + devbread, + fswrite, + devbwrite, + fsremove, + fswstat +}; diff --git a/emu/Plan9/devsrv9.c b/emu/Plan9/devsrv9.c new file mode 100644 index 00000000..7ea26dfb --- /dev/null +++ b/emu/Plan9/devsrv9.c @@ -0,0 +1,395 @@ +#include "dat.h" +#include "fns.h" +#include "error.h" + +typedef struct Srv Srv; +struct Srv +{ + Ref; + int fd; /* fd for opened /srv or /srv/X, or -1 */ + int sfd; /* fd for created /srv entry or -1 */ + uvlong path; + Srv *next; +}; + +static QLock srv9lk; +static Srv *srv9; +static Srv *srvroot; + +static char* +srvname(Chan *c) +{ + char *p; + + p = strrchr(c->name->s, '/'); + if(p == nil) + return ""; + return p+1; +} + +static Srv* +srvget(uvlong path) +{ + Srv *sv; + + qlock(&srv9lk); + for(sv = srv9; sv != nil; sv = sv->next) + if(sv->path == path){ + incref(sv); + qunlock(&srv9lk); + return sv; + } + sv = smalloc(sizeof(*sv)); + sv->path = path; + sv->fd = -1; + sv->sfd = -1; + sv->ref = 1; + sv->next = srv9; + srv9 = sv; + qunlock(&srv9lk); + return sv; +} + +static void +srvput(Srv *sv) +{ + Srv **l; + int fd, sfd; + + if(sv != nil && decref(sv) == 0){ + qlock(&srv9lk); + for(l = &srv9; *l != nil; l = &(*l)->next) + if(*l == sv){ + *l = sv->next; + break; + } + qunlock(&srv9lk); + fd = sv->fd; + sfd = sv->sfd; + free(sv); + if(sfd >= 0){ + osenter(); + close(sfd); + osleave(); + } + if(fd >= 0){ + osenter(); + close(fd); + osleave(); + } + } +} + +static void +srv9init(void) +{ + Srv *sv; + + sv = mallocz(sizeof(*srvroot), 1); + sv->path = 0; + sv->fd = -1; + sv->ref = 1; /* subsequently never reaches zero */ + srvroot = srv9 = sv; +} + +static Chan* +srv9attach(char *spec) +{ + Chan *c; + + if(*spec) + error(Ebadspec); + c = devattach(L'₪', spec); + if(c != nil){ + incref(srvroot); + c->aux = srvroot; + } + return c; +} + +static Walkqid* +srv9walk(Chan *c, Chan *nc, char **name, int nname) +{ + int j, alloc; + Walkqid *wq; + char *n; + Dir *d; + + if(nname > 0) + isdir(c); + + alloc = 0; + wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); + if(waserror()){ + if(alloc) + cclose(wq->clone); + free(wq); + return nil; + } + if(nc == nil){ + nc = devclone(c); + nc->type = 0; /* device doesn't know about this channel yet */ + alloc = 1; + } + wq->clone = nc; + + for(j=0; j<nname; j++){ + if(!(nc->qid.type&QTDIR)){ + if(j==0) + error(Enotdir); + break; + } + n = name[j]; + if(strcmp(n, ".") != 0 && strcmp(n, "..") != 0){ + snprint(up->genbuf, sizeof(up->genbuf), "/srv/%s", n); + d = dirstat(up->genbuf); + if(d == nil){ + if(j == 0) + error(Enonexist); + kstrcpy(up->env->errstr, Enonexist, ERRMAX); + break; + } + nc->qid = d->qid; + free(d); + } + wq->qid[wq->nqid++] = nc->qid; + } + poperror(); + if(wq->nqid < nname){ + if(alloc) + cclose(wq->clone); + wq->clone = nil; + }else{ + /* attach cloned channel to device */ + wq->clone->type = c->type; + if(wq->clone != c) + nc->aux = srvget(nc->qid.path); + } + return wq; +} + +static int +srv9stat(Chan *c, uchar *db, int n) +{ + Srv *sv; + Dir d; + + if(c->qid.type & QTDIR){ + devdir(c, c->qid, "#₪", 0, eve, 0775, &d); + n = convD2M(&d, db, n); + if(n == 0) + error(Eshortstat); + return n; + } + sv = c->aux; + if(sv->fd >= 0){ + osenter(); + n = fstat(sv->fd, db, n); + osleave(); + }else{ + osenter(); + n = stat(srvname(c), db, n); + osleave(); + } + return n; +} + +static Chan* +srv9open(Chan *c, int omode) +{ + Srv *sv; + char *args[10]; + int fd[2], i, ifd, is9p; + Dir *d; + + sv = c->aux; + if(c->qid.type == QTDIR){ + osenter(); + sv->fd = open("/srv", omode); + osleave(); + if(sv->fd < 0) + oserror(); + c->mode = omode; + c->flag |= COPEN; + c->offset = 0; + return c; + } + + if(omode&OTRUNC || openmode(omode) != ORDWR) + error(Eperm); + if(sv->fd < 0){ + snprint(up->genbuf, sizeof(up->genbuf), "/srv/%s", srvname(c)); + + /* check permission */ + osenter(); + ifd = open(up->genbuf, omode); + osleave(); + if(ifd < 0) + oserror(); + osenter(); + d = dirfstat(ifd); + is9p = d != nil && d->qid.type & QTMOUNT; + free(d); + osleave(); + + if(is9p){ + close(ifd); + + /* spawn exportfs */ + args[0] = "exportfs"; + args[1] = "-S"; + args[2] = up->genbuf; + args[3] = nil; + if(pipe(fd) < 0) + oserror(); + /* TO DO: without RFMEM there's a copy made of each page touched by any kproc until the exec */ + switch(rfork(RFPROC|RFNOWAIT|RFREND|RFFDG|RFNAMEG|RFENVG)){ /* no sharing except NOTEG */ + case -1: + oserrstr(up->genbuf, sizeof(up->genbuf)); + close(fd[0]); + close(fd[1]); + error(up->genbuf); + case 0: + for(i=3; i<MAXNFD; i++) + if(i != fd[1]) + close(i); + dup(fd[1], 0); + if(fd[0] != 0) + close(fd[0]); + dup(0, 1); + exec("/bin/exportfs", args); + exits("exportfs failed"); + default: + sv->fd = fd[0]; + close(fd[1]); + break; + } + }else + sv->fd = ifd; + } + + c->mode = ORDWR; + c->offset = 0; + c->flag |= COPEN; + return c; +} + +static void +srv9close(Chan *c) +{ + srvput(c->aux); +} + +static long +srv9read(Chan *c, void *va, long n, vlong off) +{ + Srv *sv; + + sv = c->aux; + osenter(); + n = pread(sv->fd, va, n, off); + osleave(); + if(n < 0) + oserror(); + return n; +} + +static long +srv9write(Chan *c, void *va, long n, vlong off) +{ + Srv *sv; + + sv = c->aux; + osenter(); + n = pwrite(sv->fd, va, n, off); + osleave(); + if(n == 0) + error(Ehungup); + if(n < 0) + oserror(); + return n; +} + +static void +srv9create(Chan *c, char *name, int omode, ulong perm) +{ + Srv *sv; + int sfd, fd[2]; + vlong path; + Dir *d; + + if(openmode(omode) != ORDWR) + error(Eperm); + + if(pipe(fd) < 0) + oserror(); + if(waserror()){ + close(fd[0]); + close(fd[1]); + nexterror(); + } + + snprint(up->genbuf, sizeof(up->genbuf), "/srv/%s", name); + osenter(); + sfd = create(up->genbuf, OWRITE|ORCLOSE, perm); + osleave(); + if(sfd < 0) + oserror(); + if(waserror()){ + close(sfd); + nexterror(); + } + osenter(); + if(fprint(sfd, "%d", fd[1]) < 0){ + osleave(); + oserror(); + } + d = dirfstat(sfd); + osleave(); + if(d != nil){ + path = d->qid.path; + free(d); + }else + oserror(); + + poperror(); + poperror(); + close(fd[1]); + + if(waserror()){ + close(sfd); + close(fd[0]); + nexterror(); + } + sv = srvget(path); + sv->fd = fd[0]; + sv->sfd = sfd; + poperror(); + + srvput((Srv*)c->aux); + c->qid.type = QTFILE; + c->qid.path = path; + c->aux = sv; + c->flag |= COPEN; + c->mode = ORDWR; + c->offset = 0; +} + +Dev srv9devtab = { + L'₪', + "srv9", + + srv9init, + srv9attach, + srv9walk, + srv9stat, + srv9open, + srv9create, /* TO DO */ + srv9close, + srv9read, + devbread, + srv9write, + devbwrite, + devremove, /* TO DO */ + devwstat, /* TO DO */ +}; diff --git a/emu/Plan9/emu b/emu/Plan9/emu new file mode 100644 index 00000000..0a6c0f53 --- /dev/null +++ b/emu/Plan9/emu @@ -0,0 +1,109 @@ +dev + root + cons + env + mnt + pipe + prog + prof + srv + dup + ssl + cap + fs + cmd cmd + indir + sign + + draw win + pointer + + dynld + mem + srv9 + +# ip and eia are simply bound in from Plan 9 + +lib + interp + tk + freetype + math + draw + + memlayer + memdraw + keyring + sec + mp + dynld + 9 + +link + +mod + sys + draw + + tk + math +# srv not used on Plan 9 + keyring + loader + freetype + +port + alloc + cache + chan + dev + dial + dis + discall + env + error + errstr + exception + exportfs + exptab + inferno + latin1 + main + parse + pgrp + print + proc + qio + random + sysfile + uqid + +code + +init + emuinit + +root + /chan / + /dev / + /fd / + /prog / + /net / + /net.alt / + /nvfs / + /env / + /root / + /srv / +# /tmp / +# /dis +# /env +# /n +# /net +# /nvfs / +# /prog +# /icons +# /osinit.dis +# /dis/emuinit.dis +# /dis/lib/auth.dis +# /dis/lib/ssl.dis +# /n/local / diff --git a/emu/Plan9/emusig b/emu/Plan9/emusig new file mode 100644 index 00000000..1975a4cc --- /dev/null +++ b/emu/Plan9/emusig @@ -0,0 +1,95 @@ +dev + root + cons + env + mnt + pipe + prog + prof + srv + ssl + cap + fs + cmd cmd + indir + sign + + draw win + +# ip and eia are simply bound in from Plan 9 + +lib + interp + tk + freetype + math + draw + memlayer + memdraw + keyring + crypt + 9 + +link + +mod + sys + draw + tk + math +# srv not used on Plan 9 + keyring + loader + freetype + +port + alloc + cache + chan + dev + dial + dis + discall + env + error + errstr + exception + exportfs + inferno + latin1 + main + parse + pgrp + print + proc + qio + sysfile + uqid + +code + +init + emuinit + +root + /dev / + /prog / + /net / + /net.alt / + /chan / + /nvfs / + /env / +# /chan +# /dev +# /dis +# /env +# /n +# /net +# /nvfs / +# /prog +# /icons +# /osinit.dis +# /dis/emuinit.dis +# /dis/lib/auth.dis +# /dis/lib/ssl.dis +# /n/local / diff --git a/emu/Plan9/mkfile b/emu/Plan9/mkfile new file mode 100644 index 00000000..a7266830 --- /dev/null +++ b/emu/Plan9/mkfile @@ -0,0 +1,45 @@ +SYSTARG=Plan9 +OBJTYPE=$objtype +<../../mkconfig + +#Configurable parameters + +CONF=emu #default configuration +CONFLIST=emu +CLEANCONFLIST= + +INSTALLDIR=$ROOT/$SYSTARG/$OBJTYPE/bin #path of directory where kernel is installed + +#end configurable parameters + +<$ROOT/mkfiles/mkfile-$SYSTARG-$OBJTYPE #set vars based on target system + +<| $SHELLNAME ../port/mkdevlist $CONF #sets $IP, $DEVS, $PORT, $LIBS + +OBJ=\ + asm-$OBJTYPE.$O\ + os.$O\ + $CONF.root.$O\ + $DEVS\ + $PORT\ + + +HFILES=\ + +CFLAGS='-DROOT="'$ROOT'"' -DEMU -I. -I../port -I$ROOT/$SYSTARG/$OBJTYPE/include -I$ROOT/include -I$ROOT/libinterp $CTHREADFLAGS $CFLAGS $EMUOPTIONS +KERNDATE=`{$NDATE} + +default:V: $O.$CONF + +<../port/portmkfile + +$O.$CONF: $OBJ $CONF.c $CONF.root.h $LIBFILES + $CC $CFLAGS '-DKERNDATE='$KERNDATE $CONF.c + $LD -o $target $OBJ $CONF.$O $LIBFILES $SYSLIBS + +safeinstall:V: $O.$CONF + mv $INSTALLDIR/$CONF $INSTALLDIR/$CONF.`{date -n} + cp $O.$CONF $INSTALLDIR/$CONF + +install:V: $O.$CONF + cp $O.$CONF $INSTALLDIR/$CONF diff --git a/emu/Plan9/os.c b/emu/Plan9/os.c new file mode 100644 index 00000000..d681ec67 --- /dev/null +++ b/emu/Plan9/os.c @@ -0,0 +1,422 @@ +#include "dat.h" +#include "fns.h" +#include "error.h" + +enum +{ + KSTACK = 16*1024, + DELETE = 0x7F, +}; + +Proc **Xup; + +extern void killrefresh(void); +extern void tramp(char*, void (*)(void*), void*); + +extern int usenewwin; + +int *ustack; /* address on unshared stack: see vstack in asm*.s */ +extern int dflag; +char *hosttype = "Plan9"; +char *cputype; + +void +osblock(void) +{ + rendezvous(up, nil); +} + +void +osready(Proc *p) +{ + rendezvous(p, nil); +} + +void +pexit(char *msg, int) +{ + Osenv *e; + + USED(msg); + + lock(&procs.l); + if(up->prev) + up->prev->next = up->next; + else + procs.head = up->next; + + if(up->next) + up->next->prev = up->prev; + else + procs.tail = up->prev; + unlock(&procs.l); + +/* print("pexit: %s: %s\n", up->text, msg); /**/ + e = up->env; + if(e != nil) { + closefgrp(e->fgrp); + closepgrp(e->pgrp); + closeegrp(e->egrp); + closesigs(e->sigs); + } + free(e->user); + free(up->prog); + up->prog = nil; + up->type = Moribund; + longjmp(up->privstack, 1); +} + +int +kproc(char *name, void (*func)(void*), void *arg, int flags) +{ + int pid; + Proc *p; + Pgrp *pg; + Fgrp *fg; + Egrp *eg; + + p = newproc(); + if(p == nil) + panic("kproc: no memory"); + p->kstack = mallocz(KSTACK, 0); + if(p->kstack == nil) + panic("kproc: no memory"); + + if(flags & KPDUPPG) { + pg = up->env->pgrp; + incref(&pg->r); + p->env->pgrp = pg; + } + if(flags & KPDUPFDG) { + fg = up->env->fgrp; + incref(&fg->r); + p->env->fgrp = fg; + } + if(flags & KPDUPENVG) { + eg = up->env->egrp; + incref(&eg->r); + p->env->egrp = eg; + } + + p->env->uid = up->env->uid; + p->env->gid = up->env->gid; + kstrdup(&p->env->user, up->env->user); + + strcpy(p->text, name); + + p->func = func; + p->arg = arg; + + lock(&procs.l); + if(procs.tail != nil) { + p->prev = procs.tail; + procs.tail->next = p; + } + else { + procs.head = p; + p->prev = nil; + } + procs.tail = p; + unlock(&procs.l); + + /* + * switch back to the unshared stack to do the fork + * only the parent returns from kproc + */ + up->kid = p; + up->kidsp = p->kstack; + pid = setjmp(up->sharestack); + if(pid == 0) + longjmp(up->privstack, 1); + return pid; +} + +void +traphandler(void *reg, char *msg) +{ + int intwait; + + intwait = up->intwait; + up->intwait = 0; + /* Ignore pipe writes from devcmd */ + if(strstr(msg, "write on closed pipe") != nil) + noted(NCONT); + + if(sflag) { + if(intwait && strcmp(msg, Eintr) == 0) + noted(NCONT); + else + noted(NDFLT); + } + if(intwait == 0) + disfault(reg, msg); + noted(NCONT); +} + +int +readfile(char *path, char *buf, int n) +{ + int fd; + + fd = open(path, OREAD); + if(fd >= 0) { + n = read(fd, buf, n-1); + if(n > 0) /* both calls to readfile() have a ``default'' */ + buf[n] = '\0'; + close(fd); + return n; + } + return 0; +} + +static void +dobinds(void) +{ + char dir[MAXROOT+9]; + + snprint(dir, sizeof(dir), "%s/net", rootdir); + bind("/net", dir, MREPL); + + snprint(dir, sizeof(dir), "%s/net.alt", rootdir); + bind("/net.alt", dir, MREPL); + + snprint(dir, sizeof(dir), "%s/dev", rootdir); + bind("#t", dir, MAFTER); + bind("#A", dir, MAFTER); +} + +void +libinit(char *imod) +{ + char *sp; + Proc *xup, *p; + int fd, n, pid; + char nbuf[64]; + + xup = nil; + Xup = &xup; + + /* + * setup personality + */ + if(readfile("/dev/user", nbuf, sizeof nbuf)) + kstrdup(&eve, nbuf); + if(readfile("/dev/sysname", nbuf, sizeof nbuf)) + kstrdup(&ossysname, nbuf); + if(readfile("/env/cputype", nbuf, sizeof nbuf)) + kstrdup(&cputype, nbuf); + + /* + * guess at a safe stack for vstack + */ + ustack = &fd; + + rfork(RFNAMEG|RFREND); + + if(!dflag){ + fd = open("/dev/consctl", OWRITE); + if(fd < 0) + fprint(2, "libinit: open /dev/consctl: %r\n"); + n = write(fd, "rawon", 5); + if(n != 5) + fprint(2, "keyboard rawon (n=%d, %r)\n", n); + } + + osmillisec(); /* set the epoch */ + dobinds(); + + notify(traphandler); + + /* + * dummy up a up and stack so the first proc + * calls emuinit after setting up his private jmp_buf + */ + p = newproc(); + p->kstack = mallocz(KSTACK, 0); + if(p == nil || p->kstack == nil) + panic("libinit: no memory"); + sp = p->kstack; + p->func = emuinit; + p->arg = imod; + + /* + * set up a stack for forking kids on separate stacks. + * longjmp back here from kproc. + */ + while(setjmp(p->privstack)){ + if(up->type == Moribund){ + free(up->kstack); + free(up); + _exits(""); + } + p = up->kid; + sp = up->kidsp; + up->kid = nil; + switch(pid = rfork(RFPROC|RFMEM|RFNOWAIT)){ + case 0: + /* + * send the kid around the loop to set up his private jmp_buf + */ + break; + default: + /* + * parent just returns to his shared stack in kproc + */ + longjmp(up->sharestack, pid); + panic("longjmp failed"); + } + } + + /* + * you get here only once per Proc + * go to the shared memory stack + */ + up = p; + up->pid = up->sigid = getpid(); + tramp(sp+KSTACK, up->func, up->arg); + panic("tramp returned"); +} + +void +oshostintr(Proc *p) +{ + postnote(PNPROC, p->sigid, Eintr); +} + +void +oslongjmp(void *regs, osjmpbuf env, int val) +{ + if(regs != nil) + notejmp(regs, env, val); + else + longjmp(env, val); +} + +void +osreboot(char*, char**) +{ +} + +void +cleanexit(int x) +{ + USED(x); + killrefresh(); + postnote(PNGROUP, getpid(), "interrupt"); + exits("interrupt"); +} + +int +readkbd(void) +{ + int n; + char buf[1]; + + n = read(0, buf, sizeof(buf)); + if(n < 0) + fprint(2, "emu: keyboard read error: %r\n"); + if(n <= 0) + pexit("keyboard", 0); + switch(buf[0]) { + case DELETE: + cleanexit(0); + case '\r': + buf[0] = '\n'; + } + return buf[0]; +} + +static vlong +b2v(uchar *p) +{ + int i; + vlong v; + + v = 0; + for(i=0; i<sizeof(uvlong); i++) + v = (v<<8)|p[i]; + return v; +} + +vlong +nsec(void) +{ + int n; + static int nsecfd = -1; + uchar buf[sizeof(uvlong)]; + + if(nsecfd < 0){ + nsecfd = open("/dev/bintime", OREAD|OCEXEC); /* never closed */ + if(nsecfd<0){ + fprint(2,"can't open /dev/bintime: %r\n"); + return 0; + } + } + n = read(nsecfd, buf, sizeof(buf)); + if(n!=sizeof(buf)) { + fprint(2,"read err on /dev/bintime: %r\n"); + return 0; + } + return b2v(buf); +} + +long +osmillisec(void) +{ + static vlong nsec0 = 0; + + if(nsec0 == 0){ + nsec0 = nsec(); + return 0; + } + return (nsec()-nsec0)/1000000; +} + +/* + * Return the time since the epoch in microseconds + * The epoch is defined at 1 Jan 1970 + */ +vlong +osusectime(void) +{ + return nsec()/1000; +} + +int +osmillisleep(ulong milsec) +{ + sleep(milsec); + return 0; +} + +int +limbosleep(ulong milsec) +{ + return osmillisleep(milsec); +} + +void +osyield(void) +{ + sleep(0); +} + +void +ospause(void) +{ + for(;;) + sleep(1000000); +} + +void +oslopri(void) +{ + int fd; + char buf[32]; + + snprint(buf, sizeof(buf), "/proc/%d/ctl", getpid()); + if((fd = open(buf, OWRITE)) >= 0){ + fprint(fd, "pri 8"); + close(fd); + } +} diff --git a/emu/Plan9/win.c b/emu/Plan9/win.c new file mode 100644 index 00000000..2f280853 --- /dev/null +++ b/emu/Plan9/win.c @@ -0,0 +1,564 @@ +#include "dat.h" +#include "fns.h" +#include "kernel.h" +#include "error.h" + +#include <draw.h> +#include <memdraw.h> +#include <cursor.h> +#include "keyboard.h" + +enum +{ + Margin = 4, + Lsize = 100, +}; + +extern Memimage *screenimage; + +static ulong* attachwindow(Rectangle*, ulong*, int*, int*); + +static void plan9readmouse(void*); +static void plan9readkeybd(void*); +static int mapspecials(char *s1, char *s2, int *n); + +int usenewwin = 1; +int kbdiscons; +static int truedepth; + +static int datafd; +static int ctlfd; +static int mousefd = -1; +static int keybdfd; +static int mousepid = -1; +static int keybdpid = -1; +static int cursfd; +static char winname[64]; + +/* Following updated by attachwindow() asynchronously */ +static QLock ql; +static Rectangle tiler; +static ulong* data; +static uchar* loadbuf; +static int cursfd; +static int imageid; +static Rectangle imager; +static uchar *chunk; +static int chunksize; +static int dispbufsize; + +#define NINFO 12*12 +#define HDR 21 + + +void +killrefresh(void) +{ + if(mousepid < 0) + return; + close(mousefd); + close(ctlfd); + close(datafd); + postnote(PNPROC, mousepid, Eintr); + postnote(PNPROC, keybdpid, Eintr); +} + +uchar* +attachscreen(Rectangle *r, ulong *chan, int *d, int *width, int *softscreen) +{ + int fd; + char *p, buf[128], info[NINFO+1]; + + if(usenewwin){ + p = getenv("wsys"); + if(p == nil) + return nil; + + fd = open(p, ORDWR); + if(fd < 0) { + fprint(2, "attachscreen: can't open window manager: %r\n"); + return nil; + } + sprint(buf, "new -dx %d -dy %d", Xsize+2*Margin, Ysize+2*Margin); + if(mount(fd, -1, "/mnt/wsys", MREPL, buf) < 0) { + fprint(2, "attachscreen: can't mount window manager: %r\n"); + return nil; + } + if(bind("/mnt/wsys", "/dev", MBEFORE) < 0){ + fprint(2, "attachscreen: can't bind /mnt/wsys before /dev: %r\n"); + return nil; + } + } + + cursfd = open("/dev/cursor", OWRITE); + if(cursfd < 0) { + fprint(2, "attachscreen: open cursor: %r\n"); + return nil; + } + + /* Set up graphics window console (chars->gkbdq) */ + keybdfd = open("/dev/cons", OREAD); + if(keybdfd < 0) { + fprint(2, "attachscreen: open keyboard: %r\n"); + return nil; + } + mousefd = open("/dev/mouse", ORDWR); + if(mousefd < 0){ + fprint(2, "attachscreen: can't open mouse: %r\n"); + return nil; + } + if(usenewwin || 1){ + fd = open("/dev/consctl", OWRITE); + if(fd < 0) + fprint(2, "attachscreen: open /dev/consctl: %r\n"); + if(write(fd, "rawon", 5) != 5) + fprint(2, "attachscreen: write /dev/consctl: %r\n"); + } + + /* Set up graphics files */ + ctlfd = open("/dev/draw/new", ORDWR); + if(ctlfd < 0){ + fprint(2, "attachscreen: can't open graphics control file: %r\n"); + return nil; + } + if(read(ctlfd, info, sizeof info) < NINFO){ + close(ctlfd); + fprint(2, "attachscreen: can't read graphics control file: %r\n"); + return nil; + } + sprint(buf, "/dev/draw/%d/data", atoi(info+0*12)); + datafd = open(buf, ORDWR|OCEXEC); + if(datafd < 0){ + close(ctlfd); + fprint(2, "attachscreen: can't read graphics data file: %r\n"); + return nil; + } + dispbufsize = iounit(datafd); + if(dispbufsize <= 0) + dispbufsize = 8000; + if(dispbufsize < 512){ + close(ctlfd); + close(datafd); + fprint(2, "attachscreen: iounit %d too small\n", dispbufsize); + return nil; + } + chunksize = dispbufsize - 64; + + if(attachwindow(r, chan, d, width) == nil){ + close(ctlfd); + close(datafd); + return nil; + } + + mousepid = kproc("readmouse", plan9readmouse, nil, 0); + keybdpid = kproc("readkbd", plan9readkeybd, nil, 0); + + fd = open("/dev/label", OWRITE); + if(fd >= 0){ + snprint(buf, sizeof(buf), "inferno %d", getpid()); + write(fd, buf, strlen(buf)); + close(fd); + } + + *softscreen = 1; + return (uchar*)data; +} + +static ulong* +attachwindow(Rectangle *r, ulong *chan, int *d, int *width) +{ + int n, fd, nb; + char buf[256]; + uchar ubuf[128]; + ulong imagechan; + + /* + * Discover name of window + */ + fd = open("/mnt/wsys/winname", OREAD); + if(fd<0 || (n=read(fd, winname, sizeof winname))<=0){ + fprint(2, "attachwindow: can only run inferno under rio, not stand-alone\n"); + return nil; + } + close(fd); + /* + * If had previous window, release it + */ + if(imageid > 0){ + ubuf[0] = 'f'; + BPLONG(ubuf+1, imageid); + if(write(datafd, ubuf, 1+4) != 1+4) + fprint(2, "attachwindow: cannot free old window: %r\n"); + } + /* + * Allocate image pointing to window, and discover its ID + */ + ubuf[0] = 'n'; + ++imageid; + BPLONG(ubuf+1, imageid); + ubuf[5] = n; + memmove(ubuf+6, winname, n); + if(write(datafd, ubuf, 6+n) != 6+n){ + fprint(2, "attachwindow: cannot bind %d to window id '%s': %r\n", imageid, winname); + return nil; + } + if(read(ctlfd, buf, sizeof buf) < 12*12){ + fprint(2, "attachwindow: cannot read window id: %r\n"); + return nil; + } + imagechan = strtochan(buf+2*12); + truedepth = chantodepth(imagechan); + if(truedepth == 0){ + fprint(2, "attachwindow: cannot handle window depth specifier %.12s\n", buf+2*12); + return nil; + } + + /* + * Report back + */ + if(chan != nil) + *chan = imagechan; + if(d != nil) + *d = chantodepth(imagechan); + nb = 0; + if(r != nil){ + Xsize = atoi(buf+6*12)-atoi(buf+4*12)-2*Margin; + Ysize = atoi(buf+7*12)-atoi(buf+5*12)-2*Margin; + r->min.x = 0; + r->min.y = 0; + r->max.x = Xsize; + r->max.y = Ysize; + nb = bytesperline(*r, truedepth); + data = malloc(nb*Ysize); + loadbuf = malloc(nb*Lsize+1); + chunk = malloc(HDR+chunksize+5); /* +5 for flush (1 old, 5 new) */ + } + imager.min.x = atoi(buf+4*12); + imager.min.y = atoi(buf+5*12); + imager.max.x = atoi(buf+6*12); + imager.max.y = atoi(buf+7*12); + + if(width != nil) + *width = nb/4; + + tiler.min.x = atoi(buf+4*12)+Margin; + tiler.min.y = atoi(buf+5*12)+Margin; + tiler.max.x = atoi(buf+6*12)-Margin; + tiler.max.y = atoi(buf+7*12)-Margin; + + return data; +} + +static int +plan9loadimage(Rectangle r, uchar *data, int ndata) +{ + long dy; + int n, bpl; + + if(!rectinrect(r, imager)){ + werrstr("loadimage: bad rectangle"); + return -1; + } + bpl = bytesperline(r, truedepth); + n = bpl*Dy(r); + if(n > ndata){ + werrstr("loadimage: insufficient data"); + return -1; + } + ndata = 0; + while(r.max.y > r.min.y){ + dy = r.max.y - r.min.y; + if(dy*bpl> chunksize) + dy = chunksize/bpl; + n = dy*bpl; + chunk[0] = 'y'; + BPLONG(chunk+1, imageid); + BPLONG(chunk+5, r.min.x); + BPLONG(chunk+9, r.min.y); + BPLONG(chunk+13, r.max.x); + BPLONG(chunk+17, r.min.y+dy); + memmove(chunk+21, data, n); + ndata += n; + data += n; + r.min.y += dy; + n += 21; + if(r.min.y >= r.max.y) /* flush to screen */ + chunk[n++] = 'v'; + if(write(datafd, chunk, n) != n) + return -1; + } + return ndata; +} + +static void +_flushmemscreen(Rectangle r) +{ + int n, dy, l; + Rectangle rr; + + if(data == nil || loadbuf == nil || chunk==nil) + return; + if(!rectclip(&r, Rect(0, 0, Xsize, Ysize))) + return; + if(!rectclip(&r, Rect(0, 0, Dx(tiler), Dy(tiler)))) + return; + if(Dx(r)<=0 || Dy(r)<=0) + return; + l = bytesperline(r, truedepth); + while(r.min.y < r.max.y){ + dy = Dy(r); + if(dy > Lsize) + dy = Lsize; + rr = r; + rr.max.y = rr.min.y+dy; + n = unloadmemimage(screenimage, rr, loadbuf, l*dy); + /* offset from (0,0) to window */ + rr.min.x += tiler.min.x; + rr.min.y += tiler.min.y; + rr.max.x += tiler.min.x; + rr.max.y += tiler.min.y; + if(plan9loadimage(rr, loadbuf, n) != n) + fprint(2, "flushmemscreen: %d bytes: %r\n", n); + r.min.y += dy; + } +} + +void +flushmemscreen(Rectangle r) +{ + qlock(&ql); + _flushmemscreen(r); + qunlock(&ql); +} + +void +drawcursor(Drawcursor *c) +{ + int j, i, h, w, bpl; + uchar *bc, *bs, *cclr, *cset, curs[2*4+2*2*16]; + + /* Set the default system cursor */ + if(c->data == nil) { + write(cursfd, curs, 0); + return; + } + + BPLONG(curs+0*4, c->hotx); + BPLONG(curs+1*4, c->hoty); + + w = (c->maxx-c->minx); + h = (c->maxy-c->miny)/2; + + cclr = curs+2*4; + cset = curs+2*4+2*16; + bpl = bytesperline(Rect(c->minx, c->miny, c->maxx, c->maxy), 1); + bc = c->data; + bs = c->data + h*bpl; + + if(h > 16) + h = 16; + if(w > 16) + w = 16; + w /= 8; + for(i = 0; i < h; i++) { + for(j = 0; j < w; j++) { + cclr[j] = bc[j]; + cset[j] = bs[j]; + } + bc += bpl; + bs += bpl; + cclr += 2; + cset += 2; + } + write(cursfd, curs, sizeof curs); +} + +static int +checkmouse(char *buf, int n) +{ + int x, y, tick, b; + static int lastb, lastt, lastx, lasty, lastclick; + + switch(n){ + default: + kwerrstr("atomouse: bad count"); + return -1; + + case 1+4*12: + if(buf[0] == 'r'){ + qlock(&ql); + if(attachwindow(nil, nil, nil, nil) == nil) { + qunlock(&ql); + return -1; + } + _flushmemscreen(Rect(0, 0, Xsize, Ysize)); + qunlock(&ql); + } + x = atoi(buf+1+0*12) - tiler.min.x; + y = atoi(buf+1+1*12) - tiler.min.y; + b = atoi(buf+1+2*12); + tick = atoi(buf+1+3*12); + if(b && lastb == 0){ /* button newly pressed */ + if(b==lastclick && tick-lastt<400 + && abs(x-lastx)<10 && abs(y-lasty)<10) + b |= (1<<8); + lastt = tick; + lastclick = b&0xff; + lastx = x; + lasty = y; + } + lastb = b&0xff; + //mouse.msec = tick; + mousetrack(b, x, y, 0); + return n; + } +} + +static void +plan9readmouse(void *v) +{ + int n; + char buf[128]; + + USED(v); + for(;;){ + n = read(mousefd, buf, sizeof(buf)); + if(n < 0) /* probably interrupted */ + _exits(0); + checkmouse(buf, n); + } +} + +static void +plan9readkeybd(void*) +{ + int n, partial; + char buf[32]; + char dbuf[32 * 3]; /* overestimate but safe */ + + partial = 0; + for(;;){ + n = read(keybdfd, buf + partial, sizeof(buf) - partial); + if(n < 0) /* probably interrupted */ + _exits(0); + partial += n; + n = mapspecials(dbuf, buf, &partial); + qproduce(gkbdq, dbuf, n); + } +} + +void +setpointer(int x, int y) +{ + char buf[50]; + int n; + + if(mousefd < 0) + return; + x += tiler.min.x; + y += tiler.min.y; + n = snprint(buf, sizeof buf, "m%11d %11d ", x, y); + write(mousefd, buf, n); +} + +/* + * plan9 keyboard codes; from /sys/include/keyboard.h; can't include directly + * because constant names clash. + */ +enum { + P9KF= 0xF000, /* Rune: beginning of private Unicode space */ + P9Spec= 0xF800, + /* KF|1, KF|2, ..., KF|0xC is F1, F2, ..., F12 */ + Khome= P9KF|0x0D, + Kup= P9KF|0x0E, + Kpgup= P9KF|0x0F, + Kprint= P9KF|0x10, + Kleft= P9KF|0x11, + Kright= P9KF|0x12, + Kdown= P9Spec|0x00, + Kview= P9Spec|0x00, + Kpgdown= P9KF|0x13, + Kins= P9KF|0x14, + Kend= KF|0x18, + + Kalt= P9KF|0x15, + Kshift= P9KF|0x16, + Kctl= P9KF|0x17, +}; + +/* + * translate plan 9 special characters from s2 (of length *n) into s1; + * return number of chars placed into s1. + * any trailing incomplete chars are moved to the beginning of s2, + * and *n set to the number moved there. + */ +static int +mapspecials(char *s1, char *s2, int *n) +{ + char *s, *d, *es2; + Rune r; + d = s1; + s = s2; + es2 = s2 + *n; + while (fullrune(s, es2 - s)) { + s += chartorune(&r, s); + switch (r) { + case Kshift: + r = LShift; + break; + case Kctl: + r = LCtrl; + break; + case Kalt: + r = LAlt; + break; + case Khome: + r = Home; + break; + case Kend: + r = End; + break; + case Kup: + r = Up; + break; + case Kdown: + r = Down; + break; + case Kleft: + r = Left; + break; + case Kright: + r = Right; + break; + case Kpgup: + r = Pgup; + break; + case Kpgdown: + r = Pgdown; + break; + case Kins: + r = Ins; + break; + /* + * function keys + */ + case P9KF|1: + case P9KF|2: + case P9KF|3: + case P9KF|4: + case P9KF|5: + case P9KF|6: + case P9KF|7: + case P9KF|8: + case P9KF|9: + case P9KF|10: + case P9KF|11: + case P9KF|12: + r = (r - P9KF) + KF; + } + d += runetochar(d, &r); + } + *n = es2 - s; + memmove(s2, s, *n); + return d - s1; +} |
