ARM:
* Avoid use of uninitialized memcache pointer in user_mem_abort() * Always set HCR_EL2.xMO bits when running in VHE, allowing interrupts to be taken while TGE=0 and fixing an ugly bug on AmpereOne that occurs when taking an interrupt while clearing the xMO bits (AC03_CPU_36) * Prevent VMMs from hiding support for AArch64 at any EL virtualized by KVM * Save/restore the host value for HCRX_EL2 instead of restoring an incorrect fixed value * Make host_stage2_set_owner_locked() check that the entire requested range is memory rather than just the first page RISC-V: * Add missing reset of smstateen CSRs x86: * Forcibly leave SMM on SHUTDOWN interception on AMD CPUs to avoid causing problems due to KVM stuffing INIT on SHUTDOWN (KVM needs to sanitize the VMCB as its state is undefined after SHUTDOWN, emulating INIT is the least awful choice). * Track the valid sync/dirty fields in kvm_run as a u64 to ensure KVM KVM doesn't goof a sanity check in the future. * Free obsolete roots when (re)loading the MMU to fix a bug where pre-faulting memory can get stuck due to always encountering a stale root. * When dumping GHCB state, use KVM's snapshot instead of the raw GHCB page to print state, so that KVM doesn't print stale/wrong information. * When changing memory attributes (e.g. shared <=> private), add potential hugepage ranges to the mmu_invalidate_range_{start,end} set so that KVM doesn't create a shared/private hugepage when the the corresponding attributes will become mixed (the attributes are commited *after* KVM finishes the invalidation). * Rework the SRSO mitigation to enable BP_SPEC_REDUCE only when KVM has at least one active VM. Effectively BP_SPEC_REDUCE when KVM is loaded led to very measurable performance regressions for non-KVM workloads. -----BEGIN PGP SIGNATURE----- iQFIBAABCgAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmgfbqAUHHBib256aW5p QHJlZGhhdC5jb20ACgkQv/vSX3jHroNAywf+J9Ux+RccM8K2my3REQn7Z6WwMevX CYgvdYBGt79AG8mjMKMfISzRDo3PrTi9wr+mEHfCpJ1F7CZTec/qdGY61tIjOhnE 86A5EoJcaoWhZcl4ubtQwRc//ENapwb6qI5uy10Nt30KTqS1S38M7FcZLvTYBYBx A1Xehcnc8NOsOvXMyHvnsAi/X+yvj/wUfzETfzt5CFg8s9MHnmEFWlP+oOgNggbR TKJVIvD0CTQR8lmdEcJYDrgWfhUsRq8qZyPAO37SoAn1tWfYAcpUUHEH2t2C6waW shqmRx0HLshhbIWgySU2AdRx6Q3iyMIPSmTvzUhATEhEzM/IDk/DZstOyQ== =aJFD -----END PGP SIGNATURE----- Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm Pull KVM fixes from Paolo Bonzini: "ARM: - Avoid use of uninitialized memcache pointer in user_mem_abort() - Always set HCR_EL2.xMO bits when running in VHE, allowing interrupts to be taken while TGE=0 and fixing an ugly bug on AmpereOne that occurs when taking an interrupt while clearing the xMO bits (AC03_CPU_36) - Prevent VMMs from hiding support for AArch64 at any EL virtualized by KVM - Save/restore the host value for HCRX_EL2 instead of restoring an incorrect fixed value - Make host_stage2_set_owner_locked() check that the entire requested range is memory rather than just the first page RISC-V: - Add missing reset of smstateen CSRs x86: - Forcibly leave SMM on SHUTDOWN interception on AMD CPUs to avoid causing problems due to KVM stuffing INIT on SHUTDOWN (KVM needs to sanitize the VMCB as its state is undefined after SHUTDOWN, emulating INIT is the least awful choice). - Track the valid sync/dirty fields in kvm_run as a u64 to ensure KVM KVM doesn't goof a sanity check in the future. - Free obsolete roots when (re)loading the MMU to fix a bug where pre-faulting memory can get stuck due to always encountering a stale root. - When dumping GHCB state, use KVM's snapshot instead of the raw GHCB page to print state, so that KVM doesn't print stale/wrong information. - When changing memory attributes (e.g. shared <=> private), add potential hugepage ranges to the mmu_invalidate_range_{start,end} set so that KVM doesn't create a shared/private hugepage when the the corresponding attributes will become mixed (the attributes are commited *after* KVM finishes the invalidation). - Rework the SRSO mitigation to enable BP_SPEC_REDUCE only when KVM has at least one active VM. Effectively BP_SPEC_REDUCE when KVM is loaded led to very measurable performance regressions for non-KVM workloads" * tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm: KVM: SVM: Set/clear SRSO's BP_SPEC_REDUCE on 0 <=> 1 VM count transitions KVM: arm64: Fix memory check in host_stage2_set_owner_locked() KVM: arm64: Kill HCRX_HOST_FLAGS KVM: arm64: Properly save/restore HCRX_EL2 KVM: arm64: selftest: Don't try to disable AArch64 support KVM: arm64: Prevent userspace from disabling AArch64 support at any virtualisable EL KVM: arm64: Force HCR_EL2.xMO to 1 at all times in VHE mode KVM: arm64: Fix uninitialized memcache pointer in user_mem_abort() KVM: x86/mmu: Prevent installing hugepages when mem attributes are changing KVM: SVM: Update dump_ghcb() to use the GHCB snapshot fields KVM: RISC-V: reset smstateen CSRs KVM: x86/mmu: Check and free obsolete roots in kvm_mmu_reload() KVM: x86: Check that the high 32bits are clear in kvm_arch_vcpu_ioctl_run() KVM: SVM: Forcibly leave SMM mode on SHUTDOWN interception
This commit is contained in:
commit
cd802e7e5f
16 changed files with 210 additions and 82 deletions
|
@ -52,7 +52,7 @@
|
|||
mrs x0, id_aa64mmfr1_el1
|
||||
ubfx x0, x0, #ID_AA64MMFR1_EL1_HCX_SHIFT, #4
|
||||
cbz x0, .Lskip_hcrx_\@
|
||||
mov_q x0, HCRX_HOST_FLAGS
|
||||
mov_q x0, (HCRX_EL2_MSCEn | HCRX_EL2_TCR2En | HCRX_EL2_EnFPM)
|
||||
|
||||
/* Enable GCS if supported */
|
||||
mrs_s x1, SYS_ID_AA64PFR1_EL1
|
||||
|
|
|
@ -100,9 +100,8 @@
|
|||
HCR_FMO | HCR_IMO | HCR_PTW | HCR_TID3 | HCR_TID1)
|
||||
#define HCR_HOST_NVHE_FLAGS (HCR_RW | HCR_API | HCR_APK | HCR_ATA)
|
||||
#define HCR_HOST_NVHE_PROTECTED_FLAGS (HCR_HOST_NVHE_FLAGS | HCR_TSC)
|
||||
#define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H)
|
||||
#define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H | HCR_AMO | HCR_IMO | HCR_FMO)
|
||||
|
||||
#define HCRX_HOST_FLAGS (HCRX_EL2_MSCEn | HCRX_EL2_TCR2En | HCRX_EL2_EnFPM)
|
||||
#define MPAMHCR_HOST_FLAGS 0
|
||||
|
||||
/* TCR_EL2 Registers bits */
|
||||
|
|
|
@ -235,6 +235,8 @@ static inline void __deactivate_traps_mpam(void)
|
|||
|
||||
static inline void __activate_traps_common(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_cpu_context *hctxt = host_data_ptr(host_ctxt);
|
||||
|
||||
/* Trap on AArch32 cp15 c15 (impdef sysregs) accesses (EL1 or EL0) */
|
||||
write_sysreg(1 << 15, hstr_el2);
|
||||
|
||||
|
@ -245,11 +247,8 @@ static inline void __activate_traps_common(struct kvm_vcpu *vcpu)
|
|||
* EL1 instead of being trapped to EL2.
|
||||
*/
|
||||
if (system_supports_pmuv3()) {
|
||||
struct kvm_cpu_context *hctxt;
|
||||
|
||||
write_sysreg(0, pmselr_el0);
|
||||
|
||||
hctxt = host_data_ptr(host_ctxt);
|
||||
ctxt_sys_reg(hctxt, PMUSERENR_EL0) = read_sysreg(pmuserenr_el0);
|
||||
write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
|
||||
vcpu_set_flag(vcpu, PMUSERENR_ON_CPU);
|
||||
|
@ -269,6 +268,7 @@ static inline void __activate_traps_common(struct kvm_vcpu *vcpu)
|
|||
hcrx &= ~clr;
|
||||
}
|
||||
|
||||
ctxt_sys_reg(hctxt, HCRX_EL2) = read_sysreg_s(SYS_HCRX_EL2);
|
||||
write_sysreg_s(hcrx, SYS_HCRX_EL2);
|
||||
}
|
||||
|
||||
|
@ -278,19 +278,18 @@ static inline void __activate_traps_common(struct kvm_vcpu *vcpu)
|
|||
|
||||
static inline void __deactivate_traps_common(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_cpu_context *hctxt = host_data_ptr(host_ctxt);
|
||||
|
||||
write_sysreg(*host_data_ptr(host_debug_state.mdcr_el2), mdcr_el2);
|
||||
|
||||
write_sysreg(0, hstr_el2);
|
||||
if (system_supports_pmuv3()) {
|
||||
struct kvm_cpu_context *hctxt;
|
||||
|
||||
hctxt = host_data_ptr(host_ctxt);
|
||||
write_sysreg(ctxt_sys_reg(hctxt, PMUSERENR_EL0), pmuserenr_el0);
|
||||
vcpu_clear_flag(vcpu, PMUSERENR_ON_CPU);
|
||||
}
|
||||
|
||||
if (cpus_have_final_cap(ARM64_HAS_HCX))
|
||||
write_sysreg_s(HCRX_HOST_FLAGS, SYS_HCRX_EL2);
|
||||
write_sysreg_s(ctxt_sys_reg(hctxt, HCRX_EL2), SYS_HCRX_EL2);
|
||||
|
||||
__deactivate_traps_hfgxtr(vcpu);
|
||||
__deactivate_traps_mpam();
|
||||
|
|
|
@ -503,7 +503,7 @@ int host_stage2_set_owner_locked(phys_addr_t addr, u64 size, u8 owner_id)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (!addr_is_memory(addr))
|
||||
if (!range_is_memory(addr, addr + size))
|
||||
return -EPERM;
|
||||
|
||||
ret = host_stage2_try(kvm_pgtable_stage2_set_owner, &host_mmu.pgt,
|
||||
|
|
|
@ -429,23 +429,27 @@ u64 __vgic_v3_get_gic_config(void)
|
|||
/*
|
||||
* To check whether we have a MMIO-based (GICv2 compatible)
|
||||
* CPU interface, we need to disable the system register
|
||||
* view. To do that safely, we have to prevent any interrupt
|
||||
* from firing (which would be deadly).
|
||||
* view.
|
||||
*
|
||||
* Note that this only makes sense on VHE, as interrupts are
|
||||
* already masked for nVHE as part of the exception entry to
|
||||
* EL2.
|
||||
*/
|
||||
if (has_vhe())
|
||||
flags = local_daif_save();
|
||||
|
||||
/*
|
||||
* Table 11-2 "Permitted ICC_SRE_ELx.SRE settings" indicates
|
||||
* that to be able to set ICC_SRE_EL1.SRE to 0, all the
|
||||
* interrupt overrides must be set. You've got to love this.
|
||||
*
|
||||
* As we always run VHE with HCR_xMO set, no extra xMO
|
||||
* manipulation is required in that case.
|
||||
*
|
||||
* To safely disable SRE, we have to prevent any interrupt
|
||||
* from firing (which would be deadly). This only makes sense
|
||||
* on VHE, as interrupts are already masked for nVHE as part
|
||||
* of the exception entry to EL2.
|
||||
*/
|
||||
if (has_vhe()) {
|
||||
flags = local_daif_save();
|
||||
} else {
|
||||
sysreg_clear_set(hcr_el2, 0, HCR_AMO | HCR_FMO | HCR_IMO);
|
||||
isb();
|
||||
}
|
||||
|
||||
write_gicreg(0, ICC_SRE_EL1);
|
||||
isb();
|
||||
|
||||
|
@ -453,11 +457,13 @@ u64 __vgic_v3_get_gic_config(void)
|
|||
|
||||
write_gicreg(sre, ICC_SRE_EL1);
|
||||
isb();
|
||||
|
||||
if (has_vhe()) {
|
||||
local_daif_restore(flags);
|
||||
} else {
|
||||
sysreg_clear_set(hcr_el2, HCR_AMO | HCR_FMO | HCR_IMO, 0);
|
||||
isb();
|
||||
|
||||
if (has_vhe())
|
||||
local_daif_restore(flags);
|
||||
}
|
||||
|
||||
val = (val & ICC_SRE_EL1_SRE) ? 0 : (1ULL << 63);
|
||||
val |= read_gicreg(ICH_VTR_EL2);
|
||||
|
|
|
@ -1501,6 +1501,11 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
|||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (!is_protected_kvm_enabled())
|
||||
memcache = &vcpu->arch.mmu_page_cache;
|
||||
else
|
||||
memcache = &vcpu->arch.pkvm_memcache;
|
||||
|
||||
/*
|
||||
* Permission faults just need to update the existing leaf entry,
|
||||
* and so normally don't require allocations from the memcache. The
|
||||
|
@ -1510,13 +1515,11 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
|||
if (!fault_is_perm || (logging_active && write_fault)) {
|
||||
int min_pages = kvm_mmu_cache_min_pages(vcpu->arch.hw_mmu);
|
||||
|
||||
if (!is_protected_kvm_enabled()) {
|
||||
memcache = &vcpu->arch.mmu_page_cache;
|
||||
if (!is_protected_kvm_enabled())
|
||||
ret = kvm_mmu_topup_memory_cache(memcache, min_pages);
|
||||
} else {
|
||||
memcache = &vcpu->arch.pkvm_memcache;
|
||||
else
|
||||
ret = topup_hyp_memcache(memcache, min_pages);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -1945,6 +1945,12 @@ static int set_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
|
|||
if ((hw_val & mpam_mask) == (user_val & mpam_mask))
|
||||
user_val &= ~ID_AA64PFR0_EL1_MPAM_MASK;
|
||||
|
||||
/* Fail the guest's request to disable the AA64 ISA at EL{0,1,2} */
|
||||
if (!FIELD_GET(ID_AA64PFR0_EL1_EL0, user_val) ||
|
||||
!FIELD_GET(ID_AA64PFR0_EL1_EL1, user_val) ||
|
||||
(vcpu_has_nv(vcpu) && !FIELD_GET(ID_AA64PFR0_EL1_EL2, user_val)))
|
||||
return -EINVAL;
|
||||
|
||||
return set_id_reg(vcpu, rd, user_val);
|
||||
}
|
||||
|
||||
|
|
|
@ -77,6 +77,8 @@ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu)
|
|||
memcpy(cntx, reset_cntx, sizeof(*cntx));
|
||||
spin_unlock(&vcpu->arch.reset_cntx_lock);
|
||||
|
||||
memset(&vcpu->arch.smstateen_csr, 0, sizeof(vcpu->arch.smstateen_csr));
|
||||
|
||||
kvm_riscv_vcpu_fp_reset(vcpu);
|
||||
|
||||
kvm_riscv_vcpu_vector_reset(vcpu);
|
||||
|
|
|
@ -104,6 +104,9 @@ void kvm_mmu_track_write(struct kvm_vcpu *vcpu, gpa_t gpa, const u8 *new,
|
|||
|
||||
static inline int kvm_mmu_reload(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (kvm_check_request(KVM_REQ_MMU_FREE_OBSOLETE_ROOTS, vcpu))
|
||||
kvm_mmu_free_obsolete_roots(vcpu);
|
||||
|
||||
/*
|
||||
* Checking root.hpa is sufficient even when KVM has mirror root.
|
||||
* We can have either:
|
||||
|
|
|
@ -5974,6 +5974,7 @@ void kvm_mmu_free_obsolete_roots(struct kvm_vcpu *vcpu)
|
|||
__kvm_mmu_free_obsolete_roots(vcpu->kvm, &vcpu->arch.root_mmu);
|
||||
__kvm_mmu_free_obsolete_roots(vcpu->kvm, &vcpu->arch.guest_mmu);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_mmu_free_obsolete_roots);
|
||||
|
||||
static u64 mmu_pte_write_fetch_gpte(struct kvm_vcpu *vcpu, gpa_t *gpa,
|
||||
int *bytes)
|
||||
|
@ -7669,32 +7670,6 @@ void kvm_mmu_pre_destroy_vm(struct kvm *kvm)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES
|
||||
bool kvm_arch_pre_set_memory_attributes(struct kvm *kvm,
|
||||
struct kvm_gfn_range *range)
|
||||
{
|
||||
/*
|
||||
* Zap SPTEs even if the slot can't be mapped PRIVATE. KVM x86 only
|
||||
* supports KVM_MEMORY_ATTRIBUTE_PRIVATE, and so it *seems* like KVM
|
||||
* can simply ignore such slots. But if userspace is making memory
|
||||
* PRIVATE, then KVM must prevent the guest from accessing the memory
|
||||
* as shared. And if userspace is making memory SHARED and this point
|
||||
* is reached, then at least one page within the range was previously
|
||||
* PRIVATE, i.e. the slot's possible hugepage ranges are changing.
|
||||
* Zapping SPTEs in this case ensures KVM will reassess whether or not
|
||||
* a hugepage can be used for affected ranges.
|
||||
*/
|
||||
if (WARN_ON_ONCE(!kvm_arch_has_private_mem(kvm)))
|
||||
return false;
|
||||
|
||||
/* Unmap the old attribute page. */
|
||||
if (range->arg.attributes & KVM_MEMORY_ATTRIBUTE_PRIVATE)
|
||||
range->attr_filter = KVM_FILTER_SHARED;
|
||||
else
|
||||
range->attr_filter = KVM_FILTER_PRIVATE;
|
||||
|
||||
return kvm_unmap_gfn_range(kvm, range);
|
||||
}
|
||||
|
||||
static bool hugepage_test_mixed(struct kvm_memory_slot *slot, gfn_t gfn,
|
||||
int level)
|
||||
{
|
||||
|
@ -7713,6 +7688,69 @@ static void hugepage_set_mixed(struct kvm_memory_slot *slot, gfn_t gfn,
|
|||
lpage_info_slot(gfn, slot, level)->disallow_lpage |= KVM_LPAGE_MIXED_FLAG;
|
||||
}
|
||||
|
||||
bool kvm_arch_pre_set_memory_attributes(struct kvm *kvm,
|
||||
struct kvm_gfn_range *range)
|
||||
{
|
||||
struct kvm_memory_slot *slot = range->slot;
|
||||
int level;
|
||||
|
||||
/*
|
||||
* Zap SPTEs even if the slot can't be mapped PRIVATE. KVM x86 only
|
||||
* supports KVM_MEMORY_ATTRIBUTE_PRIVATE, and so it *seems* like KVM
|
||||
* can simply ignore such slots. But if userspace is making memory
|
||||
* PRIVATE, then KVM must prevent the guest from accessing the memory
|
||||
* as shared. And if userspace is making memory SHARED and this point
|
||||
* is reached, then at least one page within the range was previously
|
||||
* PRIVATE, i.e. the slot's possible hugepage ranges are changing.
|
||||
* Zapping SPTEs in this case ensures KVM will reassess whether or not
|
||||
* a hugepage can be used for affected ranges.
|
||||
*/
|
||||
if (WARN_ON_ONCE(!kvm_arch_has_private_mem(kvm)))
|
||||
return false;
|
||||
|
||||
if (WARN_ON_ONCE(range->end <= range->start))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* If the head and tail pages of the range currently allow a hugepage,
|
||||
* i.e. reside fully in the slot and don't have mixed attributes, then
|
||||
* add each corresponding hugepage range to the ongoing invalidation,
|
||||
* e.g. to prevent KVM from creating a hugepage in response to a fault
|
||||
* for a gfn whose attributes aren't changing. Note, only the range
|
||||
* of gfns whose attributes are being modified needs to be explicitly
|
||||
* unmapped, as that will unmap any existing hugepages.
|
||||
*/
|
||||
for (level = PG_LEVEL_2M; level <= KVM_MAX_HUGEPAGE_LEVEL; level++) {
|
||||
gfn_t start = gfn_round_for_level(range->start, level);
|
||||
gfn_t end = gfn_round_for_level(range->end - 1, level);
|
||||
gfn_t nr_pages = KVM_PAGES_PER_HPAGE(level);
|
||||
|
||||
if ((start != range->start || start + nr_pages > range->end) &&
|
||||
start >= slot->base_gfn &&
|
||||
start + nr_pages <= slot->base_gfn + slot->npages &&
|
||||
!hugepage_test_mixed(slot, start, level))
|
||||
kvm_mmu_invalidate_range_add(kvm, start, start + nr_pages);
|
||||
|
||||
if (end == start)
|
||||
continue;
|
||||
|
||||
if ((end + nr_pages) > range->end &&
|
||||
(end + nr_pages) <= (slot->base_gfn + slot->npages) &&
|
||||
!hugepage_test_mixed(slot, end, level))
|
||||
kvm_mmu_invalidate_range_add(kvm, end, end + nr_pages);
|
||||
}
|
||||
|
||||
/* Unmap the old attribute page. */
|
||||
if (range->arg.attributes & KVM_MEMORY_ATTRIBUTE_PRIVATE)
|
||||
range->attr_filter = KVM_FILTER_SHARED;
|
||||
else
|
||||
range->attr_filter = KVM_FILTER_PRIVATE;
|
||||
|
||||
return kvm_unmap_gfn_range(kvm, range);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool hugepage_has_attrs(struct kvm *kvm, struct kvm_memory_slot *slot,
|
||||
gfn_t gfn, int level, unsigned long attrs)
|
||||
{
|
||||
|
|
|
@ -131,6 +131,7 @@ void kvm_smm_changed(struct kvm_vcpu *vcpu, bool entering_smm)
|
|||
|
||||
kvm_mmu_reset_context(vcpu);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_smm_changed);
|
||||
|
||||
void process_smi(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
|
|
|
@ -3173,9 +3173,14 @@ skip_vmsa_free:
|
|||
kvfree(svm->sev_es.ghcb_sa);
|
||||
}
|
||||
|
||||
static u64 kvm_ghcb_get_sw_exit_code(struct vmcb_control_area *control)
|
||||
{
|
||||
return (((u64)control->exit_code_hi) << 32) | control->exit_code;
|
||||
}
|
||||
|
||||
static void dump_ghcb(struct vcpu_svm *svm)
|
||||
{
|
||||
struct ghcb *ghcb = svm->sev_es.ghcb;
|
||||
struct vmcb_control_area *control = &svm->vmcb->control;
|
||||
unsigned int nbits;
|
||||
|
||||
/* Re-use the dump_invalid_vmcb module parameter */
|
||||
|
@ -3184,18 +3189,24 @@ static void dump_ghcb(struct vcpu_svm *svm)
|
|||
return;
|
||||
}
|
||||
|
||||
nbits = sizeof(ghcb->save.valid_bitmap) * 8;
|
||||
nbits = sizeof(svm->sev_es.valid_bitmap) * 8;
|
||||
|
||||
pr_err("GHCB (GPA=%016llx):\n", svm->vmcb->control.ghcb_gpa);
|
||||
/*
|
||||
* Print KVM's snapshot of the GHCB values that were (unsuccessfully)
|
||||
* used to handle the exit. If the guest has since modified the GHCB
|
||||
* itself, dumping the raw GHCB won't help debug why KVM was unable to
|
||||
* handle the VMGEXIT that KVM observed.
|
||||
*/
|
||||
pr_err("GHCB (GPA=%016llx) snapshot:\n", svm->vmcb->control.ghcb_gpa);
|
||||
pr_err("%-20s%016llx is_valid: %u\n", "sw_exit_code",
|
||||
ghcb->save.sw_exit_code, ghcb_sw_exit_code_is_valid(ghcb));
|
||||
kvm_ghcb_get_sw_exit_code(control), kvm_ghcb_sw_exit_code_is_valid(svm));
|
||||
pr_err("%-20s%016llx is_valid: %u\n", "sw_exit_info_1",
|
||||
ghcb->save.sw_exit_info_1, ghcb_sw_exit_info_1_is_valid(ghcb));
|
||||
control->exit_info_1, kvm_ghcb_sw_exit_info_1_is_valid(svm));
|
||||
pr_err("%-20s%016llx is_valid: %u\n", "sw_exit_info_2",
|
||||
ghcb->save.sw_exit_info_2, ghcb_sw_exit_info_2_is_valid(ghcb));
|
||||
control->exit_info_2, kvm_ghcb_sw_exit_info_2_is_valid(svm));
|
||||
pr_err("%-20s%016llx is_valid: %u\n", "sw_scratch",
|
||||
ghcb->save.sw_scratch, ghcb_sw_scratch_is_valid(ghcb));
|
||||
pr_err("%-20s%*pb\n", "valid_bitmap", nbits, ghcb->save.valid_bitmap);
|
||||
svm->sev_es.sw_scratch, kvm_ghcb_sw_scratch_is_valid(svm));
|
||||
pr_err("%-20s%*pb\n", "valid_bitmap", nbits, svm->sev_es.valid_bitmap);
|
||||
}
|
||||
|
||||
static void sev_es_sync_to_ghcb(struct vcpu_svm *svm)
|
||||
|
@ -3266,11 +3277,6 @@ static void sev_es_sync_from_ghcb(struct vcpu_svm *svm)
|
|||
memset(ghcb->save.valid_bitmap, 0, sizeof(ghcb->save.valid_bitmap));
|
||||
}
|
||||
|
||||
static u64 kvm_ghcb_get_sw_exit_code(struct vmcb_control_area *control)
|
||||
{
|
||||
return (((u64)control->exit_code_hi) << 32) | control->exit_code;
|
||||
}
|
||||
|
||||
static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
|
||||
{
|
||||
struct vmcb_control_area *control = &svm->vmcb->control;
|
||||
|
|
|
@ -607,9 +607,6 @@ static void svm_disable_virtualization_cpu(void)
|
|||
kvm_cpu_svm_disable();
|
||||
|
||||
amd_pmu_disable_virt();
|
||||
|
||||
if (cpu_feature_enabled(X86_FEATURE_SRSO_BP_SPEC_REDUCE))
|
||||
msr_clear_bit(MSR_ZEN4_BP_CFG, MSR_ZEN4_BP_CFG_BP_SPEC_REDUCE_BIT);
|
||||
}
|
||||
|
||||
static int svm_enable_virtualization_cpu(void)
|
||||
|
@ -687,9 +684,6 @@ static int svm_enable_virtualization_cpu(void)
|
|||
rdmsr(MSR_TSC_AUX, sev_es_host_save_area(sd)->tsc_aux, msr_hi);
|
||||
}
|
||||
|
||||
if (cpu_feature_enabled(X86_FEATURE_SRSO_BP_SPEC_REDUCE))
|
||||
msr_set_bit(MSR_ZEN4_BP_CFG, MSR_ZEN4_BP_CFG_BP_SPEC_REDUCE_BIT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1518,6 +1512,63 @@ static void svm_vcpu_free(struct kvm_vcpu *vcpu)
|
|||
__free_pages(virt_to_page(svm->msrpm), get_order(MSRPM_SIZE));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_MITIGATIONS
|
||||
static DEFINE_SPINLOCK(srso_lock);
|
||||
static atomic_t srso_nr_vms;
|
||||
|
||||
static void svm_srso_clear_bp_spec_reduce(void *ign)
|
||||
{
|
||||
struct svm_cpu_data *sd = this_cpu_ptr(&svm_data);
|
||||
|
||||
if (!sd->bp_spec_reduce_set)
|
||||
return;
|
||||
|
||||
msr_clear_bit(MSR_ZEN4_BP_CFG, MSR_ZEN4_BP_CFG_BP_SPEC_REDUCE_BIT);
|
||||
sd->bp_spec_reduce_set = false;
|
||||
}
|
||||
|
||||
static void svm_srso_vm_destroy(void)
|
||||
{
|
||||
if (!cpu_feature_enabled(X86_FEATURE_SRSO_BP_SPEC_REDUCE))
|
||||
return;
|
||||
|
||||
if (atomic_dec_return(&srso_nr_vms))
|
||||
return;
|
||||
|
||||
guard(spinlock)(&srso_lock);
|
||||
|
||||
/*
|
||||
* Verify a new VM didn't come along, acquire the lock, and increment
|
||||
* the count before this task acquired the lock.
|
||||
*/
|
||||
if (atomic_read(&srso_nr_vms))
|
||||
return;
|
||||
|
||||
on_each_cpu(svm_srso_clear_bp_spec_reduce, NULL, 1);
|
||||
}
|
||||
|
||||
static void svm_srso_vm_init(void)
|
||||
{
|
||||
if (!cpu_feature_enabled(X86_FEATURE_SRSO_BP_SPEC_REDUCE))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Acquire the lock on 0 => 1 transitions to ensure a potential 1 => 0
|
||||
* transition, i.e. destroying the last VM, is fully complete, e.g. so
|
||||
* that a delayed IPI doesn't clear BP_SPEC_REDUCE after a vCPU runs.
|
||||
*/
|
||||
if (atomic_inc_not_zero(&srso_nr_vms))
|
||||
return;
|
||||
|
||||
guard(spinlock)(&srso_lock);
|
||||
|
||||
atomic_inc(&srso_nr_vms);
|
||||
}
|
||||
#else
|
||||
static void svm_srso_vm_init(void) { }
|
||||
static void svm_srso_vm_destroy(void) { }
|
||||
#endif
|
||||
|
||||
static void svm_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
|
@ -1550,6 +1601,11 @@ static void svm_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
|
|||
(!boot_cpu_has(X86_FEATURE_V_TSC_AUX) || !sev_es_guest(vcpu->kvm)))
|
||||
kvm_set_user_return_msr(tsc_aux_uret_slot, svm->tsc_aux, -1ull);
|
||||
|
||||
if (cpu_feature_enabled(X86_FEATURE_SRSO_BP_SPEC_REDUCE) &&
|
||||
!sd->bp_spec_reduce_set) {
|
||||
sd->bp_spec_reduce_set = true;
|
||||
msr_set_bit(MSR_ZEN4_BP_CFG, MSR_ZEN4_BP_CFG_BP_SPEC_REDUCE_BIT);
|
||||
}
|
||||
svm->guest_state_loaded = true;
|
||||
}
|
||||
|
||||
|
@ -2231,6 +2287,10 @@ static int shutdown_interception(struct kvm_vcpu *vcpu)
|
|||
*/
|
||||
if (!sev_es_guest(vcpu->kvm)) {
|
||||
clear_page(svm->vmcb);
|
||||
#ifdef CONFIG_KVM_SMM
|
||||
if (is_smm(vcpu))
|
||||
kvm_smm_changed(vcpu, false);
|
||||
#endif
|
||||
kvm_vcpu_reset(vcpu, true);
|
||||
}
|
||||
|
||||
|
@ -5036,6 +5096,8 @@ static void svm_vm_destroy(struct kvm *kvm)
|
|||
{
|
||||
avic_vm_destroy(kvm);
|
||||
sev_vm_destroy(kvm);
|
||||
|
||||
svm_srso_vm_destroy();
|
||||
}
|
||||
|
||||
static int svm_vm_init(struct kvm *kvm)
|
||||
|
@ -5061,6 +5123,7 @@ static int svm_vm_init(struct kvm *kvm)
|
|||
return ret;
|
||||
}
|
||||
|
||||
svm_srso_vm_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -335,6 +335,8 @@ struct svm_cpu_data {
|
|||
u32 next_asid;
|
||||
u32 min_asid;
|
||||
|
||||
bool bp_spec_reduce_set;
|
||||
|
||||
struct vmcb *save_area;
|
||||
unsigned long save_area_pa;
|
||||
|
||||
|
|
|
@ -4597,7 +4597,7 @@ static bool kvm_is_vm_type_supported(unsigned long type)
|
|||
return type < 32 && (kvm_caps.supported_vm_types & BIT(type));
|
||||
}
|
||||
|
||||
static inline u32 kvm_sync_valid_fields(struct kvm *kvm)
|
||||
static inline u64 kvm_sync_valid_fields(struct kvm *kvm)
|
||||
{
|
||||
return kvm && kvm->arch.has_protected_state ? 0 : KVM_SYNC_X86_VALID_FIELDS;
|
||||
}
|
||||
|
@ -11493,7 +11493,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
|
|||
{
|
||||
struct kvm_queued_exception *ex = &vcpu->arch.exception;
|
||||
struct kvm_run *kvm_run = vcpu->run;
|
||||
u32 sync_valid_fields;
|
||||
u64 sync_valid_fields;
|
||||
int r;
|
||||
|
||||
r = kvm_mmu_post_init_vm(vcpu->kvm);
|
||||
|
|
|
@ -129,10 +129,10 @@ static const struct reg_ftr_bits ftr_id_aa64pfr0_el1[] = {
|
|||
REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, DIT, 0),
|
||||
REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, SEL2, 0),
|
||||
REG_FTR_BITS(FTR_EXACT, ID_AA64PFR0_EL1, GIC, 0),
|
||||
REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, EL3, 0),
|
||||
REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, EL2, 0),
|
||||
REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, EL1, 0),
|
||||
REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, EL0, 0),
|
||||
REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, EL3, 1),
|
||||
REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, EL2, 1),
|
||||
REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, EL1, 1),
|
||||
REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, EL0, 1),
|
||||
REG_FTR_END,
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue