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

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

Merge mainline changes.

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