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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since eadaeae8 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 9.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>
[3e6a98c5]48#include <stdbool.h>
[8d2dd7f2]49#include <stddef.h>
[bfd1546]50#include <ipc/services.h>
[c98e6ee]51#include <ipc/loader.h>
[79ae36dd]52#include <ns.h>
[c98e6ee]53#include <loader/pcb.h>
[f798178]54#include <entry_point.h>
[c98e6ee]55#include <errno.h>
56#include <async.h>
[19f857a]57#include <str.h>
[c98e6ee]58#include <as.h>
[90b8d58]59#include <elf/elf.h>
[bfdb5af1]60#include <elf/elf_load.h>
[7171760]61#include <vfs/vfs.h>
[bb9ec2d]62#include <vfs/inbox.h>
[c98e6ee]63
[7fb3f1c]64#define DPRINTF(...)
[1ea99cc]65
[bb9ec2d]66/** File that will be loaded */
67static char *progname = NULL;
68static int program_fd = -1;
[c98e6ee]69
70/** The Program control block */
71static pcb_t pcb;
72
[622cdbe]73/** Current working directory */
74static char *cwd = NULL;
75
[c98e6ee]76/** Number of arguments */
77static int argc = 0;
78/** Argument vector */
79static char **argv = NULL;
80/** Buffer holding all arguments */
81static char *arg_buf = NULL;
82
[bb9ec2d]83/** Inbox entries. */
84static struct pcb_inbox_entry inbox[INBOX_MAX_ENTRIES];
85static int inbox_entries = 0;
[bbdbf86]86
[4470e26]87static elf_info_t prog_info;
88
[bfd1546]89/** Used to limit number of connections to one. */
[007e6efa]90static bool connected = false;
[4470e26]91
[bbdbf86]92static void ldr_get_taskid(ipc_callid_t rid, ipc_call_t *request)
[47e0a05b]93{
94 ipc_callid_t callid;
95 task_id_t task_id;
96 size_t len;
[a35b458]97
[47e0a05b]98 task_id = task_get_id();
[a35b458]99
[0da4e41]100 if (!async_data_read_receive(&callid, &len)) {
[ffa2c8ef]101 async_answer_0(callid, EINVAL);
102 async_answer_0(rid, EINVAL);
[47e0a05b]103 return;
104 }
[a35b458]105
[2f57690]106 if (len > sizeof(task_id))
107 len = sizeof(task_id);
[a35b458]108
[0da4e41]109 async_data_read_finalize(callid, &task_id, len);
[ffa2c8ef]110 async_answer_0(rid, EOK);
[47e0a05b]111}
112
[622cdbe]113/** Receive a call setting the current working directory.
[c98e6ee]114 *
115 * @param rid
116 * @param request
117 */
[622cdbe]118static void ldr_set_cwd(ipc_callid_t rid, ipc_call_t *request)
[c98e6ee]119{
[472c09d]120 char *buf;
[b7fd2a0]121 errno_t rc = async_data_write_accept((void **) &buf, true, 0, 0, 0, NULL);
[a35b458]122
[472c09d]123 if (rc == EOK) {
124 if (cwd != NULL)
125 free(cwd);
[a35b458]126
[472c09d]127 cwd = buf;
[c98e6ee]128 }
[a35b458]129
[ffa2c8ef]130 async_answer_0(rid, rc);
[622cdbe]131}
[47e0a05b]132
[bb9ec2d]133/** Receive a call setting the program to execute.
[c98e6ee]134 *
135 * @param rid
136 * @param request
137 */
[bb9ec2d]138static void ldr_set_program(ipc_callid_t rid, ipc_call_t *request)
[c98e6ee]139{
[bb9ec2d]140 ipc_callid_t writeid;
141 size_t namesize;
142 if (!async_data_write_receive(&writeid, &namesize)) {
143 async_answer_0(rid, EINVAL);
144 return;
145 }
146
147 char* name = malloc(namesize);
[b7fd2a0]148 errno_t rc = async_data_write_finalize(writeid, name, namesize);
[bb9ec2d]149 if (rc != EOK) {
150 async_answer_0(rid, EINVAL);
151 return;
152 }
153
[f77c1c9]154 int file;
155 rc = vfs_receive_handle(true, &file);
156 if (rc != EOK) {
[bb9ec2d]157 async_answer_0(rid, EINVAL);
158 return;
[c98e6ee]159 }
[a35b458]160
[bb9ec2d]161 progname = name;
162 program_fd = file;
163 async_answer_0(rid, EOK);
[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;
[b7fd2a0]175 errno_t rc = async_data_write_accept((void **) &buf, true, 0, 0, 0, &buf_size);
[a35b458]176
[472c09d]177 if (rc == EOK) {
178 /*
179 * Count number of arguments
180 */
181 char *cur = buf;
182 int count = 0;
[a35b458]183
[472c09d]184 while (cur < buf + buf_size) {
185 size_t arg_size = str_size(cur);
186 cur += arg_size + 1;
187 count++;
188 }
[a35b458]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 }
[a35b458]199
[472c09d]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;
[a35b458]207
[472c09d]208 size_t arg_size = str_size(cur);
209 cur += arg_size + 1;
210 count++;
211 }
212 _argv[count] = NULL;
[a35b458]213
[472c09d]214 /*
215 * Copy temporary data to global variables
216 */
217 if (arg_buf != NULL)
218 free(arg_buf);
[a35b458]219
[472c09d]220 if (argv != NULL)
221 free(argv);
[a35b458]222
[472c09d]223 argc = count;
224 arg_buf = buf;
225 argv = _argv;
[c98e6ee]226 }
[a35b458]227
[ffa2c8ef]228 async_answer_0(rid, rc);
[c98e6ee]229}
230
[bb9ec2d]231/** Receive a call setting inbox files of the program to execute.
[bbdbf86]232 *
233 * @param rid
234 * @param request
235 */
[bb9ec2d]236static void ldr_add_inbox(ipc_callid_t rid, ipc_call_t *request)
[bbdbf86]237{
[bb9ec2d]238 if (inbox_entries == INBOX_MAX_ENTRIES) {
239 async_answer_0(rid, ERANGE);
[b7f69f2]240 return;
[bb9ec2d]241 }
[7171760]242
[bb9ec2d]243 ipc_callid_t writeid;
244 size_t namesize;
245 if (!async_data_write_receive(&writeid, &namesize)) {
246 async_answer_0(rid, EINVAL);
247 return;
248 }
249
250 char* name = malloc(namesize);
[b7fd2a0]251 errno_t rc = async_data_write_finalize(writeid, name, namesize);
[bb9ec2d]252 if (rc != EOK) {
253 async_answer_0(rid, EINVAL);
254 return;
255 }
256
[f77c1c9]257 int file;
258 rc = vfs_receive_handle(true, &file);
259 if (rc != EOK) {
[bb9ec2d]260 async_answer_0(rid, EINVAL);
261 return;
[bbdbf86]262 }
[7171760]263
[ea56098]264 /*
265 * We need to set the root early for dynamically linked binaries so
266 * that the loader can use it too.
267 */
268 if (str_cmp(name, "root") == 0)
269 vfs_root_set(file);
270
[bb9ec2d]271 inbox[inbox_entries].name = name;
272 inbox[inbox_entries].file = file;
273 inbox_entries++;
[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{
[bb9ec2d]285 int rc = elf_load(program_fd, &prog_info);
[409b0d6]286 if (rc != EE_OK) {
[bb9ec2d]287 DPRINTF("Failed to load executable for '%s'.\n", progname);
[ffa2c8ef]288 async_answer_0(rid, EINVAL);
[c98e6ee]289 return 1;
290 }
[a35b458]291
[17341d4]292 elf_set_pcb(&prog_info, &pcb);
[a35b458]293
[622cdbe]294 pcb.cwd = cwd;
[a35b458]295
[c98e6ee]296 pcb.argc = argc;
297 pcb.argv = argv;
[a35b458]298
[bb9ec2d]299 pcb.inbox = inbox;
300 pcb.inbox_entries = inbox_entries;
[a35b458]301
[1569a9b]302 async_answer_0(rid, EOK);
[c98e6ee]303 return 0;
304}
305
[4470e26]306/** Run the previously loaded program.
307 *
308 * @param rid
309 * @param request
310 * @return 0 on success, !0 on error.
311 */
[31a30fa]312static __attribute__((noreturn)) void ldr_run(ipc_callid_t rid,
313 ipc_call_t *request)
[4470e26]314{
[a6dffb8]315 DPRINTF("Set task name\n");
316
[bc18d63]317 /* Set the task name. */
[bb9ec2d]318 task_set_name(progname);
[a35b458]319
[a6dffb8]320 /* Run program */
321 DPRINTF("Reply OK\n");
322 async_answer_0(rid, EOK);
323 DPRINTF("Jump to entry point at %p\n", pcb.entry);
[17341d4]324 entry_point_jmp(prog_info.finfo.entry, &pcb);
[a35b458]325
[4470e26]326 /* Not reached */
327}
328
[c98e6ee]329/** Handle loader connection.
330 *
331 * Receive and carry out commands (of which the last one should be
332 * to execute the loaded program).
333 */
[9934f7d]334static void ldr_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
[c98e6ee]335{
[bfd1546]336 /* Already have a connection? */
337 if (connected) {
[ffa2c8ef]338 async_answer_0(iid, ELIMIT);
[bfd1546]339 return;
340 }
[a35b458]341
[bfd1546]342 connected = true;
[a35b458]343
[bfd1546]344 /* Accept the connection */
[ffa2c8ef]345 async_answer_0(iid, EOK);
[a35b458]346
[c98e6ee]347 /* Ignore parameters, the connection is already open */
[2f57690]348 (void) icall;
[a35b458]349
[79ae36dd]350 while (true) {
[b7fd2a0]351 errno_t retval;
[79ae36dd]352 ipc_call_t call;
353 ipc_callid_t callid = async_get_call(&call);
[a35b458]354
[79ae36dd]355 if (!IPC_GET_IMETHOD(call))
[86e3d62]356 exit(0);
[a35b458]357
[79ae36dd]358 switch (IPC_GET_IMETHOD(call)) {
[47e0a05b]359 case LOADER_GET_TASKID:
[bbdbf86]360 ldr_get_taskid(callid, &call);
[47e0a05b]361 continue;
[622cdbe]362 case LOADER_SET_CWD:
363 ldr_set_cwd(callid, &call);
364 continue;
[bb9ec2d]365 case LOADER_SET_PROGRAM:
366 ldr_set_program(callid, &call);
[c98e6ee]367 continue;
368 case LOADER_SET_ARGS:
[bbdbf86]369 ldr_set_args(callid, &call);
370 continue;
[bb9ec2d]371 case LOADER_ADD_INBOX:
372 ldr_add_inbox(callid, &call);
[4470e26]373 continue;
374 case LOADER_LOAD:
[bbdbf86]375 ldr_load(callid, &call);
[4470e26]376 continue;
[c98e6ee]377 case LOADER_RUN:
[bbdbf86]378 ldr_run(callid, &call);
[4470e26]379 /* Not reached */
[c98e6ee]380 default:
[8c3bc75]381 retval = EINVAL;
[c98e6ee]382 break;
383 }
[a35b458]384
[79ae36dd]385 async_answer_0(callid, retval);
[c98e6ee]386 }
387}
388
389/** Program loader main function.
390 */
391int main(int argc, char *argv[])
392{
[b688fd8]393 async_set_fallback_port_handler(ldr_connection, NULL);
[a35b458]394
[5d96851b]395 /* Introduce this task to the NS (give it our task ID). */
[007e6efa]396 task_id_t id = task_get_id();
[b7fd2a0]397 errno_t rc = ns_intro(id);
[5d96851b]398 if (rc != EOK)
[b39b5cb]399 return rc;
[a35b458]400
[566992e1]401 /* Create port */
402 port_id_t port;
403 rc = async_create_port(INTERFACE_LOADER, ldr_connection, NULL, &port);
404 if (rc != EOK)
405 return rc;
[a35b458]406
[bfd1546]407 /* Register at naming service. */
[566992e1]408 rc = service_register(SERVICE_LOADER);
[b39b5cb]409 if (rc != EOK)
410 return rc;
[a35b458]411
[c98e6ee]412 async_manager();
[a35b458]413
[bfd1546]414 /* Never reached */
[c98e6ee]415 return 0;
416}
417
418/** @}
419 */
Note: See TracBrowser for help on using the repository browser.