|
@@ -257,10 +257,26 @@ u64 kvm_get_apic_base(struct kvm_vcpu *vcpu)
|
|
|
}
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(kvm_get_apic_base);
|
|
EXPORT_SYMBOL_GPL(kvm_get_apic_base);
|
|
|
|
|
|
|
|
-void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data)
|
|
|
|
|
-{
|
|
|
|
|
- /* TODO: reserve bits check */
|
|
|
|
|
- kvm_lapic_set_base(vcpu, data);
|
|
|
|
|
|
|
+int kvm_set_apic_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
|
|
|
|
+{
|
|
|
|
|
+ u64 old_state = vcpu->arch.apic_base &
|
|
|
|
|
+ (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE);
|
|
|
|
|
+ u64 new_state = msr_info->data &
|
|
|
|
|
+ (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE);
|
|
|
|
|
+ u64 reserved_bits = ((~0ULL) << cpuid_maxphyaddr(vcpu)) |
|
|
|
|
|
+ 0x2ff | (guest_cpuid_has_x2apic(vcpu) ? 0 : X2APIC_ENABLE);
|
|
|
|
|
+
|
|
|
|
|
+ if (!msr_info->host_initiated &&
|
|
|
|
|
+ ((msr_info->data & reserved_bits) != 0 ||
|
|
|
|
|
+ new_state == X2APIC_ENABLE ||
|
|
|
|
|
+ (new_state == MSR_IA32_APICBASE_ENABLE &&
|
|
|
|
|
+ old_state == (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE)) ||
|
|
|
|
|
+ (new_state == (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE) &&
|
|
|
|
|
+ old_state == 0)))
|
|
|
|
|
+ return 1;
|
|
|
|
|
+
|
|
|
|
|
+ kvm_lapic_set_base(vcpu, msr_info->data);
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(kvm_set_apic_base);
|
|
EXPORT_SYMBOL_GPL(kvm_set_apic_base);
|
|
|
|
|
|
|
@@ -2009,8 +2025,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
|
|
case 0x200 ... 0x2ff:
|
|
case 0x200 ... 0x2ff:
|
|
|
return set_msr_mtrr(vcpu, msr, data);
|
|
return set_msr_mtrr(vcpu, msr, data);
|
|
|
case MSR_IA32_APICBASE:
|
|
case MSR_IA32_APICBASE:
|
|
|
- kvm_set_apic_base(vcpu, data);
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ return kvm_set_apic_base(vcpu, msr_info);
|
|
|
case APIC_BASE_MSR ... APIC_BASE_MSR + 0x3ff:
|
|
case APIC_BASE_MSR ... APIC_BASE_MSR + 0x3ff:
|
|
|
return kvm_x2apic_msr_write(vcpu, msr, data);
|
|
return kvm_x2apic_msr_write(vcpu, msr, data);
|
|
|
case MSR_IA32_TSCDEADLINE:
|
|
case MSR_IA32_TSCDEADLINE:
|
|
@@ -6412,6 +6427,7 @@ EXPORT_SYMBOL_GPL(kvm_task_switch);
|
|
|
int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
|
|
int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
|
|
|
struct kvm_sregs *sregs)
|
|
struct kvm_sregs *sregs)
|
|
|
{
|
|
{
|
|
|
|
|
+ struct msr_data apic_base_msr;
|
|
|
int mmu_reset_needed = 0;
|
|
int mmu_reset_needed = 0;
|
|
|
int pending_vec, max_bits, idx;
|
|
int pending_vec, max_bits, idx;
|
|
|
struct desc_ptr dt;
|
|
struct desc_ptr dt;
|
|
@@ -6435,7 +6451,9 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
|
|
|
|
|
|
|
|
mmu_reset_needed |= vcpu->arch.efer != sregs->efer;
|
|
mmu_reset_needed |= vcpu->arch.efer != sregs->efer;
|
|
|
kvm_x86_ops->set_efer(vcpu, sregs->efer);
|
|
kvm_x86_ops->set_efer(vcpu, sregs->efer);
|
|
|
- kvm_set_apic_base(vcpu, sregs->apic_base);
|
|
|
|
|
|
|
+ apic_base_msr.data = sregs->apic_base;
|
|
|
|
|
+ apic_base_msr.host_initiated = true;
|
|
|
|
|
+ kvm_set_apic_base(vcpu, &apic_base_msr);
|
|
|
|
|
|
|
|
mmu_reset_needed |= kvm_read_cr0(vcpu) != sregs->cr0;
|
|
mmu_reset_needed |= kvm_read_cr0(vcpu) != sregs->cr0;
|
|
|
kvm_x86_ops->set_cr0(vcpu, sregs->cr0);
|
|
kvm_x86_ops->set_cr0(vcpu, sregs->cr0);
|