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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since da680b4b was 984a9ba, checked in by Martin Decky <martin@…>, 7 years ago

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

  • Property mode set to 100644
File size: 8.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>
[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
[984a9ba]92static void ldr_get_taskid(ipc_call_t *req)
[47e0a05b]93{
[984a9ba]94 ipc_call_t call;
[47e0a05b]95 task_id_t task_id;
96 size_t len;
[a35b458]97
[47e0a05b]98 task_id = task_get_id();
[a35b458]99
[984a9ba]100 if (!async_data_read_receive(&call, &len)) {
101 async_answer_0(&call, EINVAL);
102 async_answer_0(req, EINVAL);
[47e0a05b]103 return;
104 }
[a35b458]105
[2f57690]106 if (len > sizeof(task_id))
107 len = sizeof(task_id);
[a35b458]108
[984a9ba]109 async_data_read_finalize(&call, &task_id, len);
110 async_answer_0(req, EOK);
[47e0a05b]111}
112
[622cdbe]113/** Receive a call setting the current working directory.
[c98e6ee]114 *
115 */
[984a9ba]116static void ldr_set_cwd(ipc_call_t *req)
[c98e6ee]117{
[472c09d]118 char *buf;
[b7fd2a0]119 errno_t rc = async_data_write_accept((void **) &buf, true, 0, 0, 0, NULL);
[a35b458]120
[472c09d]121 if (rc == EOK) {
122 if (cwd != NULL)
123 free(cwd);
[a35b458]124
[472c09d]125 cwd = buf;
[c98e6ee]126 }
[a35b458]127
[984a9ba]128 async_answer_0(req, rc);
[622cdbe]129}
[47e0a05b]130
[bb9ec2d]131/** Receive a call setting the program to execute.
[c98e6ee]132 *
133 */
[984a9ba]134static void ldr_set_program(ipc_call_t *req)
[c98e6ee]135{
[984a9ba]136 ipc_call_t call;
[bb9ec2d]137 size_t namesize;
[984a9ba]138 if (!async_data_write_receive(&call, &namesize)) {
139 async_answer_0(req, EINVAL);
[bb9ec2d]140 return;
141 }
142
[3bacee1]143 char *name = malloc(namesize);
[984a9ba]144 // FIXME: check return value
145
146 errno_t rc = async_data_write_finalize(&call, name, namesize);
[bb9ec2d]147 if (rc != EOK) {
[984a9ba]148 async_answer_0(req, EINVAL);
[bb9ec2d]149 return;
150 }
151
[f77c1c9]152 int file;
153 rc = vfs_receive_handle(true, &file);
154 if (rc != EOK) {
[984a9ba]155 async_answer_0(req, EINVAL);
[bb9ec2d]156 return;
[c98e6ee]157 }
[a35b458]158
[bb9ec2d]159 progname = name;
160 program_fd = file;
[984a9ba]161 async_answer_0(req, EOK);
[c98e6ee]162}
163
164/** Receive a call setting arguments of the program to execute.
165 *
166 */
[984a9ba]167static void ldr_set_args(ipc_call_t *req)
[c98e6ee]168{
[472c09d]169 char *buf;
170 size_t buf_size;
[b7fd2a0]171 errno_t rc = async_data_write_accept((void **) &buf, true, 0, 0, 0, &buf_size);
[a35b458]172
[472c09d]173 if (rc == EOK) {
174 /*
175 * Count number of arguments
176 */
177 char *cur = buf;
178 int count = 0;
[a35b458]179
[472c09d]180 while (cur < buf + buf_size) {
181 size_t arg_size = str_size(cur);
182 cur += arg_size + 1;
183 count++;
184 }
[a35b458]185
[472c09d]186 /*
187 * Allocate new argv
188 */
189 char **_argv = (char **) malloc((count + 1) * sizeof(char *));
190 if (_argv == NULL) {
191 free(buf);
[984a9ba]192 async_answer_0(req, ENOMEM);
[472c09d]193 return;
194 }
[a35b458]195
[472c09d]196 /*
197 * Fill the new argv with argument pointers
198 */
199 cur = buf;
200 count = 0;
201 while (cur < buf + buf_size) {
202 _argv[count] = cur;
[a35b458]203
[472c09d]204 size_t arg_size = str_size(cur);
205 cur += arg_size + 1;
206 count++;
207 }
208 _argv[count] = NULL;
[a35b458]209
[472c09d]210 /*
211 * Copy temporary data to global variables
212 */
213 if (arg_buf != NULL)
214 free(arg_buf);
[a35b458]215
[472c09d]216 if (argv != NULL)
217 free(argv);
[a35b458]218
[472c09d]219 argc = count;
220 arg_buf = buf;
221 argv = _argv;
[c98e6ee]222 }
[a35b458]223
[984a9ba]224 async_answer_0(req, rc);
[c98e6ee]225}
226
[bb9ec2d]227/** Receive a call setting inbox files of the program to execute.
[bbdbf86]228 *
229 */
[984a9ba]230static void ldr_add_inbox(ipc_call_t *req)
[bbdbf86]231{
[bb9ec2d]232 if (inbox_entries == INBOX_MAX_ENTRIES) {
[984a9ba]233 async_answer_0(req, ERANGE);
[b7f69f2]234 return;
[bb9ec2d]235 }
[7171760]236
[984a9ba]237 ipc_call_t call;
[bb9ec2d]238 size_t namesize;
[984a9ba]239 if (!async_data_write_receive(&call, &namesize)) {
240 async_answer_0(req, EINVAL);
[bb9ec2d]241 return;
242 }
243
[3bacee1]244 char *name = malloc(namesize);
[984a9ba]245 errno_t rc = async_data_write_finalize(&call, name, namesize);
[bb9ec2d]246 if (rc != EOK) {
[984a9ba]247 async_answer_0(req, EINVAL);
[bb9ec2d]248 return;
249 }
250
[f77c1c9]251 int file;
252 rc = vfs_receive_handle(true, &file);
253 if (rc != EOK) {
[984a9ba]254 async_answer_0(req, EINVAL);
[bb9ec2d]255 return;
[bbdbf86]256 }
[7171760]257
[ea56098]258 /*
259 * We need to set the root early for dynamically linked binaries so
260 * that the loader can use it too.
261 */
262 if (str_cmp(name, "root") == 0)
263 vfs_root_set(file);
264
[bb9ec2d]265 inbox[inbox_entries].name = name;
266 inbox[inbox_entries].file = file;
267 inbox_entries++;
[984a9ba]268 async_answer_0(req, EOK);
[bbdbf86]269}
270
[4470e26]271/** Load the previously selected program.
[c98e6ee]272 *
273 * @return 0 on success, !0 on error.
[984a9ba]274 *
[c98e6ee]275 */
[984a9ba]276static int ldr_load(ipc_call_t *req)
[c98e6ee]277{
[bb9ec2d]278 int rc = elf_load(program_fd, &prog_info);
[409b0d6]279 if (rc != EE_OK) {
[bb9ec2d]280 DPRINTF("Failed to load executable for '%s'.\n", progname);
[984a9ba]281 async_answer_0(req, EINVAL);
[c98e6ee]282 return 1;
283 }
[a35b458]284
[17341d4]285 elf_set_pcb(&prog_info, &pcb);
[a35b458]286
[622cdbe]287 pcb.cwd = cwd;
[a35b458]288
[c98e6ee]289 pcb.argc = argc;
290 pcb.argv = argv;
[a35b458]291
[bb9ec2d]292 pcb.inbox = inbox;
293 pcb.inbox_entries = inbox_entries;
[a35b458]294
[984a9ba]295 async_answer_0(req, EOK);
[c98e6ee]296 return 0;
297}
298
[4470e26]299/** Run the previously loaded program.
300 *
301 * @return 0 on success, !0 on error.
[984a9ba]302 *
[4470e26]303 */
[984a9ba]304static __attribute__((noreturn)) void ldr_run(ipc_call_t *req)
[4470e26]305{
[a6dffb8]306 DPRINTF("Set task name\n");
307
[bc18d63]308 /* Set the task name. */
[bb9ec2d]309 task_set_name(progname);
[a35b458]310
[a6dffb8]311 /* Run program */
312 DPRINTF("Reply OK\n");
[984a9ba]313 async_answer_0(req, EOK);
[a6dffb8]314 DPRINTF("Jump to entry point at %p\n", pcb.entry);
[17341d4]315 entry_point_jmp(prog_info.finfo.entry, &pcb);
[a35b458]316
[4470e26]317 /* Not reached */
318}
319
[c98e6ee]320/** Handle loader connection.
321 *
322 * Receive and carry out commands (of which the last one should be
323 * to execute the loaded program).
[984a9ba]324 *
[c98e6ee]325 */
[984a9ba]326static void ldr_connection(ipc_call_t *icall, void *arg)
[c98e6ee]327{
[bfd1546]328 /* Already have a connection? */
329 if (connected) {
[984a9ba]330 async_answer_0(icall, ELIMIT);
[bfd1546]331 return;
332 }
[a35b458]333
[bfd1546]334 connected = true;
[a35b458]335
[bfd1546]336 /* Accept the connection */
[984a9ba]337 async_answer_0(icall, EOK);
[a35b458]338
[c98e6ee]339 /* Ignore parameters, the connection is already open */
[2f57690]340 (void) icall;
[a35b458]341
[79ae36dd]342 while (true) {
[b7fd2a0]343 errno_t retval;
[79ae36dd]344 ipc_call_t call;
[984a9ba]345 async_get_call(&call);
[a35b458]346
[79ae36dd]347 if (!IPC_GET_IMETHOD(call))
[86e3d62]348 exit(0);
[a35b458]349
[79ae36dd]350 switch (IPC_GET_IMETHOD(call)) {
[47e0a05b]351 case LOADER_GET_TASKID:
[984a9ba]352 ldr_get_taskid(&call);
[47e0a05b]353 continue;
[622cdbe]354 case LOADER_SET_CWD:
[984a9ba]355 ldr_set_cwd(&call);
[622cdbe]356 continue;
[bb9ec2d]357 case LOADER_SET_PROGRAM:
[984a9ba]358 ldr_set_program(&call);
[c98e6ee]359 continue;
360 case LOADER_SET_ARGS:
[984a9ba]361 ldr_set_args(&call);
[bbdbf86]362 continue;
[bb9ec2d]363 case LOADER_ADD_INBOX:
[984a9ba]364 ldr_add_inbox(&call);
[4470e26]365 continue;
366 case LOADER_LOAD:
[984a9ba]367 ldr_load(&call);
[4470e26]368 continue;
[c98e6ee]369 case LOADER_RUN:
[984a9ba]370 ldr_run(&call);
[4470e26]371 /* Not reached */
[c98e6ee]372 default:
[8c3bc75]373 retval = EINVAL;
[c98e6ee]374 break;
375 }
[a35b458]376
[984a9ba]377 async_answer_0(&call, retval);
[c98e6ee]378 }
379}
380
381/** Program loader main function.
382 */
383int main(int argc, char *argv[])
384{
[b688fd8]385 async_set_fallback_port_handler(ldr_connection, NULL);
[a35b458]386
[5d96851b]387 /* Introduce this task to the NS (give it our task ID). */
[007e6efa]388 task_id_t id = task_get_id();
[b7fd2a0]389 errno_t rc = ns_intro(id);
[5d96851b]390 if (rc != EOK)
[b39b5cb]391 return rc;
[a35b458]392
[566992e1]393 /* Create port */
394 port_id_t port;
395 rc = async_create_port(INTERFACE_LOADER, ldr_connection, NULL, &port);
396 if (rc != EOK)
397 return rc;
[a35b458]398
[bfd1546]399 /* Register at naming service. */
[566992e1]400 rc = service_register(SERVICE_LOADER);
[b39b5cb]401 if (rc != EOK)
402 return rc;
[a35b458]403
[c98e6ee]404 async_manager();
[a35b458]405
[bfd1546]406 /* Never reached */
[c98e6ee]407 return 0;
408}
409
410/** @}
411 */
Note: See TracBrowser for help on using the repository browser.