diff options
author | Jim Mattson <jmattson@google.com> | 2018-05-09 16:56:04 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2018-05-14 12:14:25 -0400 |
commit | 588716494258899389206fa50426e78cc9df89b9 (patch) | |
tree | bdc5a412da6eb60065c0c17e374fff398cd6f47e | |
parent | ceef7d10dfb6284d512c499292e6daa35ea83f90 (diff) |
kvm: vmx: Introduce lapic_mode enumeration
The local APIC can be in one of three modes: disabled, xAPIC or
x2APIC. (A fourth mode, "invalid," is included for completeness.)
Using the new enumeration can make some of the APIC mode logic easier
to read. In kvm_set_apic_base, for instance, it is clear that one
cannot transition directly from x2APIC mode to xAPIC mode or directly
from APIC disabled to x2APIC mode.
Signed-off-by: Jim Mattson <jmattson@google.com>
Signed-off-by: Krish Sadhukhan <krish.sadhukhan@oracle.com>
[Check invalid bits even if msr_info->host_initiated. Reported by
Wanpeng Li. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r-- | arch/x86/kvm/lapic.h | 14 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 26 |
2 files changed, 29 insertions, 11 deletions
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index edce055e9fd7..ed0ed39abd36 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h | |||
@@ -16,6 +16,13 @@ | |||
16 | #define APIC_BUS_CYCLE_NS 1 | 16 | #define APIC_BUS_CYCLE_NS 1 |
17 | #define APIC_BUS_FREQUENCY (1000000000ULL / APIC_BUS_CYCLE_NS) | 17 | #define APIC_BUS_FREQUENCY (1000000000ULL / APIC_BUS_CYCLE_NS) |
18 | 18 | ||
19 | enum lapic_mode { | ||
20 | LAPIC_MODE_DISABLED = 0, | ||
21 | LAPIC_MODE_INVALID = X2APIC_ENABLE, | ||
22 | LAPIC_MODE_XAPIC = MSR_IA32_APICBASE_ENABLE, | ||
23 | LAPIC_MODE_X2APIC = MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE, | ||
24 | }; | ||
25 | |||
19 | struct kvm_timer { | 26 | struct kvm_timer { |
20 | struct hrtimer timer; | 27 | struct hrtimer timer; |
21 | s64 period; /* unit: ns */ | 28 | s64 period; /* unit: ns */ |
@@ -89,6 +96,7 @@ u64 kvm_get_apic_base(struct kvm_vcpu *vcpu); | |||
89 | int kvm_set_apic_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info); | 96 | int kvm_set_apic_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info); |
90 | int kvm_apic_get_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s); | 97 | int kvm_apic_get_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s); |
91 | int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s); | 98 | int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s); |
99 | enum lapic_mode kvm_get_apic_mode(struct kvm_vcpu *vcpu); | ||
92 | int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu); | 100 | int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu); |
93 | 101 | ||
94 | u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu); | 102 | u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu); |
@@ -220,4 +228,10 @@ void kvm_lapic_switch_to_hv_timer(struct kvm_vcpu *vcpu); | |||
220 | void kvm_lapic_expired_hv_timer(struct kvm_vcpu *vcpu); | 228 | void kvm_lapic_expired_hv_timer(struct kvm_vcpu *vcpu); |
221 | bool kvm_lapic_hv_timer_in_use(struct kvm_vcpu *vcpu); | 229 | bool kvm_lapic_hv_timer_in_use(struct kvm_vcpu *vcpu); |
222 | void kvm_lapic_restart_hv_timer(struct kvm_vcpu *vcpu); | 230 | void kvm_lapic_restart_hv_timer(struct kvm_vcpu *vcpu); |
231 | |||
232 | static inline enum lapic_mode kvm_apic_mode(u64 apic_base) | ||
233 | { | ||
234 | return apic_base & (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE); | ||
235 | } | ||
236 | |||
223 | #endif | 237 | #endif |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index e6b4e5665d74..182693f8bd71 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -318,23 +318,27 @@ u64 kvm_get_apic_base(struct kvm_vcpu *vcpu) | |||
318 | } | 318 | } |
319 | EXPORT_SYMBOL_GPL(kvm_get_apic_base); | 319 | EXPORT_SYMBOL_GPL(kvm_get_apic_base); |
320 | 320 | ||
321 | enum lapic_mode kvm_get_apic_mode(struct kvm_vcpu *vcpu) | ||
322 | { | ||
323 | return kvm_apic_mode(kvm_get_apic_base(vcpu)); | ||
324 | } | ||
325 | EXPORT_SYMBOL_GPL(kvm_get_apic_mode); | ||
326 | |||
321 | int kvm_set_apic_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info) | 327 | int kvm_set_apic_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info) |
322 | { | 328 | { |
323 | u64 old_state = vcpu->arch.apic_base & | 329 | enum lapic_mode old_mode = kvm_get_apic_mode(vcpu); |
324 | (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE); | 330 | enum lapic_mode new_mode = kvm_apic_mode(msr_info->data); |
325 | u64 new_state = msr_info->data & | ||
326 | (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE); | ||
327 | u64 reserved_bits = ((~0ULL) << cpuid_maxphyaddr(vcpu)) | 0x2ff | | 331 | u64 reserved_bits = ((~0ULL) << cpuid_maxphyaddr(vcpu)) | 0x2ff | |
328 | (guest_cpuid_has(vcpu, X86_FEATURE_X2APIC) ? 0 : X2APIC_ENABLE); | 332 | (guest_cpuid_has(vcpu, X86_FEATURE_X2APIC) ? 0 : X2APIC_ENABLE); |
329 | 333 | ||
330 | if ((msr_info->data & reserved_bits) || new_state == X2APIC_ENABLE) | 334 | if ((msr_info->data & reserved_bits) != 0 || new_mode == LAPIC_MODE_INVALID) |
331 | return 1; | ||
332 | if (!msr_info->host_initiated && | ||
333 | ((new_state == MSR_IA32_APICBASE_ENABLE && | ||
334 | old_state == (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE)) || | ||
335 | (new_state == (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE) && | ||
336 | old_state == 0))) | ||
337 | return 1; | 335 | return 1; |
336 | if (!msr_info->host_initiated) { | ||
337 | if (old_mode == LAPIC_MODE_X2APIC && new_mode == LAPIC_MODE_XAPIC) | ||
338 | return 1; | ||
339 | if (old_mode == LAPIC_MODE_DISABLED && new_mode == LAPIC_MODE_X2APIC) | ||
340 | return 1; | ||
341 | } | ||
338 | 342 | ||
339 | kvm_lapic_set_base(vcpu, msr_info->data); | 343 | kvm_lapic_set_base(vcpu, msr_info->data); |
340 | return 0; | 344 | return 0; |