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 
19 namespace Ldr {
20 
21 
22 struct 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 
48 template< typename STACK, typename PROG_INFO = Prog_start_info>
49 class Base_app_model
50 {
51 public:
52   typedef STACK Stack;
53   typedef PROG_INFO Prog_info;
54 
55 protected:
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 
66 public:
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 
128 template< typename STACK, typename PROG_INFO >
129 int
130 Base_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 
164 template< typename App_model_, typename Dbg_ >
165 class Loader
166 {
167 public:
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 
202 template< typename App_model_, typename Dbg_ >
203 void
204 Loader<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