direct-io.hg

annotate xen/arch/x86/hvm/vmx/vmcs.c @ 10666:16b4abe0f925

[HVM][VMX] Clean up some writes to 64-bit VMCS fields in 32-bit Xen.
Signed-off-by: Eddie Dong <eddie.dong@intel.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Mon Jul 10 17:47:28 2006 +0100 (2006-07-10)
parents 82f481bda1c7
children 415614d3a1ee
rev   line source
kaf24@8708 1 /*
kaf24@8708 2 * vmcs.c: VMCS management
kaf24@8708 3 * Copyright (c) 2004, Intel Corporation.
kaf24@8708 4 *
kaf24@8708 5 * This program is free software; you can redistribute it and/or modify it
kaf24@8708 6 * under the terms and conditions of the GNU General Public License,
kaf24@8708 7 * version 2, as published by the Free Software Foundation.
kaf24@8708 8 *
kaf24@8708 9 * This program is distributed in the hope it will be useful, but WITHOUT
kaf24@8708 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
kaf24@8708 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
kaf24@8708 12 * more details.
kaf24@8708 13 *
kaf24@8708 14 * You should have received a copy of the GNU General Public License along with
kaf24@8708 15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
kaf24@8708 16 * Place - Suite 330, Boston, MA 02111-1307 USA.
kaf24@8708 17 */
kaf24@8708 18
kaf24@8708 19 #include <xen/config.h>
kaf24@8708 20 #include <xen/init.h>
kaf24@8708 21 #include <xen/mm.h>
kaf24@8708 22 #include <xen/lib.h>
kaf24@8708 23 #include <xen/errno.h>
kaf24@8708 24 #include <xen/domain_page.h>
kaf24@8708 25 #include <asm/current.h>
kaf24@8708 26 #include <asm/cpufeature.h>
kaf24@8708 27 #include <asm/processor.h>
kaf24@8708 28 #include <asm/msr.h>
kaf24@8708 29 #include <asm/hvm/hvm.h>
kaf24@8708 30 #include <asm/hvm/io.h>
kaf24@8708 31 #include <asm/hvm/support.h>
kaf24@8708 32 #include <asm/hvm/vmx/vmx.h>
kaf24@8708 33 #include <asm/hvm/vmx/vmcs.h>
kaf24@8708 34 #include <asm/flushtlb.h>
kaf24@8708 35 #include <xen/event.h>
kaf24@8708 36 #include <xen/kernel.h>
kaf24@8752 37 #include <asm/shadow.h>
kaf24@10011 38 #include <xen/keyhandler.h>
kaf24@10581 39
kaf24@8752 40 #if CONFIG_PAGING_LEVELS >= 3
kaf24@8708 41 #include <asm/shadow_64.h>
kaf24@8708 42 #endif
kaf24@8708 43
kfraser@10634 44 static int vmcs_size;
kfraser@10634 45 static int vmcs_order;
kfraser@10634 46 static u32 vmcs_revision_id;
kaf24@8708 47
kfraser@10634 48 void vmx_init_vmcs_config(void)
kaf24@8708 49 {
kaf24@8708 50 u32 vmx_msr_low, vmx_msr_high;
kaf24@8708 51
kfraser@10634 52 if ( vmcs_size )
kfraser@10634 53 return;
kfraser@10634 54
kaf24@8708 55 rdmsr(MSR_IA32_VMX_BASIC_MSR, vmx_msr_low, vmx_msr_high);
kfraser@10634 56
kfraser@10634 57 vmcs_revision_id = vmx_msr_low;
kfraser@10634 58
kfraser@10634 59 vmcs_size = vmx_msr_high & 0x1fff;
kfraser@10634 60 vmcs_order = get_order_from_bytes(vmcs_size);
kfraser@10634 61 }
kaf24@8708 62
kfraser@10634 63 static struct vmcs_struct *vmx_alloc_vmcs(void)
kfraser@10634 64 {
kfraser@10634 65 struct vmcs_struct *vmcs;
kfraser@10634 66
kfraser@10634 67 if ( (vmcs = alloc_xenheap_pages(vmcs_order)) == NULL )
kfraser@10634 68 {
kfraser@10634 69 DPRINTK("Failed to allocate VMCS.\n");
kfraser@10634 70 return NULL;
kfraser@10634 71 }
kfraser@10634 72
kfraser@10634 73 memset(vmcs, 0, vmcs_size); /* don't remove this */
kfraser@10634 74 vmcs->vmcs_revision_id = vmcs_revision_id;
kfraser@10634 75
kaf24@8708 76 return vmcs;
kaf24@8708 77 }
kaf24@8708 78
kfraser@10634 79 static void vmx_free_vmcs(struct vmcs_struct *vmcs)
kaf24@8708 80 {
kfraser@10634 81 free_xenheap_pages(vmcs, vmcs_order);
kaf24@8708 82 }
kaf24@8708 83
kaf24@10318 84 static void __vmx_clear_vmcs(void *info)
kaf24@8708 85 {
kaf24@10318 86 struct vcpu *v = info;
kfraser@10634 87
kaf24@10318 88 __vmpclear(virt_to_maddr(v->arch.hvm_vmx.vmcs));
kfraser@10634 89
kaf24@10318 90 v->arch.hvm_vmx.active_cpu = -1;
kaf24@10318 91 v->arch.hvm_vmx.launched = 0;
kaf24@10318 92 }
kaf24@8708 93
kaf24@10318 94 static void vmx_clear_vmcs(struct vcpu *v)
kaf24@10318 95 {
kaf24@10478 96 int cpu = v->arch.hvm_vmx.active_cpu;
kaf24@10478 97
kaf24@10478 98 if ( cpu == -1 )
kaf24@10478 99 return;
kaf24@10318 100
kaf24@10478 101 if ( cpu == smp_processor_id() )
kaf24@10478 102 return __vmx_clear_vmcs(v);
kaf24@10478 103
kaf24@10478 104 on_selected_cpus(cpumask_of_cpu(cpu), __vmx_clear_vmcs, v, 1, 1);
kaf24@10318 105 }
kaf24@10318 106
kaf24@10318 107 static void vmx_load_vmcs(struct vcpu *v)
kaf24@10318 108 {
kaf24@10318 109 __vmptrld(virt_to_maddr(v->arch.hvm_vmx.vmcs));
kaf24@10318 110 v->arch.hvm_vmx.active_cpu = smp_processor_id();
kaf24@8708 111 }
kaf24@8708 112
kaf24@10318 113 void vmx_vmcs_enter(struct vcpu *v)
kaf24@8799 114 {
kaf24@10318 115 /*
kaf24@10318 116 * NB. We must *always* run an HVM VCPU on its own VMCS, except for
kaf24@10318 117 * vmx_vmcs_enter/exit critical regions. This leads to some XXX TODOs XXX:
kaf24@10318 118 * 1. Move construct_vmcs() much earlier, to domain creation or
kaf24@10318 119 * context initialisation.
kaf24@10318 120 * 2. VMPTRLD as soon as we context-switch to a HVM VCPU.
kaf24@10318 121 * 3. VMCS destruction needs to happen later (from domain_destroy()).
kaf24@10478 122 * We can relax this a bit if a paused VCPU always commits its
kaf24@10478 123 * architectural state to a software structure.
kaf24@10318 124 */
kaf24@10318 125 if ( v == current )
kaf24@10318 126 return;
kaf24@8799 127
kaf24@10318 128 vcpu_pause(v);
kaf24@10318 129 spin_lock(&v->arch.hvm_vmx.vmcs_lock);
kaf24@8799 130
kaf24@10318 131 vmx_clear_vmcs(v);
kaf24@10318 132 vmx_load_vmcs(v);
kaf24@8799 133 }
kaf24@8799 134
kaf24@10318 135 void vmx_vmcs_exit(struct vcpu *v)
kaf24@8799 136 {
kaf24@10318 137 if ( v == current )
kaf24@10318 138 return;
kaf24@8799 139
kaf24@10318 140 /* Don't confuse arch_vmx_do_resume (for @v or @current!) */
kaf24@10318 141 vmx_clear_vmcs(v);
kaf24@10318 142 if ( hvm_guest(current) )
kaf24@10318 143 vmx_load_vmcs(current);
kaf24@10318 144
kaf24@10318 145 spin_unlock(&v->arch.hvm_vmx.vmcs_lock);
kaf24@10318 146 vcpu_unpause(v);
kaf24@8708 147 }
kaf24@8708 148
kfraser@10634 149 struct vmcs_struct *vmx_alloc_host_vmcs(void)
kfraser@10634 150 {
kfraser@10634 151 return vmx_alloc_vmcs();
kfraser@10634 152 }
kfraser@10634 153
kfraser@10634 154 void vmx_free_host_vmcs(struct vmcs_struct *vmcs)
kfraser@10634 155 {
kfraser@10634 156 vmx_free_vmcs(vmcs);
kfraser@10634 157 }
kfraser@10634 158
kaf24@8708 159 static inline int construct_vmcs_controls(struct arch_vmx_struct *arch_vmx)
kaf24@8708 160 {
kaf24@8708 161 int error = 0;
kaf24@8708 162
kaf24@8708 163 error |= __vmwrite(PIN_BASED_VM_EXEC_CONTROL,
kaf24@8708 164 MONITOR_PIN_BASED_EXEC_CONTROLS);
kaf24@8708 165
kaf24@8708 166 error |= __vmwrite(VM_EXIT_CONTROLS, MONITOR_VM_EXIT_CONTROLS);
kaf24@8708 167
kaf24@8708 168 error |= __vmwrite(VM_ENTRY_CONTROLS, MONITOR_VM_ENTRY_CONTROLS);
kaf24@8708 169
kfraser@10666 170 error |= __vmwrite(IO_BITMAP_A, virt_to_maddr(arch_vmx->io_bitmap_a));
kfraser@10666 171 error |= __vmwrite(IO_BITMAP_B, virt_to_maddr(arch_vmx->io_bitmap_b));
kfraser@10666 172
kfraser@10666 173 #ifdef CONFIG_X86_PAE
kfraser@10666 174 /* On PAE bitmaps may in future be above 4GB. Write high words. */
kfraser@10666 175 error |= __vmwrite(IO_BITMAP_A_HIGH,
kfraser@10666 176 (paddr_t)virt_to_maddr(arch_vmx->io_bitmap_a) >> 32);
kfraser@10666 177 error |= __vmwrite(IO_BITMAP_B_HIGH,
kfraser@10666 178 (paddr_t)virt_to_maddr(arch_vmx->io_bitmap_b) >> 32);
kfraser@10666 179 #endif
kaf24@8708 180
kaf24@8708 181 return error;
kaf24@8708 182 }
kaf24@8708 183
kaf24@8708 184 #define GUEST_LAUNCH_DS 0x08
kaf24@8708 185 #define GUEST_LAUNCH_CS 0x10
kaf24@8708 186 #define GUEST_SEGMENT_LIMIT 0xffffffff
kaf24@8708 187 #define HOST_SEGMENT_LIMIT 0xffffffff
kaf24@8708 188
kaf24@8708 189 struct host_execution_env {
kaf24@8708 190 /* selectors */
kaf24@8708 191 unsigned short ldtr_selector;
kaf24@8708 192 unsigned short tr_selector;
kaf24@8708 193 unsigned short ds_selector;
kaf24@8708 194 unsigned short cs_selector;
kaf24@8708 195 /* limits */
kaf24@8708 196 unsigned short gdtr_limit;
kaf24@8708 197 unsigned short ldtr_limit;
kaf24@8708 198 unsigned short idtr_limit;
kaf24@8708 199 unsigned short tr_limit;
kaf24@8708 200 /* base */
kaf24@8708 201 unsigned long gdtr_base;
kaf24@8708 202 unsigned long ldtr_base;
kaf24@8708 203 unsigned long idtr_base;
kaf24@8708 204 unsigned long tr_base;
kaf24@8708 205 unsigned long ds_base;
kaf24@8708 206 unsigned long cs_base;
kaf24@8708 207 #ifdef __x86_64__
kaf24@8708 208 unsigned long fs_base;
kaf24@8708 209 unsigned long gs_base;
kaf24@8708 210 #endif
kaf24@8708 211 };
kaf24@8708 212
kaf24@8708 213 static void vmx_set_host_env(struct vcpu *v)
kaf24@8708 214 {
kaf24@8708 215 unsigned int tr, cpu, error = 0;
kaf24@8708 216 struct host_execution_env host_env;
kaf24@8708 217 struct Xgt_desc_struct desc;
kaf24@8708 218
kaf24@8708 219 cpu = smp_processor_id();
kaf24@8708 220 __asm__ __volatile__ ("sidt (%0) \n" :: "a"(&desc) : "memory");
kaf24@8708 221 host_env.idtr_limit = desc.size;
kaf24@8708 222 host_env.idtr_base = desc.address;
kaf24@8708 223 error |= __vmwrite(HOST_IDTR_BASE, host_env.idtr_base);
kaf24@8708 224
kaf24@8708 225 __asm__ __volatile__ ("sgdt (%0) \n" :: "a"(&desc) : "memory");
kaf24@8708 226 host_env.gdtr_limit = desc.size;
kaf24@8708 227 host_env.gdtr_base = desc.address;
kaf24@8708 228 error |= __vmwrite(HOST_GDTR_BASE, host_env.gdtr_base);
kaf24@8708 229
kaf24@8708 230 __asm__ __volatile__ ("str (%0) \n" :: "a"(&tr) : "memory");
kaf24@8708 231 host_env.tr_selector = tr;
kaf24@8708 232 host_env.tr_limit = sizeof(struct tss_struct);
kaf24@8708 233 host_env.tr_base = (unsigned long) &init_tss[cpu];
kaf24@8708 234 error |= __vmwrite(HOST_TR_SELECTOR, host_env.tr_selector);
kaf24@8708 235 error |= __vmwrite(HOST_TR_BASE, host_env.tr_base);
kaf24@8799 236 error |= __vmwrite(HOST_RSP, (unsigned long)get_stack_bottom());
kaf24@8708 237 }
kaf24@8708 238
kaf24@8708 239 static void vmx_do_launch(struct vcpu *v)
kaf24@8708 240 {
kaf24@8708 241 /* Update CR3, GDT, LDT, TR */
kaf24@8708 242 unsigned int error = 0;
kaf24@8708 243 unsigned long cr0, cr4;
kaf24@8708 244
kaf24@8708 245 if (v->vcpu_id == 0)
kaf24@8708 246 hvm_setup_platform(v->domain);
kaf24@8708 247
kaf24@8935 248 if ( evtchn_bind_vcpu(iopacket_port(v), v->vcpu_id) < 0 )
kaf24@8935 249 {
kaf24@8935 250 printk("VMX domain bind port %d to vcpu %d failed!\n",
kaf24@8935 251 iopacket_port(v), v->vcpu_id);
kaf24@8935 252 domain_crash_synchronous();
kaf24@8935 253 }
kaf24@8935 254
kaf24@8935 255 HVM_DBG_LOG(DBG_LEVEL_1, "eport: %x", iopacket_port(v));
kaf24@8935 256
kaf24@8935 257 clear_bit(iopacket_port(v),
kaf24@8935 258 &v->domain->shared_info->evtchn_mask[0]);
kaf24@8935 259
kaf24@8708 260 __asm__ __volatile__ ("mov %%cr0,%0" : "=r" (cr0) : );
kaf24@8708 261
kaf24@8708 262 error |= __vmwrite(GUEST_CR0, cr0);
kaf24@8708 263 cr0 &= ~X86_CR0_PG;
kaf24@8708 264 error |= __vmwrite(CR0_READ_SHADOW, cr0);
kaf24@8708 265 error |= __vmwrite(CPU_BASED_VM_EXEC_CONTROL,
kaf24@8708 266 MONITOR_CPU_BASED_EXEC_CONTROLS);
kaf24@9195 267 v->arch.hvm_vcpu.u.vmx.exec_control = MONITOR_CPU_BASED_EXEC_CONTROLS;
kaf24@8708 268
kaf24@8708 269 __asm__ __volatile__ ("mov %%cr4,%0" : "=r" (cr4) : );
kaf24@8708 270
kaf24@8708 271 error |= __vmwrite(GUEST_CR4, cr4 & ~X86_CR4_PSE);
kaf24@8770 272 cr4 &= ~(X86_CR4_PGE | X86_CR4_VMXE | X86_CR4_PAE);
kaf24@8708 273
kaf24@8708 274 error |= __vmwrite(CR4_READ_SHADOW, cr4);
kaf24@8708 275
kaf24@8708 276 vmx_stts();
kaf24@8708 277
kaf24@8708 278 if(hvm_apic_support(v->domain))
kaf24@8708 279 vlapic_init(v);
kaf24@8708 280
kaf24@8708 281 vmx_set_host_env(v);
kaf24@8708 282 init_timer(&v->arch.hvm_vmx.hlt_timer, hlt_timer_fn, v, v->processor);
kaf24@8708 283
kaf24@8708 284 error |= __vmwrite(GUEST_LDTR_SELECTOR, 0);
kaf24@8708 285 error |= __vmwrite(GUEST_LDTR_BASE, 0);
kaf24@8708 286 error |= __vmwrite(GUEST_LDTR_LIMIT, 0);
kaf24@8708 287
kaf24@8708 288 error |= __vmwrite(GUEST_TR_BASE, 0);
kaf24@8708 289 error |= __vmwrite(GUEST_TR_LIMIT, 0xff);
kaf24@8708 290
kaf24@8708 291 __vmwrite(GUEST_CR3, pagetable_get_paddr(v->domain->arch.phys_table));
kaf24@8708 292 __vmwrite(HOST_CR3, pagetable_get_paddr(v->arch.monitor_table));
kaf24@8708 293
kaf24@8708 294 v->arch.schedule_tail = arch_vmx_do_resume;
kaf24@8708 295
kaf24@8708 296 /* init guest tsc to start from 0 */
kaf24@9324 297 set_guest_time(v, 0);
kaf24@8708 298 }
kaf24@8708 299
kaf24@8708 300 /*
kaf24@8708 301 * Initially set the same environement as host.
kaf24@8708 302 */
kaf24@8708 303 static inline int construct_init_vmcs_guest(cpu_user_regs_t *regs)
kaf24@8708 304 {
kaf24@8708 305 int error = 0;
kaf24@8708 306 union vmcs_arbytes arbytes;
kaf24@8708 307 unsigned long dr7;
kaf24@8708 308 unsigned long eflags;
kaf24@8708 309
kaf24@8708 310 /* MSR */
kaf24@8708 311 error |= __vmwrite(VM_EXIT_MSR_LOAD_ADDR, 0);
kaf24@8708 312 error |= __vmwrite(VM_EXIT_MSR_STORE_ADDR, 0);
kaf24@8708 313
kaf24@8708 314 error |= __vmwrite(VM_EXIT_MSR_STORE_COUNT, 0);
kaf24@8708 315 error |= __vmwrite(VM_EXIT_MSR_LOAD_COUNT, 0);
kaf24@8708 316 error |= __vmwrite(VM_ENTRY_MSR_LOAD_COUNT, 0);
kaf24@8708 317 /* interrupt */
kaf24@8708 318 error |= __vmwrite(VM_ENTRY_INTR_INFO_FIELD, 0);
kaf24@8708 319 /* mask */
kaf24@8708 320 error |= __vmwrite(CR0_GUEST_HOST_MASK, -1UL);
kaf24@8708 321 error |= __vmwrite(CR4_GUEST_HOST_MASK, -1UL);
kaf24@8708 322
kaf24@8708 323 error |= __vmwrite(PAGE_FAULT_ERROR_CODE_MASK, 0);
kaf24@8708 324 error |= __vmwrite(PAGE_FAULT_ERROR_CODE_MATCH, 0);
kaf24@8708 325
kaf24@8708 326 /* TSC */
kaf24@8708 327 error |= __vmwrite(CR3_TARGET_COUNT, 0);
kaf24@8708 328
kaf24@8708 329 /* Guest Selectors */
kaf24@8708 330 error |= __vmwrite(GUEST_ES_SELECTOR, GUEST_LAUNCH_DS);
kaf24@8708 331 error |= __vmwrite(GUEST_SS_SELECTOR, GUEST_LAUNCH_DS);
kaf24@8708 332 error |= __vmwrite(GUEST_DS_SELECTOR, GUEST_LAUNCH_DS);
kaf24@8708 333 error |= __vmwrite(GUEST_FS_SELECTOR, GUEST_LAUNCH_DS);
kaf24@8708 334 error |= __vmwrite(GUEST_GS_SELECTOR, GUEST_LAUNCH_DS);
kaf24@8708 335 error |= __vmwrite(GUEST_CS_SELECTOR, GUEST_LAUNCH_CS);
kaf24@8708 336
kaf24@8708 337 /* Guest segment bases */
kaf24@8708 338 error |= __vmwrite(GUEST_ES_BASE, 0);
kaf24@8708 339 error |= __vmwrite(GUEST_SS_BASE, 0);
kaf24@8708 340 error |= __vmwrite(GUEST_DS_BASE, 0);
kaf24@8708 341 error |= __vmwrite(GUEST_FS_BASE, 0);
kaf24@8708 342 error |= __vmwrite(GUEST_GS_BASE, 0);
kaf24@8708 343 error |= __vmwrite(GUEST_CS_BASE, 0);
kaf24@8708 344
kaf24@8708 345 /* Guest segment Limits */
kaf24@8708 346 error |= __vmwrite(GUEST_ES_LIMIT, GUEST_SEGMENT_LIMIT);
kaf24@8708 347 error |= __vmwrite(GUEST_SS_LIMIT, GUEST_SEGMENT_LIMIT);
kaf24@8708 348 error |= __vmwrite(GUEST_DS_LIMIT, GUEST_SEGMENT_LIMIT);
kaf24@8708 349 error |= __vmwrite(GUEST_FS_LIMIT, GUEST_SEGMENT_LIMIT);
kaf24@8708 350 error |= __vmwrite(GUEST_GS_LIMIT, GUEST_SEGMENT_LIMIT);
kaf24@8708 351 error |= __vmwrite(GUEST_CS_LIMIT, GUEST_SEGMENT_LIMIT);
kaf24@8708 352
kaf24@8708 353 /* Guest segment AR bytes */
kaf24@8708 354 arbytes.bytes = 0;
kaf24@8708 355 arbytes.fields.seg_type = 0x3; /* type = 3 */
kaf24@8708 356 arbytes.fields.s = 1; /* code or data, i.e. not system */
kaf24@8708 357 arbytes.fields.dpl = 0; /* DPL = 3 */
kaf24@8708 358 arbytes.fields.p = 1; /* segment present */
kaf24@8708 359 arbytes.fields.default_ops_size = 1; /* 32-bit */
kaf24@8708 360 arbytes.fields.g = 1;
kaf24@8708 361 arbytes.fields.null_bit = 0; /* not null */
kaf24@8708 362
kaf24@8708 363 error |= __vmwrite(GUEST_ES_AR_BYTES, arbytes.bytes);
kaf24@8708 364 error |= __vmwrite(GUEST_SS_AR_BYTES, arbytes.bytes);
kaf24@8708 365 error |= __vmwrite(GUEST_DS_AR_BYTES, arbytes.bytes);
kaf24@8708 366 error |= __vmwrite(GUEST_FS_AR_BYTES, arbytes.bytes);
kaf24@8708 367 error |= __vmwrite(GUEST_GS_AR_BYTES, arbytes.bytes);
kaf24@8708 368
kaf24@8708 369 arbytes.fields.seg_type = 0xb; /* type = 0xb */
kaf24@8708 370 error |= __vmwrite(GUEST_CS_AR_BYTES, arbytes.bytes);
kaf24@8708 371
kaf24@8708 372 /* Guest GDT */
kaf24@8708 373 error |= __vmwrite(GUEST_GDTR_BASE, 0);
kaf24@8708 374 error |= __vmwrite(GUEST_GDTR_LIMIT, 0);
kaf24@8708 375
kaf24@8708 376 /* Guest IDT */
kaf24@8708 377 error |= __vmwrite(GUEST_IDTR_BASE, 0);
kaf24@8708 378 error |= __vmwrite(GUEST_IDTR_LIMIT, 0);
kaf24@8708 379
kaf24@8708 380 /* Guest LDT & TSS */
kaf24@8708 381 arbytes.fields.s = 0; /* not code or data segement */
kaf24@8708 382 arbytes.fields.seg_type = 0x2; /* LTD */
kaf24@8708 383 arbytes.fields.default_ops_size = 0; /* 16-bit */
kaf24@8708 384 arbytes.fields.g = 0;
kaf24@8708 385 error |= __vmwrite(GUEST_LDTR_AR_BYTES, arbytes.bytes);
kaf24@8708 386
kaf24@8708 387 arbytes.fields.seg_type = 0xb; /* 32-bit TSS (busy) */
kaf24@8708 388 error |= __vmwrite(GUEST_TR_AR_BYTES, arbytes.bytes);
kaf24@8708 389 /* CR3 is set in vmx_final_setup_guest */
kaf24@8708 390
kaf24@8708 391 error |= __vmwrite(GUEST_RSP, 0);
kaf24@8708 392 error |= __vmwrite(GUEST_RIP, regs->eip);
kaf24@8708 393
kaf24@8708 394 /* Guest EFLAGS */
kaf24@8708 395 eflags = regs->eflags & ~HVM_EFLAGS_RESERVED_0; /* clear 0s */
kaf24@8708 396 eflags |= HVM_EFLAGS_RESERVED_1; /* set 1s */
kaf24@8708 397 error |= __vmwrite(GUEST_RFLAGS, eflags);
kaf24@8708 398
kaf24@8708 399 error |= __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
kaf24@8708 400 __asm__ __volatile__ ("mov %%dr7, %0\n" : "=r" (dr7));
kaf24@8708 401 error |= __vmwrite(GUEST_DR7, dr7);
kfraser@10666 402 error |= __vmwrite(VMCS_LINK_POINTER, ~0UL);
kfraser@10666 403 #if defined(__i386__)
kfraser@10666 404 error |= __vmwrite(VMCS_LINK_POINTER_HIGH, ~0UL);
kfraser@10666 405 #endif
kaf24@8708 406
kaf24@8708 407 return error;
kaf24@8708 408 }
kaf24@8708 409
kaf24@9200 410 static inline int construct_vmcs_host(void)
kaf24@8708 411 {
kaf24@8708 412 int error = 0;
kaf24@8708 413 #ifdef __x86_64__
kaf24@8708 414 unsigned long fs_base;
kaf24@8708 415 unsigned long gs_base;
kaf24@8708 416 #endif
kaf24@8708 417 unsigned long crn;
kaf24@8708 418
kaf24@8708 419 /* Host Selectors */
kaf24@8708 420 error |= __vmwrite(HOST_ES_SELECTOR, __HYPERVISOR_DS);
kaf24@8708 421 error |= __vmwrite(HOST_SS_SELECTOR, __HYPERVISOR_DS);
kaf24@8708 422 error |= __vmwrite(HOST_DS_SELECTOR, __HYPERVISOR_DS);
kfraser@10666 423 #if defined(__i386__)
kaf24@8708 424 error |= __vmwrite(HOST_FS_SELECTOR, __HYPERVISOR_DS);
kaf24@8708 425 error |= __vmwrite(HOST_GS_SELECTOR, __HYPERVISOR_DS);
kaf24@8708 426 error |= __vmwrite(HOST_FS_BASE, 0);
kaf24@8708 427 error |= __vmwrite(HOST_GS_BASE, 0);
kaf24@8708 428
kaf24@8708 429 #else
kaf24@8708 430 rdmsrl(MSR_FS_BASE, fs_base);
kaf24@8708 431 rdmsrl(MSR_GS_BASE, gs_base);
kaf24@8708 432 error |= __vmwrite(HOST_FS_BASE, fs_base);
kaf24@8708 433 error |= __vmwrite(HOST_GS_BASE, gs_base);
kaf24@8708 434
kaf24@8708 435 #endif
kaf24@8708 436 error |= __vmwrite(HOST_CS_SELECTOR, __HYPERVISOR_CS);
kaf24@8708 437
kaf24@8708 438 __asm__ __volatile__ ("mov %%cr0,%0" : "=r" (crn) : );
kaf24@8708 439 error |= __vmwrite(HOST_CR0, crn); /* same CR0 */
kaf24@8708 440
kaf24@8708 441 /* CR3 is set in vmx_final_setup_hostos */
kaf24@8708 442 __asm__ __volatile__ ("mov %%cr4,%0" : "=r" (crn) : );
kaf24@8708 443 error |= __vmwrite(HOST_CR4, crn);
kaf24@8708 444
kaf24@8708 445 error |= __vmwrite(HOST_RIP, (unsigned long) vmx_asm_vmexit_handler);
kaf24@8708 446 #ifdef __x86_64__
kaf24@8708 447 /* TBD: support cr8 for 64-bit guest */
kaf24@8708 448 __vmwrite(VIRTUAL_APIC_PAGE_ADDR, 0);
kaf24@8708 449 __vmwrite(TPR_THRESHOLD, 0);
kaf24@8708 450 __vmwrite(SECONDARY_VM_EXEC_CONTROL, 0);
kaf24@8708 451 #endif
kaf24@8708 452
kaf24@8708 453 return error;
kaf24@8708 454 }
kaf24@8708 455
kaf24@8708 456 /*
kfraser@10634 457 * the working VMCS pointer has been set properly
kfraser@10634 458 * just before entering this function.
kaf24@8708 459 */
kaf24@10318 460 static int construct_vmcs(struct vcpu *v,
kaf24@8708 461 cpu_user_regs_t *regs)
kaf24@8708 462 {
kaf24@10318 463 struct arch_vmx_struct *arch_vmx = &v->arch.hvm_vmx;
kaf24@8708 464 int error;
kaf24@8708 465
kfraser@10634 466 if ( (error = construct_vmcs_controls(arch_vmx)) ) {
kfraser@10634 467 printk("construct_vmcs: construct_vmcs_controls failed.\n");
kfraser@10634 468 return error;
kaf24@8708 469 }
kaf24@10318 470
kaf24@8708 471 /* host selectors */
kfraser@10634 472 if ( (error = construct_vmcs_host()) ) {
kfraser@10634 473 printk("construct_vmcs: construct_vmcs_host failed.\n");
kfraser@10634 474 return error;
kaf24@8708 475 }
kaf24@10318 476
kaf24@8708 477 /* guest selectors */
kfraser@10634 478 if ( (error = construct_init_vmcs_guest(regs)) ) {
kfraser@10634 479 printk("construct_vmcs: construct_vmcs_guest failed.\n");
kfraser@10634 480 return error;
kfraser@10634 481 }
kfraser@10634 482
kfraser@10634 483 if ( (error = __vmwrite(EXCEPTION_BITMAP,
kfraser@10634 484 MONITOR_DEFAULT_EXCEPTION_BITMAP)) ) {
kfraser@10634 485 printk("construct_vmcs: setting exception bitmap failed.\n");
kfraser@10634 486 return error;
kaf24@8708 487 }
kaf24@10318 488
kfraser@10634 489 if ( regs->eflags & EF_TF )
kfraser@10634 490 error = __vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
kfraser@10634 491 else
kfraser@10634 492 error = __vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
kaf24@8708 493
kfraser@10634 494 return error;
kfraser@10634 495 }
kaf24@8708 496
kfraser@10634 497 int vmx_create_vmcs(struct vcpu *v)
kfraser@10634 498 {
kfraser@10634 499 if ( (v->arch.hvm_vmx.vmcs = vmx_alloc_vmcs()) == NULL )
kfraser@10634 500 return -ENOMEM;
kfraser@10634 501 __vmx_clear_vmcs(v);
kaf24@8708 502 return 0;
kaf24@8708 503 }
kaf24@8708 504
kaf24@10318 505 void vmx_destroy_vmcs(struct vcpu *v)
kaf24@8708 506 {
kaf24@10318 507 struct arch_vmx_struct *arch_vmx = &v->arch.hvm_vmx;
kaf24@10318 508
kaf24@10581 509 if ( arch_vmx->vmcs == NULL )
kaf24@10581 510 return;
kaf24@10581 511
kaf24@10318 512 vmx_clear_vmcs(v);
kaf24@10318 513
kfraser@10634 514 free_xenheap_pages(arch_vmx->io_bitmap_a, IO_BITMAP_ORDER);
kfraser@10634 515 free_xenheap_pages(arch_vmx->io_bitmap_b, IO_BITMAP_ORDER);
kaf24@8708 516
kaf24@8708 517 arch_vmx->io_bitmap_a = NULL;
kfraser@10634 518 arch_vmx->io_bitmap_b = NULL;
kaf24@8708 519
kfraser@10634 520 vmx_free_vmcs(arch_vmx->vmcs);
kfraser@10634 521 arch_vmx->vmcs = NULL;
kaf24@8708 522 }
kaf24@8708 523
kaf24@8708 524 void vm_launch_fail(unsigned long eflags)
kaf24@8708 525 {
kaf24@8708 526 unsigned long error;
kaf24@8708 527 __vmread(VM_INSTRUCTION_ERROR, &error);
kaf24@8708 528 printk("<vm_launch_fail> error code %lx\n", error);
kaf24@8708 529 __hvm_bug(guest_cpu_user_regs());
kaf24@8708 530 }
kaf24@8708 531
kaf24@8708 532 void vm_resume_fail(unsigned long eflags)
kaf24@8708 533 {
kaf24@8708 534 unsigned long error;
kaf24@8708 535 __vmread(VM_INSTRUCTION_ERROR, &error);
kaf24@8708 536 printk("<vm_resume_fail> error code %lx\n", error);
kaf24@8708 537 __hvm_bug(guest_cpu_user_regs());
kaf24@8708 538 }
kaf24@8708 539
kaf24@8708 540 void arch_vmx_do_resume(struct vcpu *v)
kaf24@8708 541 {
kaf24@10318 542 if ( v->arch.hvm_vmx.active_cpu == smp_processor_id() )
kaf24@8708 543 {
kaf24@10318 544 vmx_load_vmcs(v);
kaf24@8708 545 }
kaf24@8708 546 else
kaf24@8708 547 {
kaf24@10318 548 vmx_clear_vmcs(v);
kaf24@10318 549 vmx_load_vmcs(v);
kaf24@8799 550 vmx_migrate_timers(v);
kaf24@8799 551 vmx_set_host_env(v);
kaf24@8708 552 }
kaf24@10318 553
kaf24@10318 554 vmx_do_resume(v);
kaf24@10318 555 reset_stack_and_jump(vmx_asm_do_vmentry);
kaf24@8708 556 }
kaf24@8708 557
kaf24@8708 558 void arch_vmx_do_launch(struct vcpu *v)
kaf24@8708 559 {
kaf24@8708 560 cpu_user_regs_t *regs = &current->arch.guest_context.user_regs;
kaf24@8708 561
kfraser@10634 562 vmx_load_vmcs(v);
kfraser@10634 563
kfraser@10634 564 if ( construct_vmcs(v, regs) < 0 )
kaf24@8708 565 {
kfraser@10634 566 if ( v->vcpu_id == 0 ) {
kfraser@10634 567 printk("Failed to construct VMCS for BSP.\n");
kaf24@8708 568 } else {
kfraser@10634 569 printk("Failed to construct VMCS for AP %d.\n", v->vcpu_id);
kaf24@8708 570 }
kaf24@8708 571 domain_crash_synchronous();
kaf24@8708 572 }
kfraser@10634 573
kaf24@8708 574 vmx_do_launch(v);
kaf24@10318 575 reset_stack_and_jump(vmx_asm_do_vmentry);
kaf24@8708 576 }
kaf24@8708 577
kaf24@10011 578
kaf24@10011 579 /* Dump a section of VMCS */
kaf24@10011 580 static void print_section(char *header, uint32_t start,
kaf24@10011 581 uint32_t end, int incr)
kaf24@10011 582 {
kaf24@10011 583 uint32_t addr, j;
kaf24@10011 584 unsigned long val;
kaf24@10011 585 int code;
kaf24@10011 586 char *fmt[4] = {"0x%04lx ", "0x%016lx ", "0x%08lx ", "0x%016lx "};
kaf24@10011 587 char *err[4] = {"------ ", "------------------ ",
kaf24@10011 588 "---------- ", "------------------ "};
kaf24@10011 589
kaf24@10011 590 /* Find width of the field (encoded in bits 14:13 of address) */
kaf24@10011 591 code = (start>>13)&3;
kaf24@10011 592
kaf24@10011 593 if (header)
kaf24@10011 594 printk("\t %s", header);
kaf24@10011 595
kaf24@10011 596 for (addr=start, j=0; addr<=end; addr+=incr, j++) {
kaf24@10011 597
kaf24@10011 598 if (!(j&3))
kaf24@10011 599 printk("\n\t\t0x%08x: ", addr);
kaf24@10011 600
kaf24@10011 601 if (!__vmread(addr, &val))
kaf24@10011 602 printk(fmt[code], val);
kaf24@10011 603 else
kaf24@10011 604 printk("%s", err[code]);
kaf24@10011 605 }
kaf24@10011 606
kaf24@10011 607 printk("\n");
kaf24@10011 608 }
kaf24@10011 609
kaf24@10011 610 /* Dump current VMCS */
kaf24@10011 611 void vmcs_dump_vcpu(void)
kaf24@10011 612 {
kaf24@10011 613 print_section("16-bit Guest-State Fields", 0x800, 0x80e, 2);
kaf24@10011 614 print_section("16-bit Host-State Fields", 0xc00, 0xc0c, 2);
kaf24@10011 615 print_section("64-bit Control Fields", 0x2000, 0x2013, 1);
kaf24@10011 616 print_section("64-bit Guest-State Fields", 0x2800, 0x2803, 1);
kaf24@10011 617 print_section("32-bit Control Fields", 0x4000, 0x401c, 2);
kaf24@10011 618 print_section("32-bit RO Data Fields", 0x4400, 0x440e, 2);
kaf24@10011 619 print_section("32-bit Guest-State Fields", 0x4800, 0x482a, 2);
kaf24@10011 620 print_section("32-bit Host-State Fields", 0x4c00, 0x4c00, 2);
kaf24@10011 621 print_section("Natural 64-bit Control Fields", 0x6000, 0x600e, 2);
kaf24@10011 622 print_section("64-bit RO Data Fields", 0x6400, 0x640A, 2);
kaf24@10011 623 print_section("Natural 64-bit Guest-State Fields", 0x6800, 0x6826, 2);
kaf24@10011 624 print_section("Natural 64-bit Host-State Fields", 0x6c00, 0x6c16, 2);
kaf24@10011 625 }
kaf24@10011 626
kaf24@10011 627
kaf24@10011 628 static void vmcs_dump(unsigned char ch)
kaf24@10011 629 {
kaf24@10011 630 struct domain *d;
kaf24@10011 631 struct vcpu *v;
kaf24@10011 632
kaf24@10011 633 printk("*********** VMCS Areas **************\n");
kaf24@10011 634 for_each_domain(d) {
kaf24@10011 635 printk("\n>>> Domain %d <<<\n", d->domain_id);
kaf24@10011 636 for_each_vcpu(d, v) {
kaf24@10011 637
kaf24@10011 638 /*
kaf24@10011 639 * Presumably, if a domain is not an HVM guest,
kaf24@10011 640 * the very first CPU will not pass this test
kaf24@10011 641 */
kaf24@10011 642 if (!hvm_guest(v)) {
kaf24@10011 643 printk("\t\tNot HVM guest\n");
kaf24@10011 644 break;
kaf24@10011 645 }
kaf24@10011 646 printk("\tVCPU %d\n", v->vcpu_id);
kaf24@10011 647
kaf24@10318 648 vmx_vmcs_enter(v);
kaf24@10011 649 vmcs_dump_vcpu();
kaf24@10318 650 vmx_vmcs_exit(v);
kaf24@10011 651 }
kaf24@10011 652 }
kaf24@10011 653
kaf24@10011 654 printk("**************************************\n");
kaf24@10011 655 }
kaf24@10011 656
kaf24@10011 657 static int __init setup_vmcs_dump(void)
kaf24@10011 658 {
kaf24@10011 659 register_keyhandler('v', vmcs_dump, "dump Intel's VMCS");
kaf24@10011 660 return 0;
kaf24@10011 661 }
kaf24@10011 662
kaf24@10011 663 __initcall(setup_vmcs_dump);
kaf24@10011 664
kaf24@8708 665 /*
kaf24@8708 666 * Local variables:
kaf24@8708 667 * mode: C
kaf24@8708 668 * c-set-style: "BSD"
kaf24@8708 669 * c-basic-offset: 4
kaf24@8708 670 * tab-width: 4
kaf24@8708 671 * indent-tabs-mode: nil
kaf24@8708 672 * End:
kaf24@8708 673 */