diff options
Diffstat (limited to 'xen/arch/x86/hvm/vmx/vmx.c')
-rw-r--r-- | xen/arch/x86/hvm/vmx/vmx.c | 218 |
1 files changed, 54 insertions, 164 deletions
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 658ee8ae73..0233f26595 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -26,9 +26,9 @@ #include <xen/softirq.h> #include <xen/domain_page.h> #include <xen/hypercall.h> +#include <xen/perfc.h> #include <asm/current.h> #include <asm/io.h> -#include <asm/shadow.h> #include <asm/regs.h> #include <asm/cpufeature.h> #include <asm/processor.h> @@ -40,10 +40,7 @@ #include <asm/hvm/vmx/vmx.h> #include <asm/hvm/vmx/vmcs.h> #include <asm/hvm/vmx/cpu.h> -#include <asm/shadow.h> -#if CONFIG_PAGING_LEVELS >= 3 -#include <asm/shadow_64.h> -#endif +#include <asm/shadow2.h> #include <public/sched.h> #include <public/hvm/ioreq.h> #include <asm/hvm/vpic.h> @@ -69,11 +66,16 @@ static int vmx_initialize_guest_resources(struct vcpu *v) if ( v->vcpu_id != 0 ) return 1; - for_each_vcpu ( d, vc ) + if ( !shadow2_mode_external(d) ) { - /* Initialize monitor page table */ - vc->arch.monitor_table = pagetable_null(); + DPRINTK("Can't init HVM for dom %u vcpu %u: " + "not in shadow2 external mode\n", + d->domain_id, v->vcpu_id); + domain_crash(d); + } + for_each_vcpu ( d, vc ) + { memset(&vc->arch.hvm_vmx, 0, sizeof(struct arch_vmx_struct)); if ( (rc = vmx_create_vmcs(vc)) != 0 ) @@ -107,6 +109,7 @@ static int vmx_initialize_guest_resources(struct vcpu *v) vc->arch.hvm_vmx.io_bitmap_a = io_bitmap_a; vc->arch.hvm_vmx.io_bitmap_b = io_bitmap_b; + } /* @@ -116,11 +119,6 @@ static int vmx_initialize_guest_resources(struct vcpu *v) memset(&d->shared_info->evtchn_mask[0], 0xff, sizeof(d->shared_info->evtchn_mask)); - /* Put the domain in shadow mode even though we're going to be using - * the shared 1:1 page table initially. It shouldn't hurt */ - shadow_mode_enable( - d, SHM_enable|SHM_refcounts|SHM_translate|SHM_external|SHM_wr_pt_pte); - return 1; } @@ -133,7 +131,6 @@ static void vmx_relinquish_guest_resources(struct domain *d) vmx_destroy_vmcs(v); if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) ) continue; - free_monitor_pagetable(v); kill_timer(&v->arch.hvm_vcpu.hlt_timer); if ( hvm_apic_support(v->domain) && (VLAPIC(v) != NULL) ) { @@ -153,8 +150,6 @@ static void vmx_relinquish_guest_resources(struct domain *d) if ( d->arch.hvm_domain.buffered_io_va ) unmap_domain_page_global((void *)d->arch.hvm_domain.buffered_io_va); - - shadow_direct_map_clean(d); } #ifdef __x86_64__ @@ -595,14 +590,6 @@ static void vmx_load_cpu_guest_regs(struct vcpu *v, struct cpu_user_regs *regs) vmx_vmcs_exit(v); } -static int vmx_realmode(struct vcpu *v) -{ - unsigned long rflags; - - __vmread(GUEST_RFLAGS, &rflags); - return rflags & X86_EFLAGS_VM; -} - static int vmx_instruction_length(struct vcpu *v) { unsigned long inst_len; @@ -622,6 +609,8 @@ static unsigned long vmx_get_ctrl_reg(struct vcpu *v, unsigned int num) return v->arch.hvm_vmx.cpu_cr2; case 3: return v->arch.hvm_vmx.cpu_cr3; + case 4: + return v->arch.hvm_vmx.cpu_shadow_cr4; default: BUG(); } @@ -753,9 +742,13 @@ static void vmx_setup_hvm_funcs(void) hvm_funcs.realmode = vmx_realmode; hvm_funcs.paging_enabled = vmx_paging_enabled; + hvm_funcs.long_mode_enabled = vmx_long_mode_enabled; + hvm_funcs.guest_x86_mode = vmx_guest_x86_mode; hvm_funcs.instruction_length = vmx_instruction_length; hvm_funcs.get_guest_ctrl_reg = vmx_get_ctrl_reg; + hvm_funcs.update_host_cr3 = vmx_update_host_cr3; + hvm_funcs.stts = vmx_stts; hvm_funcs.set_tsc_offset = vmx_set_tsc_offset; @@ -855,53 +848,25 @@ static void inline __update_guest_eip(unsigned long inst_len) __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0); } - static int vmx_do_page_fault(unsigned long va, struct cpu_user_regs *regs) { - unsigned long gpa; /* FIXME: PAE */ int result; #if 0 /* keep for debugging */ { - unsigned long eip; + unsigned long eip, cs; + __vmread(GUEST_CS_BASE, &cs); __vmread(GUEST_RIP, &eip); HVM_DBG_LOG(DBG_LEVEL_VMMU, - "vmx_do_page_fault = 0x%lx, eip = %lx, error_code = %lx", - va, eip, (unsigned long)regs->error_code); + "vmx_do_page_fault = 0x%lx, cs_base=%lx, " + "eip = %lx, error_code = %lx\n", + va, cs, eip, (unsigned long)regs->error_code); } #endif - if ( !vmx_paging_enabled(current) ) - { - /* construct 1-to-1 direct mapping */ - if ( shadow_direct_map_fault(va, regs) ) - return 1; - - handle_mmio(va, va); - TRACE_VMEXIT (2,2); - return 1; - } - gpa = gva_to_gpa(va); - - /* Use 1:1 page table to identify MMIO address space */ - if ( mmio_space(gpa) ){ - struct vcpu *v = current; - /* No support for APIC */ - if (!hvm_apic_support(v->domain) && gpa >= 0xFEC00000) { - u32 inst_len; - __vmread(VM_EXIT_INSTRUCTION_LEN, &(inst_len)); - __update_guest_eip(inst_len); - return 1; - } - TRACE_VMEXIT (2,2); - /* in the case of MMIO, we are more interested in gpa than in va */ - TRACE_VMEXIT (4,gpa); - handle_mmio(va, gpa); - return 1; - } + result = shadow2_fault(va, regs); - result = shadow_fault(va, regs); TRACE_VMEXIT (2,result); #if 0 if ( !result ) @@ -972,23 +937,11 @@ static void vmx_vmexit_do_cpuid(struct cpu_user_regs *regs) clear_bit(X86_FEATURE_APIC, &edx); } -#if CONFIG_PAGING_LEVELS < 3 - edx &= ~(bitmaskof(X86_FEATURE_PAE) | - bitmaskof(X86_FEATURE_PSE) | - bitmaskof(X86_FEATURE_PSE36)); -#else - if ( v->domain->arch.ops->guest_paging_levels == PAGING_L2 ) - { - if ( v->domain->arch.hvm_domain.params[HVM_PARAM_PAE_ENABLED] ) - clear_bit(X86_FEATURE_PSE36, &edx); - else - { - clear_bit(X86_FEATURE_PAE, &edx); - clear_bit(X86_FEATURE_PSE, &edx); - clear_bit(X86_FEATURE_PSE36, &edx); - } - } +#if CONFIG_PAGING_LEVELS >= 3 + if ( !v->domain->arch.hvm_domain.params[HVM_PARAM_PAE_ENABLED] ) #endif + clear_bit(X86_FEATURE_PAE, &edx); + clear_bit(X86_FEATURE_PSE36, &edx); ebx &= NUM_THREADS_RESET_MASK; @@ -1086,7 +1039,7 @@ static void vmx_vmexit_do_invlpg(unsigned long va) * We do the safest things first, then try to update the shadow * copying from guest */ - shadow_invlpg(v, va); + shadow2_invlpg(v, va); } @@ -1307,11 +1260,8 @@ vmx_world_restore(struct vcpu *v, struct vmx_assist_context *c) error |= __vmwrite(CR0_READ_SHADOW, c->cr0); - if (!vmx_paging_enabled(v)) { - HVM_DBG_LOG(DBG_LEVEL_VMMU, "switching to vmxassist. use phys table"); - __vmwrite(GUEST_CR3, pagetable_get_paddr(v->domain->arch.phys_table)); + if (!vmx_paging_enabled(v)) goto skip_cr3; - } if (c->cr3 == v->arch.hvm_vmx.cpu_cr3) { /* @@ -1325,7 +1275,6 @@ vmx_world_restore(struct vcpu *v, struct vmx_assist_context *c) domain_crash_synchronous(); return 0; } - shadow_sync_all(v->domain); } else { /* * If different, make a shadow. Check if the PDBR is valid @@ -1348,13 +1297,17 @@ vmx_world_restore(struct vcpu *v, struct vmx_assist_context *c) * arch.shadow_table should now hold the next CR3 for shadow */ v->arch.hvm_vmx.cpu_cr3 = c->cr3; - update_pagetables(v); - HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR3 value = %x", c->cr3); - __vmwrite(GUEST_CR3, pagetable_get_paddr(v->arch.shadow_table)); } skip_cr3: + shadow2_update_paging_modes(v); + if (!vmx_paging_enabled(v)) + HVM_DBG_LOG(DBG_LEVEL_VMMU, "switching to vmxassist. use phys table"); + else + HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR3 value = %x", c->cr3); + __vmwrite(GUEST_CR3, v->arch.hvm_vcpu.hw_cr3); + error |= __vmread(CR4_READ_SHADOW, &old_cr4); error |= __vmwrite(GUEST_CR4, (c->cr4 | VMX_CR4_HOST_MASK)); error |= __vmwrite(CR4_READ_SHADOW, c->cr4); @@ -1485,6 +1438,7 @@ static int vmx_set_cr0(unsigned long value) int paging_enabled; unsigned long vm_entry_value; unsigned long old_cr0; + unsigned long old_base_mfn; /* * CR0: We don't want to lose PE and PG. @@ -1514,7 +1468,8 @@ static int vmx_set_cr0(unsigned long value) v->arch.hvm_vmx.cpu_cr3 >> PAGE_SHIFT)) || !get_page(mfn_to_page(mfn), v->domain) ) { - printk("Invalid CR3 value = %lx", v->arch.hvm_vmx.cpu_cr3); + printk("Invalid CR3 value = %lx (mfn=%lx)\n", + v->arch.hvm_vmx.cpu_cr3, mfn); domain_crash_synchronous(); /* need to take a clean path */ } @@ -1539,51 +1494,22 @@ static int vmx_set_cr0(unsigned long value) __vmread(VM_ENTRY_CONTROLS, &vm_entry_value); vm_entry_value |= VM_ENTRY_CONTROLS_IA32E_MODE; __vmwrite(VM_ENTRY_CONTROLS, vm_entry_value); - - if ( !shadow_set_guest_paging_levels(v->domain, PAGING_L4) ) - { - printk("Unsupported guest paging levels\n"); - domain_crash_synchronous(); /* need to take a clean path */ - } } - else -#endif /* __x86_64__ */ - { -#if CONFIG_PAGING_LEVELS >= 3 - /* seems it's a 32-bit or 32-bit PAE guest */ - - if ( test_bit(VMX_CPU_STATE_PAE_ENABLED, - &v->arch.hvm_vmx.cpu_state) ) - { - /* The guest enables PAE first and then it enables PG, it is - * really a PAE guest */ - if ( !shadow_set_guest_paging_levels(v->domain, PAGING_L3) ) - { - printk("Unsupported guest paging levels\n"); - domain_crash_synchronous(); - } - } - else - { - if ( !shadow_set_guest_paging_levels(v->domain, PAGING_L2) ) - { - printk("Unsupported guest paging levels\n"); - domain_crash_synchronous(); /* need to take a clean path */ - } - } #endif - } /* * Now arch.guest_table points to machine physical. */ + old_base_mfn = pagetable_get_pfn(v->arch.guest_table); v->arch.guest_table = pagetable_from_pfn(mfn); - update_pagetables(v); + if (old_base_mfn) + put_page(mfn_to_page(old_base_mfn)); + shadow2_update_paging_modes(v); HVM_DBG_LOG(DBG_LEVEL_VMMU, "New arch.guest_table = %lx", (unsigned long) (mfn << PAGE_SHIFT)); - __vmwrite(GUEST_CR3, pagetable_get_paddr(v->arch.shadow_table)); + __vmwrite(GUEST_CR3, v->arch.hvm_vcpu.hw_cr3); /* * arch->shadow_table should hold the next CR3 for shadow */ @@ -1625,7 +1551,6 @@ static int vmx_set_cr0(unsigned long value) } } - clear_all_shadow_status(v->domain); if ( vmx_assist(v, VMX_ASSIST_INVOKE) ) { set_bit(VMX_CPU_STATE_ASSIST_ENABLED, &v->arch.hvm_vmx.cpu_state); __vmread(GUEST_RIP, &eip); @@ -1651,9 +1576,8 @@ static int vmx_set_cr0(unsigned long value) } else if ( (value & (X86_CR0_PE | X86_CR0_PG)) == X86_CR0_PE ) { - /* we should take care of this kind of situation */ - clear_all_shadow_status(v->domain); - __vmwrite(GUEST_CR3, pagetable_get_paddr(v->domain->arch.phys_table)); + __vmwrite(GUEST_CR3, v->arch.hvm_vcpu.hw_cr3); + shadow2_update_paging_modes(v); } return 1; @@ -1738,7 +1662,7 @@ static int mov_to_cr(int gp, int cr, struct cpu_user_regs *regs) mfn = get_mfn_from_gpfn(value >> PAGE_SHIFT); if (mfn != pagetable_get_pfn(v->arch.guest_table)) __hvm_bug(regs); - shadow_sync_all(v->domain); + shadow2_update_cr3(v); } else { /* * If different, make a shadow. Check if the PDBR is valid @@ -1759,16 +1683,11 @@ static int mov_to_cr(int gp, int cr, struct cpu_user_regs *regs) /* * arch.shadow_table should now hold the next CR3 for shadow */ -#if CONFIG_PAGING_LEVELS >= 3 - if ( v->domain->arch.ops->guest_paging_levels == PAGING_L3 ) - shadow_sync_all(v->domain); -#endif - v->arch.hvm_vmx.cpu_cr3 = value; - update_pagetables(v); + update_cr3(v); HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR3 value = %lx", value); - __vmwrite(GUEST_CR3, pagetable_get_paddr(v->arch.shadow_table)); + __vmwrite(GUEST_CR3, v->arch.hvm_vcpu.hw_cr3); } break; } @@ -1786,12 +1705,6 @@ static int mov_to_cr(int gp, int cr, struct cpu_user_regs *regs) #if CONFIG_PAGING_LEVELS >= 3 unsigned long mfn, old_base_mfn; - if( !shadow_set_guest_paging_levels(v->domain, PAGING_L3) ) - { - printk("Unsupported guest paging levels\n"); - domain_crash_synchronous(); /* need to take a clean path */ - } - if ( !VALID_MFN(mfn = get_mfn_from_gpfn( v->arch.hvm_vmx.cpu_cr3 >> PAGE_SHIFT)) || !get_page(mfn_to_page(mfn), v->domain) ) @@ -1800,21 +1713,20 @@ static int mov_to_cr(int gp, int cr, struct cpu_user_regs *regs) domain_crash_synchronous(); /* need to take a clean path */ } - old_base_mfn = pagetable_get_pfn(v->arch.guest_table); - if ( old_base_mfn ) - put_page(mfn_to_page(old_base_mfn)); /* * Now arch.guest_table points to machine physical. */ + old_base_mfn = pagetable_get_pfn(v->arch.guest_table); v->arch.guest_table = pagetable_from_pfn(mfn); - update_pagetables(v); + if ( old_base_mfn ) + put_page(mfn_to_page(old_base_mfn)); HVM_DBG_LOG(DBG_LEVEL_VMMU, "New arch.guest_table = %lx", (unsigned long) (mfn << PAGE_SHIFT)); - __vmwrite(GUEST_CR3, pagetable_get_paddr(v->arch.shadow_table)); + __vmwrite(GUEST_CR3, v->arch.hvm_vcpu.hw_cr3); /* * arch->shadow_table should hold the next CR3 for shadow @@ -1824,27 +1736,6 @@ static int mov_to_cr(int gp, int cr, struct cpu_user_regs *regs) v->arch.hvm_vmx.cpu_cr3, mfn); #endif } - else - { - /* The guest is a 64 bit or 32-bit PAE guest. */ -#if CONFIG_PAGING_LEVELS >= 3 - if ( (v->domain->arch.ops != NULL) && - v->domain->arch.ops->guest_paging_levels == PAGING_L2) - { - /* Seems the guest first enables PAE without enabling PG, - * it must enable PG after that, and it is a 32-bit PAE - * guest */ - - if ( !shadow_set_guest_paging_levels(v->domain, - PAGING_L3) ) - { - printk("Unsupported guest paging levels\n"); - /* need to take a clean path */ - domain_crash_synchronous(); - } - } -#endif - } } else if ( value & X86_CR4_PAE ) set_bit(VMX_CPU_STATE_PAE_ENABLED, &v->arch.hvm_vmx.cpu_state); @@ -1864,8 +1755,7 @@ static int mov_to_cr(int gp, int cr, struct cpu_user_regs *regs) * all TLB entries except global entries. */ if ( (old_cr ^ value) & (X86_CR4_PSE | X86_CR4_PGE | X86_CR4_PAE) ) - shadow_sync_all(v->domain); - + shadow2_update_paging_modes(v); break; } default: |