Mercurial > hg > Members > tobaru > CbC_xv6
diff src/exec.c @ 0:83c23a36980d
Init
author | Tatsuki IHA <e125716@ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 26 May 2017 23:11:05 +0900 |
parents | |
children | 397e74cbf14e |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/exec.c Fri May 26 23:11:05 2017 +0900 @@ -0,0 +1,143 @@ +#include "types.h" +#include "param.h" +#include "defs.h" +#include "memlayout.h" +#include "mmu.h" +#include "proc.h" +#include "elf.h" +#include "arm.h" + +// load a user program for execution +int exec (char *path, char **argv) +{ + struct elfhdr elf; + struct inode *ip; + struct proghdr ph; + pde_t *pgdir; + pde_t *oldpgdir; + char *s; + char *last; + int i; + int off; + uint argc; + uint sz; + uint sp; + uint ustack[3 + MAXARG + 1]; + + if ((ip = namei(path)) == 0) { + return -1; + } + + ilock(ip); + + // Check ELF header + if (readi(ip, (char*) &elf, 0, sizeof(elf)) < sizeof(elf)) { + goto bad; + } + + if (elf.magic != ELF_MAGIC) { + goto bad; + } + + pgdir = 0; + + if ((pgdir = kpt_alloc()) == 0) { + goto bad; + } + + // Load program into memory. + sz = 0; + + for (i = 0, off = elf.phoff; i < elf.phnum; i++, off += sizeof(ph)) { + if (readi(ip, (char*) &ph, off, sizeof(ph)) != sizeof(ph)) { + goto bad; + } + + if (ph.type != ELF_PROG_LOAD) { + continue; + } + + if (ph.memsz < ph.filesz) { + goto bad; + } + + if ((sz = allocuvm(pgdir, sz, ph.vaddr + ph.memsz)) == 0) { + goto bad; + } + + if (loaduvm(pgdir, (char*) ph.vaddr, ip, ph.off, ph.filesz) < 0) { + goto bad; + } + } + + iunlockput(ip); + ip = 0; + + // Allocate two pages at the next page boundary. + // Make the first inaccessible. Use the second as the user stack. + sz = align_up (sz, PTE_SZ); + + if ((sz = allocuvm(pgdir, sz, sz + 2 * PTE_SZ)) == 0) { + goto bad; + } + + clearpteu(pgdir, (char*) (sz - 2 * PTE_SZ)); + + sp = sz; + + // Push argument strings, prepare rest of stack in ustack. + for (argc = 0; argv[argc]; argc++) { + if (argc >= MAXARG) { + goto bad; + } + + sp = (sp - (strlen(argv[argc]) + 1)) & ~3; + + if (copyout(pgdir, sp, argv[argc], strlen(argv[argc]) + 1) < 0) { + goto bad; + } + + ustack[argc] = sp; + } + + ustack[argc] = 0; + + // in ARM, parameters are passed in r0 and r1 + proc->tf->r0 = argc; + proc->tf->r1 = sp - (argc + 1) * 4; + + sp -= (argc + 1) * 4; + + if (copyout(pgdir, sp, ustack, (argc + 1) * 4) < 0) { + goto bad; + } + + // Save program name for debugging. + for (last = s = path; *s; s++) { + if (*s == '/') { + last = s + 1; + } + } + + safestrcpy(proc->name, last, sizeof(proc->name)); + + // Commit to the user image. + oldpgdir = proc->pgdir; + proc->pgdir = pgdir; + proc->sz = sz; + proc->tf->pc = elf.entry; + proc->tf->sp_usr = sp; + + switchuvm(proc); + freevm(oldpgdir); + return 0; + + bad: if (pgdir) { + freevm(pgdir); + } + + if (ip) { + iunlockput(ip); + } + return -1; +}