xen-vtx-unstable

annotate xen/arch/x86/vmx_vmcs.c @ 6100:bf98996dded2

Separate out VMCS host state initialization from the rest

This is needed to support virtual cpu migration, because the host state
initialization is done on every migration, but the rest of the initialization
is done once per vcpu.

Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
Signed-off-by: Arun Sharma <arun.sharma@intel.com>
author kaf24@firebug.cl.cam.ac.uk
date Thu Aug 11 21:01:36 2005 +0000 (2005-08-11)
parents d1034eae9708
children 57b3fdca5dae
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@5398 47 vmcs = alloc_xenheap_pages(get_order(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@5775 58 order = get_order(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@5836 79 io_bitmap_a = (void*) alloc_xenheap_pages(get_order(0x1000));
kaf24@5836 80 io_bitmap_b = (void*) alloc_xenheap_pages(get_order(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
iap10@3707 151 mpfn = phys_to_machine_mapping(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@5356 178 mpfn = phys_to_machine_mapping(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
arun@5615 182 VMX_DBG_LOG(DBG_LEVEL_1, "eport: %x\n", iopacket_port(d->domain));
arun@5615 183
arun@5608 184 clear_bit(iopacket_port(d->domain),
arun@5608 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@5820 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
kaf24@6100 216 void vmx_do_launch(struct vcpu *v)
kaf24@6100 217 {
kaf24@6100 218 /* Update CR3, GDT, LDT, TR */
kaf24@6100 219 unsigned int error = 0;
kaf24@6100 220 unsigned long pfn = 0;
kaf24@6100 221 struct pfn_info *page;
kaf24@6100 222 struct cpu_user_regs *regs = guest_cpu_user_regs();
kaf24@6100 223
kaf24@6100 224 vmx_stts();
kaf24@6100 225
kaf24@6100 226 page = (struct pfn_info *) alloc_domheap_page(NULL);
kaf24@6100 227 pfn = (unsigned long) (page - frame_table);
kaf24@6100 228
kaf24@6100 229 vmx_setup_platform(v, regs);
kaf24@6100 230
kaf24@6100 231 vmx_set_host_env(v);
kaf24@6100 232
iap10@3290 233 error |= __vmwrite(GUEST_LDTR_SELECTOR, 0);
iap10@3290 234 error |= __vmwrite(GUEST_LDTR_BASE, 0);
iap10@3290 235 error |= __vmwrite(GUEST_LDTR_LIMIT, 0);
iap10@3290 236
iap10@3290 237 error |= __vmwrite(GUEST_TR_BASE, 0);
iap10@3290 238 error |= __vmwrite(GUEST_TR_LIMIT, 0xff);
iap10@3290 239
kaf24@5289 240 __vmwrite(GUEST_CR3, pagetable_get_paddr(v->arch.guest_table));
kaf24@5289 241 __vmwrite(HOST_CR3, pagetable_get_paddr(v->arch.monitor_table));
kaf24@5414 242 __vmwrite(HOST_RSP, (unsigned long)get_stack_bottom());
iap10@3290 243
kaf24@5289 244 v->arch.schedule_tail = arch_vmx_do_resume;
iap10@3290 245 }
iap10@3290 246
iap10@3290 247 /*
iap10@3290 248 * Initially set the same environement as host.
iap10@3290 249 */
iap10@3290 250 static inline int
kaf24@4683 251 construct_init_vmcs_guest(struct cpu_user_regs *regs,
kaf24@4683 252 struct vcpu_guest_context *ctxt,
iap10@3290 253 struct host_execution_env *host_env)
iap10@3290 254 {
iap10@3290 255 int error = 0;
iap10@3290 256 union vmcs_arbytes arbytes;
iap10@3290 257 unsigned long dr7;
iap10@3290 258 unsigned long eflags, shadow_cr;
iap10@3290 259
iap10@3290 260 /* MSR */
iap10@3290 261 error |= __vmwrite(VM_EXIT_MSR_LOAD_ADDR, 0);
iap10@3290 262 error |= __vmwrite(VM_EXIT_MSR_STORE_ADDR, 0);
iap10@3290 263
iap10@3290 264 error |= __vmwrite(VM_EXIT_MSR_STORE_COUNT, 0);
iap10@3290 265 error |= __vmwrite(VM_EXIT_MSR_LOAD_COUNT, 0);
iap10@3290 266 error |= __vmwrite(VM_ENTRY_MSR_LOAD_COUNT, 0);
iap10@3290 267 /* interrupt */
iap10@3290 268 error |= __vmwrite(VM_ENTRY_INTR_INFO_FIELD, 0);
iap10@3290 269 /* mask */
kaf24@5658 270 error |= __vmwrite(CR0_GUEST_HOST_MASK, -1UL);
kaf24@5658 271 error |= __vmwrite(CR4_GUEST_HOST_MASK, -1UL);
iap10@3290 272
iap10@3290 273 error |= __vmwrite(PAGE_FAULT_ERROR_CODE_MASK, 0);
iap10@3290 274 error |= __vmwrite(PAGE_FAULT_ERROR_CODE_MATCH, 0);
iap10@3290 275
iap10@3290 276 /* TSC */
iap10@3290 277 error |= __vmwrite(TSC_OFFSET, 0);
iap10@3290 278 error |= __vmwrite(CR3_TARGET_COUNT, 0);
iap10@3290 279
iap10@3290 280 /* Guest Selectors */
kaf24@4683 281 error |= __vmwrite(GUEST_CS_SELECTOR, regs->cs);
kaf24@4683 282 error |= __vmwrite(GUEST_ES_SELECTOR, regs->es);
kaf24@4683 283 error |= __vmwrite(GUEST_SS_SELECTOR, regs->ss);
kaf24@4683 284 error |= __vmwrite(GUEST_DS_SELECTOR, regs->ds);
kaf24@4683 285 error |= __vmwrite(GUEST_FS_SELECTOR, regs->fs);
kaf24@4683 286 error |= __vmwrite(GUEST_GS_SELECTOR, regs->gs);
iap10@3290 287
iap10@3290 288 /* Guest segment Limits */
iap10@3290 289 error |= __vmwrite(GUEST_CS_LIMIT, GUEST_SEGMENT_LIMIT);
iap10@3290 290 error |= __vmwrite(GUEST_ES_LIMIT, GUEST_SEGMENT_LIMIT);
iap10@3290 291 error |= __vmwrite(GUEST_SS_LIMIT, GUEST_SEGMENT_LIMIT);
iap10@3290 292 error |= __vmwrite(GUEST_DS_LIMIT, GUEST_SEGMENT_LIMIT);
iap10@3290 293 error |= __vmwrite(GUEST_FS_LIMIT, GUEST_SEGMENT_LIMIT);
iap10@3290 294 error |= __vmwrite(GUEST_GS_LIMIT, GUEST_SEGMENT_LIMIT);
iap10@3290 295
iap10@3290 296 error |= __vmwrite(GUEST_IDTR_LIMIT, host_env->idtr_limit);
iap10@3290 297
iap10@3290 298 /* AR bytes */
iap10@3290 299 arbytes.bytes = 0;
iap10@3290 300 arbytes.fields.seg_type = 0x3; /* type = 3 */
iap10@3290 301 arbytes.fields.s = 1; /* code or data, i.e. not system */
iap10@3290 302 arbytes.fields.dpl = 0; /* DPL = 3 */
iap10@3290 303 arbytes.fields.p = 1; /* segment present */
iap10@3290 304 arbytes.fields.default_ops_size = 1; /* 32-bit */
iap10@3290 305 arbytes.fields.g = 1;
iap10@3290 306 arbytes.fields.null_bit = 0; /* not null */
iap10@3290 307
iap10@3290 308 error |= __vmwrite(GUEST_ES_AR_BYTES, arbytes.bytes);
iap10@3290 309 error |= __vmwrite(GUEST_SS_AR_BYTES, arbytes.bytes);
iap10@3290 310 error |= __vmwrite(GUEST_DS_AR_BYTES, arbytes.bytes);
iap10@3290 311 error |= __vmwrite(GUEST_FS_AR_BYTES, arbytes.bytes);
iap10@3290 312 error |= __vmwrite(GUEST_GS_AR_BYTES, arbytes.bytes);
iap10@3290 313
iap10@3290 314 arbytes.fields.seg_type = 0xb; /* type = 0xb */
iap10@3290 315 error |= __vmwrite(GUEST_CS_AR_BYTES, arbytes.bytes);
iap10@3290 316
kaf24@4683 317 error |= __vmwrite(GUEST_GDTR_BASE, regs->edx);
kaf24@4683 318 regs->edx = 0;
kaf24@4683 319 error |= __vmwrite(GUEST_GDTR_LIMIT, regs->eax);
kaf24@4683 320 regs->eax = 0;
iap10@3290 321
iap10@3290 322 arbytes.fields.s = 0; /* not code or data segement */
iap10@3290 323 arbytes.fields.seg_type = 0x2; /* LTD */
iap10@3290 324 arbytes.fields.default_ops_size = 0; /* 16-bit */
iap10@3290 325 arbytes.fields.g = 0;
iap10@3290 326 error |= __vmwrite(GUEST_LDTR_AR_BYTES, arbytes.bytes);
iap10@3290 327
iap10@3290 328 arbytes.fields.seg_type = 0xb; /* 32-bit TSS (busy) */
iap10@3290 329 error |= __vmwrite(GUEST_TR_AR_BYTES, arbytes.bytes);
iap10@3290 330
iap10@3290 331 error |= __vmwrite(GUEST_CR0, host_env->cr0); /* same CR0 */
iap10@3290 332
iap10@3290 333 /* Initally PG, PE are not set*/
iap10@3290 334 shadow_cr = host_env->cr0;
arun@5186 335 shadow_cr &= ~X86_CR0_PG;
iap10@3290 336 error |= __vmwrite(CR0_READ_SHADOW, shadow_cr);
kaf24@3755 337 /* CR3 is set in vmx_final_setup_guest */
kaf24@5658 338 #ifdef __x86_64__
kaf24@5727 339 error |= __vmwrite(GUEST_CR4, host_env->cr4 & ~X86_CR4_PSE);
kaf24@5658 340 #else
iap10@3290 341 error |= __vmwrite(GUEST_CR4, host_env->cr4);
kaf24@5658 342 #endif
iap10@3290 343 shadow_cr = host_env->cr4;
kaf24@5658 344
kaf24@5658 345 #ifdef __x86_64__
kaf24@5658 346 shadow_cr &= ~(X86_CR4_PGE | X86_CR4_VMXE | X86_CR4_PAE);
kaf24@5658 347 #else
iap10@3290 348 shadow_cr &= ~(X86_CR4_PGE | X86_CR4_VMXE);
kaf24@5658 349 #endif
iap10@3290 350 error |= __vmwrite(CR4_READ_SHADOW, shadow_cr);
iap10@3290 351
iap10@3290 352 error |= __vmwrite(GUEST_ES_BASE, host_env->ds_base);
iap10@3290 353 error |= __vmwrite(GUEST_CS_BASE, host_env->cs_base);
iap10@3290 354 error |= __vmwrite(GUEST_SS_BASE, host_env->ds_base);
iap10@3290 355 error |= __vmwrite(GUEST_DS_BASE, host_env->ds_base);
iap10@3290 356 error |= __vmwrite(GUEST_FS_BASE, host_env->ds_base);
iap10@3290 357 error |= __vmwrite(GUEST_GS_BASE, host_env->ds_base);
iap10@3290 358 error |= __vmwrite(GUEST_IDTR_BASE, host_env->idtr_base);
iap10@3290 359
kaf24@5414 360 error |= __vmwrite(GUEST_RSP, regs->esp);
kaf24@5414 361 error |= __vmwrite(GUEST_RIP, regs->eip);
iap10@3290 362
kaf24@4683 363 eflags = regs->eflags & ~VMCS_EFLAGS_RESERVED_0; /* clear 0s */
iap10@3290 364 eflags |= VMCS_EFLAGS_RESERVED_1; /* set 1s */
iap10@3290 365
kaf24@5414 366 error |= __vmwrite(GUEST_RFLAGS, eflags);
iap10@3290 367
iap10@3290 368 error |= __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
iap10@3290 369 __asm__ __volatile__ ("mov %%dr7, %0\n" : "=r" (dr7));
iap10@3290 370 error |= __vmwrite(GUEST_DR7, dr7);
kaf24@5414 371 error |= __vmwrite(VMCS_LINK_POINTER, 0xffffffff);
kaf24@5414 372 error |= __vmwrite(VMCS_LINK_POINTER_HIGH, 0xffffffff);
iap10@3290 373
iap10@3290 374 return error;
iap10@3290 375 }
iap10@3290 376
iap10@3290 377 static inline int construct_vmcs_host(struct host_execution_env *host_env)
iap10@3290 378 {
iap10@3290 379 int error = 0;
iap10@3290 380 unsigned long crn;
iap10@3290 381
iap10@3290 382 /* Host Selectors */
iap10@3290 383 host_env->ds_selector = __HYPERVISOR_DS;
iap10@3290 384 error |= __vmwrite(HOST_ES_SELECTOR, host_env->ds_selector);
iap10@3290 385 error |= __vmwrite(HOST_SS_SELECTOR, host_env->ds_selector);
iap10@3290 386 error |= __vmwrite(HOST_DS_SELECTOR, host_env->ds_selector);
kaf24@5658 387 #if defined (__i386__)
iap10@3290 388 error |= __vmwrite(HOST_FS_SELECTOR, host_env->ds_selector);
iap10@3290 389 error |= __vmwrite(HOST_GS_SELECTOR, host_env->ds_selector);
kaf24@5658 390 error |= __vmwrite(HOST_FS_BASE, host_env->ds_base);
kaf24@5658 391 error |= __vmwrite(HOST_GS_BASE, host_env->ds_base);
iap10@3290 392
kaf24@5658 393 #else
kaf24@5658 394 rdmsrl(MSR_FS_BASE, host_env->fs_base);
kaf24@5658 395 rdmsrl(MSR_GS_BASE, host_env->gs_base);
kaf24@5658 396 error |= __vmwrite(HOST_FS_BASE, host_env->fs_base);
kaf24@5658 397 error |= __vmwrite(HOST_GS_BASE, host_env->gs_base);
kaf24@5658 398
kaf24@5658 399 #endif
iap10@3290 400 host_env->cs_selector = __HYPERVISOR_CS;
iap10@3290 401 error |= __vmwrite(HOST_CS_SELECTOR, host_env->cs_selector);
iap10@3290 402
iap10@3290 403 host_env->ds_base = 0;
iap10@3290 404 host_env->cs_base = 0;
iap10@3290 405
kaf24@5193 406 __asm__ __volatile__ ("mov %%cr0,%0" : "=r" (crn) : );
iap10@3290 407 host_env->cr0 = crn;
iap10@3290 408 error |= __vmwrite(HOST_CR0, crn); /* same CR0 */
iap10@3290 409
iap10@3290 410 /* CR3 is set in vmx_final_setup_hostos */
kaf24@5193 411 __asm__ __volatile__ ("mov %%cr4,%0" : "=r" (crn) : );
iap10@3290 412 host_env->cr4 = crn;
iap10@3290 413 error |= __vmwrite(HOST_CR4, crn);
kaf24@5820 414
kaf24@5414 415 error |= __vmwrite(HOST_RIP, (unsigned long) vmx_asm_vmexit_handler);
kaf24@5658 416 #ifdef __x86_64__
kaf24@5658 417 /* TBD: support cr8 for 64-bit guest */
kaf24@5658 418 __vmwrite(VIRTUAL_APIC_PAGE_ADDR, 0);
kaf24@5658 419 __vmwrite(TPR_THRESHOLD, 0);
kaf24@5658 420 __vmwrite(SECONDARY_VM_EXEC_CONTROL, 0);
kaf24@5658 421 #endif
iap10@3290 422
iap10@3290 423 return error;
iap10@3290 424 }
iap10@3290 425
iap10@3290 426 /*
iap10@3290 427 * Need to extend to support full virtualization.
iap10@3290 428 * The variable use_host_env indicates if the new VMCS needs to use
iap10@3290 429 * the same setups as the host has (xenolinux).
iap10@3290 430 */
iap10@3290 431
iap10@3290 432 int construct_vmcs(struct arch_vmx_struct *arch_vmx,
kaf24@4683 433 struct cpu_user_regs *regs,
kaf24@4683 434 struct vcpu_guest_context *ctxt,
iap10@3290 435 int use_host_env)
iap10@3290 436 {
iap10@3290 437 int error;
iap10@3290 438 u64 vmcs_phys_ptr;
iap10@3290 439
iap10@3290 440 struct host_execution_env host_env;
iap10@3290 441
iap10@3290 442 if (use_host_env != VMCS_USE_HOST_ENV)
iap10@3290 443 return -EINVAL;
iap10@3290 444
iap10@3290 445 memset(&host_env, 0, sizeof(struct host_execution_env));
iap10@3290 446
iap10@3290 447 vmcs_phys_ptr = (u64) virt_to_phys(arch_vmx->vmcs);
iap10@3290 448
iap10@3290 449 if ((error = __vmpclear (vmcs_phys_ptr))) {
iap10@3290 450 printk("construct_vmcs: VMCLEAR failed\n");
iap10@3290 451 return -EINVAL;
iap10@3290 452 }
iap10@3290 453 if ((error = load_vmcs(arch_vmx, vmcs_phys_ptr))) {
iap10@3290 454 printk("construct_vmcs: load_vmcs failed: VMCS = %lx\n",
iap10@3290 455 (unsigned long) vmcs_phys_ptr);
iap10@3290 456 return -EINVAL;
iap10@3290 457 }
kaf24@5836 458 if ((error = construct_vmcs_controls(arch_vmx))) {
iap10@3290 459 printk("construct_vmcs: construct_vmcs_controls failed\n");
iap10@3290 460 return -EINVAL;
iap10@3290 461 }
iap10@3290 462 /* host selectors */
iap10@3290 463 if ((error = construct_vmcs_host(&host_env))) {
iap10@3290 464 printk("construct_vmcs: construct_vmcs_host failed\n");
iap10@3290 465 return -EINVAL;
iap10@3290 466 }
iap10@3290 467 /* guest selectors */
kaf24@4683 468 if ((error = construct_init_vmcs_guest(regs, ctxt, &host_env))) {
iap10@3290 469 printk("construct_vmcs: construct_vmcs_guest failed\n");
iap10@3290 470 return -EINVAL;
iap10@3290 471 }
iap10@3290 472
iap10@3290 473 if ((error |= __vmwrite(EXCEPTION_BITMAP,
iap10@3290 474 MONITOR_DEFAULT_EXCEPTION_BITMAP))) {
iap10@3290 475 printk("construct_vmcs: setting Exception bitmap failed\n");
iap10@3290 476 return -EINVAL;
iap10@3290 477 }
iap10@3290 478
kaf24@5821 479 if (regs->eflags & EF_TF)
kaf24@5821 480 __vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
kaf24@5821 481 else
kaf24@5821 482 __vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
kaf24@5821 483
kaf24@5821 484 return 0;
kaf24@5821 485 }
kaf24@5821 486
kaf24@5821 487 /*
kaf24@5821 488 * modify guest eflags and execption bitmap for gdb
kaf24@5821 489 */
kaf24@5821 490 int modify_vmcs(struct arch_vmx_struct *arch_vmx,
kaf24@5821 491 struct cpu_user_regs *regs)
kaf24@5821 492 {
kaf24@5821 493 int error;
kaf24@5821 494 u64 vmcs_phys_ptr, old, old_phys_ptr;
kaf24@5821 495 vmcs_phys_ptr = (u64) virt_to_phys(arch_vmx->vmcs);
kaf24@5821 496
kaf24@5821 497 old_phys_ptr = virt_to_phys(&old);
kaf24@5821 498 __vmptrst(old_phys_ptr);
kaf24@5821 499 if ((error = load_vmcs(arch_vmx, vmcs_phys_ptr))) {
kaf24@5821 500 printk("modify_vmcs: load_vmcs failed: VMCS = %lx\n",
kaf24@5821 501 (unsigned long) vmcs_phys_ptr);
kaf24@5821 502 return -EINVAL;
kaf24@5821 503 }
kaf24@5821 504 load_cpu_user_regs(regs);
kaf24@5821 505
kaf24@5821 506 __vmptrld(old_phys_ptr);
kaf24@5821 507
iap10@3290 508 return 0;
iap10@3290 509 }
iap10@3290 510
iap10@3290 511 int load_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr)
iap10@3290 512 {
iap10@3290 513 int error;
iap10@3290 514
iap10@3290 515 if ((error = __vmptrld(phys_ptr))) {
iap10@3290 516 clear_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
iap10@3290 517 return error;
iap10@3290 518 }
iap10@3290 519 set_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
iap10@3290 520 return 0;
iap10@3290 521 }
iap10@3290 522
iap10@3290 523 int store_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr)
iap10@3290 524 {
iap10@3290 525 /* take the current VMCS */
iap10@3290 526 __vmptrst(phys_ptr);
iap10@3290 527 clear_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
iap10@3290 528 return 0;
iap10@3290 529 }
iap10@3290 530
iap10@3290 531 void vm_launch_fail(unsigned long eflags)
iap10@3290 532 {
kaf24@6099 533 unsigned long error;
kaf24@6099 534 __vmread(VM_INSTRUCTION_ERROR, &error);
kaf24@6099 535 printk("<vm_launch_fail> error code %lx\n", error);
arun@5382 536 __vmx_bug(guest_cpu_user_regs());
iap10@3290 537 }
iap10@3290 538
iap10@3290 539 void vm_resume_fail(unsigned long eflags)
iap10@3290 540 {
kaf24@6099 541 unsigned long error;
kaf24@6099 542 __vmread(VM_INSTRUCTION_ERROR, &error);
kaf24@6099 543 printk("<vm_resume_fail> error code %lx\n", error);
arun@5382 544 __vmx_bug(guest_cpu_user_regs());
iap10@3290 545 }
iap10@3290 546
mafetter@3717 547 #endif /* CONFIG_VMX */
kaf24@3914 548
kaf24@3914 549 /*
kaf24@3914 550 * Local variables:
kaf24@3914 551 * mode: C
kaf24@3914 552 * c-set-style: "BSD"
kaf24@3914 553 * c-basic-offset: 4
kaf24@3914 554 * tab-width: 4
kaf24@3914 555 * indent-tabs-mode: nil
kaf24@3988 556 * End:
kaf24@3914 557 */