ia64/xen-unstable

view xen/arch/x86/vmx_vmcs.c @ 4585:98554eb54a58

bitkeeper revision 1.1333 (42662dd7ZAAvK_ZarFhk1lamxPIQdg)

[PATCH] x86-64-eax.patch

vmx_vmcs.c:
fix inline asms for x86-64

Signed-Off-By: Benjamin Liu <benjamin.liu@intel.com>
Signed-Off-By: Arun Sharma <arun.sharma@intel.com>
author arun.sharma@intel.com[kaf24]
date Wed Apr 20 10:24:23 2005 +0000 (2005-04-20)
parents a01199a95070
children b1cb9f7f34f9
line source
1 /*
2 * vmx_vmcs.c: VMCS management
3 * Copyright (c) 2004, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16 * Place - Suite 330, Boston, MA 02111-1307 USA.
17 *
18 */
20 #include <xen/config.h>
21 #include <xen/init.h>
22 #include <xen/mm.h>
23 #include <xen/lib.h>
24 #include <xen/errno.h>
26 #include <asm/cpufeature.h>
27 #include <asm/processor.h>
28 #include <asm/msr.h>
29 #include <asm/vmx.h>
30 #include <xen/event.h>
31 #include <xen/kernel.h>
32 #include <public/io/ioreq.h>
33 #include <asm/domain_page.h>
35 #ifdef CONFIG_VMX
37 struct vmcs_struct *alloc_vmcs(void)
38 {
39 struct vmcs_struct *vmcs;
40 unsigned int cpu_sig = cpuid_eax(0x00000001);
42 vmcs = (struct vmcs_struct *) alloc_xenheap_pages(get_order(vmcs_size));
43 memset((char *) vmcs, 0, vmcs_size); /* don't remove this */
45 vmcs->vmcs_revision_id = (cpu_sig > 0xf41)? 3 : 1;
46 return vmcs;
47 }
49 void free_vmcs(struct vmcs_struct *vmcs)
50 {
51 int order;
53 order = (vmcs_size >> PAGE_SHIFT) - 1;
54 free_xenheap_pages((unsigned long) vmcs, order);
55 }
57 static inline int construct_vmcs_controls(void)
58 {
59 int error = 0;
61 error |= __vmwrite(PIN_BASED_VM_EXEC_CONTROL,
62 MONITOR_PIN_BASED_EXEC_CONTROLS);
64 error |= __vmwrite(CPU_BASED_VM_EXEC_CONTROL,
65 MONITOR_CPU_BASED_EXEC_CONTROLS);
67 error |= __vmwrite(VM_EXIT_CONTROLS, MONITOR_VM_EXIT_CONTROLS);
68 error |= __vmwrite(VM_ENTRY_CONTROLS, MONITOR_VM_ENTRY_CONTROLS);
70 return error;
71 }
73 #define GUEST_SEGMENT_LIMIT 0xffffffff
74 #define HOST_SEGMENT_LIMIT 0xffffffff
76 struct host_execution_env {
77 /* selectors */
78 unsigned short ldtr_selector;
79 unsigned short tr_selector;
80 unsigned short ds_selector;
81 unsigned short cs_selector;
82 /* limits */
83 unsigned short gdtr_limit;
84 unsigned short ldtr_limit;
85 unsigned short idtr_limit;
86 unsigned short tr_limit;
87 /* base */
88 unsigned long gdtr_base;
89 unsigned long ldtr_base;
90 unsigned long idtr_base;
91 unsigned long tr_base;
92 unsigned long ds_base;
93 unsigned long cs_base;
94 /* control registers */
95 unsigned long cr3;
96 unsigned long cr0;
97 unsigned long cr4;
98 unsigned long dr7;
99 };
101 #define round_pgdown(_p) ((_p)&PAGE_MASK) /* coped from domain.c */
103 int vmx_setup_platform(struct exec_domain *d, execution_context_t *context)
104 {
105 int i;
106 unsigned int n;
107 unsigned long *p, mpfn, offset, addr;
108 struct e820entry *e820p;
109 unsigned long gpfn = 0;
111 context->ebx = 0; /* Linux expects ebx to be 0 for boot proc */
113 n = context->ecx;
114 if (n > 32) {
115 VMX_DBG_LOG(DBG_LEVEL_1, "Too many e820 entries: %d", n);
116 return -1;
117 }
119 addr = context->edi;
120 offset = (addr & ~PAGE_MASK);
121 addr = round_pgdown(addr);
122 mpfn = phys_to_machine_mapping(addr >> PAGE_SHIFT);
123 p = map_domain_mem(mpfn << PAGE_SHIFT);
125 e820p = (struct e820entry *) ((unsigned long) p + offset);
127 #ifndef NDEBUG
128 print_e820_memory_map(e820p, n);
129 #endif
131 for (i = 0; i < n; i++) {
132 if (e820p[i].type == E820_SHARED_PAGE) {
133 gpfn = (e820p[i].addr >> PAGE_SHIFT);
134 break;
135 }
136 }
138 if (gpfn == 0) {
139 printk("No shared Page ?\n");
140 unmap_domain_mem(p);
141 return -1;
142 }
143 unmap_domain_mem(p);
145 mpfn = phys_to_machine_mapping(gpfn);
146 p = map_domain_mem(mpfn << PAGE_SHIFT);
147 ASSERT(p != NULL);
149 /* Initialise shared page */
150 memset(p, 0, PAGE_SIZE);
152 d->arch.arch_vmx.vmx_platform.shared_page_va = (unsigned long) p;
154 return 0;
155 }
157 void vmx_do_launch(struct exec_domain *ed)
158 {
159 /* Update CR3, GDT, LDT, TR */
160 unsigned int tr, cpu, error = 0;
161 struct host_execution_env host_env;
162 struct Xgt_desc_struct desc;
163 struct list_head *list_ent;
164 unsigned long i, pfn = 0;
165 struct pfn_info *page;
166 execution_context_t *ec = get_execution_context();
167 struct domain *d = ed->domain;
169 cpu = smp_processor_id();
170 d->arch.min_pfn = d->arch.max_pfn = 0;
172 spin_lock(&d->page_alloc_lock);
173 list_ent = d->page_list.next;
175 for ( i = 0; list_ent != &d->page_list; i++ )
176 {
177 pfn = list_entry(list_ent, struct pfn_info, list) - frame_table;
178 d->arch.min_pfn = min(d->arch.min_pfn, pfn);
179 d->arch.max_pfn = max(d->arch.max_pfn, pfn);
180 list_ent = frame_table[pfn].list.next;
181 }
183 spin_unlock(&d->page_alloc_lock);
185 page = (struct pfn_info *) alloc_domheap_page(NULL);
186 pfn = (unsigned long) (page - frame_table);
188 vmx_setup_platform(ed, ec);
190 __asm__ __volatile__ ("sgdt (%0) \n" :: "a"(&desc) : "memory");
191 host_env.gdtr_limit = desc.size;
192 host_env.gdtr_base = desc.address;
194 error |= __vmwrite(HOST_GDTR_BASE, host_env.gdtr_base);
196 error |= __vmwrite(GUEST_LDTR_SELECTOR, 0);
197 error |= __vmwrite(GUEST_LDTR_BASE, 0);
198 error |= __vmwrite(GUEST_LDTR_LIMIT, 0);
200 __asm__ __volatile__ ("str (%0) \n" :: "a"(&tr) : "memory");
201 host_env.tr_selector = tr;
202 host_env.tr_limit = sizeof(struct tss_struct);
203 host_env.tr_base = (unsigned long) &init_tss[cpu];
205 error |= __vmwrite(HOST_TR_SELECTOR, host_env.tr_selector);
206 error |= __vmwrite(HOST_TR_BASE, host_env.tr_base);
207 error |= __vmwrite(GUEST_TR_BASE, 0);
208 error |= __vmwrite(GUEST_TR_LIMIT, 0xff);
210 __vmwrite(GUEST_CR3, pagetable_val(ed->arch.guest_table));
211 __vmwrite(HOST_CR3, pagetable_val(ed->arch.monitor_table));
212 __vmwrite(HOST_ESP, (unsigned long)get_stack_bottom());
214 ed->arch.schedule_tail = arch_vmx_do_resume;
215 }
217 /*
218 * Initially set the same environement as host.
219 */
220 static inline int
221 construct_init_vmcs_guest(execution_context_t *context,
222 full_execution_context_t *full_context,
223 struct host_execution_env *host_env)
224 {
225 int error = 0;
226 union vmcs_arbytes arbytes;
227 unsigned long dr7;
228 unsigned long eflags, shadow_cr;
230 /* MSR */
231 error |= __vmwrite(VM_EXIT_MSR_LOAD_ADDR, 0);
232 error |= __vmwrite(VM_EXIT_MSR_STORE_ADDR, 0);
234 error |= __vmwrite(VM_EXIT_MSR_STORE_COUNT, 0);
235 error |= __vmwrite(VM_EXIT_MSR_LOAD_COUNT, 0);
236 error |= __vmwrite(VM_ENTRY_MSR_LOAD_COUNT, 0);
237 /* interrupt */
238 error |= __vmwrite(VM_ENTRY_INTR_INFO_FIELD, 0);
239 /* mask */
240 error |= __vmwrite(CR0_GUEST_HOST_MASK, 0xffffffff);
241 error |= __vmwrite(CR4_GUEST_HOST_MASK, 0xffffffff);
243 error |= __vmwrite(PAGE_FAULT_ERROR_CODE_MASK, 0);
244 error |= __vmwrite(PAGE_FAULT_ERROR_CODE_MATCH, 0);
246 /* TSC */
247 error |= __vmwrite(TSC_OFFSET, 0);
248 error |= __vmwrite(CR3_TARGET_COUNT, 0);
250 /* Guest Selectors */
251 error |= __vmwrite(GUEST_CS_SELECTOR, context->cs);
252 error |= __vmwrite(GUEST_ES_SELECTOR, context->es);
253 error |= __vmwrite(GUEST_SS_SELECTOR, context->ss);
254 error |= __vmwrite(GUEST_DS_SELECTOR, context->ds);
255 error |= __vmwrite(GUEST_FS_SELECTOR, context->fs);
256 error |= __vmwrite(GUEST_GS_SELECTOR, context->gs);
258 /* Guest segment Limits */
259 error |= __vmwrite(GUEST_CS_LIMIT, GUEST_SEGMENT_LIMIT);
260 error |= __vmwrite(GUEST_ES_LIMIT, GUEST_SEGMENT_LIMIT);
261 error |= __vmwrite(GUEST_SS_LIMIT, GUEST_SEGMENT_LIMIT);
262 error |= __vmwrite(GUEST_DS_LIMIT, GUEST_SEGMENT_LIMIT);
263 error |= __vmwrite(GUEST_FS_LIMIT, GUEST_SEGMENT_LIMIT);
264 error |= __vmwrite(GUEST_GS_LIMIT, GUEST_SEGMENT_LIMIT);
266 error |= __vmwrite(GUEST_IDTR_LIMIT, host_env->idtr_limit);
268 /* AR bytes */
269 arbytes.bytes = 0;
270 arbytes.fields.seg_type = 0x3; /* type = 3 */
271 arbytes.fields.s = 1; /* code or data, i.e. not system */
272 arbytes.fields.dpl = 0; /* DPL = 3 */
273 arbytes.fields.p = 1; /* segment present */
274 arbytes.fields.default_ops_size = 1; /* 32-bit */
275 arbytes.fields.g = 1;
276 arbytes.fields.null_bit = 0; /* not null */
278 error |= __vmwrite(GUEST_ES_AR_BYTES, arbytes.bytes);
279 error |= __vmwrite(GUEST_SS_AR_BYTES, arbytes.bytes);
280 error |= __vmwrite(GUEST_DS_AR_BYTES, arbytes.bytes);
281 error |= __vmwrite(GUEST_FS_AR_BYTES, arbytes.bytes);
282 error |= __vmwrite(GUEST_GS_AR_BYTES, arbytes.bytes);
284 arbytes.fields.seg_type = 0xb; /* type = 0xb */
285 error |= __vmwrite(GUEST_CS_AR_BYTES, arbytes.bytes);
287 error |= __vmwrite(GUEST_GDTR_BASE, context->edx);
288 context->edx = 0;
289 error |= __vmwrite(GUEST_GDTR_LIMIT, context->eax);
290 context->eax = 0;
292 arbytes.fields.s = 0; /* not code or data segement */
293 arbytes.fields.seg_type = 0x2; /* LTD */
294 arbytes.fields.default_ops_size = 0; /* 16-bit */
295 arbytes.fields.g = 0;
296 error |= __vmwrite(GUEST_LDTR_AR_BYTES, arbytes.bytes);
298 arbytes.fields.seg_type = 0xb; /* 32-bit TSS (busy) */
299 error |= __vmwrite(GUEST_TR_AR_BYTES, arbytes.bytes);
301 error |= __vmwrite(GUEST_CR0, host_env->cr0); /* same CR0 */
303 /* Initally PG, PE are not set*/
304 shadow_cr = host_env->cr0;
305 shadow_cr &= ~(X86_CR0_PE | X86_CR0_PG);
306 error |= __vmwrite(CR0_READ_SHADOW, shadow_cr);
307 /* CR3 is set in vmx_final_setup_guest */
308 error |= __vmwrite(GUEST_CR4, host_env->cr4);
309 shadow_cr = host_env->cr4;
310 shadow_cr &= ~(X86_CR4_PGE | X86_CR4_VMXE);
311 error |= __vmwrite(CR4_READ_SHADOW, shadow_cr);
313 error |= __vmwrite(GUEST_ES_BASE, host_env->ds_base);
314 error |= __vmwrite(GUEST_CS_BASE, host_env->cs_base);
315 error |= __vmwrite(GUEST_SS_BASE, host_env->ds_base);
316 error |= __vmwrite(GUEST_DS_BASE, host_env->ds_base);
317 error |= __vmwrite(GUEST_FS_BASE, host_env->ds_base);
318 error |= __vmwrite(GUEST_GS_BASE, host_env->ds_base);
319 error |= __vmwrite(GUEST_IDTR_BASE, host_env->idtr_base);
321 error |= __vmwrite(GUEST_ESP, context->esp);
322 error |= __vmwrite(GUEST_EIP, context->eip);
324 eflags = context->eflags & ~VMCS_EFLAGS_RESERVED_0; /* clear 0s */
325 eflags |= VMCS_EFLAGS_RESERVED_1; /* set 1s */
327 error |= __vmwrite(GUEST_EFLAGS, eflags);
329 error |= __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
330 __asm__ __volatile__ ("mov %%dr7, %0\n" : "=r" (dr7));
331 error |= __vmwrite(GUEST_DR7, dr7);
332 error |= __vmwrite(GUEST_VMCS0, 0xffffffff);
333 error |= __vmwrite(GUEST_VMCS1, 0xffffffff);
335 return error;
336 }
338 static inline int construct_vmcs_host(struct host_execution_env *host_env)
339 {
340 int error = 0;
341 unsigned long crn;
342 struct Xgt_desc_struct desc;
344 /* Host Selectors */
345 host_env->ds_selector = __HYPERVISOR_DS;
346 error |= __vmwrite(HOST_ES_SELECTOR, host_env->ds_selector);
347 error |= __vmwrite(HOST_SS_SELECTOR, host_env->ds_selector);
348 error |= __vmwrite(HOST_DS_SELECTOR, host_env->ds_selector);
349 error |= __vmwrite(HOST_FS_SELECTOR, host_env->ds_selector);
350 error |= __vmwrite(HOST_GS_SELECTOR, host_env->ds_selector);
352 host_env->cs_selector = __HYPERVISOR_CS;
353 error |= __vmwrite(HOST_CS_SELECTOR, host_env->cs_selector);
355 host_env->ds_base = 0;
356 host_env->cs_base = 0;
357 error |= __vmwrite(HOST_FS_BASE, host_env->ds_base);
358 error |= __vmwrite(HOST_GS_BASE, host_env->ds_base);
360 /* Debug */
361 __asm__ __volatile__ ("sidt (%0) \n" :: "a"(&desc) : "memory");
362 host_env->idtr_limit = desc.size;
363 host_env->idtr_base = desc.address;
364 error |= __vmwrite(HOST_IDTR_BASE, host_env->idtr_base);
366 __asm__ __volatile__ ("movl %%cr0,%0" : "=r" (crn) : );
367 host_env->cr0 = crn;
368 error |= __vmwrite(HOST_CR0, crn); /* same CR0 */
370 /* CR3 is set in vmx_final_setup_hostos */
371 __asm__ __volatile__ ("movl %%cr4,%0" : "=r" (crn) : );
372 host_env->cr4 = crn;
373 error |= __vmwrite(HOST_CR4, crn);
374 error |= __vmwrite(HOST_EIP, (unsigned long) vmx_asm_vmexit_handler);
376 return error;
377 }
379 /*
380 * Need to extend to support full virtualization.
381 * The variable use_host_env indicates if the new VMCS needs to use
382 * the same setups as the host has (xenolinux).
383 */
385 int construct_vmcs(struct arch_vmx_struct *arch_vmx,
386 execution_context_t *context,
387 full_execution_context_t *full_context,
388 int use_host_env)
389 {
390 int error;
391 u64 vmcs_phys_ptr;
393 struct host_execution_env host_env;
395 if (use_host_env != VMCS_USE_HOST_ENV)
396 return -EINVAL;
398 memset(&host_env, 0, sizeof(struct host_execution_env));
400 vmcs_phys_ptr = (u64) virt_to_phys(arch_vmx->vmcs);
402 if ((error = __vmpclear (vmcs_phys_ptr))) {
403 printk("construct_vmcs: VMCLEAR failed\n");
404 return -EINVAL;
405 }
406 if ((error = load_vmcs(arch_vmx, vmcs_phys_ptr))) {
407 printk("construct_vmcs: load_vmcs failed: VMCS = %lx\n",
408 (unsigned long) vmcs_phys_ptr);
409 return -EINVAL;
410 }
411 if ((error = construct_vmcs_controls())) {
412 printk("construct_vmcs: construct_vmcs_controls failed\n");
413 return -EINVAL;
414 }
415 /* host selectors */
416 if ((error = construct_vmcs_host(&host_env))) {
417 printk("construct_vmcs: construct_vmcs_host failed\n");
418 return -EINVAL;
419 }
420 /* guest selectors */
421 if ((error = construct_init_vmcs_guest(context, full_context, &host_env))) {
422 printk("construct_vmcs: construct_vmcs_guest failed\n");
423 return -EINVAL;
424 }
426 if ((error |= __vmwrite(EXCEPTION_BITMAP,
427 MONITOR_DEFAULT_EXCEPTION_BITMAP))) {
428 printk("construct_vmcs: setting Exception bitmap failed\n");
429 return -EINVAL;
430 }
432 return 0;
433 }
435 int load_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr)
436 {
437 int error;
439 if ((error = __vmptrld(phys_ptr))) {
440 clear_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
441 return error;
442 }
443 set_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
444 return 0;
445 }
447 int store_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr)
448 {
449 /* take the current VMCS */
450 __vmptrst(phys_ptr);
451 clear_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
452 return 0;
453 }
455 void vm_launch_fail(unsigned long eflags)
456 {
457 BUG();
458 }
460 void vm_resume_fail(unsigned long eflags)
461 {
462 BUG();
463 }
465 #endif /* CONFIG_VMX */
467 /*
468 * Local variables:
469 * mode: C
470 * c-set-style: "BSD"
471 * c-basic-offset: 4
472 * tab-width: 4
473 * indent-tabs-mode: nil
474 * End:
475 */