source: mainline/uspace/srv/loader/main.c@ 7fb3f1c

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

Make all architectures buildable. Only allow enabling dynamic linking on ia32.

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