diff options
author | Avi Kivity <avi@redhat.com> | 2012-08-21 10:06:58 -0400 |
---|---|---|
committer | Marcelo Tosatti <mtosatti@redhat.com> | 2012-08-27 19:02:19 -0400 |
commit | baa7e81e325bbb6ddebd7680ac1068859244b61d (patch) | |
tree | 6112cb18cfe6a8c06bdcaf5f30dbc5f3dfe69f96 /arch/x86/kvm/vmx.c | |
parent | dd856efafe6097a5c9104725c2bca74430423db8 (diff) |
KVM: VMX: Separate saving pre-realmode state from setting segments
Commit b246dd5df139 ("KVM: VMX: Fix KVM_SET_SREGS with big real mode
segments") moved fix_rmode_seg() to vmx_set_segment(), so that it is
applied not just on transitions to real mode, but also on KVM_SET_SREGS
(migration). However fix_rmode_seg() not only munges the vmcs segments,
it also sets up the save area for us to restore when returning to
protected mode or to return in vmx_get_segment().
Move saving the segment into a new function, save_rmode_seg(), and
call it just during the transition.
Signed-off-by: Avi Kivity <avi@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.c | 20 |
1 files changed, 13 insertions, 7 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 13e0296cea46..4e49caf9224d 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -2768,7 +2768,7 @@ static gva_t rmode_tss_base(struct kvm *kvm) | |||
2768 | return kvm->arch.tss_addr; | 2768 | return kvm->arch.tss_addr; |
2769 | } | 2769 | } |
2770 | 2770 | ||
2771 | static void fix_rmode_seg(int seg, struct kvm_save_segment *save) | 2771 | static void save_rmode_seg(int seg, struct kvm_save_segment *save) |
2772 | { | 2772 | { |
2773 | struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; | 2773 | struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; |
2774 | 2774 | ||
@@ -2776,6 +2776,12 @@ static void fix_rmode_seg(int seg, struct kvm_save_segment *save) | |||
2776 | save->base = vmcs_readl(sf->base); | 2776 | save->base = vmcs_readl(sf->base); |
2777 | save->limit = vmcs_read32(sf->limit); | 2777 | save->limit = vmcs_read32(sf->limit); |
2778 | save->ar = vmcs_read32(sf->ar_bytes); | 2778 | save->ar = vmcs_read32(sf->ar_bytes); |
2779 | } | ||
2780 | |||
2781 | static void fix_rmode_seg(int seg, struct kvm_save_segment *save) | ||
2782 | { | ||
2783 | struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; | ||
2784 | |||
2779 | vmcs_write16(sf->selector, save->base >> 4); | 2785 | vmcs_write16(sf->selector, save->base >> 4); |
2780 | vmcs_write32(sf->base, save->base & 0xffff0); | 2786 | vmcs_write32(sf->base, save->base & 0xffff0); |
2781 | vmcs_write32(sf->limit, 0xffff); | 2787 | vmcs_write32(sf->limit, 0xffff); |
@@ -2798,6 +2804,12 @@ static void enter_rmode(struct kvm_vcpu *vcpu) | |||
2798 | vmx->emulation_required = 1; | 2804 | vmx->emulation_required = 1; |
2799 | vmx->rmode.vm86_active = 1; | 2805 | vmx->rmode.vm86_active = 1; |
2800 | 2806 | ||
2807 | save_rmode_seg(VCPU_SREG_TR, &vmx->rmode.tr); | ||
2808 | save_rmode_seg(VCPU_SREG_ES, &vmx->rmode.es); | ||
2809 | save_rmode_seg(VCPU_SREG_DS, &vmx->rmode.ds); | ||
2810 | save_rmode_seg(VCPU_SREG_FS, &vmx->rmode.fs); | ||
2811 | save_rmode_seg(VCPU_SREG_GS, &vmx->rmode.gs); | ||
2812 | |||
2801 | /* | 2813 | /* |
2802 | * Very old userspace does not call KVM_SET_TSS_ADDR before entering | 2814 | * Very old userspace does not call KVM_SET_TSS_ADDR before entering |
2803 | * vcpu. Call it here with phys address pointing 16M below 4G. | 2815 | * vcpu. Call it here with phys address pointing 16M below 4G. |
@@ -2812,14 +2824,8 @@ static void enter_rmode(struct kvm_vcpu *vcpu) | |||
2812 | 2824 | ||
2813 | vmx_segment_cache_clear(vmx); | 2825 | vmx_segment_cache_clear(vmx); |
2814 | 2826 | ||
2815 | vmx->rmode.tr.selector = vmcs_read16(GUEST_TR_SELECTOR); | ||
2816 | vmx->rmode.tr.base = vmcs_readl(GUEST_TR_BASE); | ||
2817 | vmcs_writel(GUEST_TR_BASE, rmode_tss_base(vcpu->kvm)); | 2827 | vmcs_writel(GUEST_TR_BASE, rmode_tss_base(vcpu->kvm)); |
2818 | |||
2819 | vmx->rmode.tr.limit = vmcs_read32(GUEST_TR_LIMIT); | ||
2820 | vmcs_write32(GUEST_TR_LIMIT, RMODE_TSS_SIZE - 1); | 2828 | vmcs_write32(GUEST_TR_LIMIT, RMODE_TSS_SIZE - 1); |
2821 | |||
2822 | vmx->rmode.tr.ar = vmcs_read32(GUEST_TR_AR_BYTES); | ||
2823 | vmcs_write32(GUEST_TR_AR_BYTES, 0x008b); | 2829 | vmcs_write32(GUEST_TR_AR_BYTES, 0x008b); |
2824 | 2830 | ||
2825 | flags = vmcs_readl(GUEST_RFLAGS); | 2831 | flags = vmcs_readl(GUEST_RFLAGS); |