// vi:ft=cpp /* * (c) 2008-2009 Adam Lackorzynski , * Alexander Warg * economic rights: Technische Universität Dresden (Germany) * This file is part of TUD:OS and distributed under the terms of the * GNU Lesser General Public License 2.1. * Please see the COPYING-LGPL-2.1 file for details. */ #pragma once #include #include #include #include namespace Ldr { struct Prog_start_info { l4_umword_t dyn_exec_entry; l4_umword_t dyn_phdrs; l4_umword_t dyn_num_phdrs; l4_umword_t dyn_interp_base; l4_umword_t ldr_flags; l4_umword_t l4re_dbg; l4_addr_t entry; l4_addr_t kip; l4_addr_t stack_addr; l4_size_t stack_size; l4_addr_t utcbs_start; unsigned char utcbs_log2size; l4_fpage_t parent; l4_fpage_t mem_alloc; l4_fpage_t scheduler; l4_fpage_t rm; l4_fpage_t log; l4_fpage_t factory; }; template< typename STACK, typename PROG_INFO = Prog_start_info> class Base_app_model { public: typedef STACK Stack; typedef PROG_INFO Prog_info; protected: Stack _stack; Prog_info _info; struct Arg_array { char const *a0, *al; Arg_array() : a0(0) {} int push(Base_app_model *am, bool basename); }; public: Arg_array argv; Arg_array envp; Stack *stack() { return &_stack; } Stack const *stack() const { return &_stack; } Prog_info *prog_info() { return &_info; } Prog_info const *prog_info() const { return &_info; } void extra_elf_auxv() {} void push_envp() { envp.push(this, false); } void push_argv() { l4_umword_t argc = argv.push(this, false); _stack.push(argc); } }; template< typename STACK, typename PROG_INFO > int Base_app_model::Arg_array::push(Base_app_model *am, bool basename) { // push array terminator am->stack()->push(l4_umword_t(0)); l4_umword_t argc = 0; if (a0) { do { if (basename && al == a0) { // just use the basename for ARGV[0] for (; *al; ++al) ; for (; al >= a0 && *al != '/'; --al) ; if (*al == '/') ++al; } am->stack()->push_local_ptr(al); ++argc; // scan for previous argument, remember the stack is top down for (; al < a0 && *al; ++al) ; ++al; } while (al <= a0); } return argc; } template< typename App_model_, typename Dbg_ > class Loader { public: typedef Dbg_ Dbg_log; typedef App_model_ App_model; typedef typename App_model::Const_dataspace Const_dataspace; typedef typename App_model::Stack Stack; void launch(App_model *model, Const_dataspace bin, Dbg_ const &dbg); void launch(App_model *model, char const *prog, Dbg_ const &dbg) { typename App_model::Const_dataspace bin = model->open_file(prog); launch(model, bin, dbg); } template< typename App_task, typename Prog > void launch(App_task task, Prog prog, Const_dataspace bin, Dbg_ const &dbg) { typedef App_model Am; Am am(task, prog); launch(&am, bin, dbg); } template< typename App_task, typename Prog > void launch(App_task task, Prog prog, char const *bin, Dbg_ const &dbg) { typedef App_model Am; Am am(task, prog); launch(&am, bin, dbg); } virtual void read_infos(App_model *, Const_dataspace bin, Dbg_log const &ldr) = 0; virtual void load(App_model *, Const_dataspace bin, Dbg_log const &ldr) = 0; virtual ~Loader() {} }; template< typename App_model_, typename Dbg_ > void Loader::launch(App_model *am, Const_dataspace bin, Dbg_ const &dbg) { typedef App_model Am; typedef typename Am::Dataspace Dataspace; read_infos(am, bin, dbg); Dataspace app_stack = am->alloc_app_stack(); // put args on stack // put env strings on stack am->init_prog(); Stack &stack = *am->stack(); stack.align(sizeof(l4_umword_t)); void const *l4aux_ptr; { // add all the VMAs to the region map and stack char const *before_vma = stack.ptr(); // load the program into memory, prepare all the VMAs // and stuff on the application stack load(am, bin, dbg); am->prog_attach_stack(app_stack); am->prog_reserve_utcb_area(); am->prog_attach_kip(); l4aux_ptr = am->generate_l4aux(before_vma, am->argv.a0); } L4Re::Env *env = am->add_env(); stack.align(sizeof(l4_umword_t)); const char *stack_before_auxv = stack.ptr(); // AUXV NULL stack.push(l4_umword_t(0)); stack.push(l4_umword_t(0)); // L4Re Env Pointer stack.push_local_ptr(env); stack.push(l4_umword_t(0xF1)); if (l4aux_ptr) { stack.push_local_ptr(l4aux_ptr); stack.push(l4_umword_t(0xF0)); } am->extra_elf_auxv(); stack.push(l4_umword_t(L4_PAGESIZE)); stack.push(l4_umword_t(AT_PAGESZ)); stack.push(l4_umword_t(0)); stack.push(l4_umword_t(AT_UID)); stack.push(l4_umword_t(0)); stack.push(l4_umword_t(AT_EUID)); stack.push(l4_umword_t(0)); stack.push(l4_umword_t(AT_GID)); stack.push(l4_umword_t(0)); stack.push(l4_umword_t(AT_EGID)); if (am->prog_info()->dyn_exec_entry) { stack.push(l4_umword_t(am->prog_info()->dyn_exec_entry)); stack.push(l4_umword_t(AT_ENTRY)); stack.push(l4_umword_t(am->prog_info()->dyn_phdrs)); stack.push(l4_umword_t(AT_PHDR)); stack.push(l4_umword_t(am->prog_info()->dyn_num_phdrs)); stack.push(l4_umword_t(AT_PHNUM)); stack.push(l4_umword_t(am->prog_info()->dyn_interp_base)); stack.push(l4_umword_t(AT_BASE)); } am->push_envp(); am->push_argv(); const char *p = stack.ptr(); l4_umword_t offs; stack.ptr(adjust_sp((char *)p, &offs)); if (p != stack.ptr() + offs) memmove((char *)stack.ptr() + offs, p, stack_before_auxv - p); // the stack is now ready for the app am->start_prog(env); } }