aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/vmx.c
diff options
context:
space:
mode:
authorGleb Natapov <gleb@redhat.com>2012-12-20 09:57:45 -0500
committerMarcelo Tosatti <mtosatti@redhat.com>2013-01-02 16:36:29 -0500
commitd99e415275dd3f757b75981adad8645cdc26da45 (patch)
tree5a5c5c21c22aba3a33d60a6e3ea50f7d4a81453a /arch/x86/kvm/vmx.c
parent89efbed02cfd7e9ce3324de0b44a70ee1c716fac (diff)
KVM: VMX: fix emulation of invalid guest state.
Currently when emulation of invalid guest state is enable (emulate_invalid_guest_state=1) segment registers are still fixed for entry to vm86 mode some times. Segment register fixing is avoided in enter_rmode(), but vmx_set_segment() still does it unconditionally. The patch fixes it. Signed-off-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kvm/vmx.c')
-rw-r--r--arch/x86/kvm/vmx.c122
1 files changed, 68 insertions, 54 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 7ebcac25725b..9dff310a2e95 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -624,6 +624,8 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu,
624 struct kvm_segment *var, int seg); 624 struct kvm_segment *var, int seg);
625static void vmx_get_segment(struct kvm_vcpu *vcpu, 625static void vmx_get_segment(struct kvm_vcpu *vcpu,
626 struct kvm_segment *var, int seg); 626 struct kvm_segment *var, int seg);
627static bool guest_state_valid(struct kvm_vcpu *vcpu);
628static u32 vmx_segment_access_rights(struct kvm_segment *var);
627 629
628static DEFINE_PER_CPU(struct vmcs *, vmxarea); 630static DEFINE_PER_CPU(struct vmcs *, vmxarea);
629static DEFINE_PER_CPU(struct vmcs *, current_vmcs); 631static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
@@ -2758,18 +2760,23 @@ static __exit void hardware_unsetup(void)
2758 free_kvm_area(); 2760 free_kvm_area();
2759} 2761}
2760 2762
2761static void fix_pmode_dataseg(struct kvm_vcpu *vcpu, int seg, struct kvm_segment *save) 2763static void fix_pmode_dataseg(struct kvm_vcpu *vcpu, int seg,
2764 struct kvm_segment *save)
2762{ 2765{
2763 const struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; 2766 if (!emulate_invalid_guest_state) {
2764 struct kvm_segment tmp = *save; 2767 /*
2765 2768 * CS and SS RPL should be equal during guest entry according
2766 if (!(vmcs_readl(sf->base) == tmp.base && tmp.s)) { 2769 * to VMX spec, but in reality it is not always so. Since vcpu
2767 tmp.base = vmcs_readl(sf->base); 2770 * is in the middle of the transition from real mode to
2768 tmp.selector = vmcs_read16(sf->selector); 2771 * protected mode it is safe to assume that RPL 0 is a good
2769 tmp.dpl = tmp.selector & SELECTOR_RPL_MASK; 2772 * default value.
2770 tmp.s = 1; 2773 */
2774 if (seg == VCPU_SREG_CS || seg == VCPU_SREG_SS)
2775 save->selector &= ~SELECTOR_RPL_MASK;
2776 save->dpl = save->selector & SELECTOR_RPL_MASK;
2777 save->s = 1;
2771 } 2778 }
2772 vmx_set_segment(vcpu, &tmp, seg); 2779 vmx_set_segment(vcpu, save, seg);
2773} 2780}
2774 2781
2775static void enter_pmode(struct kvm_vcpu *vcpu) 2782static void enter_pmode(struct kvm_vcpu *vcpu)
@@ -2777,6 +2784,17 @@ static void enter_pmode(struct kvm_vcpu *vcpu)
2777 unsigned long flags; 2784 unsigned long flags;
2778 struct vcpu_vmx *vmx = to_vmx(vcpu); 2785 struct vcpu_vmx *vmx = to_vmx(vcpu);
2779 2786
2787 /*
2788 * Update real mode segment cache. It may be not up-to-date if sement
2789 * register was written while vcpu was in a guest mode.
2790 */
2791 vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_ES], VCPU_SREG_ES);
2792 vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_DS], VCPU_SREG_DS);
2793 vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_FS], VCPU_SREG_FS);
2794 vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_GS], VCPU_SREG_GS);
2795 vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_SS], VCPU_SREG_SS);
2796 vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_CS], VCPU_SREG_CS);
2797
2780 vmx->emulation_required = 1; 2798 vmx->emulation_required = 1;
2781 vmx->rmode.vm86_active = 0; 2799 vmx->rmode.vm86_active = 0;
2782 2800
@@ -2794,22 +2812,12 @@ static void enter_pmode(struct kvm_vcpu *vcpu)
2794 2812
2795 update_exception_bitmap(vcpu); 2813 update_exception_bitmap(vcpu);
2796 2814
2797 if (emulate_invalid_guest_state) 2815 fix_pmode_dataseg(vcpu, VCPU_SREG_CS, &vmx->rmode.segs[VCPU_SREG_CS]);
2798 return; 2816 fix_pmode_dataseg(vcpu, VCPU_SREG_SS, &vmx->rmode.segs[VCPU_SREG_SS]);
2799
2800 fix_pmode_dataseg(vcpu, VCPU_SREG_ES, &vmx->rmode.segs[VCPU_SREG_ES]); 2817 fix_pmode_dataseg(vcpu, VCPU_SREG_ES, &vmx->rmode.segs[VCPU_SREG_ES]);
2801 fix_pmode_dataseg(vcpu, VCPU_SREG_DS, &vmx->rmode.segs[VCPU_SREG_DS]); 2818 fix_pmode_dataseg(vcpu, VCPU_SREG_DS, &vmx->rmode.segs[VCPU_SREG_DS]);
2802 fix_pmode_dataseg(vcpu, VCPU_SREG_FS, &vmx->rmode.segs[VCPU_SREG_FS]); 2819 fix_pmode_dataseg(vcpu, VCPU_SREG_FS, &vmx->rmode.segs[VCPU_SREG_FS]);
2803 fix_pmode_dataseg(vcpu, VCPU_SREG_GS, &vmx->rmode.segs[VCPU_SREG_GS]); 2820 fix_pmode_dataseg(vcpu, VCPU_SREG_GS, &vmx->rmode.segs[VCPU_SREG_GS]);
2804
2805 vmx_segment_cache_clear(vmx);
2806
2807 vmcs_write16(GUEST_SS_SELECTOR, 0);
2808 vmcs_write32(GUEST_SS_AR_BYTES, 0x93);
2809
2810 vmcs_write16(GUEST_CS_SELECTOR,
2811 vmcs_read16(GUEST_CS_SELECTOR) & ~SELECTOR_RPL_MASK);
2812 vmcs_write32(GUEST_CS_AR_BYTES, 0x9b);
2813} 2821}
2814 2822
2815static gva_t rmode_tss_base(struct kvm *kvm) 2823static gva_t rmode_tss_base(struct kvm *kvm)
@@ -2831,22 +2839,40 @@ static gva_t rmode_tss_base(struct kvm *kvm)
2831static void fix_rmode_seg(int seg, struct kvm_segment *save) 2839static void fix_rmode_seg(int seg, struct kvm_segment *save)
2832{ 2840{
2833 const struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; 2841 const struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
2842 struct kvm_segment var = *save;
2834 2843
2835 vmcs_write16(sf->selector, save->base >> 4); 2844 var.dpl = 0x3;
2836 vmcs_write32(sf->base, save->base & 0xffff0); 2845 if (seg == VCPU_SREG_CS)
2837 vmcs_write32(sf->limit, 0xffff); 2846 var.type = 0x3;
2838 vmcs_write32(sf->ar_bytes, 0xf3); 2847
2839 if (save->base & 0xf) 2848 if (!emulate_invalid_guest_state) {
2840 printk_once(KERN_WARNING "kvm: segment base is not paragraph" 2849 var.selector = var.base >> 4;
2841 " aligned when entering protected mode (seg=%d)", 2850 var.base = var.base & 0xffff0;
2842 seg); 2851 var.limit = 0xffff;
2852 var.g = 0;
2853 var.db = 0;
2854 var.present = 1;
2855 var.s = 1;
2856 var.l = 0;
2857 var.unusable = 0;
2858 var.type = 0x3;
2859 var.avl = 0;
2860 if (save->base & 0xf)
2861 printk_once(KERN_WARNING "kvm: segment base is not "
2862 "paragraph aligned when entering "
2863 "protected mode (seg=%d)", seg);
2864 }
2865
2866 vmcs_write16(sf->selector, var.selector);
2867 vmcs_write32(sf->base, var.base);
2868 vmcs_write32(sf->limit, var.limit);
2869 vmcs_write32(sf->ar_bytes, vmx_segment_access_rights(&var));
2843} 2870}
2844 2871
2845static void enter_rmode(struct kvm_vcpu *vcpu) 2872static void enter_rmode(struct kvm_vcpu *vcpu)
2846{ 2873{
2847 unsigned long flags; 2874 unsigned long flags;
2848 struct vcpu_vmx *vmx = to_vmx(vcpu); 2875 struct vcpu_vmx *vmx = to_vmx(vcpu);
2849 struct kvm_segment var;
2850 2876
2851 if (enable_unrestricted_guest) 2877 if (enable_unrestricted_guest)
2852 return; 2878 return;
@@ -2862,7 +2888,6 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
2862 vmx->emulation_required = 1; 2888 vmx->emulation_required = 1;
2863 vmx->rmode.vm86_active = 1; 2889 vmx->rmode.vm86_active = 1;
2864 2890
2865
2866 /* 2891 /*
2867 * Very old userspace does not call KVM_SET_TSS_ADDR before entering 2892 * Very old userspace does not call KVM_SET_TSS_ADDR before entering
2868 * vcpu. Call it here with phys address pointing 16M below 4G. 2893 * vcpu. Call it here with phys address pointing 16M below 4G.
@@ -2890,28 +2915,13 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
2890 vmcs_writel(GUEST_CR4, vmcs_readl(GUEST_CR4) | X86_CR4_VME); 2915 vmcs_writel(GUEST_CR4, vmcs_readl(GUEST_CR4) | X86_CR4_VME);
2891 update_exception_bitmap(vcpu); 2916 update_exception_bitmap(vcpu);
2892 2917
2893 if (emulate_invalid_guest_state) 2918 fix_rmode_seg(VCPU_SREG_SS, &vmx->rmode.segs[VCPU_SREG_SS]);
2894 goto continue_rmode; 2919 fix_rmode_seg(VCPU_SREG_CS, &vmx->rmode.segs[VCPU_SREG_CS]);
2895 2920 fix_rmode_seg(VCPU_SREG_ES, &vmx->rmode.segs[VCPU_SREG_ES]);
2896 vmx_get_segment(vcpu, &var, VCPU_SREG_SS); 2921 fix_rmode_seg(VCPU_SREG_DS, &vmx->rmode.segs[VCPU_SREG_DS]);
2897 vmx_set_segment(vcpu, &var, VCPU_SREG_SS); 2922 fix_rmode_seg(VCPU_SREG_GS, &vmx->rmode.segs[VCPU_SREG_GS]);
2923 fix_rmode_seg(VCPU_SREG_FS, &vmx->rmode.segs[VCPU_SREG_FS]);
2898 2924
2899 vmx_get_segment(vcpu, &var, VCPU_SREG_CS);
2900 vmx_set_segment(vcpu, &var, VCPU_SREG_CS);
2901
2902 vmx_get_segment(vcpu, &var, VCPU_SREG_ES);
2903 vmx_set_segment(vcpu, &var, VCPU_SREG_ES);
2904
2905 vmx_get_segment(vcpu, &var, VCPU_SREG_DS);
2906 vmx_set_segment(vcpu, &var, VCPU_SREG_DS);
2907
2908 vmx_get_segment(vcpu, &var, VCPU_SREG_GS);
2909 vmx_set_segment(vcpu, &var, VCPU_SREG_GS);
2910
2911 vmx_get_segment(vcpu, &var, VCPU_SREG_FS);
2912 vmx_set_segment(vcpu, &var, VCPU_SREG_FS);
2913
2914continue_rmode:
2915 kvm_mmu_reset_context(vcpu); 2925 kvm_mmu_reset_context(vcpu);
2916} 2926}
2917 2927
@@ -3278,7 +3288,7 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu,
3278 vmcs_write16(sf->selector, var->selector); 3288 vmcs_write16(sf->selector, var->selector);
3279 else if (var->s) 3289 else if (var->s)
3280 fix_rmode_seg(seg, &vmx->rmode.segs[seg]); 3290 fix_rmode_seg(seg, &vmx->rmode.segs[seg]);
3281 return; 3291 goto out;
3282 } 3292 }
3283 3293
3284 vmcs_writel(sf->base, var->base); 3294 vmcs_writel(sf->base, var->base);
@@ -3300,6 +3310,10 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu,
3300 var->type |= 0x1; /* Accessed */ 3310 var->type |= 0x1; /* Accessed */
3301 3311
3302 vmcs_write32(sf->ar_bytes, vmx_segment_access_rights(var)); 3312 vmcs_write32(sf->ar_bytes, vmx_segment_access_rights(var));
3313
3314out:
3315 if (!vmx->emulation_required)
3316 vmx->emulation_required = !guest_state_valid(vcpu);
3303} 3317}
3304 3318
3305static void vmx_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) 3319static void vmx_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)