]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/svm.cpp
update
[l4.git] / kernel / fiasco / src / kern / ia32 / svm.cpp
1 INTERFACE:
2
3 class Svm
4 {
5 };
6
7 //-----------------------------------------------------------------------------
8 INTERFACE[svm]:
9
10 #include "per_cpu_data.h"
11 #include "virt.h"
12 #include "cpu_lock.h"
13
14 EXTENSION class Svm
15 {
16 public:
17   static Per_cpu<Svm> cpus;
18
19   enum Msr_perms
20   {
21     Msr_intercept = 3,
22     Msr_ro        = 2,
23     Msr_wo        = 1,
24     Msr_rw        = 0,
25   };
26
27 private:
28   void *_vm_hsave_area;
29   void *_iopm;
30   void *_msrpm;
31   Unsigned32 _next_asid;
32   Unsigned32 _global_asid_generation;
33   Unsigned32 _max_asid;
34   bool _flush_all_asids;
35   bool _svm_enabled;
36   bool _has_npt;
37   Unsigned64 _iopm_base_pa;
38   Unsigned64 _msrpm_base_pa;
39   Vmcb *_kernel_vmcb;
40   Address _kernel_vmcb_pa;
41 };
42
43 //-----------------------------------------------------------------------------
44 INTERFACE [svm && ia32]:
45
46 EXTENSION class Svm
47 {
48 public:
49   enum { Gpregs_words = 10 };
50 };
51
52 //-----------------------------------------------------------------------------
53 INTERFACE [svm && amd64]:
54
55 EXTENSION class Svm
56 {
57 public:
58   enum { Gpregs_words = 18 };
59 };
60
61 // -----------------------------------------------------------------------
62 IMPLEMENTATION[svm]:
63
64 #include "cpu.h"
65 #include "kmem.h"
66 #include "l4_types.h"
67 #include "warn.h"
68 #include <cstring>
69
70 DEFINE_PER_CPU Per_cpu<Svm> Svm::cpus(true);
71
72 PUBLIC
73 Svm::Svm(unsigned cpu)
74 {
75   Cpu &c = Cpu::cpus.cpu(cpu);
76   _svm_enabled = false;
77   _next_asid = 1;
78   _global_asid_generation = 0;
79   _max_asid = 0;
80   _flush_all_asids = true;
81   _has_npt = false;
82
83   if (!c.svm())
84     return;
85
86   Unsigned64 efer, vmcr;
87
88   vmcr = c.rdmsr(MSR_VM_CR);
89   if (vmcr & (1 << 4)) // VM_CR.SVMDIS
90     {
91       printf("SVM supported but locked.\n");
92       return;
93     }
94
95   printf("Enabling SVM support\n");
96
97   efer = c.rdmsr(MSR_EFER);
98   efer |= 1 << 12;
99   c.wrmsr(efer, MSR_EFER);
100
101   Unsigned32 eax, ebx, ecx, edx;
102   c.cpuid (0x8000000a, &eax, &ebx, &ecx, &edx);
103   if (edx & 1)
104     {
105       printf("Nested Paging supported\n");
106       _has_npt = true;
107     }
108   printf("NASID: 0x%x\n", ebx);
109   _max_asid = ebx - 1;
110
111   // FIXME: MUST NOT PANIC ON CPU HOTPLUG
112   assert(_max_asid > 0);
113
114   enum
115   {
116     Vmcb_size   = 0x1000,
117     Io_pm_size  = 0x3000,
118     Msr_pm_size = 0x2000,
119     State_save_area_size = 0x1000,
120   };
121
122   /* 16kB IO permission map and Vmcb (16kB are good for the buddy allocator)*/
123   // FIXME: MUST NOT PANIC ON CPU HOTPLUG
124   check(_iopm = Kmem_alloc::allocator()->unaligned_alloc(Io_pm_size + Vmcb_size));
125   _iopm_base_pa = Kmem::virt_to_phys(_iopm);
126   _kernel_vmcb = (Vmcb*)((char*)_iopm + Io_pm_size);
127   _kernel_vmcb_pa = Kmem::virt_to_phys(_kernel_vmcb);
128   _svm_enabled = true;
129
130   /* disbale all ports */
131   memset(_iopm, ~0, Io_pm_size);
132
133   /* clean out vmcb */
134   memset(_kernel_vmcb, 0, Vmcb_size);
135
136   /* 8kB MSR permission map */
137   // FIXME: MUST NOT PANIC ON CPU HOTPLUG
138   check(_msrpm = Kmem_alloc::allocator()->unaligned_alloc(Msr_pm_size));
139   _msrpm_base_pa = Kmem::virt_to_phys(_msrpm);
140   memset(_msrpm, ~0, Msr_pm_size);
141
142   // allow the sysenter MSRs for the guests
143   set_msr_perm(MSR_SYSENTER_CS, Msr_rw);
144   set_msr_perm(MSR_SYSENTER_EIP, Msr_rw);
145   set_msr_perm(MSR_SYSENTER_ESP, Msr_rw);
146
147   /* 4kB Host state-safe area */
148   // FIXME: MUST NOT PANIC ON CPU HOTPLUG
149   check(_vm_hsave_area = Kmem_alloc::allocator()->unaligned_alloc(State_save_area_size));
150   Unsigned64 vm_hsave_pa = Kmem::virt_to_phys(_vm_hsave_area);
151
152   c.wrmsr(vm_hsave_pa, MSR_VM_HSAVE_PA);
153 }
154
155 PUBLIC
156 void
157 Svm::set_msr_perm(Unsigned32 msr, Msr_perms perms)
158 {
159   unsigned offs;
160   if (msr <= 0x1fff)
161     offs = 0;
162   else if (0xc0000000 <= msr && msr <= 0xc0001fff)
163     offs = 0x800;
164   else if (0xc0010000 <= msr && msr <= 0xc0011fff)
165     offs = 0x1000;
166   else
167     {
168       WARN("Illegal MSR %x\n", msr);
169       return;
170     }
171
172   msr &= 0x1fff;
173   offs += msr / 4;
174
175   unsigned char *pm = (unsigned char *)_msrpm;
176
177   unsigned shift = (msr & 3) * 2;
178   pm[offs] = (pm[offs] & ~(3 << shift)) | ((unsigned char)perms << shift);
179 }
180
181 PUBLIC
182 Unsigned64
183 Svm::iopm_base_pa()
184 { return _iopm_base_pa; }
185
186 PUBLIC
187 Unsigned64
188 Svm::msrpm_base_pa()
189 { return _msrpm_base_pa; }
190
191 PUBLIC
192 Vmcb *
193 Svm::kernel_vmcb()
194 { return _kernel_vmcb; }
195
196 PUBLIC
197 Address
198 Svm::kernel_vmcb_pa()
199 { return _kernel_vmcb_pa; }
200
201 PUBLIC
202 bool
203 Svm::svm_enabled()
204 { return _svm_enabled; }
205
206 PUBLIC
207 bool
208 Svm::has_npt()
209 { return _has_npt; }
210
211 PUBLIC
212 bool
213 Svm::asid_valid (Unsigned32 asid, Unsigned32 generation)
214 {
215   return ((asid > 0) &&
216           (asid <= _max_asid) &&
217           (generation <= _global_asid_generation));
218 }
219
220 PUBLIC
221 bool
222 Svm::flush_all_asids()
223 { return _flush_all_asids; }
224
225 PUBLIC
226 void
227 Svm::flush_all_asids(bool val)
228 { _flush_all_asids = val; }
229
230 PUBLIC
231 Unsigned32
232 Svm::global_asid_generation()
233 { return _global_asid_generation; }
234
235 PUBLIC
236 Unsigned32
237 Svm::next_asid ()
238 {
239   assert(cpu_lock.test());
240   _flush_all_asids = false;
241   if (_next_asid > _max_asid)
242     {
243       _global_asid_generation++;
244       _next_asid = 1;
245       // FIXME: must not crash on an overrun
246       assert (_global_asid_generation < ~0U);
247       _flush_all_asids = true;
248     }
249   return _next_asid++;
250 }