commit 113dc9ac8eb9cfde463b8e01a2ec53812ba82286
parent 815b5e32ee7609910ef01e75daa86e881a8b1dc2
Author: Roberto Vargas <roberto.vargas@arm.com>
Date: Fri, 30 Nov 2018 16:10:01 +0000
[dev] Add initial version plan9 version alike system
Change-Id: Id2d41a424103710fc4a68a63e49be9cc50215e8a
Diffstat:
11 files changed, 494 insertions(+), 26 deletions(-)
diff --git a/drivers/dev.c b/drivers/dev.c
@@ -1,12 +1,36 @@
#include <errno.h>
+#include <string.h>
+
#include <rcode.h>
+#include <romfw.h>
#include "dev.h"
struct devdata {
- Chan fd[NR_CHANS];
+ Chan fds[NR_CHANS];
+ Chan slash;
+ Chan dot;
};
+/*
+ * FIXME: NODEV has the same type than rootdir
+ */
+static Chan *
+newchan(void)
+{
+ Chan *c, *lim;
+ struct devdata *dinfo = bss->devinfo;
+
+ lim = &dinfo->fds[NR_CHANS];
+ for (c = dinfo->fds; c < lim; c++) {
+ if (c->type == NODEV)
+ return c;
+ }
+
+ errno = ENOMEM;
+ return NULL;
+}
+
static Chan *
fd2chan(int fd)
{
@@ -14,5 +38,338 @@ fd2chan(int fd)
errno = EBADF;
return NULL;
}
+ return &bss->devinfo->fds[fd];
+}
+
+static int
+chan2fd(Chan *c)
+{
+ return (c == NULL) ? -1 : (c - bss->devinfo->fds);
+}
+
+static int
+validmode(int mode)
+{
+ if ((mode & O_READ) && (mode & (O_WRITE | O_RDWR)))
+ goto err;
+ if ((mode & O_WRITE) && (mode & (O_READ | O_RDWR)))
+ goto err;
+ if ((mode & O_RDWR) && (mode & (O_READ | O_WRITE)))
+ goto err;
+ if ((mode & O_DIR) && (mode & (O_TRUNC)))
+ goto err;
+ return 1;
+
+err:
+ errno = EINVAL;
+ return 0;
+}
+
+static const char *
+next(const char *s, char *elem)
+{
+ int n;
+ const char *t;
+
+ while (*s == '/')
+ ++s;
+ if (*s == '\0')
+ return s;
+
+ n = 0;
+ for (t = s; *t != '/' && *t != '\0'; t++) {
+ if (n == NAMELEN) {
+ errno = ENAMETOOLONG;
+ return NULL;
+ }
+ elem[n++] = *t;
+ }
+ elem[n] = '\0';
+
+ return t;
+}
+
+static int
+devtype(int c)
+{
+ int i;
+ Dev * const *dp;
+
+ for (i = 0, dp = devtab; *dp && (*dp)->id != c; ++dp)
+ i++;
+ if (*dp == NULL) {
+ errno = ENODEV;
+ return -1;
+ }
+ return i;
+}
+
+static Chan *
+clone(Chan *c, Chan *nc)
+{
+ return devtab[c->type]->clone(c, nc);
+}
+
+static int
+walk(Chan *c, char *name)
+{
+ return devtab[c->type]->walk(c, name);
+}
+
+static void
+chanclose(Chan *c)
+{
+ c->qid = 0;
+ c->type = NODEV;
+ c->dev = 0;
+ c->offset = 0;
+}
+
+Chan *
+namec(const char *name, int mode)
+{
+ int type;
+ const char *s;
+ Chan *c;
+ struct devdata *dinfo = bss->devinfo;
+ char elem[NAMELEN];
+
+ switch (name[0]) {
+ case '/':
+ c = clone(&dinfo->slash, NULL);
+ s = name;
+ break;
+ case '#':
+ if ((s = next(name+1, elem)) == NULL)
+ return NULL;
+ if (elem[1] != '\0') {
+ errno = ENODEV;
+ return NULL;
+ }
+ if ((type = devtype(elem[0])) < 0)
+ return NULL;
+ c = devtab[type]->attach(NULL);
+ break;
+ default:
+ c = clone(&dinfo->dot, NULL);
+ s = name;
+ break;
+ }
+
+ if (!c)
+ return NULL;
+
+ for (s = next(s, elem); s && *s; s = next(s, elem)) {
+ if (walk(c, elem) < 0)
+ break;
+ }
+ if (*s == '\0')
+ return c;
+
+ chanclose(c);
+ errno = ENOENT;
return NULL;
}
+
+Chan *
+devclone(Chan *c, Chan *nc)
+{
+ if (!nc && (nc = newchan()) == NULL)
+ return NULL;
+
+ nc->qid = c->qid;
+ nc->type = c->type;
+ nc->dev = c->dev;
+ nc->mode = c->mode;
+ nc->offset = c->offset;
+
+ return nc;
+}
+
+Chan *
+devattach(const char *spec, int id)
+{
+ Chan *c;
+ int type;
+
+ if ((type = devtype(id)) < 0)
+ return NULL;
+ c = newchan();
+ c->qid = CHDIR;
+ c->type = devtype(id);
+ return c;
+}
+
+int
+devwalk(Chan *c, const char *name, const Dirtab *tab, int ntab, Devgen *gen)
+{
+ int i;
+ Dir dir;
+
+ if (name[0] == '.' && name[1] == '\0')
+ return 1;
+ for (i = 0; ;i++) {
+ switch ((*gen)(c, tab, ntab, i, &dir)) {
+ case -1:
+ errno = ENOENT;
+ return 0;
+ case 0:
+ continue;
+ case 1:
+ if (strcmp(name, dir.name))
+ continue;
+ c->qid = dir.qid;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int
+devdirread(Chan *c, char *buf, int nbytes, const Dirtab *tab, int ntab, Devgen *gen)
+{
+ int n, cnt, i;
+ Dir dir;
+
+ for (i = c->offset/DIRLEN; nbytes >= DIRLEN; i++) {
+ switch ((*gen)(c, tab, ntab, i, &dir)) {
+ case -1:
+ return cnt;
+ case 0:
+ c->offset += DIRLEN;
+ break;
+ case 1:
+ memcpy(buf + cnt, &dir, DIRLEN);
+ nbytes -= n;
+ cnt += n;
+ }
+ }
+
+ return cnt;
+}
+
+int
+devgen(Chan *c, const Dirtab *tab, int ntab, int n, Dir *dir)
+{
+ const Dirtab *dp;
+
+ if (!tab || n >= ntab)
+ return -1;
+
+ dp = &tab[n];
+ strcpy(dir->name, dp->name);
+ dir->length = dp->length;
+ dir->qid = dp->qid;
+ dir->mode = dp->perm;
+ if (dp->qid & CHDIR)
+ dir->mode |= O_DIR;
+ dir->type = c->type;
+ dir->dev = c->dev;
+
+ return 1;
+}
+
+int
+open(const char *fname, int mode)
+{
+ Chan *c;
+
+ if (!validmode(mode))
+ return -1;
+ c = namec(fname, mode);
+
+ return chan2fd(c);
+}
+
+int
+close(int fd)
+{
+ Chan *c;
+
+ if ((c = fd2chan(fd)) == NULL)
+ return -1;
+ chanclose(c);
+ return 0;
+}
+
+int
+read(int fd, void *buf, int n)
+{
+ Chan *c;
+
+ if ((c = fd2chan(fd)) == NULL)
+ return -1;
+
+ if ((c->qid & CHDIR) && (n < DIRLEN)) {
+ errno = EINVAL;
+ return -1;
+ }
+ n = devtab[c->type]->read(c, buf, n);
+ c->offset += n;
+ return n;
+}
+
+int
+write(int fd, void *buf, int n)
+{
+ Chan *c;
+
+ if ((c = fd2chan(fd)) == NULL)
+ return -1;
+
+ if (c->qid & CHDIR) {
+ errno = EISDIR;
+ return -1;
+ }
+
+ n = devtab[c->type]->write(c, buf, n);
+ c->offset += n;
+ return n;
+}
+
+int
+seek(int fd, long long off, int whence)
+{
+ Chan *c;
+
+ if ((c = fd2chan(fd)) == NULL)
+ return -1;
+
+ if (c->qid & CHDIR) {
+ errno = EISDIR;
+ return -1;
+ }
+
+ switch (whence) {
+ case 0:
+ c->offset = off;
+ break;
+ case 1:
+ c->offset += off;
+ break;
+ case 2:
+ panic("seek"); /* TODO */
+ break;
+ }
+
+ return 0;
+}
+
+void
+idev(void)
+{
+ struct devdata *dinfo;
+ Chan *c;
+
+ dinfo = alloc(sizeof(*dinfo));
+ bss->devinfo = dinfo;
+
+ if ((c = devattach(NULL, '/')) == NULL)
+ panic("idev:attach");
+
+ if (!clone(c, &dinfo->slash) || !clone(c, &dinfo->dot))
+ panic("idev:clone");
+
+ chanclose(c);
+}
diff --git a/drivers/dev.h b/drivers/dev.h
@@ -1,22 +1,58 @@
#include <stddef.h>
#define NR_CHANS 4
+#define NODEV 0
+#define NAMELEN 8
+#define DIRLEN sizeof(Dir)
+#define CHDIR (1 << 15)
typedef struct dev Dev;
typedef struct chan Chan;
+typedef struct dirtab Dirtab;
+typedef struct dir Dir;
+typedef int Devgen(Chan *, const Dirtab *, int, int, Dir *);
+typedef short Qid;
+
+struct dir {
+ char name[NAMELEN];
+ unsigned long long length;
+ unsigned char mode;
+ unsigned char type;
+ unsigned char dev;
+ Qid qid;
+};
+
+struct dirtab {
+ char name[NAMELEN];
+ Qid qid;
+ unsigned long long length;
+ unsigned char perm;
+};
struct dev {
char id;
- char *name;
+ char name[NAMELEN];
+ Chan * (*clone)(Chan *c, Chan *nc);
+ int (*walk)(Chan *c, const char *name);
+ Chan * (*attach)(const char *spec);
+ int (*read)(Chan *c, void *buf, int n);
+ int (*write)(Chan *c, void *buf, int n);
};
struct chan {
+ Qid qid;
unsigned char type;
unsigned char dev;
- unsigned short qid;
unsigned char mode;
- unsigned char iref;
- unsigned long long offset; /* 2 bytes of padding here */
+
+ unsigned long long offset; /* 3 bytes of padding here */
};
extern Dev *const devtab[];
+
+extern Chan *devclone(Chan *c, Chan *nc);
+extern Chan *devattach(const char *spec, int id);
+extern Chan *devclone(Chan *c, Chan *nc);
+extern int devgen(Chan *c, const Dirtab *tab, int ntab, int n, Dir *dir);
+extern int devwalk(Chan *c, const char *name, const Dirtab *tab, int ntab, Devgen *gen);
+extern int devdirread(Chan *c, char *buf, int nbytes, const Dirtab *tab, int ntab, Devgen *gen);
diff --git a/drivers/devroot.c b/drivers/devroot.c
@@ -1,6 +1,45 @@
+#include <rcode.h>
+
#include "dev.h"
-const Dev devroot = {
+#define NELEM(tab) (sizeof(tab) / sizeof(tab[0]))
+
+enum Orootqid {
+ Qslash,
+ Qdev,
+ Qrealm,
+};
+
+static const Dirtab rootdirtab[] = {
+ {"dev", CHDIR | Qdev, 0, O_READ},
+ {"realm", CHDIR | Qrealm, 0, O_READ},
+};
+
+static int
+rootwalk(Chan *c, const char *name)
+{
+ return devwalk(c, name, rootdirtab, NELEM(rootdirtab), devgen);
+}
+
+static Chan *
+rootattach(const char *spec)
+{
+ return devattach(spec, '/');
+}
+
+static int
+rootread(Chan *c, void *buf, int n)
+{
+ if (c->qid & CHDIR)
+ return devdirread(c, buf, n, rootdirtab, NELEM(rootdirtab), devgen);
+ return -1;
+}
+
+const Dev rootdevtab = {
.id = '/',
.name = "root",
+ .clone = devclone,
+ .attach = rootattach,
+ .walk = rootwalk,
+ .read = rootread,
};
diff --git a/drivers/devuart.c b/drivers/devuart.c
@@ -1,6 +1,6 @@
#include "dev.h"
-const Dev devuart = {
+const Dev uartdevtab = {
.id = 't',
.name = "uart",
};
diff --git a/drivers/mkdevc b/drivers/mkdevc
@@ -7,7 +7,7 @@ awk '
BEGIN {print "#include \"dev.h\"\n"}
/^dev/ {dev = 1; next}
/^[^ \t]/ {dev = 0; next}
-dev && /^[ \t]/ {devs["dev" $1] = 1}
+dev && /^[ \t]/ {devs[$1 "devtab"] = 1}
END {for (i in devs)
printf "extern Dev %s;\n", i
print "\nDev *const devtab[] = {"
diff --git a/include/rcode.h b/include/rcode.h
@@ -14,10 +14,12 @@
#define IDISABLE 0
enum devflags {
- OCREATE = 1 << 0,
- OREAD = 1 << 1,
- OWRITE = 1 << 2,
- ODIR = 1 << 3,
+ O_CREATE = 1 << 0,
+ O_READ = 1 << 1,
+ O_WRITE = 1 << 2,
+ O_RDWR = 1 << 3,
+ O_DIR = 1 << 4,
+ O_TRUNC = 1 << 5,
};
typedef struct rmucmd Rmucmd;
@@ -68,6 +70,7 @@ extern noreturn void trap(struct trapframe *fp);
extern noreturn void badcmd(int error);
extern void rmc(Rmucmd *cmd);
extern int debug(void);
+extern void idev(void);
/* driver functions */
extern int create(const char *name, int flags);
@@ -79,6 +82,7 @@ extern int seek(int fd, long long off, int whence);
extern int bind(const char *path, char *where);
/* architectural functions */
+extern void *alloc(size_t size);
extern noreturn void dohalt(void);
extern noreturn void dopanic(void);
extern noreturn void doswtch(struct trapframe *fp);
diff --git a/include/romfw.h b/include/romfw.h
@@ -4,6 +4,8 @@
struct rmctab;
struct trapframe;
+struct rmucmd;
+struct Fgrp;
struct bssmap {
unsigned char in_panic;
@@ -19,12 +21,14 @@ struct bssmap {
jmp_buf dbgrecover;
struct rmctab *rmctab;
struct trapframe *fp;
- Rmucmd *cmd;
+ struct rmucmd *cmd;
unsigned char enable; /* System realm enablement */
unsigned char hascrypto; /* System-wide memory encryption */
int errno_;
+
+ struct devdata *devinfo;
};
extern struct bssmap *bss(void);
diff --git a/target/hosted/Makefile b/target/hosted/Makefile
@@ -15,7 +15,7 @@ RAMOBJS = arch.o \
ramtab.o \
$(SRCDIR)/ramfw/builtin.o \
-TARGET = $(BINDIR)/romfw.elf $(BINDIR)/ramfw.elf
+TARGET = $(BINDIR)/romfw.elf
DIRS = crt
all: $(TARGET)
@@ -39,3 +39,4 @@ $(BINDIR)/ramfw.elf: $(RAMOBJS) $(LIBDEP)
clean:
$(FORALL)
+ rm -f romtab.c ramtab.c
diff --git a/target/hosted/rom.c b/target/hosted/rom.c
@@ -1,20 +1,44 @@
#include <setjmp.h>
+#include <stdlib.h>
#include <string.h>
#include <rcode.h>
#include <romfw.h>
-int
-main(int argc, char *argv[])
+#include "hosted.h"
+
+struct bssmap bssmap;
+
+void *
+alloc(size_t size)
{
- extern jmp_buf recover;
+ void * p;
+ if ((p = malloc(size)) == NULL)
+ panic("alloc");
+ return p;
+}
+
+static void
+imach(void)
+{
if (setjmp(recover))
- return 1;
+ exit(EXIT_FAILURE);
+}
- memset(bss, 0, sizeof(struct bssmap));
+static void
+ibss(void)
+{
bss->rmctab = &romtab;
bss->fp = &(struct trapframe) {0};
+}
+
+int
+main(int argc, char *argv[])
+{
+ imach();
+ ibss();
+ idev();
return debug();
}
diff --git a/target/native/.gitignore b/target/native/.gitignore
@@ -1,3 +1,5 @@
sysreg.h
sysreg.s
version.h
+romtab.c
+ramtab.c
diff --git a/target/native/rom.c b/target/native/rom.c
@@ -44,6 +44,12 @@ getenviron(void)
return bss->environ;
}
+void *
+alloc(size_t size)
+{
+ return NULL;
+}
+
static void
imach(Mach *mp, void *txt, size_t txtsiz, void *ram, size_t ramsiz)
{
@@ -105,12 +111,6 @@ ibss(Mach *mp)
}
static void
-idev(Mach *mp)
-{
- uartinit(UARTCLK, UARTBAUDRATE);
-}
-
-static void
info(Mach *mp)
{
dbg("romfw: version %s\n"
@@ -134,7 +134,8 @@ main(void *txt, size_t txtsiz, void *ram, size_t ramsiz)
imach(&mach, txt, txtsiz, ram, ramsiz);
ibss(&mach);
- idev(&mach);
+ idev();
+ uartinit(UARTCLK, UARTBAUDRATE);
intr(IENABLE);
barrier(ISB);
info(&mach);