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