0
|
1 #include "types.h"
|
|
2 #include "param.h"
|
|
3 #include "defs.h"
|
|
4 #include "memlayout.h"
|
|
5 #include "mmu.h"
|
|
6 #include "proc.h"
|
|
7 #include "elf.h"
|
|
8 #include "arm.h"
|
|
9
|
|
10 // load a user program for execution
|
|
11 int exec (char *path, char **argv)
|
|
12 {
|
|
13 struct elfhdr elf;
|
|
14 struct inode *ip;
|
|
15 struct proghdr ph;
|
22
|
16 pde_t *pgdir = 0;
|
0
|
17 pde_t *oldpgdir;
|
|
18 char *s;
|
|
19 char *last;
|
|
20 int i;
|
|
21 int off;
|
|
22 uint argc;
|
|
23 uint sz;
|
|
24 uint sp;
|
|
25 uint ustack[3 + MAXARG + 1];
|
|
26
|
|
27 if ((ip = namei(path)) == 0) {
|
|
28 return -1;
|
|
29 }
|
|
30
|
|
31 ilock(ip);
|
|
32
|
|
33 // Check ELF header
|
|
34 if (readi(ip, (char*) &elf, 0, sizeof(elf)) < sizeof(elf)) {
|
|
35 goto bad;
|
|
36 }
|
|
37
|
|
38 if (elf.magic != ELF_MAGIC) {
|
|
39 goto bad;
|
|
40 }
|
|
41
|
|
42 if ((pgdir = kpt_alloc()) == 0) {
|
|
43 goto bad;
|
|
44 }
|
|
45
|
|
46 // Load program into memory.
|
|
47 sz = 0;
|
|
48
|
|
49 for (i = 0, off = elf.phoff; i < elf.phnum; i++, off += sizeof(ph)) {
|
|
50 if (readi(ip, (char*) &ph, off, sizeof(ph)) != sizeof(ph)) {
|
|
51 goto bad;
|
|
52 }
|
|
53
|
|
54 if (ph.type != ELF_PROG_LOAD) {
|
|
55 continue;
|
|
56 }
|
|
57
|
|
58 if (ph.memsz < ph.filesz) {
|
|
59 goto bad;
|
|
60 }
|
|
61
|
|
62 if ((sz = allocuvm(pgdir, sz, ph.vaddr + ph.memsz)) == 0) {
|
|
63 goto bad;
|
|
64 }
|
|
65
|
|
66 if (loaduvm(pgdir, (char*) ph.vaddr, ip, ph.off, ph.filesz) < 0) {
|
|
67 goto bad;
|
|
68 }
|
|
69 }
|
|
70
|
|
71 iunlockput(ip);
|
|
72 ip = 0;
|
|
73
|
|
74 // Allocate two pages at the next page boundary.
|
|
75 // Make the first inaccessible. Use the second as the user stack.
|
|
76 sz = align_up (sz, PTE_SZ);
|
|
77
|
|
78 if ((sz = allocuvm(pgdir, sz, sz + 2 * PTE_SZ)) == 0) {
|
|
79 goto bad;
|
|
80 }
|
|
81
|
|
82 clearpteu(pgdir, (char*) (sz - 2 * PTE_SZ));
|
|
83
|
|
84 sp = sz;
|
|
85
|
|
86 // Push argument strings, prepare rest of stack in ustack.
|
|
87 for (argc = 0; argv[argc]; argc++) {
|
|
88 if (argc >= MAXARG) {
|
|
89 goto bad;
|
|
90 }
|
|
91
|
|
92 sp = (sp - (strlen(argv[argc]) + 1)) & ~3;
|
|
93
|
|
94 if (copyout(pgdir, sp, argv[argc], strlen(argv[argc]) + 1) < 0) {
|
|
95 goto bad;
|
|
96 }
|
|
97
|
|
98 ustack[argc] = sp;
|
|
99 }
|
|
100
|
|
101 ustack[argc] = 0;
|
|
102
|
|
103 // in ARM, parameters are passed in r0 and r1
|
|
104 proc->tf->r0 = argc;
|
|
105 proc->tf->r1 = sp - (argc + 1) * 4;
|
|
106
|
|
107 sp -= (argc + 1) * 4;
|
|
108
|
|
109 if (copyout(pgdir, sp, ustack, (argc + 1) * 4) < 0) {
|
|
110 goto bad;
|
|
111 }
|
|
112
|
|
113 // Save program name for debugging.
|
|
114 for (last = s = path; *s; s++) {
|
|
115 if (*s == '/') {
|
|
116 last = s + 1;
|
|
117 }
|
|
118 }
|
|
119
|
|
120 safestrcpy(proc->name, last, sizeof(proc->name));
|
|
121
|
|
122 // Commit to the user image.
|
|
123 oldpgdir = proc->pgdir;
|
|
124 proc->pgdir = pgdir;
|
|
125 proc->sz = sz;
|
|
126 proc->tf->pc = elf.entry;
|
|
127 proc->tf->sp_usr = sp;
|
|
128
|
|
129 switchuvm(proc);
|
|
130 freevm(oldpgdir);
|
|
131 return 0;
|
|
132
|
|
133 bad: if (pgdir) {
|
|
134 freevm(pgdir);
|
|
135 }
|
|
136
|
|
137 if (ip) {
|
|
138 iunlockput(ip);
|
|
139 }
|
|
140 return -1;
|
|
141 }
|