Rev 4344 | Rev 4347 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 4344 | Rev 4345 | ||
|---|---|---|---|
| Line 25... | Line 25... | ||
| 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | */ |
27 | */ |
| 28 | 28 | ||
| 29 | /** @addtogroup loader |
29 | /** @addtogroup loader |
| 30 | * @brief Loads and runs programs from VFS. |
30 | * @brief Loads and runs programs from VFS. |
| 31 | * @{ |
31 | * @{ |
| 32 | */ |
32 | */ |
| 33 | /** |
33 | /** |
| 34 | * @file |
34 | * @file |
| 35 | * @brief Loads and runs programs from VFS. |
35 | * @brief Loads and runs programs from VFS. |
| 36 | * |
36 | * |
| 37 | * The program loader is a special init binary. Its image is used |
37 | * The program loader is a special init binary. Its image is used |
| 38 | * to create a new task upon a @c task_spawn syscall. The syscall |
38 | * to create a new task upon a @c task_spawn syscall. The syscall |
| 39 | * returns the id of a phone connected to the newly created task. |
39 | * returns the id of a phone connected to the newly created task. |
| 40 | * |
40 | * |
| Line 88... | Line 88... | ||
| 88 | static void loader_get_taskid(ipc_callid_t rid, ipc_call_t *request) |
88 | static void loader_get_taskid(ipc_callid_t rid, ipc_call_t *request) |
| 89 | { |
89 | { |
| 90 | ipc_callid_t callid; |
90 | ipc_callid_t callid; |
| 91 | task_id_t task_id; |
91 | task_id_t task_id; |
| 92 | size_t len; |
92 | size_t len; |
| 93 | 93 | ||
| 94 | task_id = task_get_id(); |
94 | task_id = task_get_id(); |
| 95 | 95 | ||
| 96 | if (!ipc_data_read_receive(&callid, &len)) { |
96 | if (!ipc_data_read_receive(&callid, &len)) { |
| 97 | ipc_answer_0(callid, EINVAL); |
97 | ipc_answer_0(callid, EINVAL); |
| 98 | ipc_answer_0(rid, EINVAL); |
98 | ipc_answer_0(rid, EINVAL); |
| 99 | return; |
99 | return; |
| 100 | } |
100 | } |
| 101 | 101 | ||
| 102 | if (len > sizeof(task_id)) len = sizeof(task_id); |
102 | if (len > sizeof(task_id)) |
| - | 103 | len = sizeof(task_id); |
|
| 103 | 104 | ||
| 104 | ipc_data_read_finalize(callid, &task_id, len); |
105 | ipc_data_read_finalize(callid, &task_id, len); |
| 105 | ipc_answer_0(rid, EOK); |
106 | ipc_answer_0(rid, EOK); |
| 106 | } |
107 | } |
| 107 | 108 | ||
| 108 | 109 | ||
| Line 114... | Line 115... | ||
| 114 | static void loader_set_pathname(ipc_callid_t rid, ipc_call_t *request) |
115 | static void loader_set_pathname(ipc_callid_t rid, ipc_call_t *request) |
| 115 | { |
116 | { |
| 116 | ipc_callid_t callid; |
117 | ipc_callid_t callid; |
| 117 | size_t len; |
118 | size_t len; |
| 118 | char *name_buf; |
119 | char *name_buf; |
| 119 | 120 | ||
| 120 | if (!ipc_data_write_receive(&callid, &len)) { |
121 | if (!ipc_data_write_receive(&callid, &len)) { |
| 121 | ipc_answer_0(callid, EINVAL); |
122 | ipc_answer_0(callid, EINVAL); |
| 122 | ipc_answer_0(rid, EINVAL); |
123 | ipc_answer_0(rid, EINVAL); |
| 123 | return; |
124 | return; |
| 124 | } |
125 | } |
| 125 | 126 | ||
| 126 | name_buf = malloc(len + 1); |
127 | name_buf = malloc(len + 1); |
| 127 | if (!name_buf) { |
128 | if (!name_buf) { |
| 128 | ipc_answer_0(callid, ENOMEM); |
129 | ipc_answer_0(callid, ENOMEM); |
| 129 | ipc_answer_0(rid, ENOMEM); |
130 | ipc_answer_0(rid, ENOMEM); |
| 130 | return; |
131 | return; |
| 131 | } |
132 | } |
| 132 | 133 | ||
| 133 | ipc_data_write_finalize(callid, name_buf, len); |
134 | ipc_data_write_finalize(callid, name_buf, len); |
| 134 | ipc_answer_0(rid, EOK); |
135 | ipc_answer_0(rid, EOK); |
| 135 | 136 | ||
| 136 | if (pathname != NULL) { |
137 | if (pathname != NULL) { |
| 137 | free(pathname); |
138 | free(pathname); |
| 138 | pathname = NULL; |
139 | pathname = NULL; |
| 139 | } |
140 | } |
| 140 | 141 | ||
| 141 | name_buf[len] = '\0'; |
142 | name_buf[len] = '\0'; |
| 142 | pathname = name_buf; |
143 | pathname = name_buf; |
| 143 | } |
144 | } |
| 144 | 145 | ||
| 145 | /** Receive a call setting arguments of the program to execute. |
146 | /** Receive a call setting arguments of the program to execute. |
| Line 151... | Line 152... | ||
| 151 | { |
152 | { |
| 152 | ipc_callid_t callid; |
153 | ipc_callid_t callid; |
| 153 | size_t buf_len, arg_len; |
154 | size_t buf_len, arg_len; |
| 154 | char *p; |
155 | char *p; |
| 155 | int n; |
156 | int n; |
| 156 | 157 | ||
| 157 | if (!ipc_data_write_receive(&callid, &buf_len)) { |
158 | if (!ipc_data_write_receive(&callid, &buf_len)) { |
| 158 | ipc_answer_0(callid, EINVAL); |
159 | ipc_answer_0(callid, EINVAL); |
| 159 | ipc_answer_0(rid, EINVAL); |
160 | ipc_answer_0(rid, EINVAL); |
| 160 | return; |
161 | return; |
| 161 | } |
162 | } |
| 162 | 163 | ||
| 163 | if (arg_buf != NULL) { |
164 | if (arg_buf != NULL) { |
| 164 | free(arg_buf); |
165 | free(arg_buf); |
| 165 | arg_buf = NULL; |
166 | arg_buf = NULL; |
| 166 | } |
167 | } |
| 167 | 168 | ||
| 168 | if (argv != NULL) { |
169 | if (argv != NULL) { |
| 169 | free(argv); |
170 | free(argv); |
| 170 | argv = NULL; |
171 | argv = NULL; |
| 171 | } |
172 | } |
| 172 | 173 | ||
| 173 | arg_buf = malloc(buf_len + 1); |
174 | arg_buf = malloc(buf_len + 1); |
| 174 | if (!arg_buf) { |
175 | if (!arg_buf) { |
| 175 | ipc_answer_0(callid, ENOMEM); |
176 | ipc_answer_0(callid, ENOMEM); |
| 176 | ipc_answer_0(rid, ENOMEM); |
177 | ipc_answer_0(rid, ENOMEM); |
| 177 | return; |
178 | return; |
| 178 | } |
179 | } |
| 179 | 180 | ||
| 180 | ipc_data_write_finalize(callid, arg_buf, buf_len); |
181 | ipc_data_write_finalize(callid, arg_buf, buf_len); |
| 181 | ipc_answer_0(rid, EOK); |
182 | ipc_answer_0(rid, EOK); |
| 182 | 183 | ||
| 183 | arg_buf[buf_len] = '\0'; |
184 | arg_buf[buf_len] = '\0'; |
| 184 | 185 | ||
| 185 | /* |
186 | /* |
| 186 | * Count number of arguments |
187 | * Count number of arguments |
| 187 | */ |
188 | */ |
| 188 | p = arg_buf; |
189 | p = arg_buf; |
| 189 | n = 0; |
190 | n = 0; |
| 190 | while (p < arg_buf + buf_len) { |
191 | while (p < arg_buf + buf_len) { |
| 191 | arg_len = strlen(p); |
192 | arg_len = strlen(p); |
| 192 | p = p + arg_len + 1; |
193 | p = p + arg_len + 1; |
| 193 | ++n; |
194 | ++n; |
| 194 | } |
195 | } |
| 195 | 196 | ||
| 196 | /* Allocate argv */ |
197 | /* Allocate argv */ |
| 197 | argv = malloc((n + 1) * sizeof(char *)); |
198 | argv = malloc((n + 1) * sizeof(char *)); |
| 198 | 199 | ||
| 199 | if (argv == NULL) { |
200 | if (argv == NULL) { |
| 200 | free(arg_buf); |
201 | free(arg_buf); |
| 201 | ipc_answer_0(callid, ENOMEM); |
202 | ipc_answer_0(callid, ENOMEM); |
| 202 | ipc_answer_0(rid, ENOMEM); |
203 | ipc_answer_0(rid, ENOMEM); |
| 203 | return; |
204 | return; |
| 204 | } |
205 | } |
| 205 | 206 | ||
| 206 | /* |
207 | /* |
| 207 | * Fill argv with argument pointers |
208 | * Fill argv with argument pointers |
| 208 | */ |
209 | */ |
| 209 | p = arg_buf; |
210 | p = arg_buf; |
| 210 | n = 0; |
211 | n = 0; |
| 211 | while (p < arg_buf + buf_len) { |
212 | while (p < arg_buf + buf_len) { |
| 212 | argv[n] = p; |
213 | argv[n] = p; |
| 213 | 214 | ||
| 214 | arg_len = strlen(p); |
215 | arg_len = strlen(p); |
| 215 | p = p + arg_len + 1; |
216 | p = p + arg_len + 1; |
| 216 | ++n; |
217 | ++n; |
| 217 | } |
218 | } |
| 218 | 219 | ||
| 219 | argc = n; |
220 | argc = n; |
| 220 | argv[n] = NULL; |
221 | argv[n] = NULL; |
| 221 | } |
222 | } |
| 222 | 223 | ||
| 223 | /** Load the previously selected program. |
224 | /** Load the previously selected program. |
| Line 227... | Line 228... | ||
| 227 | * @return 0 on success, !0 on error. |
228 | * @return 0 on success, !0 on error. |
| 228 | */ |
229 | */ |
| 229 | static int loader_load(ipc_callid_t rid, ipc_call_t *request) |
230 | static int loader_load(ipc_callid_t rid, ipc_call_t *request) |
| 230 | { |
231 | { |
| 231 | int rc; |
232 | int rc; |
| 232 | 233 | ||
| 233 | rc = elf_load_file(pathname, 0, 0, &prog_info); |
234 | rc = elf_load_file(pathname, 0, 0, &prog_info); |
| 234 | if (rc < 0) { |
235 | if (rc < 0) { |
| 235 | DPRINTF("Failed to load executable '%s'.\n", pathname); |
236 | DPRINTF("Failed to load executable '%s'.\n", pathname); |
| 236 | ipc_answer_0(rid, EINVAL); |
237 | ipc_answer_0(rid, EINVAL); |
| 237 | return 1; |
238 | return 1; |
| 238 | } |
239 | } |
| 239 | 240 | ||
| 240 | elf_create_pcb(&prog_info, &pcb); |
241 | elf_create_pcb(&prog_info, &pcb); |
| 241 | 242 | ||
| 242 | pcb.argc = argc; |
243 | pcb.argc = argc; |
| 243 | pcb.argv = argv; |
244 | pcb.argv = argv; |
| 244 | 245 | ||
| 245 | if (prog_info.interp == NULL) { |
246 | if (prog_info.interp == NULL) { |
| 246 | /* Statically linked program */ |
247 | /* Statically linked program */ |
| 247 | is_dyn_linked = false; |
248 | is_dyn_linked = false; |
| 248 | ipc_answer_0(rid, EOK); |
249 | ipc_answer_0(rid, EOK); |
| 249 | return 0; |
250 | return 0; |
| 250 | } |
251 | } |
| 251 | 252 | ||
| 252 | printf("Load ELF interpreter '%s'\n", prog_info.interp); |
253 | printf("Load ELF interpreter '%s'\n", prog_info.interp); |
| 253 | rc = elf_load_file(prog_info.interp, 0, 0, &interp_info); |
254 | rc = elf_load_file(prog_info.interp, 0, 0, &interp_info); |
| 254 | if (rc < 0) { |
255 | if (rc < 0) { |
| 255 | DPRINTF("Failed to load interpreter '%s.'\n", |
256 | DPRINTF("Failed to load interpreter '%s.'\n", |
| 256 | prog_info.interp); |
257 | prog_info.interp); |
| 257 | ipc_answer_0(rid, EINVAL); |
258 | ipc_answer_0(rid, EINVAL); |
| 258 | return 1; |
259 | return 1; |
| 259 | } |
260 | } |
| 260 | 261 | ||
| 261 | printf("Run interpreter.\n"); |
262 | printf("Run interpreter.\n"); |
| 262 | printf("entry point: 0x%lx\n", interp_info.entry); |
263 | printf("entry point: 0x%lx\n", interp_info.entry); |
| 263 | printf("pcb address: 0x%lx\n", &pcb); |
264 | printf("pcb address: 0x%lx\n", &pcb); |
| 264 | printf("prog dynamic: 0x%lx\n", prog_info.dynamic); |
265 | printf("prog dynamic: 0x%lx\n", prog_info.dynamic); |
| 265 | 266 | ||
| 266 | is_dyn_linked = true; |
267 | is_dyn_linked = true; |
| 267 | ipc_answer_0(rid, EOK); |
268 | ipc_answer_0(rid, EOK); |
| 268 | 269 | ||
| 269 | return 0; |
270 | return 0; |
| 270 | } |
271 | } |
| 271 | 272 | ||
| 272 | 273 | ||
| 273 | /** Run the previously loaded program. |
274 | /** Run the previously loaded program. |
| Line 276... | Line 277... | ||
| 276 | * @param request |
277 | * @param request |
| 277 | * @return 0 on success, !0 on error. |
278 | * @return 0 on success, !0 on error. |
| 278 | */ |
279 | */ |
| 279 | static void loader_run(ipc_callid_t rid, ipc_call_t *request) |
280 | static void loader_run(ipc_callid_t rid, ipc_call_t *request) |
| 280 | { |
281 | { |
| - | 282 | const char *cp; |
|
| - | 283 | ||
| 281 | /* Set the task name. */ |
284 | /* Set the task name. */ |
| - | 285 | cp = strrchr(pathname, '/'); |
|
| - | 286 | cp = (cp == NULL) ? pathname : (cp + 1); |
|
| 282 | task_set_name(pathname); |
287 | task_set_name(cp); |
| 283 | 288 | ||
| 284 | if (is_dyn_linked == true) { |
289 | if (is_dyn_linked == true) { |
| 285 | /* Dynamically linked program */ |
290 | /* Dynamically linked program */ |
| 286 | DPRINTF("Run ELF interpreter.\n"); |
291 | DPRINTF("Run ELF interpreter.\n"); |
| 287 | DPRINTF("Entry point: 0x%lx\n", interp_info.entry); |
292 | DPRINTF("Entry point: 0x%lx\n", interp_info.entry); |
| 288 | close_console(); |
293 | close_console(); |
| 289 | 294 | ||
| 290 | ipc_answer_0(rid, EOK); |
295 | ipc_answer_0(rid, EOK); |
| 291 | program_run(interp_info.entry, &pcb); |
296 | program_run(interp_info.entry, &pcb); |
| 292 | - | ||
| 293 | } else { |
297 | } else { |
| 294 | /* Statically linked program */ |
298 | /* Statically linked program */ |
| 295 | close_console(); |
299 | close_console(); |
| 296 | ipc_answer_0(rid, EOK); |
300 | ipc_answer_0(rid, EOK); |
| 297 | program_run(prog_info.entry, &pcb); |
301 | program_run(prog_info.entry, &pcb); |
| Line 308... | Line 312... | ||
| 308 | static void loader_connection(ipc_callid_t iid, ipc_call_t *icall) |
312 | static void loader_connection(ipc_callid_t iid, ipc_call_t *icall) |
| 309 | { |
313 | { |
| 310 | ipc_callid_t callid; |
314 | ipc_callid_t callid; |
| 311 | ipc_call_t call; |
315 | ipc_call_t call; |
| 312 | int retval; |
316 | int retval; |
| 313 | 317 | ||
| 314 | /* Already have a connection? */ |
318 | /* Already have a connection? */ |
| 315 | if (connected) { |
319 | if (connected) { |
| 316 | ipc_answer_0(iid, ELIMIT); |
320 | ipc_answer_0(iid, ELIMIT); |
| 317 | return; |
321 | return; |
| 318 | } |
322 | } |
| 319 | 323 | ||
| 320 | connected = true; |
324 | connected = true; |
| 321 | 325 | ||
| 322 | /* Accept the connection */ |
326 | /* Accept the connection */ |
| 323 | ipc_answer_0(iid, EOK); |
327 | ipc_answer_0(iid, EOK); |
| 324 | 328 | ||
| 325 | /* Ignore parameters, the connection is already open */ |
329 | /* Ignore parameters, the connection is already open */ |
| - | 330 | (void) iid; |
|
| 326 | (void)iid; (void)icall; |
331 | (void) icall; |
| 327 | 332 | ||
| 328 | while (1) { |
333 | while (1) { |
| 329 | callid = async_get_call(&call); |
334 | callid = async_get_call(&call); |
| 330 | 335 | ||
| 331 | switch (IPC_GET_METHOD(call)) { |
336 | switch (IPC_GET_METHOD(call)) { |
| 332 | case IPC_M_PHONE_HUNGUP: |
337 | case IPC_M_PHONE_HUNGUP: |
| 333 | exit(0); |
338 | exit(0); |
| 334 | case LOADER_GET_TASKID: |
339 | case LOADER_GET_TASKID: |
| 335 | loader_get_taskid(callid, &call); |
340 | loader_get_taskid(callid, &call); |
| Line 362... | Line 367... | ||
| 362 | /** Program loader main function. |
367 | /** Program loader main function. |
| 363 | */ |
368 | */ |
| 364 | int main(int argc, char *argv[]) |
369 | int main(int argc, char *argv[]) |
| 365 | { |
370 | { |
| 366 | ipcarg_t phonead; |
371 | ipcarg_t phonead; |
| 367 | 372 | ||
| 368 | connected = false; |
373 | connected = false; |
| 369 | 374 | ||
| 370 | /* Set a handler of incomming connections. */ |
375 | /* Set a handler of incomming connections. */ |
| 371 | async_set_client_connection(loader_connection); |
376 | async_set_client_connection(loader_connection); |
| 372 | 377 | ||
| 373 | /* Register at naming service. */ |
378 | /* Register at naming service. */ |
| 374 | if (ipc_connect_to_me(PHONE_NS, SERVICE_LOAD, 0, 0, &phonead) != 0) |
379 | if (ipc_connect_to_me(PHONE_NS, SERVICE_LOAD, 0, 0, &phonead) != 0) |
| 375 | return -1; |
380 | return -1; |
| 376 | 381 | ||
| 377 | async_manager(); |
382 | async_manager(); |
| 378 | 383 | ||
| 379 | /* Never reached */ |
384 | /* Never reached */ |
| 380 | return 0; |
385 | return 0; |
| 381 | } |
386 | } |
| 382 | 387 | ||
| 383 | /** @} |
388 | /** @} |