]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/vm_vmx.cpp
update
[l4.git] / kernel / fiasco / src / kern / ia32 / vm_vmx.cpp
1 INTERFACE [vmx]:
2
3 #include "config.h"
4 #include "per_cpu_data.h"
5 #include "vm.h"
6 #include "vmx.h"
7
8 class Vmcs;
9
10 class Vm_vmx : public Vm
11 {
12 private:
13   static unsigned long resume_vm_vmx(Mword *regs)
14     asm("resume_vm_vmx") __attribute__((__regparm__(3)));
15
16   enum
17   {
18     EFER_LME = 1 << 8,
19     EFER_LMA = 1 << 10,
20   };
21
22 };
23
24 //----------------------------------------------------------------------------
25 IMPLEMENTATION [vmx]:
26
27 #include "context.h"
28 #include "mem_space.h"
29 #include "fpu.h"
30 #include "ref_ptr.h"
31 #include "thread.h" // XXX: circular dep, move this out here!
32 #include "thread_state.h" // XXX: circular dep, move this out here!
33 #include "virt.h"
34 #include "idt.h"
35
36
37 PUBLIC
38 Vm_vmx::Vm_vmx(Ram_quota *q)
39   : Vm(q)
40 {}
41
42 PUBLIC inline
43 void *
44 Vm_vmx::operator new (size_t size, void *p)
45 {
46   (void)size;
47   assert (size == sizeof (Vm_vmx));
48   return p;
49 }
50
51 PUBLIC
52 void
53 Vm_vmx::operator delete (void *ptr)
54 {
55   Vm_vmx *t = reinterpret_cast<Vm_vmx*>(ptr);
56   allocator<Vm_vmx>()->q_free(t->ram_quota(), ptr);
57 }
58
59
60
61
62 PRIVATE static inline
63 void *
64 Vm_vmx::field_offset(void *vmcs, unsigned field)
65 {
66   return (void *)((char *)vmcs
67                           + ((field >> 13) * 4 + ((field >> 10) & 3) + 1) * 0x80);
68 }
69
70 PRIVATE static inline
71 unsigned
72 Vm_vmx::field_width(unsigned field)
73 {
74   static const char widths[4] = { 2, 8, 4, sizeof(Mword) };
75   return widths[field >> 13];
76 }
77
78
79 PRIVATE inline
80 template<typename T>
81 Vmx_info::Flags<T>
82 Vm_vmx::load(unsigned field, void *vmcs, Vmx_info::Bit_defs<T> const &m)
83 {
84   T res = m.apply(read<T>(vmcs, field));
85   Vmx::vmwrite(field, res);
86   return Vmx_info::Flags<T>(res);
87 }
88
89 PRIVATE inline
90 void
91 Vm_vmx::load(unsigned field_first, unsigned field_last, void *vmcs)
92 {
93   for (; field_first <= field_last; field_first += 2)
94     load(field_first, vmcs);
95 }
96
97 PRIVATE inline static
98 template< typename T >
99 T
100 Vm_vmx::_internal_read(void *vmcs, unsigned field)
101 {
102   vmcs = field_offset(vmcs, field);
103   return *((T *)vmcs + ((field >> 1) & 0xff));
104 }
105
106 PRIVATE inline static
107 template< typename T >
108 void
109 Vm_vmx::_internal_write(void *vmcs, unsigned field, T value)
110 {
111   vmcs = field_offset(vmcs, field);
112   *((T*)vmcs + ((field >> 1) & 0xff)) = value;
113 }
114
115 PRIVATE inline
116 void
117 Vm_vmx::load(unsigned field, void *vmcs)
118 {
119   switch (field >> 13)
120     {
121     case 0: Vmx::vmwrite(field, _internal_read<Unsigned16>(vmcs, field)); break;
122     case 1: Vmx::vmwrite(field, _internal_read<Unsigned64>(vmcs, field)); break;
123     case 2: Vmx::vmwrite(field, _internal_read<Unsigned32>(vmcs, field)); break;
124     case 3: Vmx::vmwrite(field, _internal_read<Mword>(vmcs, field)); break;
125     }
126 }
127
128 PRIVATE inline
129 void
130 Vm_vmx::store(unsigned field, void *vmcs)
131 {
132   switch (field >> 13)
133     {
134     case 0: _internal_write(vmcs, field, Vmx::vmread<Unsigned16>(field)); break;
135     case 1: _internal_write(vmcs, field, Vmx::vmread<Unsigned64>(field)); break;
136     case 2: _internal_write(vmcs, field, Vmx::vmread<Unsigned32>(field)); break;
137     case 3: _internal_write(vmcs, field, Vmx::vmread<Mword>(field)); break;
138     }
139 }
140
141 PRIVATE inline
142 void
143 Vm_vmx::store(unsigned field_first, unsigned field_last, void *vmcs)
144 {
145   for (; field_first <= field_last; field_first += 2)
146     store(field_first, vmcs);
147 }
148
149 PRIVATE inline static
150 template< typename T >
151 void
152 Vm_vmx::write(void *vmcs, unsigned field, T value)
153 {
154   switch (field >> 13)
155     {
156     case 0: _internal_write(vmcs, field, (Unsigned16)value); break;
157     case 1: _internal_write(vmcs, field, (Unsigned64)value); break;
158     case 2: _internal_write(vmcs, field, (Unsigned32)value); break;
159     case 3: _internal_write(vmcs, field, (Mword)value); break;
160     }
161 }
162
163 PRIVATE inline static
164 template< typename T >
165 T
166 Vm_vmx::read(void *vmcs, unsigned field)
167 {
168   switch (field >> 13)
169     {
170     case 0: return _internal_read<Unsigned16>(vmcs, field);
171     case 1: return _internal_read<Unsigned64>(vmcs, field);
172     case 2: return _internal_read<Unsigned32>(vmcs, field);
173     case 3: return _internal_read<Mword>(vmcs, field);
174     }
175   return 0;
176 }
177
178
179 PRIVATE
180 void
181 Vm_vmx::load_guest_state(unsigned cpu, void *src)
182 {
183   Vmx &vmx = Vmx::cpus.cpu(cpu);
184
185   // read VM-entry controls, apply filter and keep for later
186   Vmx_info::Flags<Unsigned32> entry_ctls
187     = load<Unsigned32>(Vmx::F_entry_ctls, src, vmx.info.entry_ctls);
188
189   Vmx_info::Flags<Unsigned32> pinbased_ctls
190     = load<Unsigned32>(Vmx::F_pin_based_ctls, src, vmx.info.pinbased_ctls);
191
192   Vmx_info::Flags<Unsigned32> procbased_ctls
193     = load<Unsigned32>(Vmx::F_proc_based_ctls, src, vmx.info.procbased_ctls);
194
195   Vmx_info::Flags<Unsigned32> procbased_ctls_2;
196   if (procbased_ctls.test(Vmx::PRB1_enable_proc_based_ctls_2))
197     procbased_ctls_2 = load<Unsigned32>(Vmx::F_proc_based_ctls_2, src, vmx.info.procbased_ctls2);
198   else
199     procbased_ctls_2 = Vmx_info::Flags<Unsigned32>(0);
200
201   load<Unsigned32>(Vmx::F_exit_ctls, src, vmx.info.exit_ctls);
202
203   // write 16-bit fields
204   load(0x800, 0x80e, src);
205
206   // write 64-bit fields
207   load(0x2802, src);
208
209   // check if the following bits are allowed to be set in entry_ctls
210   if (entry_ctls.test(14)) // PAT load requested
211     load(0x2804, src);
212
213   if (entry_ctls.test(15)) // EFER load requested
214     load(0x2806, src);
215
216   if (entry_ctls.test(13)) // IA32_PERF_GLOBAL_CTRL load requested
217     load(0x2808, src);
218
219   // complete *beep*, this is Fiasco.OC internal state
220 #if 0
221   if (vmx.has_ept())
222     load(0x280a, 0x2810, src);
223 #endif
224
225   // write 32-bit fields
226   load(0x4800, 0x482a, src);
227
228   if (pinbased_ctls.test(6)) // activate vmx-preemption timer
229     load(0x482e, src);
230
231   // write natural-width fields
232   load<Mword>(0x6800, src, vmx.info.cr0_defs);
233
234   if (sizeof(long) > sizeof(int))
235     {
236       if (read<Mword>(src, 0x2806) & EFER_LME)
237         Vmx::vmwrite(0x6802, (Mword)mem_space()->phys_dir());
238       else
239         WARN("VMX: No, not possible\n");
240     }
241   else
242     {
243       // for 32bit we can just load the Vm pdbr
244       Vmx::vmwrite(0x6802, (Mword)mem_space()->phys_dir());
245     }
246
247   load<Mword>(0x6804, src, vmx.info.cr4_defs);
248   load(0x6806, 0x6826, src);
249
250   // VPID must be virtualized in Fiasco
251 #if 0
252   if (procbased_ctls_2 & Vmx::PB2_enable_vpid)
253     load(Vmx::F_vpid, src);
254 #endif
255
256   // currently io-bitmaps are unsupported
257   // currently msr-bitmaps are unsupported
258
259   // load(0x200C, src); for SMM virtualization
260   load(Vmx::F_tsc_offset, src);
261
262   // no virtual APIC yet, and has to be managed in kernel somehow
263 #if 0
264   if (procbased_ctls.test(Vmx::PRB1_tpr_shadow))
265     load(0x2012, src);
266 #endif
267
268   if (procbased_ctls_2.test(Vmx::PRB2_virtualize_apic))
269     load(Vmx::F_apic_access_addr, src);
270
271   // exception bit map and pf error-code stuff
272   load(0x4004, 0x4008, src);
273
274   // vm entry control stuff
275   Unsigned32 irq_info = read<Unsigned32>(src, Vmx::F_entry_int_info);
276   if (irq_info & (1UL << 31))
277     {
278       // do event injection
279
280       // load error code, if required
281       if (irq_info & (1UL << 11))
282         load(Vmx::F_entry_exc_error_code, src);
283
284       // types, that require an insn length have bit 10 set (type 4, 5, and 6)
285       if (irq_info & (1UL << 10))
286         load(Vmx::F_entry_insn_len, src);
287
288       Vmx::vmwrite(Vmx::F_entry_int_info, irq_info);
289     }
290
291   // hm, we have to check for sanitizing the cr0 and cr4 shadow stuff
292   load(0x6000, 0x6006, src);
293
294   // no cr3 target values supported
295 }
296
297
298 PRIVATE
299 void
300 Vm_vmx::store_guest_state(unsigned cpu, void *dest)
301 {
302   // read 16-bit fields
303   store(0x800, 0x80e, dest);
304
305   // read 64-bit fields
306   store(0x2802, dest);
307
308   Vmx_info &vmx_info = Vmx::cpus.cpu(cpu).info;
309   Vmx_info::Flags<Unsigned32> exit_ctls
310     = Vmx_info::Flags<Unsigned32>(vmx_info.exit_ctls.apply(read<Unsigned32>(dest, Vmx::F_exit_ctls)));
311
312   if (exit_ctls.test(18)) store(Vmx::F_guest_pat, dest);
313   if (exit_ctls.test(20)) store(Vmx::F_guest_efer, dest);
314   if (exit_ctls.test(22)) store(Vmx::F_preempt_timer, dest);
315
316   // EPT and PAE handling missing
317 #if 0
318   if (Vmx::cpus.cpu(cpu).has_ept())
319     store(0x280a, 0x2810, dest);
320 #endif
321
322   // read 32-bit fields
323   store(0x4800, 0x4826, dest);
324
325   // sysenter msr is not saved here, because we trap all msr accesses right now
326 #if 0
327   store(0x482a, dest);
328   store(0x6824, 0x6826, dest);
329 #endif
330
331   // read natural-width fields
332   store(0x6800, dest);
333   // skip cr3
334   store(0x6804, 0x6822, dest);
335 }
336
337 #if 0
338 PRIVATE
339 void
340 Vm_vmx::copy_execution_control_back(unsigned cpu, void *dest)
341 {
342   Vmx &v = Vmx::cpus.cpu(cpu);
343   // read 16-bit fields
344   if (v.has_vpid())
345     store(0, dest);
346
347   // read 64-bit fields
348   store(0x2000, 0x2002, dest);
349   store(0x200c, dest);
350   store(0x2010, dest);
351
352   Unsigned64 msr = Vmx::cpus.cpu(cpu).info._procbased_ctls; // IA32_VMX_PROCBASED_CTLS
353   if (msr & (1ULL<<53))
354     store(0x2012, dest);
355
356   if (vmread<Unsigned32>(0x4002) & (1 << 31))
357     {
358       msr = Vmx::cpus.cpu(cpu).info._procbased_ctls2; // IA32_VMX_PROCBASED_CTLS2
359       if (msr & (1ULL << 32))
360         store(0x2014, dest);
361     }
362
363   if (v.has_ept())
364     store(0x201a, dest);
365
366   // read 32-bit fields
367   store(0x4000, 0x4004, dest);
368   store(0x401e, dest);
369
370   // read natural-width fields
371   store(0x6000, 0x600e, dest);
372 }
373
374 PRIVATE
375 void
376 Vm_vmx::copy_exit_control_back(unsigned ,void *dest)
377 {
378   // read 64-bit fields
379   store(0x2006, 0x2008, dest);
380
381   // read 32-bit fields
382   store(0x400c, 0x4010, dest);
383 }
384
385 PRIVATE
386 void
387 Vm_vmx::copy_entry_control_back(unsigned, void *dest)
388 {
389   // read 64-bit fields
390   store(0x200a, dest);
391
392   // read 32-bit fields
393   store(0x4012, 0x401a, dest);
394 }
395 #endif
396
397 PRIVATE
398 void
399 Vm_vmx::store_exit_info(unsigned cpu, void *dest)
400 {
401   (void)cpu;
402   // read 64-bit fields, HM EPT pf stuff
403 #if 0
404   if (Vmx::cpus.cpu(cpu).has_ept())
405     store(0x2400, dest);
406 #endif
407
408   // clear the valid bit in Vm-entry interruption information
409     {
410       Unsigned32 tmp = read<Unsigned32>(dest, Vmx::F_entry_int_info);
411       if (tmp & (1UL << 31))
412         write(dest, Vmx::F_entry_int_info, tmp & ~((Unsigned32)1 << 31));
413     }
414
415   // read 32-bit fields
416   store(0x4400, 0x440e, dest);
417
418   // read natural-width fields
419   store(0x6400, 0x640a, dest);
420 }
421
422 PRIVATE
423 void
424 Vm_vmx::dump(void *v, unsigned f, unsigned t)
425 {
426   for (; f <= t; f += 2)
427     printf("%04x: VMCS: %16lx   V: %16lx\n",
428            f, Vmx::vmread<Mword>(f), read<Mword>(v, f));
429 }
430
431 PRIVATE
432 void
433 Vm_vmx::dump_state(void *v)
434 {
435   dump(v, 0x0800, 0x080e);
436   dump(v, 0x0c00, 0x0c0c);
437   dump(v, 0x2000, 0x201a);
438   dump(v, 0x2800, 0x2810);
439   dump(v, 0x2c00, 0x2804);
440   dump(v, 0x4000, 0x4022);
441   dump(v, 0x4400, 0x4420);
442   dump(v, 0x4800, 0x482a);
443   dump(v, 0x6800, 0x6826);
444   dump(v, 0x6c00, 0x6c16);
445 }
446
447 PUBLIC
448 L4_msg_tag
449 Vm_vmx::sys_vm_run(Syscall_frame *f, Utcb *utcb)
450 {
451   assert (cpu_lock.test());
452
453   /* these 4 must not use ldt entries */
454   assert (!(Cpu::get_cs() & (1 << 2)));
455   assert (!(Cpu::get_ss() & (1 << 2)));
456   assert (!(Cpu::get_ds() & (1 << 2)));
457   assert (!(Cpu::get_es() & (1 << 2)));
458
459   unsigned cpu = current_cpu();
460   Vmx &v = Vmx::cpus.cpu(cpu);
461
462   L4_msg_tag const &tag = f->tag();
463
464   if(!v.vmx_enabled())
465     {
466       WARN("VMX: not supported/enabled\n");
467       return commit_result(-L4_err::EInval);
468     }
469
470   if (EXPECT_FALSE(tag.words() < 1 + Vmx::Gpregs_words))
471     {
472       WARN("VMX: Invalid message length\n");
473       return commit_result(-L4_err::EInval);
474     }
475
476   L4_snd_item_iter vmcs_item(utcb, tag.words());
477
478   if (EXPECT_FALSE(!tag.items() || !vmcs_item.next()))
479     return commit_result(-L4_err::EInval);
480
481   L4_fpage vmcs_fpage(vmcs_item.get()->d);
482
483   if (EXPECT_FALSE(!vmcs_fpage.is_mempage()))
484     {
485       WARN("VMX: Fpage invalid\n");
486       return commit_error(utcb, L4_error::Overflow);
487     }
488
489   if (EXPECT_FALSE(vmcs_fpage.order() < 12))
490     return commit_result(-L4_err::EInval);
491
492
493   void *vmcs_s = (void *)(Virt_addr(vmcs_fpage.mem_address()).value());
494
495   Mem_space::Phys_addr phys_vmcs;
496   Mem_space::Size size;
497   bool resident;
498   unsigned int page_attribs;
499
500   Mem_space *const curr_mem_space = current()->space()->mem_space();
501   resident = curr_mem_space->v_lookup(Virt_addr(vmcs_s), &phys_vmcs, &size, &page_attribs);
502
503   if (EXPECT_FALSE(!resident))
504     {
505       WARN("VMX: VMCS invalid\n");
506       return commit_result(-L4_err::EInval);
507     }
508
509   // XXX:
510   // This generates a circular dep between thread<->task, this cries for a
511   // new abstraction...
512   if (!(current()->state() & Thread_fpu_owner))
513     {
514       if (EXPECT_FALSE(!current_thread()->switchin_fpu()))
515         {
516           WARN("VMX: switchin_fpu failed\n");
517           return commit_result(-L4_err::EInval);
518         }
519     }
520
521 #if 0
522   if (EXPECT_FALSE(read<Unsigned32>(vmcs_s, 0x201a) != 0)) // EPT POINTER
523     {
524       WARN("VMX: no nested paging available\n");
525       return commit_result(-L4_err::EInval);
526     }
527 #endif
528
529   // increment our refcount, and drop it at the end automatically
530   Ref_ptr<Vm_vmx> pin_myself(this);
531
532   // set volatile host state
533   Vmx::vmwrite<Mword>(Vmx::F_host_cr3, Cpu::get_pdbr()); // host_area.cr3
534
535   load_guest_state(cpu, vmcs_s);
536
537   Unsigned16 ldt = Cpu::get_ldt();
538
539   // set guest CR2
540   asm volatile("mov %0, %%cr2" : : "r" (read<Mword>(vmcs_s, Vmx::F_guest_cr2)));
541
542   unsigned long ret = resume_vm_vmx(&utcb->values[1]);
543   if (EXPECT_FALSE(ret & 0x40))
544     return commit_result(-L4_err::EInval);
545
546   // save guest cr2
547     {
548       Mword cpu_cr2;
549       asm volatile("mov %%cr2, %0" : "=r" (cpu_cr2));
550       write(vmcs_s, Vmx::F_guest_cr2, cpu_cr2);
551     }
552
553   Cpu::set_ldt(ldt);
554
555   // reload TSS, we use I/O bitmaps
556   // ... do this lazy ...
557   {
558     // clear busy flag
559     Gdt_entry *e = &(*Cpu::cpus.cpu(cpu).get_gdt())[Gdt::gdt_tss / 8];
560     e->access &= ~(1 << 1);
561     asm volatile("" : : "m" (*e));
562     Cpu::set_tr(Gdt::gdt_tss);
563   }
564
565   store_guest_state(cpu, vmcs_s);
566   store_exit_info(cpu, vmcs_s);
567
568   return commit_result(L4_error::None);
569 }
570
571 PUBLIC
572 void
573 Vm_vmx::invoke(L4_obj_ref obj, Mword rights, Syscall_frame *f, Utcb *utcb)
574 {
575   vm_invoke<Vm_vmx>(obj, rights, f, utcb);
576 }