diff --git a/base-linux/include/linux_cpu_session/client.h b/base-linux/include/linux_cpu_session/client.h index d3f3f7920f..a97e143306 100644 --- a/base-linux/include/linux_cpu_session/client.h +++ b/base-linux/include/linux_cpu_session/client.h @@ -79,4 +79,4 @@ namespace Genode { }; } -#endif /* _INCLUDE__CPU_SESSION__CLIENT_H_ */ +#endif /* _INCLUDE__LINUX_CPU_SESSION__CLIENT_H_ */ diff --git a/base-linux/include/linux_pd_session/client.h b/base-linux/include/linux_pd_session/client.h new file mode 100644 index 0000000000..9b8bb44015 --- /dev/null +++ b/base-linux/include/linux_pd_session/client.h @@ -0,0 +1,43 @@ +/* + * \brief Client-side PD session interface + * \author Norman Feske + * \date 2012-08-15 + */ + +/* + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__LINUX_PD_SESSION__CLIENT_H_ +#define _INCLUDE__LINUX_PD_SESSION__CLIENT_H_ + +#include +#include + +namespace Genode { + + struct Linux_pd_session_client : Rpc_client + { + explicit Linux_pd_session_client(Capability session) + : Rpc_client(session) { } + + int bind_thread(Thread_capability thread) { + return call(thread); } + + int assign_parent(Parent_capability parent) { + return call(parent); } + + + /***************************** + * Linux-specific extension ** + *****************************/ + + void start(Capability binary, Name const &name) { + call(binary, name); } + }; +} + +#endif /* _INCLUDE__LINUX_PD_SESSION__CLIENT_H_ */ diff --git a/base-linux/include/linux_pd_session/linux_pd_session.h b/base-linux/include/linux_pd_session/linux_pd_session.h new file mode 100644 index 0000000000..42b8a05178 --- /dev/null +++ b/base-linux/include/linux_pd_session/linux_pd_session.h @@ -0,0 +1,38 @@ +/* + * \brief Linux-specific extension of the PD session interface + * \author Norman Feske + * \date 2012-08-15 + */ + +/* + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__LINUX_PD_SESSION__LINUX_PD_SESSION_H_ +#define _INCLUDE__LINUX_PD_SESSION__LINUX_PD_SESSION_H_ + +#include +#include + +namespace Genode { + + struct Linux_pd_session : Pd_session + { + typedef Rpc_in_buffer<64> Name; + + void start(Capability binary, Name const &name); + + + /********************* + ** RPC declaration ** + *********************/ + + GENODE_RPC(Rpc_start, void, start, Capability, Name const &); + GENODE_RPC_INTERFACE_INHERIT(Pd_session, Rpc_start); + }; +} + +#endif /* _INCLUDE__LINUX_PD_SESSION__LINUX_PD_SESSION_H_ */ diff --git a/base-linux/src/base/process/process.cc b/base-linux/src/base/process/process.cc index b301791535..d63f9cb86e 100644 --- a/base-linux/src/base/process/process.cc +++ b/base-linux/src/base/process/process.cc @@ -16,10 +16,9 @@ #include #include #include -#include -#include +#include -/* Framework-internal includes */ +/* framework-internal includes */ #include @@ -27,50 +26,6 @@ using namespace Genode; Dataspace_capability Process::_dynamic_linker_cap; -/** - * Argument frame for passing 'execve' paremeters through 'clone' - */ -struct Execve_args -{ - const char *filename; - char *const *argv; - char *const *envp; - int parent_sd; -}; - - -/** - * Startup code of the new child process - */ -static int _exec_child(Execve_args *arg) -{ - lx_dup2(arg->parent_sd, PARENT_SOCKET_HANDLE); - - return lx_execve(arg->filename, arg->argv, arg->envp); -} - - -/** - * List of Unix environment variables, initialized by the startup code - */ -extern char **lx_environ; - - -/** - * Read environment variable as string - * - * If no matching key exists, return an empty string. - */ -static const char *get_env(const char *key) -{ - Genode::size_t key_len = Genode::strlen(key); - for (char **curr = lx_environ; curr && *curr; curr++) - if ((Genode::strcmp(*curr, key, key_len) == 0) && (*curr)[key_len] == '=') - return (const char *)(*curr + key_len + 1); - - return ""; -} - /** * Check for dynamic ELF header @@ -97,93 +52,6 @@ static bool _check_dynamic_elf(Dataspace_capability elf_ds_cap) } -const char *Process::_priv_pd_args(Parent_capability parent_cap, - Dataspace_capability elf_data_ds_cap, - const char *name, char *const argv[]) -{ - /* - * Serialize calls of this function because it uses the static 'envbuf' and - * 'stack' variables. - */ - static Lock _priv_pd_args_lock; - Lock::Guard _lock_guard(_priv_pd_args_lock); - - /* check for dynamic program header */ - if (_check_dynamic_elf(elf_data_ds_cap)) { - if (!_dynamic_linker_cap.valid()) { - PERR("Dynamically linked file found, but no dynamic linker binary present"); - return 0; - } - elf_data_ds_cap = _dynamic_linker_cap; - } - - /* pass parent capability as environment variable to the child */ - enum { ENV_STR_LEN = 256 }; - static char envbuf[5][ENV_STR_LEN]; - Genode::snprintf(envbuf[1], ENV_STR_LEN, "parent_local_name=%lu", - parent_cap.local_name()); - Genode::snprintf(envbuf[2], ENV_STR_LEN, "DISPLAY=%s", - get_env("DISPLAY")); - Genode::snprintf(envbuf[3], ENV_STR_LEN, "HOME=%s", - get_env("HOME")); - Genode::snprintf(envbuf[4], ENV_STR_LEN, "LD_LIBRARY_PATH=%s", - get_env("LD_LIBRARY_PATH")); - - char *env[] = { &envbuf[0][0], &envbuf[1][0], &envbuf[2][0], - &envbuf[3][0], &envbuf[4][0], 0 }; - - /* determine name of binary to start */ - Linux_dataspace_client elf_data_ds(elf_data_ds_cap); - Linux_dataspace::Filename fname = elf_data_ds.fname(); - fname.buf[sizeof(fname.buf) - 1] = 0; - - /* prefix name of Linux program (helps killing some zombies) */ - char pname_buf[9 + Linux_dataspace::FNAME_LEN]; - snprintf(pname_buf, sizeof(pname_buf), "[Genode] %s", name); - - /* it may happen, that argv is null */ - char *argv_buf[2]; - if (!argv) { - argv_buf[0] = pname_buf; - argv_buf[1] = 0; - argv = argv_buf; - } else - ((char **)argv)[0] = pname_buf; - - /* - * We cannot create the new process via 'fork()' because all our used - * memory including stack memory is backed by dataspaces, which had been - * mapped with the 'MAP_SHARED' flag. Therefore, after being created, the - * new process starts using the stack with the same physical memory pages - * as used by parent process. This would ultimately lead to stack - * corruption. To prevent both processes from concurrently accessing the - * same stack, we pause the execution of the parent until the child calls - * 'execve'. From then on, the child has its private memory layout. The - * desired behaviour is normally provided by 'vfork' but we use the more - * modern 'clone' call for this purpose. - */ - enum { STACK_SIZE = 4096 }; - static char stack[STACK_SIZE]; /* initial stack used by the child until - calling 'execve' */ - /* - * Argument frame as passed to 'clone'. Because, we can only pass a single - * pointer, all arguments are embedded within the 'execve_args' struct. - */ - Execve_args arg = { fname.buf, argv, env, parent_cap.dst().socket }; - - pid_t pid = lx_create_process((int (*)(void *))_exec_child, - stack + STACK_SIZE - sizeof(umword_t), &arg); - - /* - * We create a pseudo pd session with the new pd's pid as argument - * to enable Core to kill the process when the pd session gets closed. - */ - snprintf(_priv_pd_argbuf, sizeof(_priv_pd_argbuf), "PID=%d", pid); - - return _priv_pd_argbuf; -} - - Process::Process(Dataspace_capability elf_data_ds_cap, Ram_session_capability ram_session_cap, Cpu_session_capability cpu_session_cap, @@ -192,10 +60,23 @@ Process::Process(Dataspace_capability elf_data_ds_cap, const char *name, char *const argv[]) : - _pd(_priv_pd_args(parent_cap, elf_data_ds_cap, name, argv)), _cpu_session_client(Cpu_session_capability()), _rm_session_client(Rm_session_capability()) -{ } +{ + /* check for dynamic program header */ + if (_check_dynamic_elf(elf_data_ds_cap)) { + if (!_dynamic_linker_cap.valid()) { + PERR("Dynamically linked file found, but no dynamic linker binary present"); + return; + } + elf_data_ds_cap = _dynamic_linker_cap; + } + + Linux_pd_session_client lx_pd(static_cap_cast(_pd.cap())); + + lx_pd.assign_parent(parent_cap); + lx_pd.start(elf_data_ds_cap, name); +} Process::~Process() { } diff --git a/base-linux/src/core/include/core_linux_syscalls.h b/base-linux/src/core/include/core_linux_syscalls.h index 2ca0c60d02..659ffd4343 100644 --- a/base-linux/src/core/include/core_linux_syscalls.h +++ b/base-linux/src/core/include/core_linux_syscalls.h @@ -65,6 +65,13 @@ inline int lx_stat(const char *path, struct stat64 *buf) ** Process creation and destruction ** **************************************/ +inline int lx_execve(const char *filename, char *const argv[], + char *const envp[]) +{ + return lx_syscall(SYS_execve, filename, argv, envp); +} + + /** * Send signal to process * @@ -76,6 +83,13 @@ inline int lx_kill(int pid, int signal) } +inline int lx_create_process(int (*entry)(void *), void *stack, void *arg) +{ + int flags = CLONE_VFORK | SIGCHLD; + return lx_clone((int (*)(void *))entry, stack, flags, arg); +} + + /******************************************** ** Communication over Unix-domain sockets ** ********************************************/ diff --git a/base-linux/src/core/include/pd_session_component.h b/base-linux/src/core/include/pd_session_component.h index c8f53c0228..616b2b9f3d 100644 --- a/base-linux/src/core/include/pd_session_component.h +++ b/base-linux/src/core/include/pd_session_component.h @@ -1,61 +1,62 @@ /* - * \brief CORE-specific instance of the PD session interface for Linux + * \brief Linux-specific PD session * \author Norman Feske - * \date 2006-08-14 - * - * On Linux, we use a pd session only for keeping the information about the - * existence of protection domains to enable us to destruct all pds of a whole - * subtree. A pd is killed by CORE when closing the corresponding pd session. - * The PID of the process is passed to CORE as an argument of the session - * construction. + * \date 2012-08-15 */ /* - * Copyright (C) 2006-2012 Genode Labs GmbH + * Copyright (C) 2012 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ -#ifndef _CORE__INCLUDE__LINUX__PD_SESSION_COMPONENT_H_ -#define _CORE__INCLUDE__LINUX__PD_SESSION_COMPONENT_H_ +#ifndef _CORE__INCLUDE__PD_SESSION_COMPONENT_H_ +#define _CORE__INCLUDE__PD_SESSION_COMPONENT_H_ /* Genode includes */ -#include -#include #include -#include +#include -/* local includes */ -#include "platform.h" +/* core includes */ +#include namespace Genode { - class Pd_session_component : public Rpc_object + class Pd_session_component : public Rpc_object { private: - unsigned long _pid; + unsigned long _pid; + Parent_capability _parent; + Rpc_entrypoint *_ds_ep; public: - Pd_session_component(Rpc_entrypoint *thread_ep, - const char *args); + /** + * Constructor + * + * \param ds_ep entrypoint where the dataspaces are managed + */ + Pd_session_component(Rpc_entrypoint *ds_ep, const char *args); ~Pd_session_component(); - /****************************/ - /** Pd session interface **/ - /****************************/ + /************************** + ** PD session interface ** + **************************/ - /* - * This interface is not functional on Linux. - */ + int bind_thread(Thread_capability); + int assign_parent(Parent_capability parent); - int bind_thread(Thread_capability thread); - int assign_parent(Parent_capability); + + /****************************** + ** Linux-specific extension ** + ******************************/ + + void start(Capability binary, Name const &name); }; } -#endif /* _CORE__INCLUDE__LINUX__PD_SESSION_COMPONENT_H_ */ +#endif /* _CORE__INCLUDE__PD_SESSION_COMPONENT_H_ */ diff --git a/base-linux/src/core/pd_session_component.cc b/base-linux/src/core/pd_session_component.cc index f9f93b2bad..bf4c2edc2b 100644 --- a/base-linux/src/core/pd_session_component.cc +++ b/base-linux/src/core/pd_session_component.cc @@ -1,23 +1,23 @@ -/** +/* * \brief Core implementation of the PD session interface - * \author Christian Helmuth - * \date 2006-07-17 - * - * FIXME arg_string and quota missing + * \author Norman Feske + * \date 2012-08-15 */ /* - * Copyright (C) 2006-2012 Genode Labs GmbH + * Copyright (C) 2012 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ -/* Genode */ +/* Genode includes */ #include +#include -/* Core */ +/* core-local includes */ #include +#include /* Linux includes */ #include @@ -25,13 +25,63 @@ using namespace Genode; -Pd_session_component::Pd_session_component(Rpc_entrypoint *thread_ep, - const char *args) +/*************** + ** Utilities ** + ***************/ + +/** + * Argument frame for passing 'execve' paremeters through 'clone' + */ +struct Execve_args { - _pid = Arg_string::find_arg(args, "PID").long_value(0); + const char *filename; + char *const *argv; + char *const *envp; + int parent_sd; +}; + + +/** + * Startup code of the new child process + */ +static int _exec_child(Execve_args *arg) +{ + lx_dup2(arg->parent_sd, PARENT_SOCKET_HANDLE); + + return lx_execve(arg->filename, arg->argv, arg->envp); } +/** + * List of Unix environment variables, initialized by the startup code + */ +extern char **lx_environ; + + +/** + * Read environment variable as string + * + * If no matching key exists, return an empty string. + */ +static const char *get_env(const char *key) +{ + Genode::size_t key_len = Genode::strlen(key); + for (char **curr = lx_environ; curr && *curr; curr++) + if ((Genode::strcmp(*curr, key, key_len) == 0) && (*curr)[key_len] == '=') + return (const char *)(*curr + key_len + 1); + + return ""; +} + + +/************************** + ** PD session interface ** + **************************/ + +Pd_session_component::Pd_session_component(Rpc_entrypoint *ds_ep, const char *) +: _pid(0), _ds_ep(ds_ep) { } + + Pd_session_component::~Pd_session_component() { if (_pid) @@ -39,13 +89,72 @@ Pd_session_component::~Pd_session_component() } -int Pd_session_component::bind_thread(Thread_capability) -{ - return -1; +int Pd_session_component::bind_thread(Thread_capability) { return -1; } -int Pd_session_component::assign_parent(Parent_capability) +int Pd_session_component::assign_parent(Parent_capability parent) { - return -1; + _parent = parent; + return 0; } + + +void Pd_session_component::start(Capability binary, Name const &name) +{ + /* lookup binary dataspace */ + Dataspace_component *ds = reinterpret_cast(_ds_ep->obj_by_cap(binary)); + + if (!ds) { + PERR("could not lookup binary, aborted PD startup"); + return; /* XXX reflect error to client */ + } + + Linux_dataspace::Filename filename = ds->fname(); + + /* pass parent capability as environment variable to the child */ + enum { ENV_STR_LEN = 256 }; + static char envbuf[5][ENV_STR_LEN]; + Genode::snprintf(envbuf[1], ENV_STR_LEN, "parent_local_name=%lu", + _parent.local_name()); + Genode::snprintf(envbuf[2], ENV_STR_LEN, "DISPLAY=%s", + get_env("DISPLAY")); + Genode::snprintf(envbuf[3], ENV_STR_LEN, "HOME=%s", + get_env("HOME")); + Genode::snprintf(envbuf[4], ENV_STR_LEN, "LD_LIBRARY_PATH=%s", + get_env("LD_LIBRARY_PATH")); + + char *env[] = { &envbuf[0][0], &envbuf[1][0], &envbuf[2][0], + &envbuf[3][0], &envbuf[4][0], 0 }; + + /* prefix name of Linux program (helps killing some zombies) */ + char pname_buf[9 + Linux_dataspace::FNAME_LEN]; + snprintf(pname_buf, sizeof(pname_buf), "[Genode] %s", name.string()); + char *argv_buf[2]; + argv_buf[0] = pname_buf; + argv_buf[1] = 0; + + /* + * We cannot create the new process via 'fork()' because all our used + * memory including stack memory is backed by dataspaces, which had been + * mapped with the 'MAP_SHARED' flag. Therefore, after being created, the + * new process starts using the stack with the same physical memory pages + * as used by parent process. This would ultimately lead to stack + * corruption. To prevent both processes from concurrently accessing the + * same stack, we pause the execution of the parent until the child calls + * 'execve'. From then on, the child has its private memory layout. The + * desired behaviour is normally provided by 'vfork' but we use the more + * modern 'clone' call for this purpose. + */ + enum { STACK_SIZE = 4096 }; + static char stack[STACK_SIZE]; /* initial stack used by the child until + calling 'execve' */ + /* + * Argument frame as passed to 'clone'. Because, we can only pass a single + * pointer, all arguments are embedded within the 'execve_args' struct. + */ + Execve_args arg = { filename.buf, argv_buf, env, _parent.dst().socket }; + + _pid = lx_create_process((int (*)(void *))_exec_child, + stack + STACK_SIZE - sizeof(umword_t), &arg); +}; diff --git a/base-linux/src/platform/linux_syscalls.h b/base-linux/src/platform/linux_syscalls.h index 94fe7d0159..f2fddf1b0e 100644 --- a/base-linux/src/platform/linux_syscalls.h +++ b/base-linux/src/platform/linux_syscalls.h @@ -10,7 +10,7 @@ * interface directly rather than relying on convenient libc functions to be * able to link this part of the framework to a custom libc. Otherwise, we * would end up with very nasty cyclic dependencies when using framework - * functions such as IPC from the libC back end. + * functions such as IPC from the libc back end. * * The Linux syscall interface looks different for 32bit and 64bit system, in * particular regarding the socket interface. On 32bit systems, all socket @@ -165,13 +165,6 @@ inline int lx_getpeername(int sockfd, struct sockaddr *name, socklen_t *namelen) ** Functions used by the process library ** *******************************************/ -inline int lx_execve(const char *filename, char *const argv[], - char *const envp[]) -{ - return lx_syscall(SYS_execve, filename, argv, envp); -} - - inline void lx_exit(int status) { lx_syscall(SYS_exit, status); @@ -327,13 +320,6 @@ inline int lx_create_thread(void (*entry)(void *), void *stack, void *arg) } -inline int lx_create_process(int (*entry)(void *), void *stack, void *arg) -{ - int flags = CLONE_VFORK | SIGCHLD; - return lx_clone((int (*)(void *))entry, stack, flags, arg); -} - - inline pid_t lx_getpid() { return lx_syscall(SYS_getpid); } inline pid_t lx_gettid() { return lx_syscall(SYS_gettid); } inline uid_t lx_getuid() { return lx_syscall(SYS_getuid); }