/* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */ /* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */ /* Copyright (C) 2014 OSCAR lab, Stony Brook University This file is part of Graphene Library OS. Graphene Library OS is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Graphene Library OS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* * db_main.c * * This file contains the main function of the PAL loader, which loads and * processes environment, arguments and manifest. */ #include "pal_defs.h" #include "pal.h" #include "pal_internal.h" #include "pal_security.h" #include "pal_debug.h" #include "pal_error.h" #include "api.h" #include #include #include /* allocate memory for page size constants */ PAL_NUM allocsize, allocshift, allocmask; PAL_CONTROL __pal_control; PAL_CONTROL * pal_control_addr (void) { return &__pal_control; } /* initialize the value of pal_config attributes */ struct pal_config pal_config; struct pal_sec_info pal_sec_info; #define leave \ do { printf("PAL terminated at " __FILE__ ":%d\n", __LINE__); \ _DkProcessExit(1); } while (0) int load_libraries (struct config_store * root_config, const char ** msg) { /* we will not make any assumption for where the libraries are loaded */ char cfgbuf[CONFIG_MAX]; int len, ret = 0; /* loader.preload: any other libraries to preload. The can be multiple URIs, seperated by commas */ if ((len = get_config(root_config, "loader.preload", cfgbuf, CONFIG_MAX)) > 0) { char * c = cfgbuf, * token = c; do { if (*c == ',' || !(*(c))) { if (c > token) { *c = 0; if ((ret = load_elf_object(token, OBJECT_PRELOAD)) < 0) { if (msg) *msg = "Unable to load preload library\n"; return ret; } } token = c + 1; } } while (*(c++)); } return 0; } static void read_envs (const char *** envpp) { const char ** envp = *envpp; if (!pal_config.root_config) goto done; char cfgbuf[CONFIG_MAX]; /* loader.env.* and loader.exclude.env: filtering host environment * variables */ int nenvs = get_config_entries(pal_config.root_config, "loader.env", cfgbuf, CONFIG_MAX); if (nenvs > 0) { struct env { const char * str; int len, idx; } * envs = __alloca(sizeof(struct env) * nenvs); char * cfg = cfgbuf; for (int i = 0 ; i < nenvs ; i++) { int len = strlen(cfg); char * str = __alloca(len + 1); envs[i].str = str; envs[i].len = len; envs[i].idx = -1; memcpy(str, cfg, len + 1); cfg += len + 1; } int envc = 0, add = nenvs; for (const char ** e = envp ; *e ; e++) { envc++; const char * p = *e; while (*p && *p != '=') p++; for (int i = 0 ; i < nenvs ; i++) if (envs[i].len == p - *e && !memcmp(envs[i].str, *e, p - *e)) { envs[i].idx = envc - 1; add--; break; } } if (add) { const char ** new_envp = malloc(sizeof(const char *) * (envc + add + 1)); memcpy(new_envp, envp, sizeof(const char *) * envc); envp = new_envp; envp[envc + add] = NULL; } char key[CONFIG_MAX] = "loader.env."; const char ** ptr; for (int i = 0 ; i < nenvs ; i++) { const char * str = envs[i].str; int len = envs[i].len; int idx = envs[i].idx; int bytes; ptr = &envp[(idx == -1) ? envc++ : idx]; memcpy(key + 11, str, len + 1); if ((bytes = get_config(pal_config.root_config, key, cfgbuf, CONFIG_MAX)) > 0) { char * e = malloc(len + bytes + 2); memcpy(e, str, len); e[len] = '='; memcpy(e + len + 1, cfgbuf, bytes + 1); *ptr = e; } else { char * e = malloc(len + 2); memcpy(e, str, len); e[len] = '='; e[len + 1] = 0; *ptr = e; } } } done: *envpp = envp; } void start_execution (int argc, const char ** argv, const char ** envp); void pal_main (int argc, const char ** argv, const char ** envp) { char cfgbuf[CONFIG_MAX]; int ret; pal_config.pagesize = _DkGetPagesize(); pal_config.alloc_align = _DkGetAllocationAlignment(); /* some constants for page manipulation and allocation alignment */ allocsize = pal_config.alloc_align; allocshift = allocsize - 1; allocmask = ~allocshift; init_slab_mgr(); /* reloaction of loader is done here. starting from this point, the global symbols of loader should be accessible. */ pal_config.lib_text_start = (void *) &text_start; pal_config.lib_text_end = (void *) &text_end; pal_config.lib_data_start = (void *) &data_start; pal_config.lib_data_end = (void *) &data_end; __pal_control.pagesize = pal_config.pagesize; __pal_control.alloc_align = allocsize; __pal_control.library_begin = &text_start; __pal_control.library_end = &data_end; /* * _DkInitHost must set up the following values: * pal_config.manifest * pal_config.manifest_handle * pal_config.exec * pal_config.exec_handle * pal_config.root_config */ if (_DkInitHost(&argc, &argv) < 0) leave; __pal_control.manifest_handle = pal_config.manifest_handle; __pal_control.executable = pal_config.exec; /* all of the preloaded libraries are loaded, time to play with executable */ if (pal_config.exec_handle) { ret = load_elf_object_by_handle(pal_config.exec_handle, OBJECT_EXEC); if (ret < 0) { printf("Unable to load executable (%d)\n", PAL_STRERROR(ret)); leave; } } read_envs(&envp); if (pal_config.root_config) { struct config_store * cfg = pal_config.root_config; const char * msg; if (load_libraries(cfg, &msg) < 0) { printf("%s\n", msg); leave; } if (get_config(cfg, "loader.daemonize", cfgbuf, CONFIG_MAX) > 0 && cfgbuf[0] == '1' && !cfgbuf[1]) pal_config.daemonize = true; if (get_config(cfg, "loader.debug_type", cfgbuf, CONFIG_MAX) > 0) { PAL_HANDLE handle = NULL; if (!memcmp(cfgbuf, "inline", 7)) { _DkStreamOpen(&handle, "dev:tty", PAL_ACCESS_RDWR, 0, 0, 0); } else if (!memcmp(cfgbuf, "file", 5)) { if (get_config(cfg, "loader.debug_file", cfgbuf, CONFIG_MAX) > 0) { _DkStreamOpen(&handle, cfgbuf, PAL_ACCESS_RDWR, PAL_SHARE_OWNER_R|PAL_SHARE_OWNER_W, PAL_CREAT_TRY, 0); } } __pal_control.debug_stream = handle; } if ((ret = get_config(cfg, "loader.syscall_symbol", cfgbuf, CONFIG_MAX)) > 0) pal_config.syscall_sym_name = remalloc(cfgbuf, ret + 1); free_config(cfg); _DkStreamUnmap(cfg->raw_data, ALLOC_ALIGNUP(cfg->raw_size)); free(cfg); pal_config.root_config = NULL; } __pal_control.manifest_handle = pal_config.manifest_handle; __pal_control.executable = pal_config.exec; __pal_control.user_address_begin = pal_config.user_addr_start; __pal_control.user_address_end = pal_config.user_addr_end; /* Now we will start the execution */ start_execution(argc, argv, envp); /* We wish we will never reached here */ printf("unexpected termination\n"); leave; }