commit 2562a5e14a4bc650bc229330b1456bac8beaf60e
parent c4507e76f2fdd3fe7aad4c8f34cbdb7b7d0e7396
Author: Roberto Vargas <roberto.vargas@arm.com>
Date: Tue, 5 Mar 2019 12:34:07 +0000
Add initial version of devar
This device is not fully functional yet.
Change-Id: I745d88f362bee61c5a7901646ba54c19c60b19cd
Diffstat:
3 files changed, 210 insertions(+), 2 deletions(-)
diff --git a/drivers/devar.c b/drivers/devar.c
@@ -0,0 +1,203 @@
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rcode/rcode.h>
+#include <rcode/9p.h>
+
+#include "dev.h"
+
+#define NR_ARS 2
+
+#define ARMAG "!<arch>\n" /* ar "magic number" */
+#define SARMAG 8 /* strlen(ARMAG); */
+#define ARFMAG "`\n"
+#define SARNAM 16
+
+
+struct ar_hdr {
+ char ar_name[SARNAM]; /* name */
+ char ar_date[12]; /* modification time */
+ char ar_uid[6]; /* user id */
+ char ar_gid[6]; /* group id */
+ char ar_mode[8]; /* octal file permissions */
+ char ar_size[10]; /* size in bytes */
+ char ar_fmag[2]; /* consistency check */
+};
+
+enum Oarqid {
+ Qarfs,
+ Qctl,
+};
+
+static Dirtab arfstab[NR_ARS+1] = {
+ {"ctl", Qctl, 0, O_READ | O_WRITE},
+};
+
+static int nars;
+
+static int
+gethdr(Chan *c, struct ar_hdr *hdr)
+{
+ int n, ch, i;
+
+ n = devtab[c->type]->read(c, hdr, sizeof(*hdr));
+ if (n == 0)
+ return 0;
+ if (n != sizeof(*hdr) || strncmp(hdr->ar_fmag, ARFMAG, 2) != 0) {
+ errno = EFAULT; /* TODO: Put correct value */
+ return -1;
+ }
+
+ /* TODO: Check if we do the same loop and we accept not null strings */
+ for (i = SARNAM-1; i >= 0; i--) {
+ ch = hdr->ar_name[i];
+ if (ch != ' ' && ch !='/')
+ break;
+ hdr->ar_name[i] = '\0';
+ }
+
+ return 1;
+}
+
+/*
+ * TODO: This is broken, because we have a channel to
+ * talk with the dev, but we need an offset
+ * in the underlying dev.
+ */
+static int
+argen(Chan *c, const Dirtab *tab, int ntab, int n, Dir *dir)
+{
+ Qid qid;
+ int len, r;
+ Chan nc;
+ char buf[SARMAG];
+ struct ar_hdr hdr;
+
+ qid = (c->qid & ~CHDIR) - 1;
+ if (qid > nars)
+ panic("argen");
+ clone(arfstab[qid].data, &nc);
+ nc.offset = c->offset;
+
+ if (nc.offset == 0) {
+ r = devtab[nc.type]->read(&nc, buf, SARMAG);
+ if (r != SARMAG || strncmp(buf, ARMAG, SARMAG)) {
+ errno = EFAULT;
+ return -1;
+ }
+ }
+
+ if ((r = gethdr(&nc, &hdr)) <= 0)
+ return r;
+ devseek(&nc, atol(hdr.ar_size), 1);
+
+ if ((len = strlen(hdr.ar_name)) >= NAMELEN)
+ return 0;
+ memcpy(dir->name, hdr.ar_name, len);
+ dir->name[len] = '\0';
+ dir->length = atol(hdr.ar_size);
+ dir->qid = (n + 1) * (NR_ARS+1) + qid;
+ dir->mode = O_READ;
+ dir->type = c->type;
+ dir->dev = c->dev;
+ c->offset = nc.offset;
+
+ return 1;
+}
+
+static int
+arwalk(Chan *c, const char *name)
+{
+ switch (c->qid & ~CHDIR) {
+ case Qarfs:
+ return devwalk(c, name, arfstab, nars+1, devgen);
+ default:
+ return devwalk(c, name, NULL, 0, argen);
+ }
+}
+
+static int
+ardirread(Chan *c, unsigned char *buf, int nbytes)
+{
+ int n, cnt;
+ Dir dir;
+
+ for (cnt = 0; nbytes >= DIRLEN; cnt += n) {
+ switch (argen(c, NULL, 0, nbytes, &dir)) {
+ case 0:
+ return cnt;
+ case -1:
+ return (cnt > 0) ? cnt : -1;
+ case 1:
+ n = dirtop9(&dir, buf + cnt, nbytes);
+ nbytes -= n;
+ }
+ }
+
+ return cnt;
+}
+
+static int
+arread(Chan *c, void *buf, int n)
+{
+ Qid qid;
+ Chan nc;
+
+ switch (c->qid & ~CHDIR) {
+ case Qarfs:
+ return dirread(c, buf, n, arfstab, nars+1, devgen);
+ case Qctl:
+ errno = EFAULT; /* TODO: Put a correct value */
+ return -1;
+ default:
+ if (c->qid & CHDIR)
+ return ardirread(c, buf, n);
+ else {
+ qid = c->qid % (NR_ARS + 1);
+ clone(arfstab[qid].data, &nc);
+ nc.offset = c->offset;
+ n = devtab[nc.type]->read(&nc, buf, n);
+ c->offset += n;
+ return n;
+ }
+ }
+}
+
+int
+arnew(char *name)
+{
+ Qid qid;
+ Chan *c;
+ char *base, *s;
+ Dirtab *dp;
+
+ base = strrchr(name, '/');
+ base = (base) ? base+1 : name;
+
+ if (nars >= NR_ARS || strlen(base) >= NAMELEN) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ if ((c = namec(name, O_READ)) == NULL)
+ return -1;
+
+ qid = ++nars + Qctl;
+ dp = &arfstab[qid-1];
+ dp->qid = CHDIR | qid;
+ dp->perm = O_READ;
+ dp->length = 0;
+ dp->data = c;
+ strcpy(dp->name, base);
+
+ return 0;
+}
+
+const Dev ardevtab = {
+ .id = 'r',
+ .walk = arwalk,
+ .read = arread,
+ .write = devwrite,
+};
diff --git a/target/hosted/rcode b/target/hosted/rcode
@@ -4,7 +4,8 @@ dev
pl011 base=0x1c0c0000,clk=24000000,cfg=b115200 l8
pl011 base=0x1c0c0100,clk=24000000
blob
- example file=example.tar
+ example file=example.ar
+ ar
blob
- example ../target/hosted/example.tar
+ example ../target/hosted/example.ar
end
diff --git a/target/hosted/rom.c b/target/hosted/rom.c
@@ -39,6 +39,8 @@ imach(void)
framep = &trapframe;
}
+extern int arnew(char *file);
+
static void
namespace(void)
{
@@ -46,6 +48,8 @@ namespace(void)
goto error;
if (bind("#b", "/blobs") < 0)
goto error;
+ if (arnew("/blobs/example.ar") < 0)
+ goto error;
return;
error: