source: mainline/uspace/srv/loader/main.c@ 8a1fb09

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

Integrate rest of rtld/ into C library.

  • Property mode set to 100644
File size: 10.7 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
[7fb3f1c]66#ifdef CONFIG_RTLD
[8a1fb09]67#include <rtld/rtld.h>
68#include <rtld/dynamic.h>
69#include <rtld/module.h>
[a6dffb8]70
71static int ldr_load_dyn_linked(elf_info_t *p_info);
[7fb3f1c]72#endif
73
74#define DPRINTF(...)
[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
[7fb3f1c]104#ifdef CONFIG_RTLD
[a6dffb8]105/** State structure of the dynamic linker. */
106runtime_env_t dload_re;
107static module_t prog_mod;
[7fb3f1c]108#endif
[a6dffb8]109
[bbdbf86]110static void ldr_get_taskid(ipc_callid_t rid, ipc_call_t *request)
[47e0a05b]111{
112 ipc_callid_t callid;
113 task_id_t task_id;
114 size_t len;
[2f57690]115
[47e0a05b]116 task_id = task_get_id();
[2f57690]117
[0da4e41]118 if (!async_data_read_receive(&callid, &len)) {
[ffa2c8ef]119 async_answer_0(callid, EINVAL);
120 async_answer_0(rid, EINVAL);
[47e0a05b]121 return;
122 }
[2f57690]123
124 if (len > sizeof(task_id))
125 len = sizeof(task_id);
126
[0da4e41]127 async_data_read_finalize(callid, &task_id, len);
[ffa2c8ef]128 async_answer_0(rid, EOK);
[47e0a05b]129}
130
[622cdbe]131/** Receive a call setting the current working directory.
[c98e6ee]132 *
133 * @param rid
134 * @param request
135 */
[622cdbe]136static void ldr_set_cwd(ipc_callid_t rid, ipc_call_t *request)
[c98e6ee]137{
[472c09d]138 char *buf;
[eda925a]139 int rc = async_data_write_accept((void **) &buf, true, 0, 0, 0, NULL);
[2f57690]140
[472c09d]141 if (rc == EOK) {
142 if (cwd != NULL)
143 free(cwd);
144
145 cwd = buf;
[c98e6ee]146 }
[2f57690]147
[ffa2c8ef]148 async_answer_0(rid, rc);
[622cdbe]149}
[47e0a05b]150
[c98e6ee]151/** Receive a call setting pathname of the program to execute.
152 *
153 * @param rid
154 * @param request
155 */
[bbdbf86]156static void ldr_set_pathname(ipc_callid_t rid, ipc_call_t *request)
[c98e6ee]157{
[472c09d]158 char *buf;
[eda925a]159 int rc = async_data_write_accept((void **) &buf, true, 0, 0, 0, NULL);
[2f57690]160
[472c09d]161 if (rc == EOK) {
162 if (pathname != NULL)
163 free(pathname);
164
165 pathname = buf;
[c98e6ee]166 }
[2f57690]167
[ffa2c8ef]168 async_answer_0(rid, rc);
[c98e6ee]169}
170
171/** Receive a call setting arguments of the program to execute.
172 *
173 * @param rid
174 * @param request
175 */
[bbdbf86]176static void ldr_set_args(ipc_callid_t rid, ipc_call_t *request)
[c98e6ee]177{
[472c09d]178 char *buf;
179 size_t buf_size;
[eda925a]180 int rc = async_data_write_accept((void **) &buf, true, 0, 0, 0, &buf_size);
[472c09d]181
182 if (rc == EOK) {
183 /*
184 * Count number of arguments
185 */
186 char *cur = buf;
187 int count = 0;
188
189 while (cur < buf + buf_size) {
190 size_t arg_size = str_size(cur);
191 cur += arg_size + 1;
192 count++;
193 }
[2f57690]194
[472c09d]195 /*
196 * Allocate new argv
197 */
198 char **_argv = (char **) malloc((count + 1) * sizeof(char *));
199 if (_argv == NULL) {
200 free(buf);
[ffa2c8ef]201 async_answer_0(rid, ENOMEM);
[472c09d]202 return;
203 }
204
205 /*
206 * Fill the new argv with argument pointers
207 */
208 cur = buf;
209 count = 0;
210 while (cur < buf + buf_size) {
211 _argv[count] = cur;
212
213 size_t arg_size = str_size(cur);
214 cur += arg_size + 1;
215 count++;
216 }
217 _argv[count] = NULL;
[2f57690]218
[472c09d]219 /*
220 * Copy temporary data to global variables
221 */
222 if (arg_buf != NULL)
223 free(arg_buf);
224
225 if (argv != NULL)
226 free(argv);
227
228 argc = count;
229 arg_buf = buf;
230 argv = _argv;
[c98e6ee]231 }
[2f57690]232
[ffa2c8ef]233 async_answer_0(rid, rc);
[c98e6ee]234}
235
[bbdbf86]236/** Receive a call setting preset files of the program to execute.
237 *
238 * @param rid
239 * @param request
240 */
241static void ldr_set_files(ipc_callid_t rid, ipc_call_t *request)
242{
[b4cbef1]243 fdi_node_t *buf;
[bbdbf86]244 size_t buf_size;
[eda925a]245 int rc = async_data_write_accept((void **) &buf, false, 0, 0,
246 sizeof(fdi_node_t), &buf_size);
[bbdbf86]247
[472c09d]248 if (rc == EOK) {
249 int count = buf_size / sizeof(fdi_node_t);
250
251 /*
252 * Allocate new filv
253 */
[36e9cd1]254 fdi_node_t **_filv = (fdi_node_t **) calloc(count + 1, sizeof(fdi_node_t *));
[472c09d]255 if (_filv == NULL) {
256 free(buf);
[ffa2c8ef]257 async_answer_0(rid, ENOMEM);
[472c09d]258 return;
259 }
260
261 /*
262 * Fill the new filv with argument pointers
263 */
264 int i;
265 for (i = 0; i < count; i++)
[b4cbef1]266 _filv[i] = &buf[i];
[472c09d]267
268 _filv[count] = NULL;
269
270 /*
271 * Copy temporary data to global variables
272 */
273 if (fil_buf != NULL)
274 free(fil_buf);
275
276 if (filv != NULL)
277 free(filv);
278
279 filc = count;
[b4cbef1]280 fil_buf = buf;
[472c09d]281 filv = _filv;
[bbdbf86]282 }
283
[ffa2c8ef]284 async_answer_0(rid, EOK);
[bbdbf86]285}
286
[4470e26]287/** Load the previously selected program.
[c98e6ee]288 *
289 * @param rid
290 * @param request
291 * @return 0 on success, !0 on error.
292 */
[bbdbf86]293static int ldr_load(ipc_callid_t rid, ipc_call_t *request)
[c98e6ee]294{
295 int rc;
[2f57690]296
[1ea99cc]297 rc = elf_load_file(pathname, 0, 0, &prog_info);
[409b0d6]298 if (rc != EE_OK) {
[06b2b7f]299 DPRINTF("Failed to load executable '%s'.\n", pathname);
[ffa2c8ef]300 async_answer_0(rid, EINVAL);
[c98e6ee]301 return 1;
302 }
[2f57690]303
[c98e6ee]304 elf_create_pcb(&prog_info, &pcb);
[2f57690]305
[622cdbe]306 pcb.cwd = cwd;
307
[c98e6ee]308 pcb.argc = argc;
309 pcb.argv = argv;
[2f57690]310
[bbdbf86]311 pcb.filc = filc;
312 pcb.filv = filv;
313
[c98e6ee]314 if (prog_info.interp == NULL) {
315 /* Statically linked program */
[ffa2c8ef]316 async_answer_0(rid, EOK);
[c98e6ee]317 return 0;
318 }
[2f57690]319
[a6dffb8]320 DPRINTF("Binary is dynamically linked.\n");
[7fb3f1c]321#ifdef CONFIG_RTLD
[a6dffb8]322 DPRINTF(" - pcb address: %p\n", &pcb);
323 DPRINTF( "- prog dynamic: %p\n", prog_info.dynamic);
[1ea99cc]324
[a6dffb8]325 rc = ldr_load_dyn_linked(&prog_info);
[7fb3f1c]326#else
327 rc = ENOTSUP;
328#endif
[a6dffb8]329 async_answer_0(rid, rc);
[c98e6ee]330 return 0;
331}
332
[7fb3f1c]333#ifdef CONFIG_RTLD
334
[a6dffb8]335static int ldr_load_dyn_linked(elf_info_t *p_info)
336{
337 runtime_env = &dload_re;
338
339 DPRINTF("Load dynamically linked program.\n");
340
341 /*
342 * First we need to process dynamic sections of the executable
343 * program and insert it into the module graph.
344 */
345
346 DPRINTF("Parse program .dynamic section at %p\n", p_info->dynamic);
347 dynamic_parse(p_info->dynamic, 0, &prog_mod.dyn);
348 prog_mod.bias = 0;
349 prog_mod.dyn.soname = "[program]";
350
351 /* Initialize list of loaded modules */
352 list_initialize(&runtime_env->modules_head);
353 list_append(&prog_mod.modules_link, &runtime_env->modules_head);
354
355 /* Pointer to program module. Used as root of the module graph. */
356 runtime_env->program = &prog_mod;
357
358 /* Work around non-existent memory space allocation. */
359 runtime_env->next_bias = 0x1000000;
360
361 /*
362 * Now we can continue with loading all other modules.
363 */
364
365 DPRINTF("Load all program dependencies\n");
366 module_load_deps(&prog_mod);
367
368 /*
369 * Now relocate/link all modules together.
370 */
371
372 /* Process relocations in all modules */
373 DPRINTF("Relocate all modules\n");
374 modules_process_relocs(&prog_mod);
375
376 /* Pass runtime evironment pointer through PCB. */
377 pcb.rtld_runtime = (void *) runtime_env;
378
379 return 0;
380}
[7fb3f1c]381#endif
[4470e26]382
383/** Run the previously loaded program.
384 *
385 * @param rid
386 * @param request
387 * @return 0 on success, !0 on error.
388 */
[bbdbf86]389static void ldr_run(ipc_callid_t rid, ipc_call_t *request)
[4470e26]390{
[20f1597]391 const char *cp;
[2f57690]392
[a6dffb8]393 DPRINTF("Set task name\n");
394
[bc18d63]395 /* Set the task name. */
[7afb4a5]396 cp = str_rchr(pathname, '/');
[20f1597]397 cp = (cp == NULL) ? pathname : (cp + 1);
398 task_set_name(cp);
[2f57690]399
[a6dffb8]400 /* Run program */
401 DPRINTF("Reply OK\n");
402 async_answer_0(rid, EOK);
403 DPRINTF("Jump to entry point at %p\n", pcb.entry);
[f798178]404 entry_point_jmp(prog_info.entry, &pcb);
[bbdbf86]405
[4470e26]406 /* Not reached */
407}
408
[c98e6ee]409/** Handle loader connection.
410 *
411 * Receive and carry out commands (of which the last one should be
412 * to execute the loaded program).
413 */
[bbdbf86]414static void ldr_connection(ipc_callid_t iid, ipc_call_t *icall)
[c98e6ee]415{
416 ipc_callid_t callid;
417 ipc_call_t call;
418 int retval;
[2f57690]419
[bfd1546]420 /* Already have a connection? */
421 if (connected) {
[ffa2c8ef]422 async_answer_0(iid, ELIMIT);
[bfd1546]423 return;
424 }
[2f57690]425
[bfd1546]426 connected = true;
427
428 /* Accept the connection */
[ffa2c8ef]429 async_answer_0(iid, EOK);
[2f57690]430
[c98e6ee]431 /* Ignore parameters, the connection is already open */
[2f57690]432 (void) iid;
433 (void) icall;
434
[c98e6ee]435 while (1) {
436 callid = async_get_call(&call);
[2f57690]437
[228e490]438 switch (IPC_GET_IMETHOD(call)) {
[86e3d62]439 case IPC_M_PHONE_HUNGUP:
440 exit(0);
[47e0a05b]441 case LOADER_GET_TASKID:
[bbdbf86]442 ldr_get_taskid(callid, &call);
[47e0a05b]443 continue;
[622cdbe]444 case LOADER_SET_CWD:
445 ldr_set_cwd(callid, &call);
446 continue;
[c98e6ee]447 case LOADER_SET_PATHNAME:
[bbdbf86]448 ldr_set_pathname(callid, &call);
[c98e6ee]449 continue;
450 case LOADER_SET_ARGS:
[bbdbf86]451 ldr_set_args(callid, &call);
452 continue;
453 case LOADER_SET_FILES:
454 ldr_set_files(callid, &call);
[4470e26]455 continue;
456 case LOADER_LOAD:
[bbdbf86]457 ldr_load(callid, &call);
[4470e26]458 continue;
[c98e6ee]459 case LOADER_RUN:
[bbdbf86]460 ldr_run(callid, &call);
[4470e26]461 /* Not reached */
[c98e6ee]462 default:
[8c3bc75]463 retval = EINVAL;
[c98e6ee]464 break;
465 }
[8c3bc75]466
467 if (IPC_GET_IMETHOD(call) != IPC_M_PHONE_HUNGUP)
468 async_answer_0(callid, retval);
[c98e6ee]469 }
470}
471
472/** Program loader main function.
473 */
474int main(int argc, char *argv[])
475{
[007e6efa]476 /* Set a handler of incomming connections. */
477 async_set_client_connection(ldr_connection);
478
[5d96851b]479 /* Introduce this task to the NS (give it our task ID). */
[007e6efa]480 task_id_t id = task_get_id();
481 int rc = async_req_2_0(PHONE_NS, NS_ID_INTRO, LOWER32(id), UPPER32(id));
[5d96851b]482 if (rc != EOK)
483 return -1;
[2f57690]484
[bfd1546]485 /* Register at naming service. */
[007e6efa]486 if (service_register(SERVICE_LOAD) != EOK)
[5d96851b]487 return -2;
[007e6efa]488
[c98e6ee]489 async_manager();
[2f57690]490
[bfd1546]491 /* Never reached */
[c98e6ee]492 return 0;
493}
494
495/** @}
496 */
Note: See TracBrowser for help on using the repository browser.