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)
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.
15 #include "mem_layout.h"
16 #include "switch_stack.h"
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>
26 #include <l4/re/dataspace>
27 #include <l4/re/mem_alloc>
29 #include <l4/re/util/env_ns>
30 #include <l4/re/l4aux.h>
31 #include <l4/re/error_helper>
36 //#define L4RE_USE_LOCAL_PAGER_GATE 1
38 using L4Re::Mem_alloc;
39 using L4Re::Dataspace;
52 L4::Cap<L4Re::Rm> pager;
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;
64 void unmap_stack_and_start()
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);
73 L4Re_app_model::Dataspace
74 L4Re_app_model::alloc_ds(unsigned long size) const
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");
82 L4Re_app_model::Const_dataspace
83 L4Re_app_model::open_file(char const *name)
86 L4Re::Util::Env_ns ens(L4Re::Env::env(), L4Re::Cap_alloc::get_cap_alloc(Global::cap_alloc));
88 L4::Cap<L4Re::Dataspace> file;
90 file = chkcap(ens.query<L4Re::Dataspace>(name), name, 0);
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)
100 if (Global::l4re_aux->ldr_flags & L4RE_AUX_LDR_FLAG_EAGER_MAP)
101 flags |= L4Re::Rm::Eager_map;
103 chksys(_rm->attach(&addr, size, flags, ds, offset), what);
107 L4Re_app_model::copy_ds(Dataspace dst, unsigned long dst_offs,
108 Const_dataspace src, unsigned long src_offs,
111 if (dst->copy_in(dst_offs, src, src_offs, size) < 0)
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,
119 //memcpy(paddr + page_offs, data.get() + page_offs, fsz);
124 L4Re_app_model::local_attach_ds(Const_dataspace ds, unsigned long size,
125 unsigned long offset) const
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);
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;
138 L4Re_app_model::local_detach_ds(l4_addr_t addr, unsigned long /*size*/) const
140 l4_addr_t pg_addr = l4_trunc_page(addr);
141 chksys(_rm->detach(pg_addr, 0), "ELF loader: detach temporary VMA");
145 L4Re_app_model::prog_reserve_area(l4_addr_t *start, unsigned long size, unsigned flags, unsigned char align)
147 return _rm->reserve_area(start, size, flags, align);
150 L4Re_app_model::Dataspace
151 L4Re_app_model::alloc_app_stack()
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");
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));
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));
172 L4Re_app_model::extra_elf_auxv()
177 L4Re_app_model::push_envp()
179 _stack.push(l4_umword_t(0));
180 for (char const *const *e = Global::envp; *e; ++e)
185 L4Re_app_model::push_argv()
187 _stack.push(l4_umword_t(0));
188 for (int i = Global::argc - 1; i >= 0; --i)
189 _stack.push(Global::argv[i]);
192 _stack.push(l4_umword_t(Global::argc));
196 L4Re_app_model::all_segs_cow()
198 return Global::l4re_aux->ldr_flags & L4RE_AUX_LDR_FLAG_ALL_SEGS_COW;
202 L4Re_app_model::add_env()
204 L4Re::Env *e = const_cast<L4Re::Env *>(L4Re::Env::env());
206 e->rm(__loader_entry.pager);
207 e->main_thread(app_thread);
213 L4Re_app_model::start_prog(L4Re::Env const *)
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);
222 Loader_stack_size = 8 * 1024,
229 if (!__loader->__start(__binary, __rm))
231 Err(Err::Fatal).printf("could not load binary\n");
236 bool Loader::start(Cap<Dataspace> bin, Region_map *rm, l4re_aux_t * /*aux*/)
238 __loader_stack = Global::cap_alloc.alloc<Dataspace>();
239 Global::allocator->alloc(Loader_stack_size, __loader_stack);
241 if (!__loader_stack.is_valid())
243 Err(Err::Fatal).printf("could not allocate loader stack\n");
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);
252 if (__loader_stack_p == L4_INVALID_PTR)
254 Err(Err::Fatal).printf("could not attach loader stack\n");
258 L4Re::Env::env()->rm()->attach(&__loader_stack_p, Loader_stack_size, 0, __loader_stack, 0);
260 l4_umword_t *sp = (l4_umword_t*)((char*)__loader_stack_p + Loader_stack_size);
264 __loader_stack_p = sp;
272 L4::cout << "l4re: start file " << bin << " entry=" << (void*)entry.entry << '\n';
275 Env *const env = const_cast<Env *>(Env::env());
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));
283 __loader_entry.pager = L4::cap_reinterpret_cast<Rm>(env->main_thread());
286 chksys(env->factory()->create_thread(app_thread), "create app thread");
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);
293 env->first_free_utcb(env->first_free_utcb() + L4_UTCB_OFFSET);
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),
307 Loader::__start(Cap<Dataspace> bin, Region_map *)
311 launch(bin, __loader_entry.pager);
313 catch (L4::Runtime_error const &e)
318 catch (L4::Base_exception const &e)