rev |
line source |
iap10@3290
|
1 /*
|
iap10@3290
|
2 * vmx_vmcs.c: VMCS management
|
iap10@3290
|
3 * Copyright (c) 2004, Intel Corporation.
|
iap10@3290
|
4 *
|
iap10@3290
|
5 * This program is free software; you can redistribute it and/or modify it
|
iap10@3290
|
6 * under the terms and conditions of the GNU General Public License,
|
iap10@3290
|
7 * version 2, as published by the Free Software Foundation.
|
iap10@3290
|
8 *
|
iap10@3290
|
9 * This program is distributed in the hope it will be useful, but WITHOUT
|
iap10@3290
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
iap10@3290
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
iap10@3290
|
12 * more details.
|
iap10@3290
|
13 *
|
iap10@3290
|
14 * You should have received a copy of the GNU General Public License along with
|
iap10@3290
|
15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
iap10@3290
|
16 * Place - Suite 330, Boston, MA 02111-1307 USA.
|
iap10@3290
|
17 *
|
iap10@3290
|
18 */
|
iap10@3290
|
19
|
iap10@3290
|
20 #include <xen/config.h>
|
iap10@3290
|
21 #include <xen/init.h>
|
iap10@3290
|
22 #include <xen/mm.h>
|
iap10@3290
|
23 #include <xen/lib.h>
|
iap10@3290
|
24 #include <xen/errno.h>
|
kaf24@5356
|
25 #include <xen/domain_page.h>
|
cl349@5291
|
26 #include <asm/current.h>
|
iap10@3290
|
27 #include <asm/cpufeature.h>
|
iap10@3290
|
28 #include <asm/processor.h>
|
iap10@3290
|
29 #include <asm/msr.h>
|
iap10@3290
|
30 #include <asm/vmx.h>
|
kaf24@5722
|
31 #include <asm/flushtlb.h>
|
iap10@3290
|
32 #include <xen/event.h>
|
iap10@3290
|
33 #include <xen/kernel.h>
|
iap10@3290
|
34 #include <public/io/ioreq.h>
|
kaf24@5722
|
35 #if CONFIG_PAGING_LEVELS >= 4
|
kaf24@5722
|
36 #include <asm/shadow_64.h>
|
kaf24@5722
|
37 #endif
|
mafetter@3717
|
38 #ifdef CONFIG_VMX
|
mafetter@3717
|
39
|
iap10@3290
|
40 struct vmcs_struct *alloc_vmcs(void)
|
iap10@3290
|
41 {
|
iap10@3290
|
42 struct vmcs_struct *vmcs;
|
kaf24@5059
|
43 u32 vmx_msr_low, vmx_msr_high;
|
iap10@3290
|
44
|
kaf24@5059
|
45 rdmsr(MSR_IA32_VMX_BASIC_MSR, vmx_msr_low, vmx_msr_high);
|
kaf24@5059
|
46 vmcs_size = vmx_msr_high & 0x1fff;
|
kaf24@6684
|
47 vmcs = alloc_xenheap_pages(get_order_from_bytes(vmcs_size));
|
kaf24@5398
|
48 memset((char *)vmcs, 0, vmcs_size); /* don't remove this */
|
iap10@3290
|
49
|
kaf24@5059
|
50 vmcs->vmcs_revision_id = vmx_msr_low;
|
iap10@3290
|
51 return vmcs;
|
iap10@3290
|
52 }
|
iap10@3290
|
53
|
iap10@3290
|
54 void free_vmcs(struct vmcs_struct *vmcs)
|
iap10@3290
|
55 {
|
iap10@3290
|
56 int order;
|
iap10@3290
|
57
|
kaf24@6684
|
58 order = get_order_from_bytes(vmcs_size);
|
kaf24@5398
|
59 free_xenheap_pages(vmcs, order);
|
iap10@3290
|
60 }
|
iap10@3290
|
61
|
kaf24@5836
|
62 static inline int construct_vmcs_controls(struct arch_vmx_struct *arch_vmx)
|
iap10@3290
|
63 {
|
iap10@3290
|
64 int error = 0;
|
kaf24@5836
|
65 void *io_bitmap_a;
|
kaf24@5836
|
66 void *io_bitmap_b;
|
kaf24@5775
|
67
|
iap10@3290
|
68 error |= __vmwrite(PIN_BASED_VM_EXEC_CONTROL,
|
iap10@3290
|
69 MONITOR_PIN_BASED_EXEC_CONTROLS);
|
iap10@3290
|
70
|
iap10@3290
|
71 error |= __vmwrite(CPU_BASED_VM_EXEC_CONTROL,
|
iap10@3290
|
72 MONITOR_CPU_BASED_EXEC_CONTROLS);
|
kaf24@5775
|
73
|
iap10@3290
|
74 error |= __vmwrite(VM_EXIT_CONTROLS, MONITOR_VM_EXIT_CONTROLS);
|
kaf24@5775
|
75
|
iap10@3290
|
76 error |= __vmwrite(VM_ENTRY_CONTROLS, MONITOR_VM_ENTRY_CONTROLS);
|
iap10@3290
|
77
|
kaf24@5836
|
78 /* need to use 0x1000 instead of PAGE_SIZE */
|
kaf24@6684
|
79 io_bitmap_a = (void*) alloc_xenheap_pages(get_order_from_bytes(0x1000));
|
kaf24@6684
|
80 io_bitmap_b = (void*) alloc_xenheap_pages(get_order_from_bytes(0x1000));
|
kaf24@5836
|
81 memset(io_bitmap_a, 0xff, 0x1000);
|
kaf24@5836
|
82 /* don't bother debug port access */
|
kaf24@5836
|
83 clear_bit(PC_DEBUG_PORT, io_bitmap_a);
|
kaf24@5836
|
84 memset(io_bitmap_b, 0xff, 0x1000);
|
kaf24@5836
|
85
|
kaf24@5836
|
86 error |= __vmwrite(IO_BITMAP_A, (u64) virt_to_phys(io_bitmap_a));
|
kaf24@5836
|
87 error |= __vmwrite(IO_BITMAP_B, (u64) virt_to_phys(io_bitmap_b));
|
kaf24@5836
|
88
|
kaf24@5836
|
89 arch_vmx->io_bitmap_a = io_bitmap_a;
|
kaf24@5836
|
90 arch_vmx->io_bitmap_b = io_bitmap_b;
|
kaf24@5836
|
91
|
iap10@3290
|
92 return error;
|
iap10@3290
|
93 }
|
iap10@3290
|
94
|
iap10@3290
|
95 #define GUEST_SEGMENT_LIMIT 0xffffffff
|
iap10@3290
|
96 #define HOST_SEGMENT_LIMIT 0xffffffff
|
iap10@3290
|
97
|
iap10@3290
|
98 struct host_execution_env {
|
iap10@3290
|
99 /* selectors */
|
iap10@3290
|
100 unsigned short ldtr_selector;
|
iap10@3290
|
101 unsigned short tr_selector;
|
iap10@3290
|
102 unsigned short ds_selector;
|
iap10@3290
|
103 unsigned short cs_selector;
|
iap10@3290
|
104 /* limits */
|
iap10@3290
|
105 unsigned short gdtr_limit;
|
iap10@3290
|
106 unsigned short ldtr_limit;
|
iap10@3290
|
107 unsigned short idtr_limit;
|
iap10@3290
|
108 unsigned short tr_limit;
|
iap10@3290
|
109 /* base */
|
iap10@3290
|
110 unsigned long gdtr_base;
|
iap10@3290
|
111 unsigned long ldtr_base;
|
iap10@3290
|
112 unsigned long idtr_base;
|
iap10@3290
|
113 unsigned long tr_base;
|
iap10@3290
|
114 unsigned long ds_base;
|
iap10@3290
|
115 unsigned long cs_base;
|
kaf24@5658
|
116 #ifdef __x86_64__
|
kaf24@5658
|
117 unsigned long fs_base;
|
kaf24@5658
|
118 unsigned long gs_base;
|
kaf24@5658
|
119 #endif
|
kaf24@5658
|
120
|
iap10@3290
|
121 /* control registers */
|
iap10@3290
|
122 unsigned long cr3;
|
iap10@3290
|
123 unsigned long cr0;
|
iap10@3290
|
124 unsigned long cr4;
|
iap10@3290
|
125 unsigned long dr7;
|
iap10@3290
|
126 };
|
iap10@3290
|
127
|
iap10@3290
|
128 #define round_pgdown(_p) ((_p)&PAGE_MASK) /* coped from domain.c */
|
iap10@3290
|
129
|
kaf24@5289
|
130 int vmx_setup_platform(struct vcpu *d, struct cpu_user_regs *regs)
|
iap10@3290
|
131 {
|
iap10@3290
|
132 int i;
|
iap10@3290
|
133 unsigned int n;
|
iap10@3290
|
134 unsigned long *p, mpfn, offset, addr;
|
iap10@3290
|
135 struct e820entry *e820p;
|
iap10@3290
|
136 unsigned long gpfn = 0;
|
iap10@3290
|
137
|
kaf24@5727
|
138 local_flush_tlb_pge();
|
kaf24@4683
|
139 regs->ebx = 0; /* Linux expects ebx to be 0 for boot proc */
|
iap10@3290
|
140
|
kaf24@4683
|
141 n = regs->ecx;
|
iap10@3290
|
142 if (n > 32) {
|
maf46@3855
|
143 VMX_DBG_LOG(DBG_LEVEL_1, "Too many e820 entries: %d", n);
|
iap10@3290
|
144 return -1;
|
iap10@3290
|
145 }
|
iap10@3290
|
146
|
kaf24@4683
|
147 addr = regs->edi;
|
iap10@3290
|
148 offset = (addr & ~PAGE_MASK);
|
iap10@3290
|
149 addr = round_pgdown(addr);
|
kaf24@5356
|
150
|
kaf24@6481
|
151 mpfn = get_mfn_from_pfn(addr >> PAGE_SHIFT);
|
kaf24@5356
|
152 p = map_domain_page(mpfn);
|
iap10@3290
|
153
|
iap10@3290
|
154 e820p = (struct e820entry *) ((unsigned long) p + offset);
|
iap10@3290
|
155
|
maf46@3880
|
156 #ifndef NDEBUG
|
maf46@3880
|
157 print_e820_memory_map(e820p, n);
|
maf46@3880
|
158 #endif
|
maf46@3880
|
159
|
kaf24@5356
|
160 for ( i = 0; i < n; i++ )
|
kaf24@5356
|
161 {
|
kaf24@5356
|
162 if ( e820p[i].type == E820_SHARED_PAGE )
|
kaf24@5356
|
163 {
|
iap10@3290
|
164 gpfn = (e820p[i].addr >> PAGE_SHIFT);
|
iap10@3290
|
165 break;
|
iap10@3290
|
166 }
|
iap10@3290
|
167 }
|
iap10@3290
|
168
|
kaf24@5356
|
169 if ( gpfn == 0 )
|
kaf24@5356
|
170 {
|
kaf24@5356
|
171 unmap_domain_page(p);
|
iap10@3290
|
172 return -1;
|
iap10@3290
|
173 }
|
iap10@3290
|
174
|
kaf24@5356
|
175 unmap_domain_page(p);
|
iap10@3748
|
176
|
iap10@3748
|
177 /* Initialise shared page */
|
kaf24@6481
|
178 mpfn = get_mfn_from_pfn(gpfn);
|
kaf24@5356
|
179 p = map_domain_page(mpfn);
|
arun@5608
|
180 d->domain->arch.vmx_platform.shared_page_va = (unsigned long)p;
|
arun@5608
|
181
|
kaf24@6730
|
182 VMX_DBG_LOG(DBG_LEVEL_1, "eport: %x\n", iopacket_port(d->domain));
|
arun@5615
|
183
|
kaf24@6730
|
184 clear_bit(iopacket_port(d->domain),
|
kaf24@6730
|
185 &d->domain->shared_info->evtchn_mask[0]);
|
iap10@3290
|
186
|
iap10@3290
|
187 return 0;
|
iap10@3290
|
188 }
|
iap10@3290
|
189
|
kaf24@6100
|
190 void vmx_set_host_env(struct vcpu *v)
|
iap10@3290
|
191 {
|
iap10@3290
|
192 unsigned int tr, cpu, error = 0;
|
iap10@3290
|
193 struct host_execution_env host_env;
|
iap10@3290
|
194 struct Xgt_desc_struct desc;
|
cl349@4856
|
195
|
kaf24@4633
|
196 cpu = smp_processor_id();
|
kaf24@5820
|
197 __asm__ __volatile__ ("sidt (%0) \n" :: "a"(&desc) : "memory");
|
kaf24@5820
|
198 host_env.idtr_limit = desc.size;
|
kaf24@5820
|
199 host_env.idtr_base = desc.address;
|
kaf24@5820
|
200 error |= __vmwrite(HOST_IDTR_BASE, host_env.idtr_base);
|
kaf24@6113
|
201
|
arun@4585
|
202 __asm__ __volatile__ ("sgdt (%0) \n" :: "a"(&desc) : "memory");
|
iap10@3290
|
203 host_env.gdtr_limit = desc.size;
|
iap10@3290
|
204 host_env.gdtr_base = desc.address;
|
iap10@3290
|
205 error |= __vmwrite(HOST_GDTR_BASE, host_env.gdtr_base);
|
iap10@3290
|
206
|
kaf24@6100
|
207 __asm__ __volatile__ ("str (%0) \n" :: "a"(&tr) : "memory");
|
kaf24@6100
|
208 host_env.tr_selector = tr;
|
kaf24@6100
|
209 host_env.tr_limit = sizeof(struct tss_struct);
|
kaf24@6100
|
210 host_env.tr_base = (unsigned long) &init_tss[cpu];
|
kaf24@6100
|
211 error |= __vmwrite(HOST_TR_SELECTOR, host_env.tr_selector);
|
kaf24@6100
|
212 error |= __vmwrite(HOST_TR_BASE, host_env.tr_base);
|
kaf24@6100
|
213 }
|
kaf24@6100
|
214
|
kaf24@6100
|
215 void vmx_do_launch(struct vcpu *v)
|
kaf24@6100
|
216 {
|
kaf24@6100
|
217 /* Update CR3, GDT, LDT, TR */
|
kaf24@6100
|
218 unsigned int error = 0;
|
kaf24@6100
|
219 unsigned long pfn = 0;
|
kaf24@6100
|
220 struct pfn_info *page;
|
kaf24@6100
|
221 struct cpu_user_regs *regs = guest_cpu_user_regs();
|
kaf24@6100
|
222
|
kaf24@6100
|
223 vmx_stts();
|
kaf24@6100
|
224
|
kaf24@6100
|
225 page = (struct pfn_info *) alloc_domheap_page(NULL);
|
kaf24@6100
|
226 pfn = (unsigned long) (page - frame_table);
|
kaf24@6100
|
227
|
kaf24@6100
|
228 vmx_setup_platform(v, regs);
|
kaf24@6100
|
229
|
kaf24@6100
|
230 vmx_set_host_env(v);
|
kaf24@6100
|
231
|
iap10@3290
|
232 error |= __vmwrite(GUEST_LDTR_SELECTOR, 0);
|
iap10@3290
|
233 error |= __vmwrite(GUEST_LDTR_BASE, 0);
|
iap10@3290
|
234 error |= __vmwrite(GUEST_LDTR_LIMIT, 0);
|
iap10@3290
|
235
|
iap10@3290
|
236 error |= __vmwrite(GUEST_TR_BASE, 0);
|
iap10@3290
|
237 error |= __vmwrite(GUEST_TR_LIMIT, 0xff);
|
iap10@3290
|
238
|
kaf24@5289
|
239 __vmwrite(GUEST_CR3, pagetable_get_paddr(v->arch.guest_table));
|
kaf24@5289
|
240 __vmwrite(HOST_CR3, pagetable_get_paddr(v->arch.monitor_table));
|
kaf24@5414
|
241 __vmwrite(HOST_RSP, (unsigned long)get_stack_bottom());
|
iap10@3290
|
242
|
kaf24@5289
|
243 v->arch.schedule_tail = arch_vmx_do_resume;
|
iap10@3290
|
244 }
|
iap10@3290
|
245
|
iap10@3290
|
246 /*
|
iap10@3290
|
247 * Initially set the same environement as host.
|
iap10@3290
|
248 */
|
iap10@3290
|
249 static inline int
|
kaf24@4683
|
250 construct_init_vmcs_guest(struct cpu_user_regs *regs,
|
kaf24@4683
|
251 struct vcpu_guest_context *ctxt,
|
iap10@3290
|
252 struct host_execution_env *host_env)
|
iap10@3290
|
253 {
|
iap10@3290
|
254 int error = 0;
|
iap10@3290
|
255 union vmcs_arbytes arbytes;
|
iap10@3290
|
256 unsigned long dr7;
|
iap10@3290
|
257 unsigned long eflags, shadow_cr;
|
iap10@3290
|
258
|
iap10@3290
|
259 /* MSR */
|
iap10@3290
|
260 error |= __vmwrite(VM_EXIT_MSR_LOAD_ADDR, 0);
|
iap10@3290
|
261 error |= __vmwrite(VM_EXIT_MSR_STORE_ADDR, 0);
|
iap10@3290
|
262
|
iap10@3290
|
263 error |= __vmwrite(VM_EXIT_MSR_STORE_COUNT, 0);
|
iap10@3290
|
264 error |= __vmwrite(VM_EXIT_MSR_LOAD_COUNT, 0);
|
iap10@3290
|
265 error |= __vmwrite(VM_ENTRY_MSR_LOAD_COUNT, 0);
|
iap10@3290
|
266 /* interrupt */
|
iap10@3290
|
267 error |= __vmwrite(VM_ENTRY_INTR_INFO_FIELD, 0);
|
iap10@3290
|
268 /* mask */
|
kaf24@5658
|
269 error |= __vmwrite(CR0_GUEST_HOST_MASK, -1UL);
|
kaf24@5658
|
270 error |= __vmwrite(CR4_GUEST_HOST_MASK, -1UL);
|
iap10@3290
|
271
|
iap10@3290
|
272 error |= __vmwrite(PAGE_FAULT_ERROR_CODE_MASK, 0);
|
iap10@3290
|
273 error |= __vmwrite(PAGE_FAULT_ERROR_CODE_MATCH, 0);
|
iap10@3290
|
274
|
iap10@3290
|
275 /* TSC */
|
iap10@3290
|
276 error |= __vmwrite(TSC_OFFSET, 0);
|
iap10@3290
|
277 error |= __vmwrite(CR3_TARGET_COUNT, 0);
|
iap10@3290
|
278
|
iap10@3290
|
279 /* Guest Selectors */
|
kaf24@4683
|
280 error |= __vmwrite(GUEST_CS_SELECTOR, regs->cs);
|
kaf24@4683
|
281 error |= __vmwrite(GUEST_ES_SELECTOR, regs->es);
|
kaf24@4683
|
282 error |= __vmwrite(GUEST_SS_SELECTOR, regs->ss);
|
kaf24@4683
|
283 error |= __vmwrite(GUEST_DS_SELECTOR, regs->ds);
|
kaf24@4683
|
284 error |= __vmwrite(GUEST_FS_SELECTOR, regs->fs);
|
kaf24@4683
|
285 error |= __vmwrite(GUEST_GS_SELECTOR, regs->gs);
|
iap10@3290
|
286
|
iap10@3290
|
287 /* Guest segment Limits */
|
iap10@3290
|
288 error |= __vmwrite(GUEST_CS_LIMIT, GUEST_SEGMENT_LIMIT);
|
iap10@3290
|
289 error |= __vmwrite(GUEST_ES_LIMIT, GUEST_SEGMENT_LIMIT);
|
iap10@3290
|
290 error |= __vmwrite(GUEST_SS_LIMIT, GUEST_SEGMENT_LIMIT);
|
iap10@3290
|
291 error |= __vmwrite(GUEST_DS_LIMIT, GUEST_SEGMENT_LIMIT);
|
iap10@3290
|
292 error |= __vmwrite(GUEST_FS_LIMIT, GUEST_SEGMENT_LIMIT);
|
iap10@3290
|
293 error |= __vmwrite(GUEST_GS_LIMIT, GUEST_SEGMENT_LIMIT);
|
iap10@3290
|
294
|
iap10@3290
|
295 error |= __vmwrite(GUEST_IDTR_LIMIT, host_env->idtr_limit);
|
iap10@3290
|
296
|
iap10@3290
|
297 /* AR bytes */
|
iap10@3290
|
298 arbytes.bytes = 0;
|
iap10@3290
|
299 arbytes.fields.seg_type = 0x3; /* type = 3 */
|
iap10@3290
|
300 arbytes.fields.s = 1; /* code or data, i.e. not system */
|
iap10@3290
|
301 arbytes.fields.dpl = 0; /* DPL = 3 */
|
iap10@3290
|
302 arbytes.fields.p = 1; /* segment present */
|
iap10@3290
|
303 arbytes.fields.default_ops_size = 1; /* 32-bit */
|
iap10@3290
|
304 arbytes.fields.g = 1;
|
iap10@3290
|
305 arbytes.fields.null_bit = 0; /* not null */
|
iap10@3290
|
306
|
iap10@3290
|
307 error |= __vmwrite(GUEST_ES_AR_BYTES, arbytes.bytes);
|
iap10@3290
|
308 error |= __vmwrite(GUEST_SS_AR_BYTES, arbytes.bytes);
|
iap10@3290
|
309 error |= __vmwrite(GUEST_DS_AR_BYTES, arbytes.bytes);
|
iap10@3290
|
310 error |= __vmwrite(GUEST_FS_AR_BYTES, arbytes.bytes);
|
iap10@3290
|
311 error |= __vmwrite(GUEST_GS_AR_BYTES, arbytes.bytes);
|
iap10@3290
|
312
|
iap10@3290
|
313 arbytes.fields.seg_type = 0xb; /* type = 0xb */
|
iap10@3290
|
314 error |= __vmwrite(GUEST_CS_AR_BYTES, arbytes.bytes);
|
iap10@3290
|
315
|
kaf24@4683
|
316 error |= __vmwrite(GUEST_GDTR_BASE, regs->edx);
|
kaf24@4683
|
317 regs->edx = 0;
|
kaf24@4683
|
318 error |= __vmwrite(GUEST_GDTR_LIMIT, regs->eax);
|
kaf24@4683
|
319 regs->eax = 0;
|
iap10@3290
|
320
|
iap10@3290
|
321 arbytes.fields.s = 0; /* not code or data segement */
|
iap10@3290
|
322 arbytes.fields.seg_type = 0x2; /* LTD */
|
iap10@3290
|
323 arbytes.fields.default_ops_size = 0; /* 16-bit */
|
iap10@3290
|
324 arbytes.fields.g = 0;
|
iap10@3290
|
325 error |= __vmwrite(GUEST_LDTR_AR_BYTES, arbytes.bytes);
|
iap10@3290
|
326
|
iap10@3290
|
327 arbytes.fields.seg_type = 0xb; /* 32-bit TSS (busy) */
|
iap10@3290
|
328 error |= __vmwrite(GUEST_TR_AR_BYTES, arbytes.bytes);
|
iap10@3290
|
329
|
iap10@3290
|
330 error |= __vmwrite(GUEST_CR0, host_env->cr0); /* same CR0 */
|
iap10@3290
|
331
|
iap10@3290
|
332 /* Initally PG, PE are not set*/
|
iap10@3290
|
333 shadow_cr = host_env->cr0;
|
arun@5186
|
334 shadow_cr &= ~X86_CR0_PG;
|
iap10@3290
|
335 error |= __vmwrite(CR0_READ_SHADOW, shadow_cr);
|
kaf24@3755
|
336 /* CR3 is set in vmx_final_setup_guest */
|
kaf24@5658
|
337 #ifdef __x86_64__
|
kaf24@5727
|
338 error |= __vmwrite(GUEST_CR4, host_env->cr4 & ~X86_CR4_PSE);
|
kaf24@5658
|
339 #else
|
iap10@3290
|
340 error |= __vmwrite(GUEST_CR4, host_env->cr4);
|
kaf24@5658
|
341 #endif
|
iap10@3290
|
342 shadow_cr = host_env->cr4;
|
kaf24@5658
|
343
|
kaf24@5658
|
344 #ifdef __x86_64__
|
kaf24@5658
|
345 shadow_cr &= ~(X86_CR4_PGE | X86_CR4_VMXE | X86_CR4_PAE);
|
kaf24@5658
|
346 #else
|
iap10@3290
|
347 shadow_cr &= ~(X86_CR4_PGE | X86_CR4_VMXE);
|
kaf24@5658
|
348 #endif
|
iap10@3290
|
349 error |= __vmwrite(CR4_READ_SHADOW, shadow_cr);
|
iap10@3290
|
350
|
iap10@3290
|
351 error |= __vmwrite(GUEST_ES_BASE, host_env->ds_base);
|
iap10@3290
|
352 error |= __vmwrite(GUEST_CS_BASE, host_env->cs_base);
|
iap10@3290
|
353 error |= __vmwrite(GUEST_SS_BASE, host_env->ds_base);
|
iap10@3290
|
354 error |= __vmwrite(GUEST_DS_BASE, host_env->ds_base);
|
iap10@3290
|
355 error |= __vmwrite(GUEST_FS_BASE, host_env->ds_base);
|
iap10@3290
|
356 error |= __vmwrite(GUEST_GS_BASE, host_env->ds_base);
|
iap10@3290
|
357 error |= __vmwrite(GUEST_IDTR_BASE, host_env->idtr_base);
|
iap10@3290
|
358
|
kaf24@5414
|
359 error |= __vmwrite(GUEST_RSP, regs->esp);
|
kaf24@5414
|
360 error |= __vmwrite(GUEST_RIP, regs->eip);
|
iap10@3290
|
361
|
kaf24@4683
|
362 eflags = regs->eflags & ~VMCS_EFLAGS_RESERVED_0; /* clear 0s */
|
iap10@3290
|
363 eflags |= VMCS_EFLAGS_RESERVED_1; /* set 1s */
|
iap10@3290
|
364
|
kaf24@5414
|
365 error |= __vmwrite(GUEST_RFLAGS, eflags);
|
iap10@3290
|
366
|
iap10@3290
|
367 error |= __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
|
iap10@3290
|
368 __asm__ __volatile__ ("mov %%dr7, %0\n" : "=r" (dr7));
|
iap10@3290
|
369 error |= __vmwrite(GUEST_DR7, dr7);
|
kaf24@5414
|
370 error |= __vmwrite(VMCS_LINK_POINTER, 0xffffffff);
|
kaf24@5414
|
371 error |= __vmwrite(VMCS_LINK_POINTER_HIGH, 0xffffffff);
|
iap10@3290
|
372
|
iap10@3290
|
373 return error;
|
iap10@3290
|
374 }
|
iap10@3290
|
375
|
iap10@3290
|
376 static inline int construct_vmcs_host(struct host_execution_env *host_env)
|
iap10@3290
|
377 {
|
iap10@3290
|
378 int error = 0;
|
iap10@3290
|
379 unsigned long crn;
|
iap10@3290
|
380
|
iap10@3290
|
381 /* Host Selectors */
|
iap10@3290
|
382 host_env->ds_selector = __HYPERVISOR_DS;
|
iap10@3290
|
383 error |= __vmwrite(HOST_ES_SELECTOR, host_env->ds_selector);
|
iap10@3290
|
384 error |= __vmwrite(HOST_SS_SELECTOR, host_env->ds_selector);
|
iap10@3290
|
385 error |= __vmwrite(HOST_DS_SELECTOR, host_env->ds_selector);
|
kaf24@5658
|
386 #if defined (__i386__)
|
iap10@3290
|
387 error |= __vmwrite(HOST_FS_SELECTOR, host_env->ds_selector);
|
iap10@3290
|
388 error |= __vmwrite(HOST_GS_SELECTOR, host_env->ds_selector);
|
kaf24@5658
|
389 error |= __vmwrite(HOST_FS_BASE, host_env->ds_base);
|
kaf24@5658
|
390 error |= __vmwrite(HOST_GS_BASE, host_env->ds_base);
|
iap10@3290
|
391
|
kaf24@5658
|
392 #else
|
kaf24@5658
|
393 rdmsrl(MSR_FS_BASE, host_env->fs_base);
|
kaf24@5658
|
394 rdmsrl(MSR_GS_BASE, host_env->gs_base);
|
kaf24@5658
|
395 error |= __vmwrite(HOST_FS_BASE, host_env->fs_base);
|
kaf24@5658
|
396 error |= __vmwrite(HOST_GS_BASE, host_env->gs_base);
|
kaf24@5658
|
397
|
kaf24@5658
|
398 #endif
|
iap10@3290
|
399 host_env->cs_selector = __HYPERVISOR_CS;
|
iap10@3290
|
400 error |= __vmwrite(HOST_CS_SELECTOR, host_env->cs_selector);
|
iap10@3290
|
401
|
iap10@3290
|
402 host_env->ds_base = 0;
|
iap10@3290
|
403 host_env->cs_base = 0;
|
iap10@3290
|
404
|
kaf24@5193
|
405 __asm__ __volatile__ ("mov %%cr0,%0" : "=r" (crn) : );
|
iap10@3290
|
406 host_env->cr0 = crn;
|
iap10@3290
|
407 error |= __vmwrite(HOST_CR0, crn); /* same CR0 */
|
iap10@3290
|
408
|
iap10@3290
|
409 /* CR3 is set in vmx_final_setup_hostos */
|
kaf24@5193
|
410 __asm__ __volatile__ ("mov %%cr4,%0" : "=r" (crn) : );
|
iap10@3290
|
411 host_env->cr4 = crn;
|
iap10@3290
|
412 error |= __vmwrite(HOST_CR4, crn);
|
kaf24@5820
|
413
|
kaf24@5414
|
414 error |= __vmwrite(HOST_RIP, (unsigned long) vmx_asm_vmexit_handler);
|
kaf24@5658
|
415 #ifdef __x86_64__
|
kaf24@5658
|
416 /* TBD: support cr8 for 64-bit guest */
|
kaf24@5658
|
417 __vmwrite(VIRTUAL_APIC_PAGE_ADDR, 0);
|
kaf24@5658
|
418 __vmwrite(TPR_THRESHOLD, 0);
|
kaf24@5658
|
419 __vmwrite(SECONDARY_VM_EXEC_CONTROL, 0);
|
kaf24@5658
|
420 #endif
|
iap10@3290
|
421
|
iap10@3290
|
422 return error;
|
iap10@3290
|
423 }
|
iap10@3290
|
424
|
iap10@3290
|
425 /*
|
iap10@3290
|
426 * Need to extend to support full virtualization.
|
iap10@3290
|
427 * The variable use_host_env indicates if the new VMCS needs to use
|
iap10@3290
|
428 * the same setups as the host has (xenolinux).
|
iap10@3290
|
429 */
|
iap10@3290
|
430
|
iap10@3290
|
431 int construct_vmcs(struct arch_vmx_struct *arch_vmx,
|
kaf24@4683
|
432 struct cpu_user_regs *regs,
|
kaf24@4683
|
433 struct vcpu_guest_context *ctxt,
|
iap10@3290
|
434 int use_host_env)
|
iap10@3290
|
435 {
|
iap10@3290
|
436 int error;
|
iap10@3290
|
437 u64 vmcs_phys_ptr;
|
iap10@3290
|
438
|
iap10@3290
|
439 struct host_execution_env host_env;
|
iap10@3290
|
440
|
iap10@3290
|
441 if (use_host_env != VMCS_USE_HOST_ENV)
|
iap10@3290
|
442 return -EINVAL;
|
iap10@3290
|
443
|
iap10@3290
|
444 memset(&host_env, 0, sizeof(struct host_execution_env));
|
iap10@3290
|
445
|
iap10@3290
|
446 vmcs_phys_ptr = (u64) virt_to_phys(arch_vmx->vmcs);
|
iap10@3290
|
447
|
iap10@3290
|
448 if ((error = __vmpclear (vmcs_phys_ptr))) {
|
iap10@3290
|
449 printk("construct_vmcs: VMCLEAR failed\n");
|
iap10@3290
|
450 return -EINVAL;
|
iap10@3290
|
451 }
|
iap10@3290
|
452 if ((error = load_vmcs(arch_vmx, vmcs_phys_ptr))) {
|
iap10@3290
|
453 printk("construct_vmcs: load_vmcs failed: VMCS = %lx\n",
|
iap10@3290
|
454 (unsigned long) vmcs_phys_ptr);
|
iap10@3290
|
455 return -EINVAL;
|
iap10@3290
|
456 }
|
kaf24@5836
|
457 if ((error = construct_vmcs_controls(arch_vmx))) {
|
iap10@3290
|
458 printk("construct_vmcs: construct_vmcs_controls failed\n");
|
iap10@3290
|
459 return -EINVAL;
|
iap10@3290
|
460 }
|
iap10@3290
|
461 /* host selectors */
|
iap10@3290
|
462 if ((error = construct_vmcs_host(&host_env))) {
|
iap10@3290
|
463 printk("construct_vmcs: construct_vmcs_host failed\n");
|
iap10@3290
|
464 return -EINVAL;
|
iap10@3290
|
465 }
|
iap10@3290
|
466 /* guest selectors */
|
kaf24@4683
|
467 if ((error = construct_init_vmcs_guest(regs, ctxt, &host_env))) {
|
iap10@3290
|
468 printk("construct_vmcs: construct_vmcs_guest failed\n");
|
iap10@3290
|
469 return -EINVAL;
|
iap10@3290
|
470 }
|
iap10@3290
|
471
|
iap10@3290
|
472 if ((error |= __vmwrite(EXCEPTION_BITMAP,
|
iap10@3290
|
473 MONITOR_DEFAULT_EXCEPTION_BITMAP))) {
|
iap10@3290
|
474 printk("construct_vmcs: setting Exception bitmap failed\n");
|
iap10@3290
|
475 return -EINVAL;
|
iap10@3290
|
476 }
|
iap10@3290
|
477
|
kaf24@5821
|
478 if (regs->eflags & EF_TF)
|
kaf24@5821
|
479 __vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
|
kaf24@5821
|
480 else
|
kaf24@5821
|
481 __vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
|
kaf24@5821
|
482
|
kaf24@5821
|
483 return 0;
|
kaf24@5821
|
484 }
|
kaf24@5821
|
485
|
kaf24@5821
|
486 /*
|
kaf24@5821
|
487 * modify guest eflags and execption bitmap for gdb
|
kaf24@5821
|
488 */
|
kaf24@5821
|
489 int modify_vmcs(struct arch_vmx_struct *arch_vmx,
|
kaf24@5821
|
490 struct cpu_user_regs *regs)
|
kaf24@5821
|
491 {
|
kaf24@5821
|
492 int error;
|
kaf24@5821
|
493 u64 vmcs_phys_ptr, old, old_phys_ptr;
|
kaf24@5821
|
494 vmcs_phys_ptr = (u64) virt_to_phys(arch_vmx->vmcs);
|
kaf24@5821
|
495
|
kaf24@5821
|
496 old_phys_ptr = virt_to_phys(&old);
|
kaf24@5821
|
497 __vmptrst(old_phys_ptr);
|
kaf24@5821
|
498 if ((error = load_vmcs(arch_vmx, vmcs_phys_ptr))) {
|
kaf24@5821
|
499 printk("modify_vmcs: load_vmcs failed: VMCS = %lx\n",
|
kaf24@6730
|
500 (unsigned long) vmcs_phys_ptr);
|
kaf24@5821
|
501 return -EINVAL;
|
kaf24@5821
|
502 }
|
kaf24@5821
|
503 load_cpu_user_regs(regs);
|
kaf24@5821
|
504
|
kaf24@5821
|
505 __vmptrld(old_phys_ptr);
|
kaf24@5821
|
506
|
iap10@3290
|
507 return 0;
|
iap10@3290
|
508 }
|
iap10@3290
|
509
|
iap10@3290
|
510 int load_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr)
|
iap10@3290
|
511 {
|
iap10@3290
|
512 int error;
|
iap10@3290
|
513
|
iap10@3290
|
514 if ((error = __vmptrld(phys_ptr))) {
|
iap10@3290
|
515 clear_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
|
iap10@3290
|
516 return error;
|
iap10@3290
|
517 }
|
iap10@3290
|
518 set_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
|
iap10@3290
|
519 return 0;
|
iap10@3290
|
520 }
|
iap10@3290
|
521
|
iap10@3290
|
522 int store_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr)
|
iap10@3290
|
523 {
|
iap10@3290
|
524 /* take the current VMCS */
|
iap10@3290
|
525 __vmptrst(phys_ptr);
|
iap10@3290
|
526 clear_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
|
iap10@3290
|
527 return 0;
|
iap10@3290
|
528 }
|
iap10@3290
|
529
|
iap10@3290
|
530 void vm_launch_fail(unsigned long eflags)
|
iap10@3290
|
531 {
|
kaf24@6099
|
532 unsigned long error;
|
kaf24@6099
|
533 __vmread(VM_INSTRUCTION_ERROR, &error);
|
kaf24@6099
|
534 printk("<vm_launch_fail> error code %lx\n", error);
|
arun@5382
|
535 __vmx_bug(guest_cpu_user_regs());
|
iap10@3290
|
536 }
|
iap10@3290
|
537
|
iap10@3290
|
538 void vm_resume_fail(unsigned long eflags)
|
iap10@3290
|
539 {
|
kaf24@6099
|
540 unsigned long error;
|
kaf24@6099
|
541 __vmread(VM_INSTRUCTION_ERROR, &error);
|
kaf24@6099
|
542 printk("<vm_resume_fail> error code %lx\n", error);
|
arun@5382
|
543 __vmx_bug(guest_cpu_user_regs());
|
iap10@3290
|
544 }
|
iap10@3290
|
545
|
kaf24@6113
|
546 void arch_vmx_do_resume(struct vcpu *v)
|
kaf24@6113
|
547 {
|
kaf24@6113
|
548 u64 vmcs_phys_ptr = (u64) virt_to_phys(v->arch.arch_vmx.vmcs);
|
kaf24@6113
|
549
|
kaf24@6113
|
550 load_vmcs(&v->arch.arch_vmx, vmcs_phys_ptr);
|
kaf24@6113
|
551 vmx_do_resume(v);
|
kaf24@6113
|
552 reset_stack_and_jump(vmx_asm_do_resume);
|
kaf24@6113
|
553 }
|
kaf24@6113
|
554
|
kaf24@6113
|
555 void arch_vmx_do_launch(struct vcpu *v)
|
kaf24@6113
|
556 {
|
kaf24@6113
|
557 u64 vmcs_phys_ptr = (u64) virt_to_phys(v->arch.arch_vmx.vmcs);
|
kaf24@6113
|
558
|
kaf24@6113
|
559 load_vmcs(&v->arch.arch_vmx, vmcs_phys_ptr);
|
kaf24@6113
|
560 vmx_do_launch(v);
|
kaf24@6113
|
561 reset_stack_and_jump(vmx_asm_do_launch);
|
kaf24@6113
|
562 }
|
kaf24@6113
|
563
|
kaf24@6113
|
564 void arch_vmx_do_relaunch(struct vcpu *v)
|
kaf24@6113
|
565 {
|
kaf24@6113
|
566 u64 vmcs_phys_ptr = (u64) virt_to_phys(v->arch.arch_vmx.vmcs);
|
kaf24@6113
|
567
|
kaf24@6113
|
568 load_vmcs(&v->arch.arch_vmx, vmcs_phys_ptr);
|
kaf24@6113
|
569 vmx_do_resume(v);
|
kaf24@6113
|
570 vmx_set_host_env(v);
|
kaf24@6113
|
571 v->arch.schedule_tail = arch_vmx_do_resume;
|
kaf24@6113
|
572
|
kaf24@6113
|
573 reset_stack_and_jump(vmx_asm_do_relaunch);
|
kaf24@6113
|
574 }
|
kaf24@6113
|
575
|
mafetter@3717
|
576 #endif /* CONFIG_VMX */
|
kaf24@3914
|
577
|
kaf24@3914
|
578 /*
|
kaf24@3914
|
579 * Local variables:
|
kaf24@3914
|
580 * mode: C
|
kaf24@3914
|
581 * c-set-style: "BSD"
|
kaf24@3914
|
582 * c-basic-offset: 4
|
kaf24@3914
|
583 * tab-width: 4
|
kaf24@3914
|
584 * indent-tabs-mode: nil
|
kaf24@3988
|
585 * End:
|
kaf24@3914
|
586 */
|