1// vi:set ft=cpp: -*- Mode: C++ -*-
2/*
3 * (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
4 *     economic rights: Technische Universität Dresden (Germany)
5 * This file is part of TUD:OS and distributed under the terms of the
6 * GNU Lesser General Public License 2.1.
7 * Please see the COPYING-LGPL-2.1 file for details.
8 */
9
10#pragma once
11
12#include <l4/re/env>
13#include <l4/re/error_helper>
14#include <l4/sys/task>
15#include <l4/sys/thread>
16#include <l4/sys/scheduler>
17#include <l4/sys/factory>
18
19namespace Ldr {
20
21struct Remote_app_std_caps
22{
23  enum Base_cap
24  {
25    Task_cap               = 1,
26    Factory_cap            = 2,
27    Rm_thread_cap          = 3,
28    Log_cap                = 5,
29    Scheduler_cap          = 7,
30    // skip base caps
31    External_rm_cap        = 0x10,
32    Allocator_cap,
33    Names_cap,
34    Parent_cap,
35    Kip_cap,
36    First_free,
37  };
38};
39
40struct Remote_app_std_prios
41{
42  enum Prio
43  {
44    Default_thread_prio = 2
45  };
46};
47
48template< typename Base, typename STD_CAPS = Remote_app_std_caps,
49          typename PRIOS = Remote_app_std_prios >
50class Remote_app_model : public Base, protected STD_CAPS, protected PRIOS
51{
52public:
53  typedef STD_CAPS Caps;
54  typedef PRIOS Prios;
55
56  virtual ~Remote_app_model() throw() {}
57
58  template< typename A1, typename A2, typename A3 >
59  Remote_app_model(A1 const &a1, A2 const &a2, A3 const & a3)
60  : Base(a1, a2, a3) {}
61
62  template< typename A1, typename A2 >
63  Remote_app_model(A1 const &a1, A2 const &a2) : Base(a1, a2) {}
64
65  template< typename A1 >
66  explicit Remote_app_model(A1 const &a1) : Base(a1) {}
67
68  Remote_app_model() : Base() {}
69
70  L4Re::Env *add_env()
71  {
72    // the terminator
73    this->_stack.push(l4re_env_cap_entry_t());
74
75    l4_cap_idx_t first_free
76      = this->push_initial_caps(Caps::First_free << L4_CAP_SHIFT);
77
78    l4re_env_cap_entry_t *caps
79      = reinterpret_cast<l4re_env_cap_entry_t*>(this->_stack.ptr());
80
81    L4Re::Env *env = this->_stack.push(L4Re::Env());
82
83    env->mem_alloc(L4::Cap<L4Re::Mem_alloc>(Caps::Allocator_cap << L4_CAP_SHIFT));
84    env->parent(L4::Cap<L4Re::Parent>(Caps::Parent_cap << L4_CAP_SHIFT));
85    env->scheduler(L4::Cap<L4::Scheduler>(Caps::Scheduler_cap << L4_CAP_SHIFT));
86    env->rm(L4::Cap<L4Re::Rm>(Caps::External_rm_cap << L4_CAP_SHIFT));
87    env->log(L4::Cap<L4Re::Log>(Caps::Log_cap << L4_CAP_SHIFT));
88    env->main_thread(L4::Cap<L4::Thread>(Caps::Rm_thread_cap << L4_CAP_SHIFT));
89    env->factory(L4::Cap<L4::Factory>(Caps::Factory_cap << L4_CAP_SHIFT));
90    env->first_free_cap(first_free >> L4_CAP_SHIFT);
91    env->utcb_area(l4_fpage(this->_info.utcbs_start, this->_info.utcbs_log2size, 0));
92    env->first_free_utcb(this->_info.utcbs_start + L4_UTCB_OFFSET);
93    env->initial_caps(this->_stack.relocate(caps));
94    return env;
95  }
96
97  L4::Cap<void> prog_kip_ds() const
98  { return L4::Cap<void>(Caps::Kip_cap << L4_CAP_SHIFT); }
99
100  void const *generate_l4aux(char const *name)
101  {
102    this->_stack.push(l4_umword_t(this->prog_info()->ldr_flags));
103    this->_stack.push(l4_umword_t(this->prog_info()->l4re_dbg));
104    this->_stack.push(l4_umword_t(prog_kip_ds().cap()));
105    return this->_stack.push_local_ptr(name);
106  }
107
108  void prog_reserve_utcb_area()
109  {
110    this->prog_attach_ds(this->prog_info()->utcbs_start,
111                         1UL << this->prog_info()->utcbs_log2size,
112                         this->reserved_area(), 0, L4Re::Rm::F::RW,
113                         "attaching utcb area");
114  }
115
116  void prog_attach_kip()
117  {
118    this->prog_attach_ds(this->prog_info()->kip, L4_PAGESIZE,
119                         this->local_kip_ds(), 0,
120                         L4Re::Rm::F::RX,
121                         "attaching KIP segment");
122  }
123
124  void prog_attach_stack(typename Base::Dataspace app_stack)
125  {
126    this->prog_attach_ds(this->_stack.target_addr(), this->_stack.stack_size(),
127                         app_stack, 0, L4Re::Rm::F::RW,
128                         "attaching stack segment");
129  }
130
131  void start_prog(L4Re::Env const *env)
132  {
133    using L4Re::chksys;
134    using L4::Cap;
135
136    L4::Cap<L4::Task> ntask;
137    L4::Cap<L4::Thread> nthread;
138    L4::Cap<L4::Factory> factory;
139
140    this->get_task_caps(&factory, &ntask, &nthread);
141
142    chksys(factory->create_task(ntask, env->utcb_area()));
143    chksys(factory->create(nthread));
144
145    chksys(ntask->map(L4Re::This_task, ntask.fpage(),
146	  Cap<L4::Task>(L4Re::This_task).snd_base()));
147    chksys(ntask->map(L4Re::This_task, this->_info.factory,
148	  env->factory().snd_base()));
149    chksys(ntask->map(L4Re::This_task, nthread.fpage(),
150	  env->main_thread().snd_base()));
151    chksys(ntask->map(L4Re::This_task, this->_info.scheduler,
152	  env->scheduler().snd_base()));
153    chksys(ntask->map(L4Re::This_task, this->_info.parent,
154	  env->parent().snd_base()));
155    chksys(ntask->map(L4Re::This_task, this->_info.log,
156	  env->log().snd_base()));
157    chksys(ntask->map(L4Re::This_task, this->_info.rm,
158	  env->rm().snd_base()));
159    chksys(ntask->map(L4Re::This_task, this->_info.mem_alloc,
160	  env->mem_alloc().snd_base()));
161    chksys(ntask->map(L4Re::This_task, this->local_kip_cap().fpage(),
162	  prog_kip_ds().snd_base()));
163
164    this->map_initial_caps(ntask, Caps::First_free << L4_CAP_SHIFT);
165
166    L4::Thread::Attr th_attr;
167    th_attr.pager(env->rm());
168    th_attr.exc_handler(env->rm());
169    th_attr.bind((l4_utcb_t*)this->_info.utcbs_start, ntask);
170    chksys(nthread->control(th_attr));
171
172    chksys(this->run_thread(nthread,
173                            l4_sched_param(Prios::Default_thread_prio)));
174
175    nthread->ex_regs(this->_info.entry, this->_stack.target_ptr(), 0);
176  }
177
178
179};
180
181}
182