1 /*
2  * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3  *               Alexander Warg <warg@os.inf.tu-dresden.de>,
4  *               Björn Döbel <doebel@os.inf.tu-dresden.de>
5  *     economic rights: Technische Universität Dresden (Germany)
6  *
7  * This file is part of TUD:OS and distributed under the terms of the
8  * GNU General Public License 2.
9  * Please see the COPYING-GPL-2 file for details.
10  */
11 #include "loader.h"
12 #include "region.h"
13 #include "debug.h"
14 #include "globals.h"
15 #include "mem_layout.h"
16 #include "switch_stack.h"
17 
18 #include <l4/cxx/iostream>
19 #include <l4/cxx/l4iostream>
20 #include <l4/sys/types.h>
21 #include <l4/sys/factory>
22 #include <l4/sys/scheduler>
23 #include <l4/sys/thread>
24 
25 #include <l4/re/rm>
26 #include <l4/re/dataspace>
27 #include <l4/re/mem_alloc>
28 #include <l4/re/env>
29 #include <l4/re/util/env_ns>
30 #include <l4/re/l4aux.h>
31 #include <l4/re/error_helper>
32 #include <l4/sys/debugger.h>
33 
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 
38 //#define L4RE_USE_LOCAL_PAGER_GATE 1
39 
40 using L4Re::Mem_alloc;
41 using L4Re::Dataspace;
42 using L4Re::Rm;
43 using L4::Cap;
44 using L4::Thread;
45 using L4Re::Env;
46 using L4Re::chksys;
47 
48 namespace {
49 
50 struct Entry_data
51 {
52   l4_addr_t entry;
53   l4_addr_t stack;
54   L4::Cap<L4Re::Rm> pager;
55 };
56 
57 static Loader *__loader;
58 static Cap<Dataspace> __binary;
59 static Cap<Dataspace> __loader_stack;
60 static void *__loader_stack_p;
61 static Entry_data __loader_entry;
62 static Region_map *__rm;
63 static Cap<Thread> app_thread;
64 
65 static
unmap_stack_and_start()66 void unmap_stack_and_start()
67 {
68   L4Re::Env::env()->rm()->detach(l4_addr_t(__loader_stack_p) - 1, 0);
69   Global::cap_alloc->free(__loader_stack);
70   switch_stack(__loader_entry.stack, (void(*)())__loader_entry.entry);
71 }
72 
73 }
74 
75 L4Re_app_model::Dataspace
alloc_ds(unsigned long size) const76 L4Re_app_model::alloc_ds(unsigned long size) const
77 {
78   Dataspace mem = chkcap(Global::cap_alloc->alloc<L4Re::Dataspace>(),
79       "ELF loader: could not allocate capability");
80   chksys(Global::allocator->alloc(size, mem, (Global::l4re_aux->ldr_flags & L4RE_AUX_LDR_FLAG_PINNED_SEGS) ? L4Re::Mem_alloc::Pinned :0 ), "loading writable ELF segment");
81   return mem;
82 }
83 
84 L4Re_app_model::Const_dataspace
open_file(char const * name)85 L4Re_app_model::open_file(char const *name)
86 {
87   using L4Re::chkcap;
88   L4Re::Util::Env_ns ens(L4Re::Env::env(), L4Re::Cap_alloc::get_cap_alloc(*Global::cap_alloc));
89 
90   L4::Cap<L4Re::Dataspace> file;
91 
92   file = chkcap(ens.query<L4Re::Dataspace>(name), name, 0);
93 
94   return file;
95 }
96 
97 void
prog_attach_ds(l4_addr_t addr,unsigned long size,Const_dataspace ds,unsigned long offset,L4Re::Rm::Flags flags,char const * what)98 L4Re_app_model::prog_attach_ds(l4_addr_t addr, unsigned long size,
99                                Const_dataspace ds, unsigned long offset,
100                                L4Re::Rm::Flags flags, char const *what)
101 {
102   if (Global::l4re_aux->ldr_flags & L4RE_AUX_LDR_FLAG_EAGER_MAP)
103     flags |= L4Re::Rm::F::Eager_map;
104 
105   chksys(_rm->attach(&addr, size, flags,
106                      L4::Ipc::make_cap(ds, flags.cap_rights()),
107                      offset), what);
108 }
109 
110 void
copy_ds(Dataspace dst,unsigned long dst_offs,Const_dataspace src,unsigned long src_offs,unsigned long size)111 L4Re_app_model::copy_ds(Dataspace dst, unsigned long dst_offs,
112                         Const_dataspace src, unsigned long src_offs,
113                         unsigned long size)
114 {
115   L4Re::chksys(dst->copy_in(dst_offs, src, src_offs, size),
116                "l4re_kernel program launch: copy failed");
117 }
118 
119 l4_addr_t
local_attach_ds(Const_dataspace ds,unsigned long size,unsigned long offset) const120 L4Re_app_model::local_attach_ds(Const_dataspace ds, unsigned long size,
121                                 unsigned long offset) const
122 {
123   l4_addr_t pg_offset = l4_trunc_page(offset);
124   l4_addr_t in_pg_offset = offset - pg_offset;
125   unsigned long pg_size = l4_round_page(size + in_pg_offset);
126   l4_addr_t vaddr = 0;
127   chksys(_rm->attach(&vaddr, pg_size,
128                      L4Re::Rm::F::Search_addr | L4Re::Rm::F::R,
129                      ds, pg_offset),
130          "ELF loader: attach temporary VMA");
131   return vaddr + in_pg_offset;
132 }
133 
134 void
local_detach_ds(l4_addr_t addr,unsigned long) const135 L4Re_app_model::local_detach_ds(l4_addr_t addr, unsigned long /*size*/) const
136 {
137   l4_addr_t pg_addr = l4_trunc_page(addr);
138   chksys(_rm->detach(pg_addr, 0), "ELF loader: detach temporary VMA");
139 }
140 
141 int
prog_reserve_area(l4_addr_t * start,unsigned long size,L4Re::Rm::Flags flags,unsigned char align)142 L4Re_app_model::prog_reserve_area(l4_addr_t *start, unsigned long size,
143                                   L4Re::Rm::Flags flags, unsigned char align)
144 {
145   return _rm->reserve_area(start, size, flags, align);
146 }
147 
148 L4Re_app_model::Dataspace
alloc_app_stack()149 L4Re_app_model::alloc_app_stack()
150 {
151   // Allocate the stack for the application
152   L4::Cap<L4Re::Dataspace> stack
153     = chkcap(Global::cap_alloc->alloc<L4Re::Dataspace>(),
154       "ELF loader: could not allocate capability");
155 
156   //ldr.printf("  allocate 0x%zx byte stack @%lx\n",
157   //    stack_info.stack_size, stack_info.stack_addr);
158   //if (!stack_info.stack_size)
159    // chksys(-L4_EINVAL, "ELF loader: no stack size specified in binary");
160   chksys(Global::allocator->alloc(_stack.stack_size(), stack));
161 
162   void *_s = (void*)(_stack.target_addr());
163   chksys(_rm->attach(&_s, _stack.stack_size(), Rm::F::Search_addr | Rm::F::RW,
164                      L4::Ipc::make_cap_rw(stack), 0));
165   _stack.set_target_stack(l4_addr_t(_s), _stack.stack_size());
166   _stack.set_local_addr(l4_addr_t(_s));
167   return stack;
168 }
169 
170 void
extra_elf_auxv()171 L4Re_app_model::extra_elf_auxv()
172 {
173 }
174 
175 void
push_envp()176 L4Re_app_model::push_envp()
177 {
178   _stack.push(l4_umword_t(0));
179   for (char const *const *e = Global::envp; *e; ++e)
180     _stack.push(*e);
181 }
182 
183 void
push_argv()184 L4Re_app_model::push_argv()
185 {
186   _stack.push(l4_umword_t(0));
187   for (int i = Global::argc - 1; i >= 0; --i)
188     _stack.push(Global::argv[i]);
189 
190   // ARGC
191   _stack.push(l4_umword_t(Global::argc));
192 }
193 
194 bool
all_segs_cow()195 L4Re_app_model::all_segs_cow()
196 {
197   return Global::l4re_aux->ldr_flags & L4RE_AUX_LDR_FLAG_ALL_SEGS_COW;
198 }
199 
200 L4Re::Env *
add_env()201 L4Re_app_model::add_env()
202 {
203   L4Re::Env *e = const_cast<L4Re::Env *>(L4Re::Env::env());
204 
205   e->rm(__loader_entry.pager);
206   e->main_thread(app_thread);
207   return e;
208 
209 }
210 
211 void
start_prog(L4Re::Env const *)212 L4Re_app_model::start_prog(L4Re::Env const *)
213 {
214   __loader_entry.stack = l4_addr_t(_stack.ptr());
215   __loader_entry.entry = _info.entry;
216   switch_stack(__loader_entry.stack, &unmap_stack_and_start);
217 }
218 
219 enum
220 {
221   Loader_stack_size = 8 * 1024,
222 };
223 
224 #ifdef L4_LOADER_USE_ASM_STUB
225 extern "C" void loader_thread(void);
226 extern "C" void loader_thread_c(void);
loader_thread_c(void)227 void loader_thread_c(void)
228 #else
229 static void
230 loader_thread()
231 #endif
232 {
233   if (!__loader->__start(__binary, __rm))
234     {
235       Err(Err::Fatal).printf("could not load binary\n");
236       exit(1);
237     }
238 }
239 
start(Cap<Dataspace> bin,Region_map * rm,l4re_aux_t * aux)240 bool Loader::start(Cap<Dataspace> bin, Region_map *rm, l4re_aux_t *aux)
241 {
242   __loader_stack = Global::cap_alloc->alloc<Dataspace>();
243   Global::allocator->alloc(Loader_stack_size, __loader_stack);
244 
245   if (!__loader_stack.is_valid())
246     {
247       Err(Err::Fatal).printf("could not allocate loader stack\n");
248       return false;
249     }
250 
251   __loader_stack_p
252     = Global::local_rm->attach((void*)Mem_layout::Loader_vma_start,
253                                Loader_stack_size,
254                                Region_handler(__loader_stack,
255                                               __loader_stack.cap(),
256                                               0, L4Re::Rm::F::RW),
257                                L4Re::Rm::F::Search_addr);
258 
259   if (__loader_stack_p == L4_INVALID_PTR)
260     {
261       Err(Err::Fatal).printf("could not attach loader stack\n");
262       return false;
263     }
264 
265   long ret
266     = L4Re::Env::env()->rm()->attach(&__loader_stack_p, Loader_stack_size,
267                                      L4Re::Rm::F::RW,
268                                      L4::Ipc::make_cap_rw(__loader_stack), 0);
269   if (ret)
270     {
271       // The loader stack is already attached to the local region map. We
272       // tried to attach it to the remote region map (e.g. moe) as well, and
273       // this failed. This means that there is an unexpected inconsistency
274       // between the actual remote region map and our model of it. Something
275       // running in the l4re_kernel must have attached a memory region there,
276       // which is a bug, and must be fixed.
277       Err(Err::Fatal).printf("could not attach loader stack to remote region map\n");
278       return false;
279     }
280 
281   l4_umword_t *sp = (l4_umword_t*)((char*)__loader_stack_p + Loader_stack_size);
282 
283   *(--sp) = 0;
284 
285   __loader_stack_p = sp;
286 
287 
288   __loader = this;
289   __rm = rm ;
290   __binary = bin;
291 
292   if (0)
293     L4::cout << "l4re: start file " << bin
294              << " entry=" << (void *)__loader_entry.entry << '\n';
295 
296   Env *const env = const_cast<Env *>(Env::env());
297 
298   app_thread = Cap<Thread>(env->first_free_cap() << L4_CAP_SHIFT);
299   env->first_free_cap((app_thread.cap() >> L4_CAP_SHIFT)+1);
300 #ifdef L4RE_USE_LOCAL_PAGER_GATE
301   __loader_entry.pager = Global::cap_alloc.alloc<Rm>();
302   chksys(env->factory()->create_gate(__loader_entry.pager, env->main_thread(), 0));
303 #else
304   __loader_entry.pager = L4::cap_reinterpret_cast<Rm>(env->main_thread());
305 #endif
306 
307   chksys(env->factory()->create(app_thread), "create app thread");
308 
309   l4_debugger_set_object_name(app_thread.cap(),
310                               strrchr(aux->binary, '/')
311                                 ? strrchr(aux->binary, '/') + 1 : aux->binary);
312 
313   Thread::Attr attr;
314   attr.pager(__loader_entry.pager);
315   attr.exc_handler(__loader_entry.pager);
316   attr.bind((l4_utcb_t*)env->first_free_utcb(), L4Re::This_task);
317 
318   env->first_free_utcb(env->first_free_utcb() + L4_UTCB_OFFSET);
319 
320   chksys(app_thread->control(attr), "setup app thread");
321   chksys(env->scheduler()->run_thread(app_thread, l4_sched_param(L4RE_MAIN_THREAD_PRIO)));
322   chksys(app_thread->ex_regs((unsigned long)&loader_thread,
323                              (l4_addr_t)Ldr::adjust_sp((char *)__loader_stack_p), 0),
324                              "start app thread");
325 
326 
327   return true;
328 }
329 
330 
331 bool
__start(Cap<Dataspace> bin,Region_map *)332 Loader::__start(Cap<Dataspace> bin, Region_map *)
333 {
334   try
335     {
336       launch(bin, __loader_entry.pager);
337     }
338   catch (L4::Runtime_error const &e)
339     {
340       L4::cerr << e;
341       return false;
342     }
343   catch (L4::Base_exception const &e)
344     {
345       L4::cerr << e;
346       return false;
347     }
348 
349   return true;
350 }
351 
352