source: mainline/uspace/srv/loader/main.c@ f798178

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f798178 was f798178, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Merge mainline changes.

  • Property mode set to 100644
File size: 10.6 KB
RevLine 
[c98e6ee]1/*
2 * Copyright (c) 2008 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
27 */
28
29/** @addtogroup loader
[2f57690]30 * @brief Loads and runs programs from VFS.
[c98e6ee]31 * @{
[2f57690]32 */
[c98e6ee]33/**
34 * @file
[2f57690]35 * @brief Loads and runs programs from VFS.
[c98e6ee]36 *
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
39 * returns the id of a phone connected to the newly created task.
40 *
41 * The caller uses this phone to send the pathname and various other
42 * information to the loader. This is normally done by the C library
43 * and completely hidden from applications.
44 */
45
46#include <stdio.h>
47#include <stdlib.h>
48#include <unistd.h>
[4470e26]49#include <bool.h>
[c98e6ee]50#include <fcntl.h>
51#include <sys/types.h>
[bfd1546]52#include <ipc/services.h>
[c98e6ee]53#include <ipc/loader.h>
[5d96851b]54#include <ipc/ns.h>
55#include <macros.h>
[c98e6ee]56#include <loader/pcb.h>
[f798178]57#include <entry_point.h>
[c98e6ee]58#include <errno.h>
59#include <async.h>
[19f857a]60#include <str.h>
[c98e6ee]61#include <as.h>
62
63#include <elf.h>
64#include <elf_load.h>
65
[a6dffb8]66/* From librtld */
67#include <rtld.h>
68#include <dynamic.h>
69#include <elf_load.h>
70#include <module.h>
71
[06b2b7f]72#define DPRINTF(...)
73
[a6dffb8]74static int ldr_load_dyn_linked(elf_info_t *p_info);
[1ea99cc]75
[c98e6ee]76/** Pathname of the file that will be loaded */
77static char *pathname = NULL;
78
79/** The Program control block */
80static pcb_t pcb;
81
[622cdbe]82/** Current working directory */
83static char *cwd = NULL;
84
[c98e6ee]85/** Number of arguments */
86static int argc = 0;
87/** Argument vector */
88static char **argv = NULL;
89/** Buffer holding all arguments */
90static char *arg_buf = NULL;
91
[bbdbf86]92/** Number of preset files */
93static int filc = 0;
94/** Preset files vector */
[08c9f7d5]95static fdi_node_t **filv = NULL;
[bbdbf86]96/** Buffer holding all preset files */
[99272a3]97static fdi_node_t *fil_buf = NULL;
[bbdbf86]98
[4470e26]99static elf_info_t prog_info;
100
[bfd1546]101/** Used to limit number of connections to one. */
[007e6efa]102static bool connected = false;
[4470e26]103
[a6dffb8]104/** State structure of the dynamic linker. */
105runtime_env_t dload_re;
106static module_t prog_mod;
107
[bbdbf86]108static void ldr_get_taskid(ipc_callid_t rid, ipc_call_t *request)
[47e0a05b]109{
110 ipc_callid_t callid;
111 task_id_t task_id;
112 size_t len;
[2f57690]113
[47e0a05b]114 task_id = task_get_id();
[2f57690]115
[0da4e41]116 if (!async_data_read_receive(&callid, &len)) {
[ffa2c8ef]117 async_answer_0(callid, EINVAL);
118 async_answer_0(rid, EINVAL);
[47e0a05b]119 return;
120 }
[2f57690]121
122 if (len > sizeof(task_id))
123 len = sizeof(task_id);
124
[0da4e41]125 async_data_read_finalize(callid, &task_id, len);
[ffa2c8ef]126 async_answer_0(rid, EOK);
[47e0a05b]127}
128
[622cdbe]129/** Receive a call setting the current working directory.
[c98e6ee]130 *
131 * @param rid
132 * @param request
133 */
[622cdbe]134static void ldr_set_cwd(ipc_callid_t rid, ipc_call_t *request)
[c98e6ee]135{
[472c09d]136 char *buf;
[eda925a]137 int rc = async_data_write_accept((void **) &buf, true, 0, 0, 0, NULL);
[2f57690]138
[472c09d]139 if (rc == EOK) {
140 if (cwd != NULL)
141 free(cwd);
142
143 cwd = buf;
[c98e6ee]144 }
[2f57690]145
[ffa2c8ef]146 async_answer_0(rid, rc);
[622cdbe]147}
[47e0a05b]148
[c98e6ee]149/** Receive a call setting pathname of the program to execute.
150 *
151 * @param rid
152 * @param request
153 */
[bbdbf86]154static void ldr_set_pathname(ipc_callid_t rid, ipc_call_t *request)
[c98e6ee]155{
[472c09d]156 char *buf;
[eda925a]157 int rc = async_data_write_accept((void **) &buf, true, 0, 0, 0, NULL);
[2f57690]158
[472c09d]159 if (rc == EOK) {
160 if (pathname != NULL)
161 free(pathname);
162
163 pathname = buf;
[c98e6ee]164 }
[2f57690]165
[ffa2c8ef]166 async_answer_0(rid, rc);
[c98e6ee]167}
168
169/** Receive a call setting arguments of the program to execute.
170 *
171 * @param rid
172 * @param request
173 */
[bbdbf86]174static void ldr_set_args(ipc_callid_t rid, ipc_call_t *request)
[c98e6ee]175{
[472c09d]176 char *buf;
177 size_t buf_size;
[eda925a]178 int rc = async_data_write_accept((void **) &buf, true, 0, 0, 0, &buf_size);
[472c09d]179
180 if (rc == EOK) {
181 /*
182 * Count number of arguments
183 */
184 char *cur = buf;
185 int count = 0;
186
187 while (cur < buf + buf_size) {
188 size_t arg_size = str_size(cur);
189 cur += arg_size + 1;
190 count++;
191 }
[2f57690]192
[472c09d]193 /*
194 * Allocate new argv
195 */
196 char **_argv = (char **) malloc((count + 1) * sizeof(char *));
197 if (_argv == NULL) {
198 free(buf);
[ffa2c8ef]199 async_answer_0(rid, ENOMEM);
[472c09d]200 return;
201 }
202
203 /*
204 * Fill the new argv with argument pointers
205 */
206 cur = buf;
207 count = 0;
208 while (cur < buf + buf_size) {
209 _argv[count] = cur;
210
211 size_t arg_size = str_size(cur);
212 cur += arg_size + 1;
213 count++;
214 }
215 _argv[count] = NULL;
[2f57690]216
[472c09d]217 /*
218 * Copy temporary data to global variables
219 */
220 if (arg_buf != NULL)
221 free(arg_buf);
222
223 if (argv != NULL)
224 free(argv);
225
226 argc = count;
227 arg_buf = buf;
228 argv = _argv;
[c98e6ee]229 }
[2f57690]230
[ffa2c8ef]231 async_answer_0(rid, rc);
[c98e6ee]232}
233
[bbdbf86]234/** Receive a call setting preset files of the program to execute.
235 *
236 * @param rid
237 * @param request
238 */
239static void ldr_set_files(ipc_callid_t rid, ipc_call_t *request)
240{
[b4cbef1]241 fdi_node_t *buf;
[bbdbf86]242 size_t buf_size;
[eda925a]243 int rc = async_data_write_accept((void **) &buf, false, 0, 0,
244 sizeof(fdi_node_t), &buf_size);
[bbdbf86]245
[472c09d]246 if (rc == EOK) {
247 int count = buf_size / sizeof(fdi_node_t);
248
249 /*
250 * Allocate new filv
251 */
[36e9cd1]252 fdi_node_t **_filv = (fdi_node_t **) calloc(count + 1, sizeof(fdi_node_t *));
[472c09d]253 if (_filv == NULL) {
254 free(buf);
[ffa2c8ef]255 async_answer_0(rid, ENOMEM);
[472c09d]256 return;
257 }
258
259 /*
260 * Fill the new filv with argument pointers
261 */
262 int i;
263 for (i = 0; i < count; i++)
[b4cbef1]264 _filv[i] = &buf[i];
[472c09d]265
266 _filv[count] = NULL;
267
268 /*
269 * Copy temporary data to global variables
270 */
271 if (fil_buf != NULL)
272 free(fil_buf);
273
274 if (filv != NULL)
275 free(filv);
276
277 filc = count;
[b4cbef1]278 fil_buf = buf;
[472c09d]279 filv = _filv;
[bbdbf86]280 }
281
[ffa2c8ef]282 async_answer_0(rid, EOK);
[bbdbf86]283}
284
[4470e26]285/** Load the previously selected program.
[c98e6ee]286 *
287 * @param rid
288 * @param request
289 * @return 0 on success, !0 on error.
290 */
[bbdbf86]291static int ldr_load(ipc_callid_t rid, ipc_call_t *request)
[c98e6ee]292{
293 int rc;
[2f57690]294
[1ea99cc]295 rc = elf_load_file(pathname, 0, 0, &prog_info);
[409b0d6]296 if (rc != EE_OK) {
[06b2b7f]297 DPRINTF("Failed to load executable '%s'.\n", pathname);
[ffa2c8ef]298 async_answer_0(rid, EINVAL);
[c98e6ee]299 return 1;
300 }
[2f57690]301
[c98e6ee]302 elf_create_pcb(&prog_info, &pcb);
[2f57690]303
[622cdbe]304 pcb.cwd = cwd;
305
[c98e6ee]306 pcb.argc = argc;
307 pcb.argv = argv;
[2f57690]308
[bbdbf86]309 pcb.filc = filc;
310 pcb.filv = filv;
311
[c98e6ee]312 if (prog_info.interp == NULL) {
313 /* Statically linked program */
[ffa2c8ef]314 async_answer_0(rid, EOK);
[c98e6ee]315 return 0;
316 }
[2f57690]317
[a6dffb8]318 DPRINTF("Binary is dynamically linked.\n");
319 DPRINTF(" - pcb address: %p\n", &pcb);
320 DPRINTF( "- prog dynamic: %p\n", prog_info.dynamic);
[1ea99cc]321
[a6dffb8]322 rc = ldr_load_dyn_linked(&prog_info);
323
324 async_answer_0(rid, rc);
[c98e6ee]325 return 0;
326}
327
[a6dffb8]328static int ldr_load_dyn_linked(elf_info_t *p_info)
329{
330 runtime_env = &dload_re;
331
332 DPRINTF("Load dynamically linked program.\n");
333
334 /*
335 * First we need to process dynamic sections of the executable
336 * program and insert it into the module graph.
337 */
338
339 DPRINTF("Parse program .dynamic section at %p\n", p_info->dynamic);
340 dynamic_parse(p_info->dynamic, 0, &prog_mod.dyn);
341 prog_mod.bias = 0;
342 prog_mod.dyn.soname = "[program]";
343
344 /* Initialize list of loaded modules */
345 list_initialize(&runtime_env->modules_head);
346 list_append(&prog_mod.modules_link, &runtime_env->modules_head);
347
348 /* Pointer to program module. Used as root of the module graph. */
349 runtime_env->program = &prog_mod;
350
351 /* Work around non-existent memory space allocation. */
352 runtime_env->next_bias = 0x1000000;
353
354 /*
355 * Now we can continue with loading all other modules.
356 */
357
358 DPRINTF("Load all program dependencies\n");
359 module_load_deps(&prog_mod);
360
361 /*
362 * Now relocate/link all modules together.
363 */
364
365 /* Process relocations in all modules */
366 DPRINTF("Relocate all modules\n");
367 modules_process_relocs(&prog_mod);
368
369 /* Pass runtime evironment pointer through PCB. */
370 pcb.rtld_runtime = (void *) runtime_env;
371
372 return 0;
373}
[4470e26]374
375/** Run the previously loaded program.
376 *
377 * @param rid
378 * @param request
379 * @return 0 on success, !0 on error.
380 */
[bbdbf86]381static void ldr_run(ipc_callid_t rid, ipc_call_t *request)
[4470e26]382{
[20f1597]383 const char *cp;
[2f57690]384
[a6dffb8]385 DPRINTF("Set task name\n");
386
[bc18d63]387 /* Set the task name. */
[7afb4a5]388 cp = str_rchr(pathname, '/');
[20f1597]389 cp = (cp == NULL) ? pathname : (cp + 1);
390 task_set_name(cp);
[2f57690]391
[a6dffb8]392 /* Run program */
393 DPRINTF("Reply OK\n");
394 async_answer_0(rid, EOK);
395 DPRINTF("Jump to entry point at %p\n", pcb.entry);
[f798178]396 entry_point_jmp(prog_info.entry, &pcb);
[bbdbf86]397
[4470e26]398 /* Not reached */
399}
400
[c98e6ee]401/** Handle loader connection.
402 *
403 * Receive and carry out commands (of which the last one should be
404 * to execute the loaded program).
405 */
[bbdbf86]406static void ldr_connection(ipc_callid_t iid, ipc_call_t *icall)
[c98e6ee]407{
408 ipc_callid_t callid;
409 ipc_call_t call;
410 int retval;
[2f57690]411
[bfd1546]412 /* Already have a connection? */
413 if (connected) {
[ffa2c8ef]414 async_answer_0(iid, ELIMIT);
[bfd1546]415 return;
416 }
[2f57690]417
[bfd1546]418 connected = true;
419
420 /* Accept the connection */
[ffa2c8ef]421 async_answer_0(iid, EOK);
[2f57690]422
[c98e6ee]423 /* Ignore parameters, the connection is already open */
[2f57690]424 (void) iid;
425 (void) icall;
426
[c98e6ee]427 while (1) {
428 callid = async_get_call(&call);
[2f57690]429
[228e490]430 switch (IPC_GET_IMETHOD(call)) {
[86e3d62]431 case IPC_M_PHONE_HUNGUP:
432 exit(0);
[47e0a05b]433 case LOADER_GET_TASKID:
[bbdbf86]434 ldr_get_taskid(callid, &call);
[47e0a05b]435 continue;
[622cdbe]436 case LOADER_SET_CWD:
437 ldr_set_cwd(callid, &call);
438 continue;
[c98e6ee]439 case LOADER_SET_PATHNAME:
[bbdbf86]440 ldr_set_pathname(callid, &call);
[c98e6ee]441 continue;
442 case LOADER_SET_ARGS:
[bbdbf86]443 ldr_set_args(callid, &call);
444 continue;
445 case LOADER_SET_FILES:
446 ldr_set_files(callid, &call);
[4470e26]447 continue;
448 case LOADER_LOAD:
[bbdbf86]449 ldr_load(callid, &call);
[4470e26]450 continue;
[c98e6ee]451 case LOADER_RUN:
[bbdbf86]452 ldr_run(callid, &call);
[4470e26]453 /* Not reached */
[c98e6ee]454 default:
[8c3bc75]455 retval = EINVAL;
[c98e6ee]456 break;
457 }
[8c3bc75]458
459 if (IPC_GET_IMETHOD(call) != IPC_M_PHONE_HUNGUP)
460 async_answer_0(callid, retval);
[c98e6ee]461 }
462}
463
464/** Program loader main function.
465 */
466int main(int argc, char *argv[])
467{
[007e6efa]468 /* Set a handler of incomming connections. */
469 async_set_client_connection(ldr_connection);
470
[5d96851b]471 /* Introduce this task to the NS (give it our task ID). */
[007e6efa]472 task_id_t id = task_get_id();
473 int rc = async_req_2_0(PHONE_NS, NS_ID_INTRO, LOWER32(id), UPPER32(id));
[5d96851b]474 if (rc != EOK)
475 return -1;
[2f57690]476
[bfd1546]477 /* Register at naming service. */
[007e6efa]478 if (service_register(SERVICE_LOAD) != EOK)
[5d96851b]479 return -2;
[007e6efa]480
[c98e6ee]481 async_manager();
[2f57690]482
[bfd1546]483 /* Never reached */
[c98e6ee]484 return 0;
485}
486
487/** @}
488 */
Note: See TracBrowser for help on using the repository browser.