diff options
-rw-r--r-- | arch/x86/kvm/vmx.c | 70 |
1 files changed, 58 insertions, 12 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 396148ab089b..f78662ec8677 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -618,6 +618,10 @@ static void kvm_cpu_vmxon(u64 addr); | |||
618 | static void kvm_cpu_vmxoff(void); | 618 | static void kvm_cpu_vmxoff(void); |
619 | static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3); | 619 | static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3); |
620 | static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr); | 620 | static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr); |
621 | static void vmx_set_segment(struct kvm_vcpu *vcpu, | ||
622 | struct kvm_segment *var, int seg); | ||
623 | static void vmx_get_segment(struct kvm_vcpu *vcpu, | ||
624 | struct kvm_segment *var, int seg); | ||
621 | 625 | ||
622 | static DEFINE_PER_CPU(struct vmcs *, vmxarea); | 626 | static DEFINE_PER_CPU(struct vmcs *, vmxarea); |
623 | static DEFINE_PER_CPU(struct vmcs *, current_vmcs); | 627 | static DEFINE_PER_CPU(struct vmcs *, current_vmcs); |
@@ -2782,6 +2786,7 @@ static void enter_rmode(struct kvm_vcpu *vcpu) | |||
2782 | { | 2786 | { |
2783 | unsigned long flags; | 2787 | unsigned long flags; |
2784 | struct vcpu_vmx *vmx = to_vmx(vcpu); | 2788 | struct vcpu_vmx *vmx = to_vmx(vcpu); |
2789 | struct kvm_segment var; | ||
2785 | 2790 | ||
2786 | if (enable_unrestricted_guest) | 2791 | if (enable_unrestricted_guest) |
2787 | return; | 2792 | return; |
@@ -2825,20 +2830,23 @@ static void enter_rmode(struct kvm_vcpu *vcpu) | |||
2825 | if (emulate_invalid_guest_state) | 2830 | if (emulate_invalid_guest_state) |
2826 | goto continue_rmode; | 2831 | goto continue_rmode; |
2827 | 2832 | ||
2828 | vmcs_write16(GUEST_SS_SELECTOR, vmcs_readl(GUEST_SS_BASE) >> 4); | 2833 | vmx_get_segment(vcpu, &var, VCPU_SREG_SS); |
2829 | vmcs_write32(GUEST_SS_LIMIT, 0xffff); | 2834 | vmx_set_segment(vcpu, &var, VCPU_SREG_SS); |
2830 | vmcs_write32(GUEST_SS_AR_BYTES, 0xf3); | 2835 | |
2836 | vmx_get_segment(vcpu, &var, VCPU_SREG_CS); | ||
2837 | vmx_set_segment(vcpu, &var, VCPU_SREG_CS); | ||
2838 | |||
2839 | vmx_get_segment(vcpu, &var, VCPU_SREG_ES); | ||
2840 | vmx_set_segment(vcpu, &var, VCPU_SREG_ES); | ||
2831 | 2841 | ||
2832 | vmcs_write32(GUEST_CS_AR_BYTES, 0xf3); | 2842 | vmx_get_segment(vcpu, &var, VCPU_SREG_DS); |
2833 | vmcs_write32(GUEST_CS_LIMIT, 0xffff); | 2843 | vmx_set_segment(vcpu, &var, VCPU_SREG_DS); |
2834 | if (vmcs_readl(GUEST_CS_BASE) == 0xffff0000) | ||
2835 | vmcs_writel(GUEST_CS_BASE, 0xf0000); | ||
2836 | vmcs_write16(GUEST_CS_SELECTOR, vmcs_readl(GUEST_CS_BASE) >> 4); | ||
2837 | 2844 | ||
2838 | fix_rmode_seg(VCPU_SREG_ES, &vmx->rmode.es); | 2845 | vmx_get_segment(vcpu, &var, VCPU_SREG_GS); |
2839 | fix_rmode_seg(VCPU_SREG_DS, &vmx->rmode.ds); | 2846 | vmx_set_segment(vcpu, &var, VCPU_SREG_GS); |
2840 | fix_rmode_seg(VCPU_SREG_GS, &vmx->rmode.gs); | 2847 | |
2841 | fix_rmode_seg(VCPU_SREG_FS, &vmx->rmode.fs); | 2848 | vmx_get_segment(vcpu, &var, VCPU_SREG_FS); |
2849 | vmx_set_segment(vcpu, &var, VCPU_SREG_FS); | ||
2842 | 2850 | ||
2843 | continue_rmode: | 2851 | continue_rmode: |
2844 | kvm_mmu_reset_context(vcpu); | 2852 | kvm_mmu_reset_context(vcpu); |
@@ -3243,6 +3251,44 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu, | |||
3243 | 3251 | ||
3244 | vmcs_write32(sf->ar_bytes, ar); | 3252 | vmcs_write32(sf->ar_bytes, ar); |
3245 | __clear_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail); | 3253 | __clear_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail); |
3254 | |||
3255 | /* | ||
3256 | * Fix segments for real mode guest in hosts that don't have | ||
3257 | * "unrestricted_mode" or it was disabled. | ||
3258 | * This is done to allow migration of the guests from hosts with | ||
3259 | * unrestricted guest like Westmere to older host that don't have | ||
3260 | * unrestricted guest like Nehelem. | ||
3261 | */ | ||
3262 | if (!enable_unrestricted_guest && vmx->rmode.vm86_active) { | ||
3263 | switch (seg) { | ||
3264 | case VCPU_SREG_CS: | ||
3265 | vmcs_write32(GUEST_CS_AR_BYTES, 0xf3); | ||
3266 | vmcs_write32(GUEST_CS_LIMIT, 0xffff); | ||
3267 | if (vmcs_readl(GUEST_CS_BASE) == 0xffff0000) | ||
3268 | vmcs_writel(GUEST_CS_BASE, 0xf0000); | ||
3269 | vmcs_write16(GUEST_CS_SELECTOR, | ||
3270 | vmcs_readl(GUEST_CS_BASE) >> 4); | ||
3271 | break; | ||
3272 | case VCPU_SREG_ES: | ||
3273 | fix_rmode_seg(VCPU_SREG_ES, &vmx->rmode.es); | ||
3274 | break; | ||
3275 | case VCPU_SREG_DS: | ||
3276 | fix_rmode_seg(VCPU_SREG_DS, &vmx->rmode.ds); | ||
3277 | break; | ||
3278 | case VCPU_SREG_GS: | ||
3279 | fix_rmode_seg(VCPU_SREG_GS, &vmx->rmode.gs); | ||
3280 | break; | ||
3281 | case VCPU_SREG_FS: | ||
3282 | fix_rmode_seg(VCPU_SREG_FS, &vmx->rmode.fs); | ||
3283 | break; | ||
3284 | case VCPU_SREG_SS: | ||
3285 | vmcs_write16(GUEST_SS_SELECTOR, | ||
3286 | vmcs_readl(GUEST_SS_BASE) >> 4); | ||
3287 | vmcs_write32(GUEST_SS_LIMIT, 0xffff); | ||
3288 | vmcs_write32(GUEST_SS_AR_BYTES, 0xf3); | ||
3289 | break; | ||
3290 | } | ||
3291 | } | ||
3246 | } | 3292 | } |
3247 | 3293 | ||
3248 | static void vmx_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) | 3294 | static void vmx_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) |