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;
|
|
16 pde_t *pgdir;
|
|
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 pgdir = 0;
|
|
43
|
|
44 if ((pgdir = kpt_alloc()) == 0) {
|
|
45 goto bad;
|
|
46 }
|
|
47
|
|
48 // Load program into memory.
|
|
49 sz = 0;
|
|
50
|
|
51 for (i = 0, off = elf.phoff; i < elf.phnum; i++, off += sizeof(ph)) {
|
|
52 if (readi(ip, (char*) &ph, off, sizeof(ph)) != sizeof(ph)) {
|
|
53 goto bad;
|
|
54 }
|
|
55
|
|
56 if (ph.type != ELF_PROG_LOAD) {
|
|
57 continue;
|
|
58 }
|
|
59
|
|
60 if (ph.memsz < ph.filesz) {
|
|
61 goto bad;
|
|
62 }
|
|
63
|
|
64 if ((sz = allocuvm(pgdir, sz, ph.vaddr + ph.memsz)) == 0) {
|
|
65 goto bad;
|
|
66 }
|
|
67
|
|
68 if (loaduvm(pgdir, (char*) ph.vaddr, ip, ph.off, ph.filesz) < 0) {
|
|
69 goto bad;
|
|
70 }
|
|
71 }
|
|
72
|
|
73 iunlockput(ip);
|
|
74 ip = 0;
|
|
75
|
|
76 // Allocate two pages at the next page boundary.
|
|
77 // Make the first inaccessible. Use the second as the user stack.
|
|
78 sz = align_up (sz, PTE_SZ);
|
|
79
|
|
80 if ((sz = allocuvm(pgdir, sz, sz + 2 * PTE_SZ)) == 0) {
|
|
81 goto bad;
|
|
82 }
|
|
83
|
|
84 clearpteu(pgdir, (char*) (sz - 2 * PTE_SZ));
|
|
85
|
|
86 sp = sz;
|
|
87
|
|
88 // Push argument strings, prepare rest of stack in ustack.
|
|
89 for (argc = 0; argv[argc]; argc++) {
|
|
90 if (argc >= MAXARG) {
|
|
91 goto bad;
|
|
92 }
|
|
93
|
|
94 sp = (sp - (strlen(argv[argc]) + 1)) & ~3;
|
|
95
|
|
96 if (copyout(pgdir, sp, argv[argc], strlen(argv[argc]) + 1) < 0) {
|
|
97 goto bad;
|
|
98 }
|
|
99
|
|
100 ustack[argc] = sp;
|
|
101 }
|
|
102
|
|
103 ustack[argc] = 0;
|
|
104
|
|
105 // in ARM, parameters are passed in r0 and r1
|
|
106 proc->tf->r0 = argc;
|
|
107 proc->tf->r1 = sp - (argc + 1) * 4;
|
|
108
|
|
109 sp -= (argc + 1) * 4;
|
|
110
|
|
111 if (copyout(pgdir, sp, ustack, (argc + 1) * 4) < 0) {
|
|
112 goto bad;
|
|
113 }
|
|
114
|
|
115 // Save program name for debugging.
|
|
116 for (last = s = path; *s; s++) {
|
|
117 if (*s == '/') {
|
|
118 last = s + 1;
|
|
119 }
|
|
120 }
|
|
121
|
|
122 safestrcpy(proc->name, last, sizeof(proc->name));
|
|
123
|
|
124 // Commit to the user image.
|
|
125 oldpgdir = proc->pgdir;
|
|
126 proc->pgdir = pgdir;
|
|
127 proc->sz = sz;
|
|
128 proc->tf->pc = elf.entry;
|
|
129 proc->tf->sp_usr = sp;
|
|
130
|
|
131 switchuvm(proc);
|
|
132 freevm(oldpgdir);
|
|
133 return 0;
|
|
134
|
|
135 bad: if (pgdir) {
|
|
136 freevm(pgdir);
|
|
137 }
|
|
138
|
|
139 if (ip) {
|
|
140 iunlockput(ip);
|
|
141 }
|
|
142 return -1;
|
|
143 }
|