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

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

Rework the way how open files are passed from parent task to child.

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