| 1 | #include "types.h" |
| 2 | #include "param.h" |
| 3 | #include "memlayout.h" |
| 4 | #include "mmu.h" |
| 5 | #include "proc.h" |
| 6 | #include "defs.h" |
| 7 | #include "x86.h" |
| 8 | #include "elf.h" |
| 9 | |
| 10 | #ifdef FOO |
| 11 | aaa |
| 12 | #endif |
| 13 | |
| 14 | int |
| 15 | exec(char *path, char **argv) |
| 16 | { |
| 17 | char *s, *last; |
| 18 | int i, off; |
| 19 | uint argc, sz, sp, ustack[3+MAXARG+1]; |
| 20 | struct elfhdr elf; |
| 21 | struct inode *ip; |
| 22 | struct proghdr ph; |
| 23 | pde_t *pgdir, *oldpgdir; |
| 24 | struct proc *curproc = myproc(); |
| 25 | |
| 26 | begin_op(); |
| 27 | |
| 28 | if((ip = namei(path)) == 0){ |
| 29 | end_op(); |
| 30 | cprintf("exec: fail\n" ); |
| 31 | return -1; |
| 32 | } |
| 33 | ilock(ip); |
| 34 | pgdir = 0; |
| 35 | |
| 36 | // Check ELF header |
| 37 | if(readi(ip, (char*)&elf, 0, sizeof(elf)) != sizeof(elf)) |
| 38 | goto bad; |
| 39 | if(elf.magic != ELF_MAGIC) |
| 40 | goto bad; |
| 41 | |
| 42 | if((pgdir = setupkvm()) == 0) |
| 43 | goto bad; |
| 44 | |
| 45 | // Load program into memory. |
| 46 | sz = 0; |
| 47 | for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){ |
| 48 | if(readi(ip, (char*)&ph, off, sizeof(ph)) != sizeof(ph)) |
| 49 | goto bad; |
| 50 | if(ph.type != ELF_PROG_LOAD) |
| 51 | continue; |
| 52 | if(ph.memsz < ph.filesz) |
| 53 | goto bad; |
| 54 | if(ph.vaddr + ph.memsz < ph.vaddr) |
| 55 | goto bad; |
| 56 | if((sz = allocuvm(pgdir, sz, ph.vaddr + ph.memsz)) == 0) |
| 57 | goto bad; |
| 58 | if(ph.vaddr % PGSIZE != 0) |
| 59 | goto bad; |
| 60 | if(loaduvm(pgdir, (char*)ph.vaddr, ip, ph.off, ph.filesz) < 0) |
| 61 | goto bad; |
| 62 | } |
| 63 | iunlockput(ip); |
| 64 | end_op(); |
| 65 | ip = 0; |
| 66 | |
| 67 | // Allocate two pages at the next page boundary. |
| 68 | // Make the first inaccessible. Use the second as the user stack. |
| 69 | sz = PGROUNDUP(sz); |
| 70 | if((sz = allocuvm(pgdir, sz, sz + 2*PGSIZE)) == 0) |
| 71 | goto bad; |
| 72 | clearpteu(pgdir, (char*)(sz - 2*PGSIZE)); |
| 73 | sp = sz; |
| 74 | |
| 75 | // Push argument strings, prepare rest of stack in ustack. |
| 76 | for(argc = 0; argv[argc]; argc++) { |
| 77 | if(argc >= MAXARG) |
| 78 | goto bad; |
| 79 | sp = (sp - (strlen(argv[argc]) + 1)) & ~3; |
| 80 | if(copyout(pgdir, sp, argv[argc], strlen(argv[argc]) + 1) < 0) |
| 81 | goto bad; |
| 82 | ustack[3+argc] = sp; |
| 83 | } |
| 84 | ustack[3+argc] = 0; |
| 85 | |
| 86 | ustack[0] = 0xffffffff; // fake return PC |
| 87 | ustack[1] = argc; |
| 88 | ustack[2] = sp - (argc+1)*4; // argv pointer |
| 89 | |
| 90 | sp -= (3+argc+1) * 4; |
| 91 | if(copyout(pgdir, sp, ustack, (3+argc+1)*4) < 0) |
| 92 | goto bad; |
| 93 | |
| 94 | // Save program name for debugging. |
| 95 | for(last=s=path; *s; s++) |
| 96 | if(*s == '/') |
| 97 | last = s+1; |
| 98 | safestrcpy(curproc->name, last, sizeof(curproc->name)); |
| 99 | |
| 100 | // Commit to the user image. |
| 101 | oldpgdir = curproc->pgdir; |
| 102 | curproc->pgdir = pgdir; |
| 103 | curproc->sz = sz; |
| 104 | curproc->tf->eip = elf.entry; // main |
| 105 | curproc->tf->esp = sp; |
| 106 | switchuvm(curproc); |
| 107 | freevm(oldpgdir); |
| 108 | return 0; |
| 109 | |
| 110 | bad: |
| 111 | if(pgdir) |
| 112 | freevm(pgdir); |
| 113 | if(ip){ |
| 114 | iunlockput(ip); |
| 115 | end_op(); |
| 116 | } |
| 117 | return -1; |
| 118 | } |
| 119 | |