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 | |