]> 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.h"
9 #include "ref_obj.h"
10
11 class Ram_quota;
12
13 class Vm : 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       Mword cp15_tls[3];
63       Mword cp10_fpexc;
64
65       Mword pfs;
66       Mword pfa;
67       Mword exit_reason;
68     };
69
70 private:
71   typedef Slab_cache Allocator;
72
73   Mword *_state;
74   Space *_space; // space the state is contained in
75 };
76
77 //-----------------------------------------------------------------------------
78 INTERFACE [debug]:
79
80 #include "tb_entry.h"
81
82 EXTENSION class Vm
83 {
84 public:
85   struct Vm_log : public Tb_entry
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     unsigned print(int maxlen, char *buf) const;
95     unsigned vm_entry_log_fmt(int maxlen, char *buf) const;
96     unsigned vm_exit_log_fmt(int maxlen, char *buf) const;
97  };
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       return vm;
125     }
126
127   return 0;
128 }
129
130 PUBLIC
131 Vm::Vm() : _state(0), _space(0)
132 { inc_ref(); }
133
134 PUBLIC virtual
135 bool
136 Vm::put()
137 { return dec_ref() == 0; }
138
139 PUBLIC
140 inline
141 Vm::machine_state *
142 Vm::state()
143 { return reinterpret_cast<machine_state *>(_state); };
144
145 // ------------------------------------------------------------------------
146 IMPLEMENTATION [arm && tz]:
147
148 #include "thread.h"
149
150 void
151 Vm::run(Syscall_frame *f, Utcb *utcb)
152 {
153   assert(cpu_lock.test());
154   Ref_ptr<Vm> ref_ptr(this);
155
156   L4_msg_tag const &tag = f->tag();
157
158   if (tag.words() != 3)
159     {
160       WARN("tz: Invalid message length\n");
161       f->tag(commit_result(-L4_err::EInval));
162       return;
163     }
164
165   // FIXME: use a send item (fpage) for vm_state. this implementation is wrong!
166   L4_fpage state_fpage(utcb->values[1]);
167
168   if (!state_fpage.is_mempage()
169       || state_fpage.order() != 12)
170     {
171       WARN("tz: Fpage invalid\n");
172       f->tag(commit_result(-L4_err::EInval));
173       return;
174     }
175
176   _state = (Mword *)(Virt_addr(state_fpage.mem_address()).value());
177
178     {
179       bool resident;
180       Mem_space::Phys_addr phys;
181       Mem_space::Size size;
182       unsigned int attribs;
183
184       _space = current()->space();
185       assert_opt (_space);
186       Mem_space *const curr_mem_space = _space;
187       resident = curr_mem_space->v_lookup(Virt_addr(_state), &phys, &size, &attribs);
188
189       if (!resident)
190         {
191           WARN("tz: Vm_state not mapped\n");
192           f->tag(commit_result(-L4_err::EInval));
193           return;
194         }
195     }
196
197   // set the temporary label for this VM
198   Mword label = f->from_spec();
199
200   while (true)
201     {
202       Proc::preemption_point();
203
204       if (current_thread()->sender_list()->first())
205         {
206           current_thread()->do_ipc(L4_msg_tag(), 0, 0, true, 0,
207               L4_timeout_pair(L4_timeout::Zero, L4_timeout::Zero), f, 7);
208           if (EXPECT_TRUE(!f->tag().has_error()))
209             return;
210           WARN("tz: Receive event failed\n");
211         }
212
213       log_vm(this, 1);
214
215       if (!get_fpu())
216         {
217           f->tag(commit_result(-L4_err::EInval));
218           return;
219         }
220
221       Cpu::cpus.cpu(current()->cpu()).tz_switch_to_ns(_state);
222
223       assert(cpu_lock.test());
224
225       log_vm(this, 0);
226
227       if ((state()->exit_reason != 1) || 
228          ((state()->exit_reason == 1) &&
229           ((state()->r[0] & 0xffff0000) == 0xffff0000)))
230         continue;
231       else
232         break;
233     }
234
235   // set label as return value for this vm
236   f->from(label);
237   f->tag(L4_msg_tag(L4_msg_tag::Label_task, 0, 0, 0));
238   return;
239 }
240
241 IMPLEMENTATION [arm && tz && fpu]:
242
243 PUBLIC
244 bool
245 Vm::get_fpu()
246 {
247   if (!(current()->state() & Thread_fpu_owner))
248     {
249       if (!current_thread()->switchin_fpu())
250         {
251           printf("tz: switchin_fpu failed\n");
252           return false;
253         }
254     }
255   return true;
256 }
257
258 // --------------------------------------------------------------------------
259 IMPLEMENTATION [arm && tz && !fpu]:
260
261 PUBLIC
262 bool
263 Vm::get_fpu()
264 { return true; }
265
266 IMPLEMENTATION [arm && !tz]:
267
268 PUBLIC
269 L4_msg_tag
270 Vm::run(Utcb *u)
271 {
272   return L4_msg_tag(0, 0, 0, 0);
273 }
274
275 // --------------------------------------------------------------------------
276 IMPLEMENTATION:
277
278 PUBLIC
279 void *
280 Vm::operator new (size_t, void *p) throw()
281 { return p; }
282
283 PUBLIC
284 void
285 Vm::operator delete (void *_l)
286 {
287   Vm *l = reinterpret_cast<Vm*>(_l);
288   allocator()->free(l);
289 }
290
291 static Kmem_slab_t<Vm> _vm_allocator("Vm");
292
293 PRIVATE static
294 Vm::Allocator *
295 Vm::allocator()
296 { return &_vm_allocator; }
297
298 PUBLIC
299 void
300 Vm::invoke(L4_obj_ref, Mword, Syscall_frame *f, Utcb *u)
301 {
302   switch (f->tag().proto())
303     {
304     case 0:
305     case L4_msg_tag::Label_task:
306       run(nonull_static_cast<Syscall_frame*>(f), u);
307       return;
308     default:
309       break;
310     }
311
312   f->tag(L4_msg_tag(0,0,0,-L4_err::EInval));
313 }
314
315 // --------------------------------------------------------------------------
316 IMPLEMENTATION [debug]:
317
318 #include "jdb.h"
319
320 PRIVATE
321 Mword
322 Vm::jdb_get(Mword *state_ptr)
323 {
324   Mword v = ~0UL;
325   Jdb::peek(state_ptr, _space, v);
326   return v;
327 }
328
329 PUBLIC
330 void
331 Vm::dump_machine_state()
332 {
333   machine_state *s = reinterpret_cast<machine_state*>(_state);
334   printf("pc: %08lx  cpsr: %08lx exit_reason:%ld \n",
335       jdb_get(&s->pc), jdb_get(&s->cpsr), jdb_get(&s->exit_reason));
336   printf("r0: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
337       jdb_get(&s->r[0]), jdb_get(&s->r[1]), jdb_get(&s->r[2]), jdb_get(&s->r[3]),
338       jdb_get(&s->r[4]), jdb_get(&s->r[5]), jdb_get(&s->r[6]), jdb_get(&s->r[7]));
339   printf("r8: %08lx %08lx %08lx %08lx %08lx\n",
340       jdb_get(&s->r[8]), jdb_get(&s->r[9]), jdb_get(&s->r[10]), jdb_get(&s->r[11]),
341       jdb_get(&s->r[12]));
342
343   printf("usr: sp %08lx lr %08lx\n",
344       jdb_get(&s->sp_usr), jdb_get(&s->lr_usr));
345   printf("irq: sp %08lx lr %08lx psr %08lx\n",
346       jdb_get(&s->sp_irq), jdb_get(&s->lr_irq), jdb_get(&s->spsr_irq));
347   printf("fiq: sp %08lx lr %08lx psr %08lx\n",
348       jdb_get(&s->sp_fiq), jdb_get(&s->lr_fiq), jdb_get(&s->spsr_fiq));
349   printf("r8: %08lx %08lx %08lx %08lx %08lx\n",
350       jdb_get(&s->r_fiq[0]), jdb_get(&s->r_fiq[1]), jdb_get(&s->r_fiq[2]),
351       jdb_get(&s->r_fiq[3]), jdb_get(&s->r_fiq[4]));
352
353   printf("abt: sp %08lx lr %08lx psr %08lx\n",
354       jdb_get(&s->sp_abt), jdb_get(&s->lr_abt), jdb_get(&s->spsr_abt));
355   printf("und: sp %08lx lr %08lx psr %08lx\n",
356       jdb_get(&s->sp_und), jdb_get(&s->lr_und), jdb_get(&s->spsr_und));
357   printf("svc: sp %08lx lr %08lx psr %08lx\n",
358       jdb_get(&s->sp_svc), jdb_get(&s->lr_svc), jdb_get(&s->spsr_svc));
359   printf("cp15_sctlr:%08lx\n", jdb_get(&s->cp15_control));
360   printf("cp15_ttbr0:%08lx\n", jdb_get(&s->cp15_ttbr0));
361   printf("cp15_ttbr1:%08lx\n", jdb_get(&s->cp15_ttbr1));
362   printf("cp15_ttbcr:%08lx\n", jdb_get(&s->cp15_ttbcr));
363   printf("dfar: %08lx dfsr: %08lx ifar: %08lx ifsr: %08lx\n",
364       jdb_get(&s->cp15_dfar), jdb_get(&s->cp15_dfsr), jdb_get(&s->cp15_ifar),
365       jdb_get(&s->cp15_ifsr));
366 }
367
368 PUBLIC
369 int
370 Vm::show_short(char *buf, int max)
371 {
372   return snprintf(buf, max, " utcb:%lx pc:%lx ", (Mword)_state, (Mword)jdb_get(&state()->pc));
373 }
374
375 IMPLEMENT
376 unsigned
377 Vm::Vm_log::print(int maxlen, char *buf) const
378 {
379   if (is_entry)
380     return vm_entry_log_fmt(maxlen, buf);
381   else
382     return vm_exit_log_fmt(maxlen, buf);
383 }
384
385 IMPLEMENT
386 unsigned
387 Vm::Vm_log::vm_entry_log_fmt(int maxlen, char *buf) const
388 {
389   if (r0 == 0x1110)
390     return snprintf(buf, maxlen, "entry: pc:%08lx/%03lx intack irq: %lx", pc, pending_events, r1);
391
392   return snprintf(buf, maxlen, "entry: pc:%08lx/%03lx r0:%lx", pc, pending_events, r0);
393 }
394
395 IMPLEMENT
396 unsigned
397 Vm::Vm_log::vm_exit_log_fmt(int maxlen, char *buf) const
398 {
399   if ((r0 & 0xffff0000) == 0xffff0000)
400     return snprintf(buf, maxlen, "=====: pc:%08lx/%03lx [%04lx]", pc, pending_events, r0 & 0xffff);
401   if (r0 == 0x1105)
402     return snprintf(buf, maxlen, "exit:  pc:%08lx/%03lx enable irq: %lx", pc, pending_events, r1);
403   if (r0 == 0x1109)
404     return snprintf(buf, maxlen, "exit:  pc:%08lx/%03lx disable irq: %lx", pc, pending_events, r1);
405   if (r0 == 0x1110)
406     return snprintf(buf, maxlen, "exit:  pc:%08lx/%03lx intack", pc, pending_events);
407   if (r0 == 0x1115)
408     return snprintf(buf, maxlen, "exit:  pc:%08lx/%03lx send ipi:%lx", pc, pending_events, r1);
409
410   return snprintf(buf, maxlen, "exit:  pc:%08lx/%03lx r0:%lx", pc, pending_events, r0);
411 }
412
413 PUBLIC static inline
414 void
415 Vm::log_vm(Vm *vm, bool is_entry)
416 {
417   if (vm->state()->exit_reason != 1)
418       return;
419   if ((vm->state()->r[0] & 0xf000) == 0x7000)
420     return;
421   if ((is_entry && (vm->state()->r[0] & 0xffff0000) == 0xffff0000))
422     return;
423   LOG_TRACE("VM entry/entry", "VM", current(), Vm_log,
424       l->is_entry = is_entry;
425       l->pc = vm->state()->pc;
426       l->cpsr = vm->state()->cpsr;
427       l->exit_reason = vm->state()->exit_reason;
428       l->pending_events = vm->state()->pending_events;
429       l->r0 = vm->state()->r[0];
430       l->r1 = vm->state()->r[1];
431   );
432 }
433
434 // --------------------------------------------------------------------------
435 IMPLEMENTATION [!debug]:
436
437 PUBLIC static inline
438 void
439 Vm::log_vm(Vm *, bool)
440 {}