source: mainline/uspace/srv/loader/main.c@ 43ac0cc

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 43ac0cc was 79ae36dd, checked in by Martin Decky <martin@…>, 14 years ago

new async framework with integrated exchange tracking

  • strict isolation between low-level IPC and high-level async framework with integrated exchange tracking
    • each IPC connection is represented by an async_sess_t structure
    • each IPC exchange is represented by an async_exch_t structure
    • exchange management is either based on atomic messages (EXCHANGE_ATOMIC), locking (EXCHANGE_SERIALIZE) or connection cloning (EXCHANGE_CLONE)
  • async_obsolete: temporary compatibility layer to keep old async clients working (several pieces of code are currently broken, but only non-essential functionality)
  • IPC_M_PHONE_HANGUP is now method no. 0 (for elegant boolean evaluation)
  • IPC_M_DEBUG_ALL has been renamed to IPC_M_DEBUG
  • IPC_M_PING has been removed (VFS protocol now has VFS_IN_PING)
  • console routines in libc have been rewritten for better abstraction
  • additional use for libc-private header files (FILE structure opaque to the client)
  • various cstyle changes (typos, indentation, missing externs in header files, improved comments, etc.)
  • 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>
[79ae36dd]54#include <ns.h>
[c98e6ee]55#include <loader/pcb.h>
[f798178]56#include <entry_point.h>
[c98e6ee]57#include <errno.h>
58#include <async.h>
[19f857a]59#include <str.h>
[c98e6ee]60#include <as.h>
61#include <elf.h>
62#include <elf_load.h>
63
[7fb3f1c]64#ifdef CONFIG_RTLD
[8a1fb09]65#include <rtld/rtld.h>
66#include <rtld/dynamic.h>
67#include <rtld/module.h>
[a6dffb8]68
69static int ldr_load_dyn_linked(elf_info_t *p_info);
[7fb3f1c]70#endif
71
72#define DPRINTF(...)
[1ea99cc]73
[c98e6ee]74/** Pathname of the file that will be loaded */
75static char *pathname = NULL;
76
77/** The Program control block */
78static pcb_t pcb;
79
[622cdbe]80/** Current working directory */
81static char *cwd = NULL;
82
[c98e6ee]83/** Number of arguments */
84static int argc = 0;
85/** Argument vector */
86static char **argv = NULL;
87/** Buffer holding all arguments */
88static char *arg_buf = NULL;
89
[bbdbf86]90/** Number of preset files */
91static int filc = 0;
92/** Preset files vector */
[08c9f7d5]93static fdi_node_t **filv = NULL;
[bbdbf86]94/** Buffer holding all preset files */
[99272a3]95static fdi_node_t *fil_buf = NULL;
[bbdbf86]96
[4470e26]97static elf_info_t prog_info;
98
[bfd1546]99/** Used to limit number of connections to one. */
[007e6efa]100static bool connected = false;
[4470e26]101
[7fb3f1c]102#ifdef CONFIG_RTLD
[a6dffb8]103/** State structure of the dynamic linker. */
104runtime_env_t dload_re;
105static module_t prog_mod;
[7fb3f1c]106#endif
[a6dffb8]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");
[7fb3f1c]319#ifdef CONFIG_RTLD
[a6dffb8]320 DPRINTF(" - pcb address: %p\n", &pcb);
321 DPRINTF( "- prog dynamic: %p\n", prog_info.dynamic);
[1ea99cc]322
[a6dffb8]323 rc = ldr_load_dyn_linked(&prog_info);
[7fb3f1c]324#else
325 rc = ENOTSUP;
326#endif
[a6dffb8]327 async_answer_0(rid, rc);
[c98e6ee]328 return 0;
329}
330
[7fb3f1c]331#ifdef CONFIG_RTLD
332
[a6dffb8]333static int ldr_load_dyn_linked(elf_info_t *p_info)
334{
335 runtime_env = &dload_re;
336
337 DPRINTF("Load dynamically linked program.\n");
338
339 /*
340 * First we need to process dynamic sections of the executable
341 * program and insert it into the module graph.
342 */
343
344 DPRINTF("Parse program .dynamic section at %p\n", p_info->dynamic);
345 dynamic_parse(p_info->dynamic, 0, &prog_mod.dyn);
346 prog_mod.bias = 0;
347 prog_mod.dyn.soname = "[program]";
348
349 /* Initialize list of loaded modules */
350 list_initialize(&runtime_env->modules_head);
351 list_append(&prog_mod.modules_link, &runtime_env->modules_head);
352
353 /* Pointer to program module. Used as root of the module graph. */
354 runtime_env->program = &prog_mod;
355
356 /* Work around non-existent memory space allocation. */
357 runtime_env->next_bias = 0x1000000;
358
359 /*
360 * Now we can continue with loading all other modules.
361 */
362
363 DPRINTF("Load all program dependencies\n");
364 module_load_deps(&prog_mod);
365
366 /*
367 * Now relocate/link all modules together.
368 */
369
370 /* Process relocations in all modules */
371 DPRINTF("Relocate all modules\n");
372 modules_process_relocs(&prog_mod);
373
374 /* Pass runtime evironment pointer through PCB. */
375 pcb.rtld_runtime = (void *) runtime_env;
376
377 return 0;
378}
[7fb3f1c]379#endif
[4470e26]380
381/** Run the previously loaded program.
382 *
383 * @param rid
384 * @param request
385 * @return 0 on success, !0 on error.
386 */
[bbdbf86]387static void ldr_run(ipc_callid_t rid, ipc_call_t *request)
[4470e26]388{
[20f1597]389 const char *cp;
[2f57690]390
[a6dffb8]391 DPRINTF("Set task name\n");
392
[bc18d63]393 /* Set the task name. */
[7afb4a5]394 cp = str_rchr(pathname, '/');
[20f1597]395 cp = (cp == NULL) ? pathname : (cp + 1);
396 task_set_name(cp);
[2f57690]397
[a6dffb8]398 /* Run program */
399 DPRINTF("Reply OK\n");
400 async_answer_0(rid, EOK);
401 DPRINTF("Jump to entry point at %p\n", pcb.entry);
[f798178]402 entry_point_jmp(prog_info.entry, &pcb);
[bbdbf86]403
[4470e26]404 /* Not reached */
405}
406
[c98e6ee]407/** Handle loader connection.
408 *
409 * Receive and carry out commands (of which the last one should be
410 * to execute the loaded program).
411 */
[bbdbf86]412static void ldr_connection(ipc_callid_t iid, ipc_call_t *icall)
[c98e6ee]413{
[bfd1546]414 /* Already have a connection? */
415 if (connected) {
[ffa2c8ef]416 async_answer_0(iid, ELIMIT);
[bfd1546]417 return;
418 }
[2f57690]419
[bfd1546]420 connected = true;
421
422 /* Accept the connection */
[ffa2c8ef]423 async_answer_0(iid, EOK);
[2f57690]424
[c98e6ee]425 /* Ignore parameters, the connection is already open */
[2f57690]426 (void) icall;
427
[79ae36dd]428 while (true) {
429 int retval;
430 ipc_call_t call;
431 ipc_callid_t callid = async_get_call(&call);
[2f57690]432
[79ae36dd]433 if (!IPC_GET_IMETHOD(call))
[86e3d62]434 exit(0);
[79ae36dd]435
436 switch (IPC_GET_IMETHOD(call)) {
[47e0a05b]437 case LOADER_GET_TASKID:
[bbdbf86]438 ldr_get_taskid(callid, &call);
[47e0a05b]439 continue;
[622cdbe]440 case LOADER_SET_CWD:
441 ldr_set_cwd(callid, &call);
442 continue;
[c98e6ee]443 case LOADER_SET_PATHNAME:
[bbdbf86]444 ldr_set_pathname(callid, &call);
[c98e6ee]445 continue;
446 case LOADER_SET_ARGS:
[bbdbf86]447 ldr_set_args(callid, &call);
448 continue;
449 case LOADER_SET_FILES:
450 ldr_set_files(callid, &call);
[4470e26]451 continue;
452 case LOADER_LOAD:
[bbdbf86]453 ldr_load(callid, &call);
[4470e26]454 continue;
[c98e6ee]455 case LOADER_RUN:
[bbdbf86]456 ldr_run(callid, &call);
[4470e26]457 /* Not reached */
[c98e6ee]458 default:
[8c3bc75]459 retval = EINVAL;
[c98e6ee]460 break;
461 }
[8c3bc75]462
[79ae36dd]463 async_answer_0(callid, retval);
[c98e6ee]464 }
465}
466
467/** Program loader main function.
468 */
469int main(int argc, char *argv[])
470{
[007e6efa]471 /* Set a handler of incomming connections. */
472 async_set_client_connection(ldr_connection);
473
[5d96851b]474 /* Introduce this task to the NS (give it our task ID). */
[007e6efa]475 task_id_t id = task_get_id();
[79ae36dd]476 int rc = ns_intro(id);
[5d96851b]477 if (rc != EOK)
478 return -1;
[2f57690]479
[bfd1546]480 /* Register at naming service. */
[007e6efa]481 if (service_register(SERVICE_LOAD) != EOK)
[5d96851b]482 return -2;
[007e6efa]483
[c98e6ee]484 async_manager();
[2f57690]485
[bfd1546]486 /* Never reached */
[c98e6ee]487 return 0;
488}
489
490/** @}
491 */
Note: See TracBrowser for help on using the repository browser.