diff options
author | Nadav Amit <namit@cs.technion.ac.il> | 2014-06-18 10:19:24 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2014-06-19 06:52:14 -0400 |
commit | a449c7aa51e10c9bde0ea9bee4e682d6d067ebab (patch) | |
tree | 3689ce719fd1bb431d1a250691b474ca2021a91a | |
parent | 5777392e83c96e3a0799dd2985598e0fc76cf4aa (diff) |
KVM: x86: Hypercall handling does not considers opsize correctly
Currently, the hypercall handling routine only considers LME as an indication
to whether the guest uses 32/64-bit mode. This is incosistent with hyperv
hypercalls handling and against the common sense of considering cs.l as well.
This patch uses is_64_bit_mode instead of is_long_mode for that matter. In
addition, the result is masked in respect to the guest execution mode. Last, it
changes kvm_hv_hypercall to use is_64_bit_mode as well to simplify the code.
Signed-off-by: Nadav Amit <namit@cs.technion.ac.il>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r-- | arch/x86/kvm/x86.c | 11 |
1 files changed, 6 insertions, 5 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 451d6acea808..874607ae0583 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -5669,7 +5669,6 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) | |||
5669 | u64 param, ingpa, outgpa, ret; | 5669 | u64 param, ingpa, outgpa, ret; |
5670 | uint16_t code, rep_idx, rep_cnt, res = HV_STATUS_SUCCESS, rep_done = 0; | 5670 | uint16_t code, rep_idx, rep_cnt, res = HV_STATUS_SUCCESS, rep_done = 0; |
5671 | bool fast, longmode; | 5671 | bool fast, longmode; |
5672 | int cs_db, cs_l; | ||
5673 | 5672 | ||
5674 | /* | 5673 | /* |
5675 | * hypercall generates UD from non zero cpl and real mode | 5674 | * hypercall generates UD from non zero cpl and real mode |
@@ -5680,8 +5679,7 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) | |||
5680 | return 0; | 5679 | return 0; |
5681 | } | 5680 | } |
5682 | 5681 | ||
5683 | kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); | 5682 | longmode = is_64_bit_mode(vcpu); |
5684 | longmode = is_long_mode(vcpu) && cs_l == 1; | ||
5685 | 5683 | ||
5686 | if (!longmode) { | 5684 | if (!longmode) { |
5687 | param = ((u64)kvm_register_read(vcpu, VCPU_REGS_RDX) << 32) | | 5685 | param = ((u64)kvm_register_read(vcpu, VCPU_REGS_RDX) << 32) | |
@@ -5746,7 +5744,7 @@ static void kvm_pv_kick_cpu_op(struct kvm *kvm, unsigned long flags, int apicid) | |||
5746 | int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) | 5744 | int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) |
5747 | { | 5745 | { |
5748 | unsigned long nr, a0, a1, a2, a3, ret; | 5746 | unsigned long nr, a0, a1, a2, a3, ret; |
5749 | int r = 1; | 5747 | int op_64_bit, r = 1; |
5750 | 5748 | ||
5751 | if (kvm_hv_hypercall_enabled(vcpu->kvm)) | 5749 | if (kvm_hv_hypercall_enabled(vcpu->kvm)) |
5752 | return kvm_hv_hypercall(vcpu); | 5750 | return kvm_hv_hypercall(vcpu); |
@@ -5759,7 +5757,8 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) | |||
5759 | 5757 | ||
5760 | trace_kvm_hypercall(nr, a0, a1, a2, a3); | 5758 | trace_kvm_hypercall(nr, a0, a1, a2, a3); |
5761 | 5759 | ||
5762 | if (!is_long_mode(vcpu)) { | 5760 | op_64_bit = is_64_bit_mode(vcpu); |
5761 | if (!op_64_bit) { | ||
5763 | nr &= 0xFFFFFFFF; | 5762 | nr &= 0xFFFFFFFF; |
5764 | a0 &= 0xFFFFFFFF; | 5763 | a0 &= 0xFFFFFFFF; |
5765 | a1 &= 0xFFFFFFFF; | 5764 | a1 &= 0xFFFFFFFF; |
@@ -5785,6 +5784,8 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) | |||
5785 | break; | 5784 | break; |
5786 | } | 5785 | } |
5787 | out: | 5786 | out: |
5787 | if (!op_64_bit) | ||
5788 | ret = (u32)ret; | ||
5788 | kvm_register_write(vcpu, VCPU_REGS_RAX, ret); | 5789 | kvm_register_write(vcpu, VCPU_REGS_RAX, ret); |
5789 | ++vcpu->stat.hypercalls; | 5790 | ++vcpu->stat.hypercalls; |
5790 | return r; | 5791 | return r; |