]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/l4re_kernel/server/src/loader.cc
update
[l4.git] / l4 / pkg / l4re_kernel / server / src / loader.cc
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
33 #include <cstdlib>
34 #include <cstdio>
35
36 //#define L4RE_USE_LOCAL_PAGER_GATE 1
37
38 using L4Re::Mem_alloc;
39 using L4Re::Dataspace;
40 using L4Re::Rm;
41 using L4::Cap;
42 using L4::Thread;
43 using L4Re::Env;
44 using L4Re::chksys;
45
46 namespace {
47
48 struct Entry_data
49 {
50   l4_addr_t entry;
51   l4_addr_t stack;
52   L4::Cap<L4Re::Rm> pager;
53 };
54
55 static Loader *__loader;
56 static Cap<Dataspace> __binary;
57 static Cap<Dataspace> __loader_stack;
58 static void *__loader_stack_p;
59 static Entry_data __loader_entry;
60 static Region_map *__rm;
61 static Cap<Thread> app_thread;
62
63 static
64 void unmap_stack_and_start()
65 {
66   L4Re::Env::env()->rm()->detach(l4_addr_t(__loader_stack_p) - 1, 0);
67   Global::cap_alloc.free(__loader_stack);
68   switch_stack(__loader_entry.stack, (void(*)())__loader_entry.entry);
69 }
70
71 }
72
73 L4Re_app_model::Dataspace
74 L4Re_app_model::alloc_ds(unsigned long size) const
75 {
76   Dataspace mem = chkcap(Global::cap_alloc.alloc<L4Re::Dataspace>(),
77       "ELF loader: could not allocate capability");
78   chksys(Global::allocator->alloc(size, mem, (Global::l4re_aux->ldr_flags & L4RE_AUX_LDR_FLAG_PINNED_SEGS) ? L4Re::Mem_alloc::Pinned :0 ), "loading writabel ELF segment");
79   return mem;
80 }
81
82 L4Re_app_model::Const_dataspace
83 L4Re_app_model::open_file(char const *name)
84 {
85   using L4Re::chkcap;
86   L4Re::Util::Env_ns ens(L4Re::Env::env(), L4Re::Cap_alloc::get_cap_alloc(Global::cap_alloc));
87
88   L4::Cap<L4Re::Dataspace> file;
89
90   file = chkcap(ens.query<L4Re::Dataspace>(name), name, 0);
91
92   return file;
93 }
94
95 void
96 L4Re_app_model::prog_attach_ds(l4_addr_t addr, unsigned long size,
97                                Const_dataspace ds, unsigned long offset,
98                                unsigned flags, char const *what)
99 {
100   if (Global::l4re_aux->ldr_flags & L4RE_AUX_LDR_FLAG_EAGER_MAP)
101     flags |= L4Re::Rm::Eager_map;
102
103   chksys(_rm->attach(&addr, size, flags, ds, offset), what);
104 }
105
106 void
107 L4Re_app_model::copy_ds(Dataspace dst, unsigned long dst_offs,
108                         Const_dataspace src, unsigned long src_offs,
109                         unsigned long size)
110 {
111   if (dst->copy_in(dst_offs, src, src_offs, size) < 0)
112     {
113       L4::Cap<L4Re::Rm> r = L4Re::Env::env()->rm();
114       L4Re::Rm::Auto_region<char const *> data;
115       chksys(r->attach(&data, size, L4Re::Rm::Search_addr | L4Re::Rm::Read_only,
116             src, src_offs));
117
118       // FIXME: buggy:
119       //memcpy(paddr + page_offs, data.get() + page_offs, fsz);
120     }
121 }
122
123 l4_addr_t
124 L4Re_app_model::local_attach_ds(Const_dataspace ds, unsigned long size,
125                                 unsigned long offset) const
126 {
127   l4_addr_t pg_offset = l4_trunc_page(offset);
128   l4_addr_t in_pg_offset = offset - pg_offset;
129   unsigned long pg_size = l4_round_page(size + in_pg_offset);
130   l4_addr_t vaddr = 0;
131   chksys(_rm->attach(&vaddr, pg_size,
132         L4Re::Rm::Search_addr | L4Re::Rm::Read_only,
133         ds, pg_offset), "ELF loader: attach temporary VMA");
134   return vaddr + in_pg_offset;
135 }
136
137 void
138 L4Re_app_model::local_detach_ds(l4_addr_t addr, unsigned long /*size*/) const
139 {
140   l4_addr_t pg_addr = l4_trunc_page(addr);
141   chksys(_rm->detach(pg_addr, 0), "ELF loader: detach temporary VMA");
142 }
143
144 int
145 L4Re_app_model::prog_reserve_area(l4_addr_t *start, unsigned long size, unsigned flags, unsigned char align)
146 {
147   return _rm->reserve_area(start, size, flags, align);
148 }
149
150 L4Re_app_model::Dataspace
151 L4Re_app_model::alloc_app_stack()
152 {
153   // Allocate the stack for the application
154   L4::Cap<L4Re::Dataspace> stack
155     = chkcap(Global::cap_alloc.alloc<L4Re::Dataspace>(),
156       "ELF loader: could not allocate capability");
157
158   //ldr.printf("  allocate 0x%zx byte stack @%lx\n",
159   //    stack_info.stack_size, stack_info.stack_addr);
160   //if (!stack_info.stack_size)
161    // chksys(-L4_EINVAL, "ELF loader: no stack size specified in binary");
162   chksys(Global::allocator->alloc(_stack.stack_size(), stack));
163
164   void *_s = (void*)(_stack.target_addr());
165   chksys(_rm->attach(&_s, _stack.stack_size(), Rm::Search_addr, stack, 0));
166   _stack.set_target_stack(l4_addr_t(_s), _stack.stack_size());
167   _stack.set_local_addr(l4_addr_t(_s));
168   return stack;
169 }
170
171 void
172 L4Re_app_model::extra_elf_auxv()
173 {
174 }
175
176 void
177 L4Re_app_model::push_envp()
178 {
179   _stack.push(l4_umword_t(0));
180   for (char const *const *e = Global::envp; *e; ++e)
181     _stack.push(*e);
182 }
183
184 void
185 L4Re_app_model::push_argv()
186 {
187   _stack.push(l4_umword_t(0));
188   for (int i = Global::argc - 1; i >= 0; --i)
189     _stack.push(Global::argv[i]);
190
191   // ARGC
192   _stack.push(l4_umword_t(Global::argc));
193 }
194
195 bool
196 L4Re_app_model::all_segs_cow()
197 {
198   return Global::l4re_aux->ldr_flags & L4RE_AUX_LDR_FLAG_ALL_SEGS_COW;
199 }
200
201 L4Re::Env *
202 L4Re_app_model::add_env()
203 {
204   L4Re::Env *e = const_cast<L4Re::Env *>(L4Re::Env::env());
205
206   e->rm(__loader_entry.pager);
207   e->main_thread(app_thread);
208   return e;
209
210 }
211
212 void
213 L4Re_app_model::start_prog(L4Re::Env const *)
214 {
215   __loader_entry.stack = l4_addr_t(_stack.ptr());
216   __loader_entry.entry = _info.entry;
217   switch_stack(__loader_entry.stack, &unmap_stack_and_start);
218 }
219
220 enum
221 {
222   Loader_stack_size = 8 * 1024,
223 };
224
225
226 static void
227 loader_thread()
228 {
229   if (!__loader->__start(__binary, __rm))
230     {
231       Err(Err::Fatal).printf("could not load binary\n");
232       exit(1);
233     }
234 }
235
236 bool Loader::start(Cap<Dataspace> bin, Region_map *rm, l4re_aux_t * /*aux*/)
237 {
238   __loader_stack = Global::cap_alloc.alloc<Dataspace>();
239   Global::allocator->alloc(Loader_stack_size, __loader_stack);
240
241   if (!__loader_stack.is_valid())
242     {
243       Err(Err::Fatal).printf("could not allocate loader stack\n");
244       return false;
245     }
246
247   __loader_stack_p
248     = Global::local_rm->attach((void*)Mem_layout::Loader_vma_start,
249         Loader_stack_size, Region_handler(__loader_stack, __loader_stack.cap()),
250         0, Region_map::Search);
251
252   if (__loader_stack_p == L4_INVALID_PTR)
253     {
254       Err(Err::Fatal).printf("could not attach loader stack\n");
255       return false;
256     }
257
258   L4Re::Env::env()->rm()->attach(&__loader_stack_p, Loader_stack_size, 0, __loader_stack, 0);
259
260   l4_umword_t *sp = (l4_umword_t*)((char*)__loader_stack_p + Loader_stack_size);
261
262   *(--sp) = 0;
263
264   __loader_stack_p = sp;
265
266
267   __loader = this;
268   __rm = rm ;
269   __binary = bin;
270
271 #if 0
272   L4::cout << "l4re: start file " << bin << " entry=" << (void*)entry.entry << '\n';
273 #endif
274
275   Env *const env = const_cast<Env *>(Env::env());
276
277   app_thread = Cap<Thread>(env->first_free_cap() << L4_CAP_SHIFT);
278   env->first_free_cap((app_thread.cap() >> L4_CAP_SHIFT)+1);
279 #ifdef L4RE_USE_LOCAL_PAGER_GATE
280   __loader_entry.pager = Global::cap_alloc.alloc<Rm>();
281   chksys(env->factory()->create_gate(__loader_entry.pager, env->main_thread(), 0));
282 #else
283   __loader_entry.pager = L4::cap_reinterpret_cast<Rm>(env->main_thread());
284 #endif
285
286   chksys(env->factory()->create_thread(app_thread), "create app thread");
287
288   Thread::Attr attr;
289   attr.pager(__loader_entry.pager);
290   attr.exc_handler(__loader_entry.pager);
291   attr.bind((l4_utcb_t*)env->first_free_utcb(), L4Re::This_task);
292
293   env->first_free_utcb(env->first_free_utcb() + L4_UTCB_OFFSET);
294
295   chksys(app_thread->control(attr), "setup app thread");
296   chksys(env->scheduler()->run_thread(app_thread, l4_sched_param(2)));
297   chksys(app_thread->ex_regs((unsigned long)&loader_thread,
298                              (l4_addr_t)Ldr::adjust_sp((char *)__loader_stack_p), 0),
299                              "start app thread");
300
301
302   return true;
303 }
304
305
306 bool
307 Loader::__start(Cap<Dataspace> bin, Region_map *)
308 {
309   try
310     {
311       launch(bin, __loader_entry.pager);
312     }
313   catch (L4::Runtime_error const &e)
314     {
315       L4::cerr << e;
316       return false;
317     }
318   catch (L4::Base_exception const &e)
319     {
320       L4::cerr << e;
321       return false;
322     }
323
324   return true;
325 }
326