]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/arm/vm.cpp
update
[l4.git] / kernel / fiasco / src / kern / arm / vm.cpp
1 INTERFACE:
2
3 #include "mapping_tree.h"
4 #include "kobject.h"
5 #include "kmem_slab.h"
6 #include "l4_types.h"
7 #include "prio_list.h"
8 #include "slab_cache_anon.h"
9 #include "ref_obj.h"
10
11 class Ram_quota;
12
13 class Vm : public Kobject_iface, public Kobject, public Ref_cnt_obj
14 {
15   FIASCO_DECLARE_KOBJ();
16
17   struct machine_state
18     {
19       Mword r[13];
20
21       Mword sp_usr;
22       Mword lr_usr;
23
24       Mword sp_irq;
25       Mword lr_irq;
26       Mword spsr_irq;
27
28       Mword r_fiq[5]; // r8 - r12
29       Mword sp_fiq;
30       Mword lr_fiq;
31       Mword spsr_fiq;
32
33       Mword sp_abt;
34       Mword lr_abt;
35       Mword spsr_abt;
36
37       Mword sp_und;
38       Mword lr_und;
39       Mword spsr_und;
40
41       Mword sp_svc;
42       Mword lr_svc;
43       Mword spsr_svc;
44       
45       Mword pc;
46       Mword cpsr;
47
48       Mword pending_events;
49       
50       Mword cp15_ttbr0;
51       Mword cp15_ttbr1;
52       Mword cp15_ttbcr;
53       Mword cp15_vector_base;
54       Mword cp15_dfsr;
55       Mword cp15_dfar;
56       Mword cp15_ifsr;
57       Mword cp15_ifar;
58       Mword cp15_control;
59       Mword cp15_prim_region_remap;
60       Mword cp15_norm_region_remap;
61       Mword cp15_cid;
62      
63       Mword pfs;
64       Mword pfa;
65       Mword exit_reason;
66     };
67
68 private:
69   typedef slab_cache_anon Allocator;
70
71   bool _valid;
72   Mword *_state;
73   Space *_space; // space the state is contained in
74
75 public:
76   virtual ~Vm();
77 };
78
79 //-----------------------------------------------------------------------------
80 INTERFACE [debug]:
81
82 EXTENSION class Vm
83 {
84 public:
85   struct Vm_log
86   {
87     bool is_entry;
88     Mword pc;
89     Mword cpsr;
90     Mword exit_reason;
91     Mword pending_events;
92     Mword r0;
93     Mword r1;
94   };
95
96   static unsigned vm_log_fmt(Tb_entry *tbe, int maxlen, char *buf)
97   asm ("__vm_log_fmt");
98 };
99
100 //-----------------------------------------------------------------------------
101
102 IMPLEMENTATION:
103
104 #include "cpu.h"
105 #include "cpu_lock.h"
106 #include "entry_frame.h"
107 #include "ipc_timeout.h"
108 #include "logdefs.h"
109 #include "mem_space.h"
110 #include "thread_state.h"
111 #include "timer.h"
112 #include "ref_ptr.h"
113
114 FIASCO_DEFINE_KOBJ(Vm);
115
116 PUBLIC
117 static
118 Vm *
119 Vm::create(Ram_quota *quota)
120 {
121   if (void *a = allocator()->q_alloc(quota))
122     {
123       Vm *vm = new (a) Vm;
124       if (vm->valid())
125         return vm;
126
127       delete vm;
128     }
129
130   return 0;
131 }
132
133 PUBLIC /*inline*/
134 Vm::Vm()
135   : _valid(true), _state(0), _space(0)
136 { inc_ref(); }
137
138 IMPLEMENT
139 Vm::~Vm()
140 { _valid = false; }
141
142 PUBLIC virtual
143 bool
144 Vm::put()
145 { return dec_ref() == 0; }
146
147 PUBLIC
148 inline
149 Vm::machine_state *
150 Vm::state()
151 { return reinterpret_cast<machine_state *>(_state); };
152
153 // ------------------------------------------------------------------------
154 IMPLEMENTATION [arm && tz]:
155
156 #include "thread.h"
157
158 void
159 Vm::run(Syscall_frame *f, Utcb *utcb)
160 {
161   assert(cpu_lock.test());
162   Ref_ptr<Vm> ref_ptr(this);
163
164   L4_msg_tag const &tag = f->tag();
165
166   if (tag.words() != 3)
167     {
168       WARN("tz: Invalid message length\n");
169       f->tag(commit_result(-L4_err::EInval));
170       return;
171     }
172
173   // FIXME: use a send item (fpage) for vm_state. this implementation is wrong!
174   L4_fpage state_fpage(utcb->values[1]);
175
176   if (!state_fpage.is_mempage()
177       || state_fpage.order() != 12)
178     {
179       WARN("tz: Fpage invalid\n");
180       f->tag(commit_result(-L4_err::EInval));
181       return;
182     }
183
184   _state = (Mword *)(Virt_addr(state_fpage.mem_address()).value());
185
186     {
187       bool resident;
188       Mem_space::Phys_addr phys;
189       Mem_space::Size size;
190       unsigned int attribs;
191
192       _space = current()->space();
193       Mem_space *const curr_mem_space = current()->space()->mem_space();
194       resident = curr_mem_space->v_lookup(Virt_addr(_state), &phys, &size, &attribs);
195
196       if (!resident)
197         {
198           WARN("tz: Vm_state not mapped\n");
199           f->tag(commit_result(-L4_err::EInval));
200           return;
201         }
202     }
203
204   // set the temporary label for this VM
205   Mword label = f->from_spec();
206
207   while (true)
208     {
209       Proc::preemption_point();
210
211       if (current_thread()->sender_list()->head())
212         {
213           current_thread()->do_ipc(L4_msg_tag(), 0, 0, true, 0,
214               L4_timeout_pair(L4_timeout::Zero, L4_timeout::Zero), f, 7);
215           if (EXPECT_TRUE(!f->tag().has_error()))
216             return;
217           WARN("tz: Receive event failed\n");
218         }
219
220       log_vm(this, 1);
221
222       if (!get_fpu())
223         {
224           f->tag(commit_result(-L4_err::EInval));
225           return;
226         }
227
228       Cpu::cpus.cpu(current()->cpu()).tz_switch_to_ns(_state);
229
230       assert(cpu_lock.test());
231
232       log_vm(this, 0);
233
234       if ((state()->exit_reason != 1) || 
235          ((state()->exit_reason == 1) &&
236           ((state()->r[0] & 0xffff0000) == 0xffff0000)))
237         continue;
238       else
239         break;
240     }
241
242   // set label as return value for this vm
243   f->from(label);
244   f->tag(L4_msg_tag(L4_msg_tag::Label_task, 0, 0, 0));
245   return;
246 }
247
248 IMPLEMENTATION [arm && tz && fpu]:
249
250 PUBLIC
251 bool
252 Vm::get_fpu()
253 {
254   if (!(current()->state() & Thread_fpu_owner))
255     {
256       if (!current_thread()->switchin_fpu())
257         {
258           printf("tz: switchin_fpu failed\n");
259           return false;
260         }
261     }
262   return true;
263 }
264
265 // --------------------------------------------------------------------------
266 IMPLEMENTATION [arm && tz && !fpu]:
267
268 PUBLIC
269 bool
270 Vm::get_fpu()
271 { return true; }
272
273 IMPLEMENTATION [arm && !tz]:
274
275 PUBLIC
276 L4_msg_tag
277 Vm::run(Utcb *u)
278 {
279   return L4_msg_tag(0, 0, 0, 0);
280 }
281
282 // --------------------------------------------------------------------------
283 IMPLEMENTATION:
284
285 PUBLIC
286 void *
287 Vm::operator new (size_t, void *p)
288 { return p; }
289
290 PUBLIC
291 void
292 Vm::operator delete (void *_l)
293 {
294   Vm *l = reinterpret_cast<Vm*>(_l);
295   allocator()->free(l);
296 }
297
298 PRIVATE static inline NOEXPORT NEEDS["kmem_slab.h"]
299 Vm::Allocator *
300 Vm::allocator()
301 {
302   static Allocator* slabs = 
303     new Kmem_slab_simple (sizeof (Vm), sizeof (Mword), "Vm");
304
305   return slabs;
306 }
307
308 PUBLIC inline
309 bool
310 Vm::valid() const
311 { return _valid; }
312
313 PUBLIC
314 void
315 Vm::invoke(L4_obj_ref, Mword, Syscall_frame *f, Utcb *u)
316 {
317   switch (f->tag().proto())
318     {
319     case 0:
320     case L4_msg_tag::Label_task:
321       run(nonull_static_cast<Syscall_frame*>(f), u);
322       return;
323     default:
324       break;
325     }
326
327   f->tag(L4_msg_tag(0,0,0,-L4_err::EInval));
328 }
329
330 // --------------------------------------------------------------------------
331 IMPLEMENTATION [debug]:
332
333 #include "jdb.h"
334
335 PRIVATE
336 Mword
337 Vm::jdb_get(Mword *state_ptr)
338 {
339   Mword v = ~0UL;
340   Jdb::peek(state_ptr, _space, v);
341   return v;
342 }
343
344 PUBLIC
345 void
346 Vm::dump_machine_state()
347 {
348   machine_state *s = reinterpret_cast<machine_state*>(_state);
349   printf("pc: %08lx  cpsr: %08lx exit_reason:%ld \n",
350       jdb_get(&s->pc), jdb_get(&s->cpsr), jdb_get(&s->exit_reason));
351   printf("r0: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
352       jdb_get(&s->r[0]), jdb_get(&s->r[1]), jdb_get(&s->r[2]), jdb_get(&s->r[3]),
353       jdb_get(&s->r[4]), jdb_get(&s->r[5]), jdb_get(&s->r[6]), jdb_get(&s->r[7]));
354   printf("r8: %08lx %08lx %08lx %08lx %08lx\n",
355       jdb_get(&s->r[8]), jdb_get(&s->r[9]), jdb_get(&s->r[10]), jdb_get(&s->r[11]),
356       jdb_get(&s->r[12]));
357
358   printf("usr: sp %08lx lr %08lx\n",
359       jdb_get(&s->sp_usr), jdb_get(&s->lr_usr));
360   printf("irq: sp %08lx lr %08lx psr %08lx\n",
361       jdb_get(&s->sp_irq), jdb_get(&s->lr_irq), jdb_get(&s->spsr_irq));
362   printf("fiq: sp %08lx lr %08lx psr %08lx\n",
363       jdb_get(&s->sp_fiq), jdb_get(&s->lr_fiq), jdb_get(&s->spsr_fiq));
364   printf("r8: %08lx %08lx %08lx %08lx %08lx\n",
365       jdb_get(&s->r_fiq[8]), jdb_get(&s->r_fiq[9]), jdb_get(&s->r_fiq[10]),
366       jdb_get(&s->r_fiq[11]), jdb_get(&s->r_fiq[12]));
367
368   printf("abt: sp %08lx lr %08lx psr %08lx\n",
369       jdb_get(&s->sp_abt), jdb_get(&s->lr_abt), jdb_get(&s->spsr_abt));
370   printf("und: sp %08lx lr %08lx psr %08lx\n",
371       jdb_get(&s->sp_und), jdb_get(&s->lr_und), jdb_get(&s->spsr_und));
372   printf("svc: sp %08lx lr %08lx psr %08lx\n",
373       jdb_get(&s->sp_svc), jdb_get(&s->lr_svc), jdb_get(&s->spsr_svc));
374   printf("cp15_sctlr:%08lx\n", jdb_get(&s->cp15_control));
375   printf("cp15_ttbr0:%08lx\n", jdb_get(&s->cp15_ttbr0));
376   printf("cp15_ttbr1:%08lx\n", jdb_get(&s->cp15_ttbr1));
377   printf("cp15_ttbcr:%08lx\n", jdb_get(&s->cp15_ttbcr));
378   printf("dfar: %08lx dfsr: %08lx ifar: %08lx ifsr: %08lx\n",
379       jdb_get(&s->cp15_dfar), jdb_get(&s->cp15_dfsr), jdb_get(&s->cp15_ifar),
380       jdb_get(&s->cp15_ifsr));
381 }
382
383 PUBLIC
384 int
385 Vm::show_short(char *buf, int max)
386 {
387   return snprintf(buf, max, " utcb:%lx pc:%lx ", (Mword)_state, (Mword)jdb_get(&state()->pc));
388 }
389
390 IMPLEMENT
391 unsigned
392 Vm::vm_log_fmt(Tb_entry *e, int maxlen, char *buf)
393 {
394   Vm_log *l = e->payload<Vm_log>();
395   if (l->is_entry)
396     return vm_entry_log_fmt(l, maxlen, buf);
397   else
398     return vm_exit_log_fmt(l, maxlen, buf);
399 }
400
401 PRIVATE static
402 unsigned
403 Vm::vm_entry_log_fmt(Vm_log *l, int maxlen, char *buf)
404 {
405   if (l->r0 == 0x1110)
406     return snprintf(buf, maxlen, "entry: pc:%08lx/%03lx intack irq: %lx", l->pc, l->pending_events, l->r1);
407
408   return snprintf(buf, maxlen, "entry: pc:%08lx/%03lx r0:%lx", l->pc, l->pending_events, l->r0);
409 }
410
411 PRIVATE static
412 unsigned
413 Vm::vm_exit_log_fmt(Vm_log *l, int maxlen, char *buf)
414 {
415   if ((l->r0 & 0xffff0000) == 0xffff0000)
416     return snprintf(buf, maxlen, "=====: pc:%08lx/%03lx [%04lx]", l->pc, l->pending_events, l->r0 & 0xffff);
417   if (l->r0 == 0x1105)
418     return snprintf(buf, maxlen, "exit:  pc:%08lx/%03lx enable irq: %lx", l->pc, l->pending_events, l->r1);
419   if (l->r0 == 0x1109)
420     return snprintf(buf, maxlen, "exit:  pc:%08lx/%03lx disable irq: %lx", l->pc, l->pending_events, l->r1);
421   if (l->r0 == 0x1110)
422     return snprintf(buf, maxlen, "exit:  pc:%08lx/%03lx intack", l->pc, l->pending_events);
423   if (l->r0 == 0x1115)
424     return snprintf(buf, maxlen, "exit:  pc:%08lx/%03lx send ipi:%lx", l->pc, l->pending_events, l->r1);
425
426   return snprintf(buf, maxlen, "exit:  pc:%08lx/%03lx r0:%lx", l->pc, l->pending_events, l->r0);
427 }
428
429 PUBLIC static inline
430 void
431 Vm::log_vm(Vm *vm, bool is_entry)
432 {
433   if (vm->state()->exit_reason != 1)
434       return;
435   if ((vm->state()->r[0] & 0xf000) == 0x7000)
436     return;
437   if ((is_entry && (vm->state()->r[0] & 0xffff0000) == 0xffff0000))
438     return;
439   LOG_TRACE("VM entry/entry", "VM", current(), __vm_log_fmt,
440       Vm::Vm_log *l = tbe->payload<Vm::Vm_log>();
441       l->is_entry = is_entry;
442       l->pc = vm->state()->pc;
443       l->cpsr = vm->state()->cpsr;
444       l->exit_reason = vm->state()->exit_reason;
445       l->pending_events = vm->state()->pending_events;
446       l->r0 = vm->state()->r[0];
447       l->r1 = vm->state()->r[1];
448   );
449 }
450
451 // --------------------------------------------------------------------------
452 IMPLEMENTATION [!debug]:
453
454 PUBLIC static inline
455 void
456 Vm::log_vm(Vm *, bool)
457 {}