1// vi:set ft=cpp: -*- Mode: C++ -*- 2/* 3 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>, 4 * Alexander Warg <warg@os.inf.tu-dresden.de> 5 * economic rights: Technische Universität Dresden (Germany) 6 * This file is part of TUD:OS and distributed under the terms of the 7 * GNU Lesser General Public License 2.1. 8 * Please see the COPYING-LGPL-2.1 file for details. 9 */ 10 11#pragma once 12 13#include <l4/re/env> 14#include <l4/util/elf.h> 15#include <l4/libloader/adjust_stack> 16 17#include <cstring> 18 19namespace Ldr { 20 21 22struct Prog_start_info 23{ 24 l4_umword_t dyn_exec_entry; 25 l4_umword_t dyn_phdrs; 26 l4_umword_t dyn_num_phdrs; 27 l4_umword_t dyn_interp_base; 28 29 30 l4_umword_t ldr_flags; 31 l4_umword_t l4re_dbg; 32 33 l4_addr_t entry; 34 l4_addr_t kip; 35 l4_addr_t stack_addr; 36 l4_size_t stack_size; 37 l4_addr_t utcbs_start; 38 unsigned char utcbs_log2size; 39 40 l4_fpage_t parent; 41 l4_fpage_t mem_alloc; 42 l4_fpage_t scheduler; 43 l4_fpage_t rm; 44 l4_fpage_t log; 45 l4_fpage_t factory; 46}; 47 48template< typename STACK, typename PROG_INFO = Prog_start_info> 49class Base_app_model 50{ 51public: 52 typedef STACK Stack; 53 typedef PROG_INFO Prog_info; 54 55protected: 56 Stack _stack; 57 Prog_info _info; 58 59 struct Arg_array 60 { 61 char const *a0, *al; 62 Arg_array() : a0(0) {} 63 int push(Base_app_model *am, bool basename); 64 }; 65 66public: 67 Arg_array argv; 68 Arg_array envp; 69 70 Stack *stack() { return &_stack; } 71 Stack const *stack() const { return &_stack; } 72 Prog_info *prog_info() { return &_info; } 73 Prog_info const *prog_info() const { return &_info; } 74 75 void extra_elf_auxv() {} 76 77 void push_envp() 78 { 79 envp.push(this, false); 80 } 81 82 void push_argv() 83 { 84 l4_umword_t argc = argv.push(this, false); 85 _stack.push(argc); 86 } 87 88 /** 89 * Get the fixed capability index for fixed initial caps. 90 * \param name The name of the initial capability. 91 * \retval L4_INVALID_CAP if the given capability has no fixed location 92 * in the target task. 93 * \retval A valid capability index corresponding to the fixed index 94 * assigned to the initial capability with the given name. 95 */ 96 l4_cap_idx_t get_fixed_cap(char const *name) 97 { 98 if (!strcmp(name, "jdb")) 99 return L4_BASE_DEBUGGER_CAP; 100 101 return L4_INVALID_CAP; 102 } 103 104 /** 105 * Get either a new capability index or the fixed index for 106 * the inital capability with the given name. 107 * 108 * \param name The name of the initial capability. 109 * \param current A pointer to the next free capability index 110 * that shall be used for dynamic assignment. 111 * The function increments `*current` to the next 112 * index if a dynamic index is assigned to the cap. 113 * \return The index that shall be used for the initial capability with the 114 * given name. 115 */ 116 l4_cap_idx_t get_initial_cap(char const *name, l4_cap_idx_t *current) 117 { 118 l4_cap_idx_t c = get_fixed_cap(name); 119 if (l4_is_valid_cap(c)) 120 return c; 121 122 c = *current; 123 *current += L4_CAP_OFFSET; 124 return c; 125 } 126}; 127 128template< typename STACK, typename PROG_INFO > 129int 130Base_app_model<STACK, PROG_INFO>::Arg_array::push(Base_app_model *am, bool basename) 131{ 132 // push array terminator 133 am->stack()->push(l4_umword_t(0)); 134 l4_umword_t argc = 0; 135 if (a0) 136 { 137 do 138 { 139 if (basename && al == a0) 140 { 141 // just use the basename for ARGV[0] 142 for (; *al; ++al) 143 ; 144 for (; al >= a0 && *al != '/'; --al) 145 ; 146 147 if (*al == '/') 148 ++al; 149 } 150 am->stack()->push_local_ptr(al); 151 ++argc; 152 153 // scan for previous argument, remember the stack is top down 154 for (; al < a0 && *al; ++al) 155 ; 156 157 ++al; 158 } 159 while (al <= a0); 160 } 161 return argc; 162} 163 164template< typename App_model_, typename Dbg_ > 165class Loader 166{ 167public: 168 typedef Dbg_ Dbg_log; 169 typedef App_model_ App_model; 170 typedef typename App_model::Const_dataspace Const_dataspace; 171 typedef typename App_model::Stack Stack; 172 173 void launch(App_model *model, Const_dataspace bin, Dbg_ const &dbg); 174 175 void launch(App_model *model, char const *prog, Dbg_ const &dbg) 176 { 177 typename App_model::Const_dataspace bin = model->open_file(prog); 178 launch(model, bin, dbg); 179 } 180 181 template< typename App_task, typename Prog > 182 void launch(App_task task, Prog prog, Const_dataspace bin, Dbg_ const &dbg) 183 { 184 typedef App_model Am; 185 Am am(task, prog); 186 launch(&am, bin, dbg); 187 } 188 189 template< typename App_task, typename Prog > 190 void launch(App_task task, Prog prog, char const *bin, Dbg_ const &dbg) 191 { 192 typedef App_model Am; 193 Am am(task, prog); 194 launch(&am, bin, dbg); 195 } 196 197 virtual void read_infos(App_model *, Const_dataspace bin, Dbg_log const &ldr) = 0; 198 virtual void load(App_model *, Const_dataspace bin, Dbg_log const &ldr) = 0; 199 virtual ~Loader() {} 200}; 201 202template< typename App_model_, typename Dbg_ > 203void 204Loader<App_model_, Dbg_>::launch(App_model *am, Const_dataspace bin, Dbg_ const &dbg) 205{ 206 typedef App_model Am; 207 typedef typename Am::Dataspace Dataspace; 208 209 read_infos(am, bin, dbg); 210 Dataspace app_stack = am->alloc_app_stack(); 211 212 // put args on stack 213 // put env strings on stack 214 am->init_prog(); 215 216 Stack &stack = *am->stack(); 217 stack.align(sizeof(l4_umword_t)); 218 219 void const *l4aux_ptr; 220 { 221 // load the program into memory, prepare all the VMAs 222 // and stuff on the application stack 223 load(am, bin, dbg); 224 225 am->prog_attach_stack(app_stack); 226 am->prog_reserve_utcb_area(); 227 am->prog_attach_kip(); 228 229 l4aux_ptr = am->generate_l4aux(am->argv.a0); 230 } 231 232 L4Re::Env *env = am->add_env(); 233 234 stack.align(sizeof(l4_umword_t)); 235 236 const char *stack_before_auxv = stack.ptr(); 237 238 // AUXV NULL 239 stack.push(l4_umword_t(0)); 240 stack.push(l4_umword_t(0)); 241 242 // L4Re Env Pointer 243 stack.push_local_ptr(env); 244 stack.push(l4_umword_t(0xF1)); 245 246 if (l4aux_ptr) 247 { 248 stack.push_local_ptr(l4aux_ptr); 249 stack.push(l4_umword_t(0xF0)); 250 } 251 252 am->extra_elf_auxv(); 253 254 stack.push(l4_umword_t(L4_PAGESIZE)); 255 stack.push(l4_umword_t(AT_PAGESZ)); 256 257 stack.push(l4_umword_t(0)); 258 stack.push(l4_umword_t(AT_UID)); 259 260 stack.push(l4_umword_t(0)); 261 stack.push(l4_umword_t(AT_EUID)); 262 263 stack.push(l4_umword_t(0)); 264 stack.push(l4_umword_t(AT_GID)); 265 266 stack.push(l4_umword_t(0)); 267 stack.push(l4_umword_t(AT_EGID)); 268 269 if (am->prog_info()->dyn_phdrs) 270 { 271 stack.push(l4_umword_t(am->prog_info()->dyn_phdrs)); 272 stack.push(l4_umword_t(AT_PHDR)); 273 274 stack.push(l4_umword_t(am->prog_info()->dyn_num_phdrs)); 275 stack.push(l4_umword_t(AT_PHNUM)); 276 } 277 278 if (am->prog_info()->dyn_exec_entry) 279 { 280 stack.push(l4_umword_t(am->prog_info()->dyn_exec_entry)); 281 stack.push(l4_umword_t(AT_ENTRY)); 282 283 stack.push(l4_umword_t(am->prog_info()->dyn_interp_base)); 284 stack.push(l4_umword_t(AT_BASE)); 285 } 286 287 am->push_envp(); 288 am->push_argv(); 289 290 const char *p = stack.ptr(); 291 l4_umword_t offs; 292 stack.ptr(adjust_sp((char *)p, &offs)); 293 294 if (p != stack.ptr() + offs) 295 memmove((char *)stack.ptr() + offs, p, stack_before_auxv - p); 296 297 // the stack is now ready for the app 298 am->start_prog(env); 299} 300 301} 302