summaryrefslogtreecommitdiff
path: root/exec.c
diff options
context:
space:
mode:
authorrsc <rsc>2007-08-21 19:22:08 +0000
committerrsc <rsc>2007-08-21 19:22:08 +0000
commitf32f3638f4c34fbf2fc4398878e6304612bb3283 (patch)
treecabca9bf9ac8b1465b2c59e27e3dc8020c02e2be /exec.c
parent2d61a40b2059b9a198e7c4ff04c6ced88cb3ce65 (diff)
downloadxv6-labs-f32f3638f4c34fbf2fc4398878e6304612bb3283.tar.gz
xv6-labs-f32f3638f4c34fbf2fc4398878e6304612bb3283.tar.bz2
xv6-labs-f32f3638f4c34fbf2fc4398878e6304612bb3283.zip
Various cleanup:
- Got rid of dummy proc[0]. Now proc[0] is init. - Added initcode.S to exec /init, so that /init is just a regular binary. - Moved exec out of sysfile to exec.c - Moved code dealing with fs guts (like struct inode) from sysfile.c to fs.c. Code dealing with system call arguments stays in sysfile.c - Refactored directory routines in fs.c; should be simpler. - Changed iget to return *unlocked* inode structure. This solves the lookup-then-use race in namei without introducing deadlocks. It also enabled getting rid of the dummy proc[0].
Diffstat (limited to 'exec.c')
-rw-r--r--exec.c136
1 files changed, 136 insertions, 0 deletions
diff --git a/exec.c b/exec.c
new file mode 100644
index 0000000..1f8b1af
--- /dev/null
+++ b/exec.c
@@ -0,0 +1,136 @@
+#include "types.h"
+#include "stat.h"
+#include "param.h"
+#include "mmu.h"
+#include "proc.h"
+#include "defs.h"
+#include "x86.h"
+#include "traps.h"
+#include "syscall.h"
+#include "spinlock.h"
+#include "buf.h"
+#include "fs.h"
+#include "fsvar.h"
+#include "elf.h"
+#include "file.h"
+#include "fcntl.h"
+
+int
+exec(char *path, char **argv)
+{
+ uint sz, sp, p1, p2;
+ int i, nargs, argbytes, len;
+ struct inode *ip;
+ struct elfhdr elf;
+ struct proghdr ph;
+ char *mem;
+ char *s, *last;
+
+ sz = 0;
+ mem = 0;
+
+ if((ip = namei(path)) == 0)
+ return -1;
+
+ if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf))
+ goto bad;
+
+ if(elf.magic != ELF_MAGIC)
+ goto bad;
+
+ for(i = 0; i < elf.phnum; i++){
+ if(readi(ip, (char*)&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;
+
+ mem = kalloc(sz);
+ if(mem == 0)
+ goto bad;
+ memset(mem, 0, sz);
+
+ argbytes = 0;
+ for(i = 0; argv[i]; i++){
+ len = strlen(argv[i]);
+ argbytes += len + 1;
+ }
+ nargs = i;
+
+ // argn\0
+ // ...
+ // arg0\0
+ // 0
+ // ptr to argn
+ // ...
+ // 12: ptr to arg0
+ // 8: argv (points to ptr to arg0)
+ // 4: argc
+ // 0: fake return pc
+ sp = sz - argbytes - (nargs+1)*4 - 4 - 4 - 4;
+ *(uint*)(mem + sp) = 0xffffffff;
+ *(uint*)(mem + sp + 4) = nargs;
+ *(uint*)(mem + sp + 8) = (uint)(sp + 12);
+
+ p1 = sp + 12;
+ p2 = sp + 12 + (nargs + 1) * 4;
+ for(i = 0; i < nargs; i++){
+ len = strlen(argv[i]);
+ memmove(mem + p2, argv[i], len + 1);
+ *(uint*)(mem + p1) = p2;
+ p1 += 4;
+ p2 += len + 1;
+ }
+ *(uint*)(mem + p1) = 0;
+
+ // Save name for debugging.
+ for(last=s=path; *s; s++)
+ if(*s == '/')
+ last = s+1;
+ safestrcpy(cp->name, last, sizeof cp->name);
+
+ // commit to the new image.
+ kfree(cp->mem, cp->sz);
+ cp->sz = sz;
+ cp->mem = mem;
+ mem = 0;
+
+ for(i = 0; i < elf.phnum; i++){
+ if(readi(ip, (char*)&ph, elf.phoff + i * sizeof(ph),
+ sizeof(ph)) != sizeof(ph))
+ goto bad2;
+ 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 = sp;
+ setupsegs(cp);
+
+ return 0;
+
+ bad:
+ if(mem)
+ kfree(mem, sz);
+ iput(ip);
+ return -1;
+
+ bad2:
+ iput(ip);
+ proc_exit();
+ return 0;
+}