summaryrefslogtreecommitdiff
path: root/os/boot/pc/kfsboot.c
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
commit74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch)
treec6e220ba61db3a6ea4052e6841296d829654e664 /os/boot/pc/kfsboot.c
parent46439007cf417cbd9ac8049bb4122c890097a0fa (diff)
20060303
Diffstat (limited to 'os/boot/pc/kfsboot.c')
-rw-r--r--os/boot/pc/kfsboot.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/os/boot/pc/kfsboot.c b/os/boot/pc/kfsboot.c
new file mode 100644
index 00000000..a99d226d
--- /dev/null
+++ b/os/boot/pc/kfsboot.c
@@ -0,0 +1,256 @@
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "fs.h"
+
+typedef struct Tag Tag;
+
+/*
+ * tags on block
+ */
+enum
+{
+ Tnone = 0,
+ Tsuper, /* the super block */
+ Tdir, /* directory contents */
+ Tind1, /* points to blocks */
+ Tind2, /* points to Tind1 */
+ Tfile, /* file contents */
+ Tfree, /* in free list */
+ Tbuck, /* cache fs bucket */
+ Tvirgo, /* fake worm virgin bits */
+ Tcache, /* cw cache things */
+ MAXTAG
+};
+
+#define QPDIR 0x80000000L
+#define QPNONE 0
+#define QPROOT 1
+#define QPSUPER 2
+
+/* DONT TOUCH, this is the disk structure */
+struct Tag
+{
+ short pad;
+ short tag;
+ long path;
+};
+
+static int thisblock = -1;
+static Fs *thisfs;
+static uchar *block;
+
+/*
+ * we end up reading 2x or 3x the number of blocks we need to read.
+ * this is okay because we need to read so few. if it wasn't okay, we could
+ * have getblock return a pointer to a block, and keep a cache of the last
+ * three read blocks. that would get us down to the minimum.
+ * but this is fine.
+ */
+static int
+getblock(Fs *fs, ulong n)
+{
+ if(!block)
+ block = malloc(16384);
+
+ if(thisblock == n && thisfs == fs)
+ return 0;
+ thisblock = -1;
+ if(fs->diskseek(fs, (vlong)n*fs->kfs.RBUFSIZE) < 0)
+ return -1;
+ if(fs->diskread(fs, block, fs->kfs.RBUFSIZE) != fs->kfs.RBUFSIZE)
+ return -1;
+ thisblock = n;
+ thisfs = fs;
+
+ return 1;
+}
+
+static int
+checktag(Fs *fs, uchar *block, int tag, long qpath)
+{
+ Tag *t;
+
+ t = (Tag*)(block+fs->kfs.BUFSIZE);
+ if(t->tag != tag)
+ return -1;
+ if(qpath != QPNONE && (qpath&~QPDIR) != t->path)
+ return -1;
+ return 1;
+}
+
+static int
+getblocktag(Fs *fs, ulong n, int tag, long qpath)
+{
+ if(getblock(fs, n) < 0 || checktag(fs, block, tag, qpath) < 0)
+ return -1;
+ return 1;
+}
+
+static int
+readinfo(Fs *fs)
+{
+ fs->kfs.RBUFSIZE = 512;
+ if(getblock(fs, 0) < 0)
+ return -1;
+
+ if(memcmp(block+256, "kfs wren device\n", 16) != 0)
+ return -1;
+
+ fs->kfs.RBUFSIZE = atoi((char*)block+256+16);
+ if(!fs->kfs.RBUFSIZE || (fs->kfs.RBUFSIZE&(fs->kfs.RBUFSIZE-1)))
+ return -1;
+
+ fs->kfs.BUFSIZE = fs->kfs.RBUFSIZE - sizeof(Tag);
+ fs->kfs.DIRPERBUF = fs->kfs.BUFSIZE / sizeof(Dentry);
+ fs->kfs.INDPERBUF = fs->kfs.BUFSIZE / sizeof(long);
+ fs->kfs.INDPERBUF2 = fs->kfs.INDPERBUF * fs->kfs.INDPERBUF;
+
+ return 1;
+}
+
+static int
+readroot(Fs *fs, Dentry *d)
+{
+ Dentry *d2;
+
+ if(getblocktag(fs, 2, Tdir, QPROOT) < 0)
+ return -1;
+ d2 = (Dentry*)block;
+ if(strcmp(d2->name, "/") != 0)
+ return -1;
+ *d = *(Dentry*)block;
+ return 1;
+}
+
+static long
+indfetch(Fs *fs, long addr, long off, int tag, long path)
+{
+ if(getblocktag(fs, addr, tag, path) < 0)
+ return -1;
+ return ((long*)block)[off];
+}
+
+static long
+rel2abs(Fs *fs, Dentry *d, long a)
+{
+ long addr;
+
+ if(a < NDBLOCK)
+ return d->dblock[a];
+ a -= NDBLOCK;
+ if(a < fs->kfs.INDPERBUF){
+ if(d->iblock == 0)
+ return 0;
+ addr = indfetch(fs, d->iblock, a, Tind1, d->qid.path);
+ if(addr == 0)
+ print("rel2abs indfetch 0 %s %ld\n", d->name, a);
+ return addr;
+ }
+ a -= fs->kfs.INDPERBUF;
+ if(a < fs->kfs.INDPERBUF2){
+ if(d->diblock == 0)
+ return 0;
+ addr = indfetch(fs, d->diblock, a/fs->kfs.INDPERBUF, Tind2, d->qid.path);
+ if(addr == 0){
+ print("rel2abs indfetch 0 %s %ld\n", d->name, a/fs->kfs.INDPERBUF);
+ return 0;
+ }
+ addr = indfetch(fs, addr, a%fs->kfs.INDPERBUF, Tind1, d->qid.path);
+ return addr;
+ }
+ print("rel2abs trip ind %s %ld\n", d->name, a);
+ return -1;
+}
+
+static int
+readdentry(Fs *fs, Dentry *d, int n, Dentry *e)
+{
+ long addr, m;
+
+ m = n/fs->kfs.DIRPERBUF;
+ if((addr = rel2abs(fs, d, m)) <= 0)
+ return addr;
+ if(getblocktag(fs, addr, Tdir, d->qid.path) < 0)
+ return -1;
+ *e = *(Dentry*)(block+(n%fs->kfs.DIRPERBUF)*sizeof(Dentry));
+ return 1;
+}
+
+static int
+getdatablock(Fs *fs, Dentry *d, long a)
+{
+ long addr;
+
+ if((addr = rel2abs(fs, d, a)) == 0)
+ return -1;
+ return getblocktag(fs, addr, Tfile, QPNONE);
+}
+
+static int
+walk(Fs *fs, Dentry *d, char *name, Dentry *e)
+{
+ int i, n;
+ Dentry x;
+
+ for(i=0;; i++){
+ if((n=readdentry(fs, d, i, &x)) <= 0)
+ return n;
+ if(strcmp(x.name, name) == 0){
+ *e = x;
+ return 1;
+ }
+ }
+}
+
+static long
+kfsread(File *f, void *va, long len)
+{
+ uchar *a;
+ long tot, off, o, n;
+ Fs *fs;
+
+ a = va;
+ fs = f->fs;
+ off = f->kfs.off;
+ tot = 0;
+ while(tot < len){
+ if(getdatablock(fs, &f->kfs, off/fs->kfs.BUFSIZE) < 0)
+ return -1;
+ o = off%fs->kfs.BUFSIZE;
+ n = fs->kfs.BUFSIZE - o;
+ if(n > len-tot)
+ n = len-tot;
+ memmove(a+tot, block+o, n);
+ off += n;
+ tot += n;
+ }
+ f->kfs.off = off;
+ return tot;
+}
+
+static int
+kfswalk(File *f, char *name)
+{
+ int n;
+
+ n = walk(f->fs, &f->kfs, name, &f->kfs);
+ if(n < 0)
+ return -1;
+ f->kfs.off = 0;
+ return 1;
+}
+
+int
+kfsinit(Fs *fs)
+{
+ if(readinfo(fs) < 0 || readroot(fs, &fs->root.kfs) < 0)
+ return -1;
+
+ fs->root.fs = fs;
+ fs->read = kfsread;
+ fs->walk = kfswalk;
+ return 0;
+}