xen-vtx-unstable

annotate xen/arch/x86/vmx_vmcs.c @ 6776:e7c7196fa329

merge?
author cl349@firebug.cl.cam.ac.uk
date Tue Sep 13 15:46:49 2005 +0000 (2005-09-13)
parents 4d899a738d59 cdfa7dd00c44
children 72e4e2aab342
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 */