diff options
| author | Charles.Forsyth <devnull@localhost> | 2009-03-25 15:55:14 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2009-03-25 15:55:14 +0000 |
| commit | dfd1934d5e1ddbeb326f77fc0e52307c801a1a3e (patch) | |
| tree | f1e8b23278caae95e01d88b00421d6c3642357ef /emu/port/devdynld.c | |
| parent | 78dfdcbd59dc8f36975e7695933e3f753957474c (diff) | |
x20090325-1554
Diffstat (limited to 'emu/port/devdynld.c')
| -rw-r--r-- | emu/port/devdynld.c | 357 |
1 files changed, 357 insertions, 0 deletions
diff --git a/emu/port/devdynld.c b/emu/port/devdynld.c new file mode 100644 index 00000000..68084707 --- /dev/null +++ b/emu/port/devdynld.c @@ -0,0 +1,357 @@ +#include "dat.h" +#include "fns.h" +#include "error.h" +#include <a.out.h> +#include <dynld.h> + +#define DBG if(1) print + +extern ulong ndevs; + +enum +{ + Qdir, + Qdynld, + Qdynsyms, + + DEVCHAR = 'L', +}; + +static Dirtab dltab[] = +{ + ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, + "dynld", {Qdynld}, 0, 0644, + "dynsyms", {Qdynsyms}, 0, 0444, +}; + +enum +{ + DLdev, + DLudev, +}; + +static Cmdtab dlcmd[] = +{ + DLdev, "dev", 2, + DLudev, "udev", 2, +}; + +typedef struct Dyndev Dyndev; + +struct Dyndev +{ + char *path; + Dynobj *o; + Dev *dev; + Dyndev *next; +}; + +static Dyndev *loaded; +static QLock dllock; + +typedef struct Fd Fd; +struct Fd { + int fd; +}; + +static long +readfd(void *a, void *buf, long nbytes) +{ + return kread(((Fd*)a)->fd, buf, nbytes); +} + +static vlong +seekfd(void *a, vlong off, int t) +{ + return kseek(((Fd*)a)->fd, off, t); +} + +static void +errfd(char *s) +{ + kstrcpy(up->env->errstr, s, ERRMAX); +} + +static void +dlfree(Dyndev *l) +{ + if(l != nil){ + free(l->path); + dynobjfree(l->o); + free(l); + } +} + +static Dyndev* +dlload(char *path, Dynsym *tab, int ntab) +{ + Fd f; + Dyndev *l; + + f.fd = kopen(path, OREAD); + if(f.fd < 0) + error("cannot open"); + if(waserror()){ + kclose(f.fd); + nexterror(); + } + l = mallocz(sizeof(Dyndev), 1); + if(l == nil) + error(Enomem); + if(waserror()){ + dlfree(l); + nexterror(); + } + l->path = strdup(path); + if(l->path == nil) + error(Enomem); + l->o = dynloadgen(&f, readfd, seekfd, errfd, tab, ntab, 0); + if(l->o == nil) + error(up->env->errstr); + poperror(); + poperror(); + kclose(f.fd); + return l; +} + +static void +devload(char *path) +{ + int i; + Dyndev *l; + Dev *dev; + char devname[32]; + + l = dlload(path, _exporttab, dyntabsize(_exporttab)); + if(waserror()){ + dlfree(l); + nexterror(); + } + snprint(devname, sizeof(devname), "%sdevtab", "XXX"); /* TO DO */ + dev = dynimport(l->o, devname, signof(*dev)); + if(dev == nil) + error("no devtab"); + if(devno(dev->dc, 1) >= 0) + error("device loaded"); + for(i = 0; devtab[i] != nil; i++) + ; + if(i >= ndevs || devtab[i+1] != nil) + error("device table full"); + l->dev = devtab[i] = dev; + dev->init(); + l->next = loaded; + loaded = l; + poperror(); +} + +static void +devunload(char *path) +{ + int i, dc; + Dyndev *l, **ll; + + dc = 0; + if(strlen(path) == 1) + dc = path[0]; + for(ll = &loaded; *ll != nil; ll = &(*ll)->next){ + if(path != nil && strcmp(path, (*ll)->path) == 0) + break; + if(dc != 0 && (*ll)->dev && dc == (*ll)->dev->dc) + break; + } + if((l = *ll) != nil){ + for(i = 0; i < ndevs; i++) + if(l->dev == devtab[i]){ + devtab[i] = nil; + break; + } +/* + if(l->dev) + l->dev->shutdown(); +*/ + *ll = l->next; + dlfree(l); + } +} + +static long +readdl(void *a, ulong n, ulong offset) +{ + char *p; + Dyndev *l; + int m, len; + + m = 0; + for(l = loaded; l != nil; l = l->next) + m++; + m *= 48; + p = malloc(m); + if(p == nil) + error(Enomem); + if(waserror()){ + free(p); + nexterror(); + } + *p = 0; + len = 0; + for(l = loaded; l != nil; l = l->next) + if(l->dev) + len += snprint(p+len, m-len, "#%C\t%.8p\t%.8lux\t%s\n", + l->dev->dc, l->o->base, l->o->size, l->dev->name); + n = readstr(offset, a, n, p); + poperror(); + free(p); + return n; +} + +static long +readsyms(char *a, ulong n, ulong offset) +{ + char *p; + Dynsym *t; + long l, nr; + + p = malloc(READSTR); + if(p == nil) + error(Enomem); + if(waserror()){ + free(p); + nexterror(); + } + nr = 0; + for(t = _exporttab; n > 0 && t->name != nil; t++){ + l = snprint(p, READSTR, "%.8lux %.8lux %s\n", t->addr, t->sig, t->name); + if(offset >= l){ + offset -= l; + continue; + } + l = readstr(offset, a, n, p); + offset = 0; + n -= l; + a += l; + nr += l; + } + poperror(); + free(p); + return nr; +} + +static Chan* +dlattach(char *spec) +{ + return devattach(DEVCHAR, spec); +} + +static Walkqid* +dlwalk(Chan *c, Chan *nc, char **name, int nname) +{ + return devwalk(c, nc, name, nname, dltab, nelem(dltab), devgen); +} + +static int +dlstat(Chan *c, uchar *db, int n) +{ + return devstat(c, db, n, dltab, nelem(dltab), devgen); +} + +static Chan* +dlopen(Chan *c, int omode) +{ + return devopen(c, omode, dltab, nelem(dltab), devgen); +} + +static void +dlclose(Chan *c) +{ + USED(c); +} + +static long +dlread(Chan *c, void *a, long n, vlong voffset) +{ + switch((ulong)c->qid.path){ + case Qdir: + return devdirread(c, a, n, dltab, nelem(dltab), devgen); + case Qdynld: + return readdl(a, n, (ulong)voffset); + case Qdynsyms: + return readsyms(a, n, (ulong)voffset); + default: + error(Egreg); + } + return n; +} + +static long +dlwrite(Chan *c, void *a, long n, vlong voffset) +{ + Cmdbuf *cmd; + Cmdtab *ct; + + USED(voffset); + switch((ulong)c->qid.path){ + case Qdynld: + cmd = parsecmd(a, n); + qlock(&dllock); + if(waserror()){ + qunlock(&dllock); + free(cmd); + nexterror(); + } + ct = lookupcmd(cmd, dlcmd, nelem(dlcmd)); + switch(ct->index){ + case DLdev: + devload(cmd->f[1]); + break; + case DLudev: + devunload(cmd->f[1]); + break; + } + poperror(); + qunlock(&dllock); + free(cmd); + break; + default: + error(Egreg); + } + return n; +} + +Dev dynlddevtab = { + DEVCHAR, + "dynld", + + devinit, + dlattach, + dlwalk, + dlstat, + dlopen, + devcreate, + dlclose, + dlread, + devbread, + dlwrite, + devbwrite, + devremove, + devwstat, +}; + +/* auxiliary routines for dynamic loading of C modules */ + +Dynobj* +dynld(int fd) +{ + Fd f; + + f.fd = fd; + return dynloadgen(&f, readfd, seekfd, errfd, _exporttab, dyntabsize(_exporttab), 0); +} + +int +dynldable(int fd) +{ + Fd f; + + f.fd = fd; + return dynloadable(&f, readfd, seekfd); +} |
