summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--defs.h1
-rw-r--r--fs.c23
-rw-r--r--main.c1
-rw-r--r--mkfs.c150
-rw-r--r--proc.c3
-rw-r--r--syscall.c100
-rw-r--r--syscall.h1
-rw-r--r--userfs.c1
-rw-r--r--usys.S1
10 files changed, 243 insertions, 42 deletions
diff --git a/Makefile b/Makefile
index d995429..d45bc6f 100644
--- a/Makefile
+++ b/Makefile
@@ -73,8 +73,8 @@ userfs : userfs.o $(ULIB)
mkfs : mkfs.c fs.h
cc -o mkfs mkfs.c
-fs.img : mkfs
- ./mkfs fs.img
+fs.img : mkfs usertests
+ ./mkfs fs.img usertests
-include *.d
diff --git a/defs.h b/defs.h
index 35a7139..84616c9 100644
--- a/defs.h
+++ b/defs.h
@@ -102,3 +102,4 @@ void iunlock(struct inode *ip);
void iincref(struct inode *ip);
void iput(struct inode *ip);
struct inode * namei(char *path);
+int readi(struct inode *ip, void *xdst, uint off, uint n);
diff --git a/fs.c b/fs.c
index 3eda6e9..3b06bc7 100644
--- a/fs.c
+++ b/fs.c
@@ -133,6 +133,29 @@ bmap(struct inode *ip, uint bn)
return x;
}
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+int
+readi(struct inode *ip, void *xdst, uint off, uint n)
+{
+ char *dst = (char *) xdst;
+ uint target = n, n1;
+ struct buf *bp;
+
+ while(n > 0 && off < ip->size){
+ bp = bread(ip->dev, bmap(ip, off / 512));
+ n1 = min(n, ip->size - off);
+ n1 = min(n1, 512 - (off % 512));
+ memmove(dst, bp->data + (off % 512), n1);
+ n -= n1;
+ off += n1;
+ dst += n1;
+ brelse(bp);
+ }
+
+ return target - n;
+}
+
struct inode *
namei(char *path)
{
diff --git a/main.c b/main.c
index 8a86908..1b8bdbe 100644
--- a/main.c
+++ b/main.c
@@ -100,6 +100,7 @@ mpmain(void)
lapic_enableintr();
// Enable interrupts on this processor.
+ cprintf("cpu %d initial nlock %d\n", cpu(), cpus[cpu()].nlock);
cpus[cpu()].nlock--;
sti();
diff --git a/mkfs.c b/mkfs.c
index 9dcb29c..ae66dfd 100644
--- a/mkfs.c
+++ b/mkfs.c
@@ -3,6 +3,7 @@
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
+#include <assert.h>
#include "types.h"
#include "param.h"
#include "fs.h"
@@ -10,14 +11,17 @@
int nblocks = 1009;
int ninodes = 100;
-int fd;
+int fsfd;
struct superblock sb;
char zeroes[512];
uint freeblock;
+uint freeinode = 1;
void wsect(uint, void *);
void winode(uint, struct dinode *);
void rsect(uint sec, void *buf);
+uint ialloc(ushort type);
+void iappend(uint inum, void *p, int n);
// convert to intel byte order
ushort
@@ -44,27 +48,21 @@ xint(uint x)
main(int argc, char *argv[])
{
- int i;
- struct dinode din;
- char dbuf[512];
- uint bn;
+ int i, cc, fd;
+ uint bn, rootino, inum;
+ struct dirent de;
+ char buf[512];
- if(argc != 2){
- fprintf(stderr, "Usage: mkfs fs.img\n");
+ if(argc < 2){
+ fprintf(stderr, "Usage: mkfs fs.img files...\n");
exit(1);
}
- if((512 % sizeof(struct dinode)) != 0){
- fprintf(stderr, "sizeof(dinode) must divide 512\n");
- exit(1);
- }
- if((512 % sizeof(struct dirent)) != 0){
- fprintf(stderr, "sizeof(dirent) must divide 512\n");
- exit(1);
- }
+ assert((512 % sizeof(struct dinode)) == 0);
+ assert((512 % sizeof(struct dirent)) == 0);
- fd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666);
- if(fd < 0){
+ fsfd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666);
+ if(fsfd < 0){
perror(argv[1]);
exit(1);
}
@@ -79,20 +77,38 @@ main(int argc, char *argv[])
wsect(1, &sb);
- bzero(&din, sizeof(din));
- din.type = xshort(T_DIR);
- din.nlink = xshort(2);
- din.size = xint(512);
- bn = freeblock++;
- din.addrs[0] = xint(bn);
- winode(1, &din);
-
- bzero(dbuf, sizeof(dbuf));
- ((struct dirent *) dbuf)[0].inum = xshort(1);
- strcpy(((struct dirent *) dbuf)[0].name, ".");
- ((struct dirent *) dbuf)[1].inum = xshort(1);
- strcpy(((struct dirent *) dbuf)[1].name, "..");
- wsect(bn, dbuf);
+ rootino = ialloc(T_DIR);
+ assert(rootino == 1);
+
+ bzero(&de, sizeof(de));
+ de.inum = xshort(rootino);
+ strcpy(de.name, ".");
+ iappend(rootino, &de, sizeof(de));
+
+ bzero(&de, sizeof(de));
+ de.inum = xshort(rootino);
+ strcpy(de.name, "..");
+ iappend(rootino, &de, sizeof(de));
+
+ for(i = 2; i < argc; i++){
+ assert(index(argv[i], '/') == 0);
+ if((fd = open(argv[i], 0)) < 0){
+ perror(argv[i]);
+ exit(1);
+ }
+
+ inum = ialloc(T_FILE);
+
+ bzero(&de, sizeof(de));
+ de.inum = xshort(inum);
+ strncpy(de.name, argv[i], DIRSIZ);
+ iappend(rootino, &de, sizeof(de));
+
+ while((cc = read(fd, buf, sizeof(buf))) > 0)
+ iappend(inum, buf, cc);
+
+ close(fd);
+ }
exit(0);
}
@@ -100,11 +116,11 @@ main(int argc, char *argv[])
void
wsect(uint sec, void *buf)
{
- if(lseek(fd, sec * 512L, 0) != sec * 512L){
+ if(lseek(fsfd, sec * 512L, 0) != sec * 512L){
perror("lseek");
exit(1);
}
- if(write(fd, buf, 512) != 512){
+ if(write(fsfd, buf, 512) != 512){
perror("write");
exit(1);
}
@@ -127,20 +143,80 @@ winode(uint inum, struct dinode *ip)
rsect(bn, buf);
dip = ((struct dinode *) buf) + (inum % IPB);
*dip = *ip;
- printf("bn %d off %d\n",
- bn, (unsigned)dip - (unsigned) buf);
wsect(bn, buf);
+ printf("wi %d size %d addrs %d %d...\n",
+ inum,
+ xint(dip->size),
+ xint(dip->addrs[0]),
+ xint(dip->addrs[1]));
+}
+
+void
+rinode(uint inum, struct dinode *ip)
+{
+ char buf[512];
+ uint bn;
+ struct dinode *dip;
+
+ bn = i2b(inum);
+ rsect(bn, buf);
+ dip = ((struct dinode *) buf) + (inum % IPB);
+ *ip = *dip;
}
void
rsect(uint sec, void *buf)
{
- if(lseek(fd, sec * 512L, 0) != sec * 512L){
+ if(lseek(fsfd, sec * 512L, 0) != sec * 512L){
perror("lseek");
exit(1);
}
- if(read(fd, buf, 512) != 512){
+ if(read(fsfd, buf, 512) != 512){
perror("read");
exit(1);
}
}
+
+uint
+ialloc(ushort type)
+{
+ uint inum = freeinode++;
+ struct dinode din;
+
+ bzero(&din, sizeof(din));
+ din.type = xshort(type);
+ din.nlink = xshort(1);
+ din.size = xint(0);
+ winode(inum, &din);
+ return inum;
+}
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+void
+iappend(uint inum, void *xp, int n)
+{
+ char *p = (char *) xp;
+ uint fbn, off, n1;
+ struct dinode din;
+ char buf[512];
+
+ rinode(inum, &din);
+
+ off = xint(din.size);
+ while(n > 0){
+ fbn = off / 512;
+ assert(fbn < NDIRECT);
+ if(din.addrs[fbn] == 0)
+ din.addrs[fbn] = xint(freeblock++);
+ n1 = min(n, (fbn + 1) * 512 - off);
+ rsect(xint(din.addrs[fbn]), buf);
+ bcopy(p, buf + off - (fbn * 512), n1);
+ wsect(xint(din.addrs[fbn]), buf);
+ n -= n1;
+ off += n1;
+ p += n1;
+ }
+ din.size = xint(off);
+ winode(inum, &din);
+}
diff --git a/proc.c b/proc.c
index 573da18..4e44a8e 100644
--- a/proc.c
+++ b/proc.c
@@ -137,6 +137,9 @@ scheduler(void)
cprintf("start scheduler on cpu %d jmpbuf %p\n", cpu(), &cpus[cpu()].jmpbuf);
cpus[cpu()].lastproc = &proc[0];
+ if(cpus[cpu()].nlock != 0)
+ panic("holding locks at first entry to scheduler");
+
for(;;){
// Loop over process table looking for process to run.
acquire(&proc_table_lock);
diff --git a/syscall.c b/syscall.c
index c6ae0db..a855774 100644
--- a/syscall.c
+++ b/syscall.c
@@ -10,6 +10,7 @@
#include "buf.h"
#include "fs.h"
#include "fsvar.h"
+#include "elf.h"
/*
* User code makes a system call with INT T_SYSCALL.
@@ -57,6 +58,21 @@ fetcharg(int argno, void *ip)
return fetchint(curproc[cpu()], esp + 4 + 4*argno, ip);
}
+// check that an entire string is valid in user space
+int
+checkstring(uint s)
+{
+ char c;
+
+ while(1){
+ if(fetchbyte(curproc[cpu()], s, &c) < 0)
+ return -1;
+ if(c == '\0')
+ return 0;
+ s++;
+ }
+}
+
int
putint(struct proc *p, uint addr, int x)
{
@@ -225,6 +241,81 @@ sys_cons_puts(void)
}
int
+sys_exec(void)
+{
+ struct proc *cp = curproc[cpu()];
+ uint arg0, sz;
+ int i;
+ struct inode *ip;
+ struct elfhdr elf;
+ struct proghdr ph;
+
+ if(fetcharg(0, &arg0) < 0)
+ return -1;
+ if(checkstring(arg0) < 0)
+ return -1;
+ ip = namei(cp->mem + arg0);
+ if(ip == 0)
+ return -1;
+
+ if(readi(ip, &elf, 0, sizeof(elf)) < sizeof(elf))
+ goto bad;
+
+ if(elf.magic != ELF_MAGIC)
+ goto bad;
+
+ sz = 0;
+ for(i = 0; i < elf.phnum; i++){
+ if(readi(ip, &ph, elf.phoff + i * sizeof(ph), sizeof(ph)) != sizeof(ph))
+ goto bad;
+ if(ph.type != ELF_PROG_LOAD)
+ continue;
+ if(ph.memsz < ph.filesz)
+ goto bad;
+ sz += ph.memsz;
+ }
+
+ sz += 4096 - (sz % 4096);
+ sz += 4096;
+
+ // commit to the new image.
+ kfree(cp->mem, cp->sz);
+ cp->sz = sz;
+ cp->mem = kalloc(cp->sz);
+
+ for(i = 0; i < elf.phnum; i++){
+ if(readi(ip, &ph, elf.phoff + i * sizeof(ph), sizeof(ph)) != sizeof(ph))
+ goto bad;
+ if(ph.type != ELF_PROG_LOAD)
+ continue;
+ if(ph.va + ph.memsz > sz)
+ goto bad2;
+ if(readi(ip, cp->mem + ph.va, ph.offset, ph.filesz) != ph.filesz)
+ goto bad2;
+ memset(cp->mem + ph.va + ph.filesz, 0, ph.memsz - ph.filesz);
+ }
+
+ iput(ip);
+
+ cp->tf->eip = elf.entry;
+ cp->tf->esp = cp->sz;
+ setupsegs(cp);
+
+ return 0;
+
+ bad:
+ cprintf("exec failed early\n");
+ iput(ip);
+ return -1;
+
+ bad2:
+ cprintf("exec failed late\n");
+ iput(ip);
+ proc_exit();
+ return 0;
+}
+
+int
sys_block(void)
{
int i, j;
@@ -248,14 +339,14 @@ sys_block(void)
ip->type, ip->nlink, ip->size, ip->addrs[0]);
iput(ip);
- ip = namei(".././//./../");
+ ip = namei(".././//./../usertests");
if(ip){
- cprintf("namei: %d %d %d %d %d %d %d %d\n",
+ cprintf("namei(usertests): %d %d %d %d %d %d %d %d\n",
ip->dev, ip->inum, ip->count, ip->busy,
ip->type, ip->nlink, ip->size, ip->addrs[0]);
iput(ip);
} else {
- cprintf("namei failed\n");
+ cprintf("namei(usertests) failed\n");
}
return 0;
@@ -317,6 +408,9 @@ syscall(void)
case SYS_cons_puts:
ret = sys_cons_puts();
break;
+ case SYS_exec:
+ ret = sys_exec();
+ break;
default:
cprintf("unknown sys call %d\n", num);
// XXX fault
diff --git a/syscall.h b/syscall.h
index 9ca3bd4..799d8ed 100644
--- a/syscall.h
+++ b/syscall.h
@@ -10,3 +10,4 @@
#define SYS_kill 10
#define SYS_panic 11
#define SYS_cons_puts 12
+#define SYS_exec 13
diff --git a/userfs.c b/userfs.c
index 5772e1d..aad9326 100644
--- a/userfs.c
+++ b/userfs.c
@@ -9,5 +9,6 @@ main(void)
{
puts("userfs running\n");
block();
+ exec("usertests");
return 0;
}
diff --git a/usys.S b/usys.S
index 45d6ca8..09c753e 100644
--- a/usys.S
+++ b/usys.S
@@ -20,3 +20,4 @@ STUB(block)
STUB(kill)
STUB(panic)
STUB(cons_puts)
+STUB(exec)