From c59361f1430ec485596d1bf5d43339af0b5a2705 Mon Sep 17 00:00:00 2001 From: rtm Date: Thu, 27 Jul 2006 21:10:00 +0000 Subject: [PATCH] primitive exec --- Makefile | 4 +- defs.h | 1 + fs.c | 23 +++++++++ main.c | 1 + mkfs.c | 148 +++++++++++++++++++++++++++++++++++++++++------------- proc.c | 3 ++ syscall.c | 100 ++++++++++++++++++++++++++++++++++-- syscall.h | 1 + userfs.c | 1 + usys.S | 1 + 10 files changed, 242 insertions(+), 41 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 #include #include +#include #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); + rootino = ialloc(T_DIR); + assert(rootino == 1); - 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); + 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) { @@ -224,6 +240,81 @@ sys_cons_puts(void) return 0; } +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) { @@ -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)