main.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008 Jiri Svoboda
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00046 #include <stdio.h>
00047 #include <stdlib.h>
00048 #include <unistd.h>
00049 #include <bool.h>
00050 #include <fcntl.h>
00051 #include <sys/types.h>
00052 #include <ipc/services.h>
00053 #include <ipc/loader.h>
00054 #include <ipc/ns.h>
00055 #include <macros.h>
00056 #include <loader/pcb.h>
00057 #include <entry_point.h>
00058 #include <errno.h>
00059 #include <async.h>
00060 #include <str.h>
00061 #include <as.h>
00062 
00063 #include <elf.h>
00064 #include <elf_load.h>
00065 
00066 #ifdef CONFIG_RTLD
00067 #include <rtld/rtld.h>
00068 #include <rtld/dynamic.h>
00069 #include <rtld/module.h>
00070 
00071 static int ldr_load_dyn_linked(elf_info_t *p_info);
00072 #endif
00073 
00074 #define DPRINTF(...)
00075 
00077 static char *pathname = NULL;
00078 
00080 static pcb_t pcb;
00081 
00083 static char *cwd = NULL;
00084 
00086 static int argc = 0;
00088 static char **argv = NULL;
00090 static char *arg_buf = NULL;
00091 
00093 static int filc = 0;
00095 static fdi_node_t **filv = NULL;
00097 static fdi_node_t *fil_buf = NULL;
00098 
00099 static elf_info_t prog_info;
00100 
00102 static bool connected = false;
00103 
00104 #ifdef CONFIG_RTLD
00105 
00106 runtime_env_t dload_re;
00107 static module_t prog_mod;
00108 #endif
00109 
00110 static void ldr_get_taskid(ipc_callid_t rid, ipc_call_t *request)
00111 {
00112         ipc_callid_t callid;
00113         task_id_t task_id;
00114         size_t len;
00115         
00116         task_id = task_get_id();
00117         
00118         if (!async_data_read_receive(&callid, &len)) {
00119                 async_answer_0(callid, EINVAL);
00120                 async_answer_0(rid, EINVAL);
00121                 return;
00122         }
00123         
00124         if (len > sizeof(task_id))
00125                 len = sizeof(task_id);
00126         
00127         async_data_read_finalize(callid, &task_id, len);
00128         async_answer_0(rid, EOK);
00129 }
00130 
00136 static void ldr_set_cwd(ipc_callid_t rid, ipc_call_t *request)
00137 {
00138         char *buf;
00139         int rc = async_data_write_accept((void **) &buf, true, 0, 0, 0, NULL);
00140         
00141         if (rc == EOK) {
00142                 if (cwd != NULL)
00143                         free(cwd);
00144                 
00145                 cwd = buf;
00146         }
00147         
00148         async_answer_0(rid, rc);
00149 }
00150 
00156 static void ldr_set_pathname(ipc_callid_t rid, ipc_call_t *request)
00157 {
00158         char *buf;
00159         int rc = async_data_write_accept((void **) &buf, true, 0, 0, 0, NULL);
00160         
00161         if (rc == EOK) {
00162                 if (pathname != NULL)
00163                         free(pathname);
00164                 
00165                 pathname = buf;
00166         }
00167         
00168         async_answer_0(rid, rc);
00169 }
00170 
00176 static void ldr_set_args(ipc_callid_t rid, ipc_call_t *request)
00177 {
00178         char *buf;
00179         size_t buf_size;
00180         int rc = async_data_write_accept((void **) &buf, true, 0, 0, 0, &buf_size);
00181         
00182         if (rc == EOK) {
00183                 /*
00184                  * Count number of arguments
00185                  */
00186                 char *cur = buf;
00187                 int count = 0;
00188                 
00189                 while (cur < buf + buf_size) {
00190                         size_t arg_size = str_size(cur);
00191                         cur += arg_size + 1;
00192                         count++;
00193                 }
00194                 
00195                 /*
00196                  * Allocate new argv
00197                  */
00198                 char **_argv = (char **) malloc((count + 1) * sizeof(char *));
00199                 if (_argv == NULL) {
00200                         free(buf);
00201                         async_answer_0(rid, ENOMEM);
00202                         return;
00203                 }
00204                 
00205                 /*
00206                  * Fill the new argv with argument pointers
00207                  */
00208                 cur = buf;
00209                 count = 0;
00210                 while (cur < buf + buf_size) {
00211                         _argv[count] = cur;
00212                         
00213                         size_t arg_size = str_size(cur);
00214                         cur += arg_size + 1;
00215                         count++;
00216                 }
00217                 _argv[count] = NULL;
00218                 
00219                 /*
00220                  * Copy temporary data to global variables
00221                  */
00222                 if (arg_buf != NULL)
00223                         free(arg_buf);
00224                 
00225                 if (argv != NULL)
00226                         free(argv);
00227                 
00228                 argc = count;
00229                 arg_buf = buf;
00230                 argv = _argv;
00231         }
00232         
00233         async_answer_0(rid, rc);
00234 }
00235 
00241 static void ldr_set_files(ipc_callid_t rid, ipc_call_t *request)
00242 {
00243         fdi_node_t *buf;
00244         size_t buf_size;
00245         int rc = async_data_write_accept((void **) &buf, false, 0, 0,
00246             sizeof(fdi_node_t), &buf_size);
00247         
00248         if (rc == EOK) {
00249                 int count = buf_size / sizeof(fdi_node_t);
00250                 
00251                 /*
00252                  * Allocate new filv
00253                  */
00254                 fdi_node_t **_filv = (fdi_node_t **) calloc(count + 1, sizeof(fdi_node_t *));
00255                 if (_filv == NULL) {
00256                         free(buf);
00257                         async_answer_0(rid, ENOMEM);
00258                         return;
00259                 }
00260                 
00261                 /*
00262                  * Fill the new filv with argument pointers
00263                  */
00264                 int i;
00265                 for (i = 0; i < count; i++)
00266                         _filv[i] = &buf[i];
00267                 
00268                 _filv[count] = NULL;
00269                 
00270                 /*
00271                  * Copy temporary data to global variables
00272                  */
00273                 if (fil_buf != NULL)
00274                         free(fil_buf);
00275                 
00276                 if (filv != NULL)
00277                         free(filv);
00278                 
00279                 filc = count;
00280                 fil_buf = buf;
00281                 filv = _filv;
00282         }
00283         
00284         async_answer_0(rid, EOK);
00285 }
00286 
00293 static int ldr_load(ipc_callid_t rid, ipc_call_t *request)
00294 {
00295         int rc;
00296         
00297         rc = elf_load_file(pathname, 0, 0, &prog_info);
00298         if (rc != EE_OK) {
00299                 DPRINTF("Failed to load executable '%s'.\n", pathname);
00300                 async_answer_0(rid, EINVAL);
00301                 return 1;
00302         }
00303         
00304         elf_create_pcb(&prog_info, &pcb);
00305         
00306         pcb.cwd = cwd;
00307         
00308         pcb.argc = argc;
00309         pcb.argv = argv;
00310         
00311         pcb.filc = filc;
00312         pcb.filv = filv;
00313         
00314         if (prog_info.interp == NULL) {
00315                 /* Statically linked program */
00316                 async_answer_0(rid, EOK);
00317                 return 0;
00318         }
00319         
00320         DPRINTF("Binary is dynamically linked.\n");
00321 #ifdef CONFIG_RTLD
00322         DPRINTF(" - pcb address: %p\n", &pcb);
00323         DPRINTF( "- prog dynamic: %p\n", prog_info.dynamic);
00324 
00325         rc = ldr_load_dyn_linked(&prog_info);
00326 #else
00327         rc = ENOTSUP;
00328 #endif
00329         async_answer_0(rid, rc);
00330         return 0;
00331 }
00332 
00333 #ifdef CONFIG_RTLD
00334 
00335 static int ldr_load_dyn_linked(elf_info_t *p_info)
00336 {
00337         runtime_env = &dload_re;
00338 
00339         DPRINTF("Load dynamically linked program.\n");
00340 
00341         /*
00342          * First we need to process dynamic sections of the executable
00343          * program and insert it into the module graph.
00344          */
00345 
00346         DPRINTF("Parse program .dynamic section at %p\n", p_info->dynamic);
00347         dynamic_parse(p_info->dynamic, 0, &prog_mod.dyn);
00348         prog_mod.bias = 0;
00349         prog_mod.dyn.soname = "[program]";
00350 
00351         /* Initialize list of loaded modules */
00352         list_initialize(&runtime_env->modules_head);
00353         list_append(&prog_mod.modules_link, &runtime_env->modules_head);
00354 
00355         /* Pointer to program module. Used as root of the module graph. */
00356         runtime_env->program = &prog_mod;
00357 
00358         /* Work around non-existent memory space allocation. */
00359         runtime_env->next_bias = 0x1000000;
00360 
00361         /*
00362          * Now we can continue with loading all other modules.
00363          */
00364 
00365         DPRINTF("Load all program dependencies\n");
00366         module_load_deps(&prog_mod);
00367 
00368         /*
00369          * Now relocate/link all modules together.
00370          */
00371 
00372         /* Process relocations in all modules */
00373         DPRINTF("Relocate all modules\n");
00374         modules_process_relocs(&prog_mod);
00375 
00376         /* Pass runtime evironment pointer through PCB. */
00377         pcb.rtld_runtime = (void *) runtime_env;
00378 
00379         return 0;
00380 }
00381 #endif
00382 
00389 static void ldr_run(ipc_callid_t rid, ipc_call_t *request)
00390 {
00391         const char *cp;
00392         
00393         DPRINTF("Set task name\n");
00394 
00395         /* Set the task name. */
00396         cp = str_rchr(pathname, '/');
00397         cp = (cp == NULL) ? pathname : (cp + 1);
00398         task_set_name(cp);
00399         
00400         /* Run program */
00401         DPRINTF("Reply OK\n");
00402         async_answer_0(rid, EOK);
00403         DPRINTF("Jump to entry point at %p\n", pcb.entry);
00404         entry_point_jmp(prog_info.entry, &pcb);
00405         
00406         /* Not reached */
00407 }
00408 
00414 static void ldr_connection(ipc_callid_t iid, ipc_call_t *icall)
00415 {
00416         ipc_callid_t callid;
00417         ipc_call_t call;
00418         int retval;
00419         
00420         /* Already have a connection? */
00421         if (connected) {
00422                 async_answer_0(iid, ELIMIT);
00423                 return;
00424         }
00425         
00426         connected = true;
00427         
00428         /* Accept the connection */
00429         async_answer_0(iid, EOK);
00430         
00431         /* Ignore parameters, the connection is already open */
00432         (void) iid;
00433         (void) icall;
00434         
00435         while (1) {
00436                 callid = async_get_call(&call);
00437                 
00438                 switch (IPC_GET_IMETHOD(call)) {
00439                 case IPC_M_PHONE_HUNGUP:
00440                         exit(0);
00441                 case LOADER_GET_TASKID:
00442                         ldr_get_taskid(callid, &call);
00443                         continue;
00444                 case LOADER_SET_CWD:
00445                         ldr_set_cwd(callid, &call);
00446                         continue;
00447                 case LOADER_SET_PATHNAME:
00448                         ldr_set_pathname(callid, &call);
00449                         continue;
00450                 case LOADER_SET_ARGS:
00451                         ldr_set_args(callid, &call);
00452                         continue;
00453                 case LOADER_SET_FILES:
00454                         ldr_set_files(callid, &call);
00455                         continue;
00456                 case LOADER_LOAD:
00457                         ldr_load(callid, &call);
00458                         continue;
00459                 case LOADER_RUN:
00460                         ldr_run(callid, &call);
00461                         /* Not reached */
00462                 default:
00463                         retval = EINVAL;
00464                         break;
00465                 }
00466                 
00467                 if (IPC_GET_IMETHOD(call) != IPC_M_PHONE_HUNGUP)
00468                         async_answer_0(callid, retval);
00469         }
00470 }
00471 
00474 int main(int argc, char *argv[])
00475 {
00476         /* Set a handler of incomming connections. */
00477         async_set_client_connection(ldr_connection);
00478         
00479         /* Introduce this task to the NS (give it our task ID). */
00480         task_id_t id = task_get_id();
00481         int rc = async_req_2_0(PHONE_NS, NS_ID_INTRO, LOWER32(id), UPPER32(id));
00482         if (rc != EOK)
00483                 return -1;
00484         
00485         /* Register at naming service. */
00486         if (service_register(SERVICE_LOAD) != EOK)
00487                 return -2;
00488         
00489         async_manager();
00490         
00491         /* Never reached */
00492         return 0;
00493 }
00494 

Generated on Thu Jun 2 07:45:42 2011 for HelenOS/USB by  doxygen 1.4.7