commit 75e333c72ec94c920d3e2b816c5898afef5c999e
parent 1b56501dec4558883add215690efc848e12729a8
Author: Roberto Vargas <roberto.vargas@arm.com>
Date: Thu, 21 Feb 2019 16:45:59 +0000
[dev] Add bind()
This is a simple implementation of bind() that doesn't support
union filesystems. This behaviour is more similar to the old
unix link() than to bind and it only works for the root
filesystem.
Change-Id: Icd99b4dc840e16fd41d97b71b4680eae8b056181
Diffstat:
5 files changed, 131 insertions(+), 60 deletions(-)
diff --git a/drivers/dev.c b/drivers/dev.c
@@ -1,3 +1,4 @@
+#include <ctype.h>
#include <errno.h>
#include <string.h>
@@ -108,7 +109,7 @@ clone(Chan *c, Chan *nc)
return devtab[c->type]->clone(c, nc);
}
-static void
+void
chanclose(Chan *c)
{
c->qid = 0;
@@ -120,7 +121,7 @@ chanclose(Chan *c)
Chan *
namec(const char *name, int mode)
{
- int type;
+ int type, n, i;
const char *s;
Chan *c;
char elem[NAMELEN];
@@ -135,13 +136,19 @@ namec(const char *name, int mode)
errno = ENOENT;
return NULL;
}
- if (elem[1] != '\0') {
+
+ if ((type = devtype(elem[0])) < 0)
+ return NULL;
+
+ for (n = 0, i = 1; isdigit(elem[i]); i++)
+ n += elem[i] - '0';
+
+ if (elem[i] != '\0') {
errno = ENODEV;
return NULL;
}
- if ((type = devtype(elem[0])) < 0)
- return NULL;
- c = devtab[type]->attach(NULL);
+
+ c = devtab[type]->attach(n);
break;
default:
errno = ENOENT;
@@ -152,6 +159,8 @@ namec(const char *name, int mode)
return NULL;
for (s = next(s, elem); *elem; s = next(s, elem)) {
+ if ((c->qid & CHDIR) == 0)
+ goto notfound;
if (devtab[c->type]->walk(c, elem) < 0)
goto notfound;
}
@@ -182,15 +191,16 @@ devclone(Chan *c, Chan *nc)
}
Chan *
-devattach(const char *spec, int id)
+devattach(int id, int dev)
{
Chan *c;
int type;
if ((type = devtype(id)) < 0)
return NULL;
- if ((c = newchan(devtype(id))) == NULL)
+ if ((c = newchan(type)) == NULL)
return NULL;
+ c->dev = dev;
c->qid = CHDIR;
return c;
@@ -223,7 +233,7 @@ devwalk(Chan *c, const char *name, const Dirtab *tab, int ntab, Devgen *gen)
}
int
-devdirread(Chan *c,
+dirread(Chan *c,
unsigned char *buf, int nbytes,
const Dirtab *tab, int ntab,
Devgen *gen)
@@ -234,10 +244,10 @@ devdirread(Chan *c,
cnt = 0;
for (i = c->offset/DIRLEN; nbytes >= DIRLEN; i++) {
switch ((*gen)(c, tab, ntab, i, &dir)) {
- case -1:
- return cnt;
case 0:
- break;
+ return cnt;
+ case -1:
+ return (cnt > 0) ? cnt : -1;
case 1:
c->offset += DIRLEN;
n = dirtop9(&dir, buf + cnt, nbytes);
@@ -255,7 +265,7 @@ devgen(Chan *c, const Dirtab *tab, int ntab, int n, Dir *dir)
const Dirtab *dp;
if (!tab || n >= ntab)
- return -1;
+ return 0;
dp = &tab[n];
strcpy(dir->name, dp->name);
@@ -358,6 +368,7 @@ int
bind(char *new, char *where)
{
Chan *cw, *cn;
+ int (*fn)(Chan *, Chan *);
if ((cw = namec(where, O_READ)) == NULL)
goto err0;
@@ -370,7 +381,16 @@ bind(char *new, char *where)
if ((cn = namec(new, O_BIND)) == NULL)
goto err1;
- panic("not implemented");
+ fn = devtab[cw->type]->bind;
+ if (!fn) {
+ errno = EINVAL;
+ goto err2;
+ }
+
+ if ((*fn)(cw, cn) < 0)
+ goto err2;
+
+ chanclose(cw);
return 0;
@@ -391,7 +411,7 @@ idev(void)
for (c = fdset; c < clim; c++)
c->type = NODEV;
- if ((c = devattach(NULL, '/')) == NULL)
+ if ((c = devattach('/', 0)) == NULL)
panic("idev:attach");
if (!clone(c, &slash))
diff --git a/drivers/dev.h b/drivers/dev.h
@@ -25,9 +25,10 @@ struct dev {
char name[NAMELEN];
Chan * (*clone)(Chan *c, Chan *nc);
int (*walk)(Chan *c, const char *name);
- Chan * (*attach)(const char *spec);
+ Chan * (*attach)(int dev);
int (*read)(Chan *c, void *buf, int n);
int (*write)(Chan *c, void *buf, int n);
+ int (*bind)(Chan *cw, Chan *cn);
};
struct chan {
@@ -44,9 +45,10 @@ struct attr {
};
extern Chan *devclone(Chan *c, Chan *nc);
-extern Chan *devattach(const char *spec, int id);
+extern Chan *devattach(int id, int dev);
extern Chan *devclone(Chan *c, Chan *nc);
extern void devlink(void);
+extern void chanclose(Chan *c);
extern int devgen(Chan *c,
const Dirtab *tab, int ntab,
int n,
@@ -55,9 +57,9 @@ extern int devwalk(Chan *c,
const char *name,
const Dirtab *tab, int ntab,
Devgen *gen);
-extern int devdirread(Chan *c,
- unsigned char *buf, int nbytes,
- const Dirtab *tab, int ntab,
- Devgen *gen);
+extern int dirread(Chan *c,
+ unsigned char *buf, int nbytes,
+ const Dirtab *tab, int ntab,
+ Devgen *gen);
extern Dev *const devtab[];
diff --git a/drivers/devroot.c b/drivers/devroot.c
@@ -4,8 +4,11 @@
#include "dev.h"
enum Orootqid {
+ Qroot,
Qdev,
+ Qdevuart,
Qrealm,
+ Qmax,
};
static const Dirtab dirtab[] = {
@@ -13,31 +16,92 @@ static const Dirtab dirtab[] = {
{"realm", CHDIR | Qrealm, 0, O_READ},
};
+static const Dirtab devfstab[] = {
+ {"uart", CHDIR | Qdevuart, 0, O_READ},
+};
+
+static Chan *bindpoint[Qmax];
+
+static int
+gettab(Qid qid, const Dirtab **tab)
+{
+ switch (qid) {
+ case Qroot:
+ *tab = dirtab;
+ return NELEM(dirtab);
+ case Qdev:
+ *tab = devfstab;
+ return NELEM(devfstab);
+ case Qdevuart:
+ case Qrealm:
+ *tab = NULL;
+ return 0;
+ default:
+ panic("gettab");
+ }
+}
+
static int
rootwalk(Chan *c, const char *name)
{
- return devwalk(c,
- name,
- dirtab, NELEM(dirtab),
- devgen);
+ int n;
+ Qid qid;
+ Chan *mnt;
+ const Dirtab *tab;
+
+ n = gettab(c->qid & ~CHDIR, &tab);
+
+ if (devwalk(c, name, tab, n, devgen) < 0)
+ return -1;
+
+ qid = c->qid & ~CHDIR;
+ if (qid > Qmax)
+ panic("rootwalk");
+
+ mnt = bindpoint[qid];
+ if (mnt != NULL)
+ *c = *mnt;
+
+ return 1;
+}
+
+static int
+rootbind(Chan *cw, Chan *cn)
+{
+ Qid qid;
+ Chan *mnt;
+
+ qid = cw->qid & ~CHDIR;
+ if (qid > Qmax)
+ panic("rootbind");
+
+ mnt = bindpoint[qid];
+ if (mnt)
+ chanclose(mnt);
+
+ bindpoint[qid] = cn;
+
+ return 0;
}
static Chan *
-rootattach(const char *spec)
+rootattach(int dev)
{
- return devattach(spec, '/');
+ return devattach('/', dev);
}
static int
rootread(Chan *c, void *buf, int n)
{
+ const Dirtab *tab;
+ int ntab;
+
if ((c->qid & CHDIR) == 0)
return -1;
- return devdirread(c,
- buf, n,
- dirtab, NELEM(dirtab),
- devgen);
+ ntab = gettab(c->qid, &tab);
+
+ return dirread(c, buf, n, dirtab, ntab, devgen);
}
static int
@@ -54,4 +118,5 @@ const Dev rootdevtab = {
.walk = rootwalk,
.read = rootread,
.write = rootwrite,
+ .bind = rootbind,
};
diff --git a/drivers/devuart.c b/drivers/devuart.c
@@ -13,7 +13,6 @@
enum Orootqid {
Quartfs,
- Qdevfs,
Qraw,
Qctl,
};
@@ -26,22 +25,6 @@ static const Dirtab dirtab[] = {
static Uart *uarts[NR_UARTS];
static int
-uartgen(Chan *c, const Dirtab *tab, int ntab, int n, Dir *dir)
-{
- if (n >= NR_UARTS)
- return -1;
-
- ksnprint(dir->name, NAMELEN, "uart%d", n);
- dir->length = 0;
- dir->qid = CHDIR | Qdevfs;
- dir->mode = O_READ | O_WRITE;
- dir->type = c->type;
- dir->dev = n;
-
- return 1;
-}
-
-static int
uartwalk(Chan *c, const char *name)
{
Qid qid;
@@ -49,11 +32,10 @@ uartwalk(Chan *c, const char *name)
qid = c->qid & ~CHDIR;
switch (qid) {
case Quartfs:
- case Qdevfs:
return devwalk(c,
name,
dirtab, NELEM(dirtab),
- (qid == Quartfs) ? uartgen : devgen);
+ devgen);
case Qraw:
case Qctl:
errno = ENOENT;
@@ -64,9 +46,9 @@ uartwalk(Chan *c, const char *name)
}
static Chan *
-uartattach(const char *spec)
+uartattach(int dev)
{
- return devattach(spec, 't');
+ return devattach('t', dev);
}
static Uart *
@@ -217,16 +199,10 @@ static int
uartread(Chan *c, void *buf, int n)
{
Uart *up;
- Qid qid;
- qid = c->qid & ~CHDIR;
switch (c->qid & ~CHDIR) {
case Quartfs:
- case Qdevfs:
- return devdirread(c,
- buf, n,
- dirtab, NELEM(dirtab),
- (qid == Quartfs) ? uartgen : devgen);
+ return dirread(c, buf, n, dirtab, NELEM(dirtab), devgen);
case Qraw:
up = getuart(c);
return (*up->phy->read)(up, buf, n);
@@ -245,7 +221,6 @@ uartwrite(Chan *c, void *buf, int n)
switch (c->qid & ~CHDIR) {
case Quartfs:
- case Qdevfs:
return -1;
case Qraw:
up = getuart(c);
diff --git a/target/hosted/rom.c b/target/hosted/rom.c
@@ -2,6 +2,7 @@
#include <stdlib.h>
#include <string.h>
+#include <libk.h>
#include <rcode/rcode.h>
#include <rcode/romfw.h>
@@ -38,11 +39,19 @@ imach(void)
framep = &trapframe;
}
+static void
+namespace(void)
+{
+ if (bind("#t0", "/dev/uart") < 0)
+ kerror("namespace");
+}
+
int
main(int argc, char *argv[])
{
imach();
idev();
+ namespace();
return debug();
}