mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
Pull kvm fixes from Paolo Bonzini:
"ARM:
- Correctly handle 'invariant' system registers for protected VMs
- Improved handling of VNCR data aborts, including external aborts
- Fixes for handling of FEAT_RAS for NV guests, providing a sane
fault context during SEA injection and preventing the use of
RASv1p1 fault injection hardware
- Ensure that page table destruction when a VM is destroyed gives an
opportunity to reschedule
- Large fix to KVM's infrastructure for managing guest context loaded
on the CPU, addressing issues where the output of AT emulation
doesn't get reflected to the guest
- Fix AT S12 emulation to actually perform stage-2 translation when
necessary
- Avoid attempting vLPI irqbypass when GICv4 has been explicitly
disabled for a VM
- Minor KVM + selftest fixes
RISC-V:
- Fix pte settings within kvm_riscv_gstage_ioremap()
- Fix comments in kvm_riscv_check_vcpu_requests()
- Fix stack overrun when setting vlenb via ONE_REG
x86:
- Use array_index_nospec() to sanitize the target vCPU ID when
handling PV IPIs and yields as the ID is guest-controlled.
- Drop a superfluous cpumask_empty() check when reclaiming SEV
memory, as the common case, by far, is that at least one CPU will
have entered the VM, and wbnoinvd_on_cpus_mask() will naturally
handle the rare case where the set of have_run_cpus is empty.
Selftests (not KVM):
- Rename the is_signed_type() macro in kselftest_harness.h to
is_signed_var() to fix a collision with linux/overflow.h. The
collision generates compiler warnings due to the two macros having
different meaning"
* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm: (29 commits)
KVM: arm64: nv: Fix ATS12 handling of single-stage translation
KVM: arm64: Remove __vcpu_{read,write}_sys_reg_{from,to}_cpu()
KVM: arm64: Fix vcpu_{read,write}_sys_reg() accessors
KVM: arm64: Simplify sysreg access on exception delivery
KVM: arm64: Check for SYSREGS_ON_CPU before accessing the 32bit state
RISC-V: KVM: fix stack overrun when loading vlenb
RISC-V: KVM: Correct kvm_riscv_check_vcpu_requests() comment
RISC-V: KVM: Fix pte settings within kvm_riscv_gstage_ioremap()
KVM: arm64: selftests: Sync ID_AA64MMFR3_EL1 in set_id_regs
KVM: arm64: Get rid of ARM64_FEATURE_MASK()
KVM: arm64: Make ID_AA64PFR1_EL1.RAS_frac writable
KVM: arm64: Make ID_AA64PFR0_EL1.RAS writable
KVM: arm64: Ignore HCR_EL2.FIEN set by L1 guest's EL2
KVM: arm64: Handle RASv1p1 registers
arm64: Add capability denoting FEAT_RASv1p1
KVM: arm64: Reschedule as needed when destroying the stage-2 page-tables
KVM: arm64: Split kvm_pgtable_stage2_destroy()
selftests: harness: Rename is_signed_type() to avoid collision with overflow.h
KVM: SEV: don't check have_run_cpus in sev_writeback_caches()
KVM: arm64: Correctly populate FAR_EL2 on nested SEA injection
...
This commit is contained in:
@@ -1160,115 +1160,8 @@ u64 kvm_vcpu_apply_reg_masks(const struct kvm_vcpu *, enum vcpu_sysreg, u64);
|
||||
__v; \
|
||||
})
|
||||
|
||||
u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg);
|
||||
void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg);
|
||||
|
||||
static inline bool __vcpu_read_sys_reg_from_cpu(int reg, u64 *val)
|
||||
{
|
||||
/*
|
||||
* *** VHE ONLY ***
|
||||
*
|
||||
* System registers listed in the switch are not saved on every
|
||||
* exit from the guest but are only saved on vcpu_put.
|
||||
*
|
||||
* SYSREGS_ON_CPU *MUST* be checked before using this helper.
|
||||
*
|
||||
* Note that MPIDR_EL1 for the guest is set by KVM via VMPIDR_EL2 but
|
||||
* should never be listed below, because the guest cannot modify its
|
||||
* own MPIDR_EL1 and MPIDR_EL1 is accessed for VCPU A from VCPU B's
|
||||
* thread when emulating cross-VCPU communication.
|
||||
*/
|
||||
if (!has_vhe())
|
||||
return false;
|
||||
|
||||
switch (reg) {
|
||||
case SCTLR_EL1: *val = read_sysreg_s(SYS_SCTLR_EL12); break;
|
||||
case CPACR_EL1: *val = read_sysreg_s(SYS_CPACR_EL12); break;
|
||||
case TTBR0_EL1: *val = read_sysreg_s(SYS_TTBR0_EL12); break;
|
||||
case TTBR1_EL1: *val = read_sysreg_s(SYS_TTBR1_EL12); break;
|
||||
case TCR_EL1: *val = read_sysreg_s(SYS_TCR_EL12); break;
|
||||
case TCR2_EL1: *val = read_sysreg_s(SYS_TCR2_EL12); break;
|
||||
case PIR_EL1: *val = read_sysreg_s(SYS_PIR_EL12); break;
|
||||
case PIRE0_EL1: *val = read_sysreg_s(SYS_PIRE0_EL12); break;
|
||||
case POR_EL1: *val = read_sysreg_s(SYS_POR_EL12); break;
|
||||
case ESR_EL1: *val = read_sysreg_s(SYS_ESR_EL12); break;
|
||||
case AFSR0_EL1: *val = read_sysreg_s(SYS_AFSR0_EL12); break;
|
||||
case AFSR1_EL1: *val = read_sysreg_s(SYS_AFSR1_EL12); break;
|
||||
case FAR_EL1: *val = read_sysreg_s(SYS_FAR_EL12); break;
|
||||
case MAIR_EL1: *val = read_sysreg_s(SYS_MAIR_EL12); break;
|
||||
case VBAR_EL1: *val = read_sysreg_s(SYS_VBAR_EL12); break;
|
||||
case CONTEXTIDR_EL1: *val = read_sysreg_s(SYS_CONTEXTIDR_EL12);break;
|
||||
case TPIDR_EL0: *val = read_sysreg_s(SYS_TPIDR_EL0); break;
|
||||
case TPIDRRO_EL0: *val = read_sysreg_s(SYS_TPIDRRO_EL0); break;
|
||||
case TPIDR_EL1: *val = read_sysreg_s(SYS_TPIDR_EL1); break;
|
||||
case AMAIR_EL1: *val = read_sysreg_s(SYS_AMAIR_EL12); break;
|
||||
case CNTKCTL_EL1: *val = read_sysreg_s(SYS_CNTKCTL_EL12); break;
|
||||
case ELR_EL1: *val = read_sysreg_s(SYS_ELR_EL12); break;
|
||||
case SPSR_EL1: *val = read_sysreg_s(SYS_SPSR_EL12); break;
|
||||
case PAR_EL1: *val = read_sysreg_par(); break;
|
||||
case DACR32_EL2: *val = read_sysreg_s(SYS_DACR32_EL2); break;
|
||||
case IFSR32_EL2: *val = read_sysreg_s(SYS_IFSR32_EL2); break;
|
||||
case DBGVCR32_EL2: *val = read_sysreg_s(SYS_DBGVCR32_EL2); break;
|
||||
case ZCR_EL1: *val = read_sysreg_s(SYS_ZCR_EL12); break;
|
||||
case SCTLR2_EL1: *val = read_sysreg_s(SYS_SCTLR2_EL12); break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool __vcpu_write_sys_reg_to_cpu(u64 val, int reg)
|
||||
{
|
||||
/*
|
||||
* *** VHE ONLY ***
|
||||
*
|
||||
* System registers listed in the switch are not restored on every
|
||||
* entry to the guest but are only restored on vcpu_load.
|
||||
*
|
||||
* SYSREGS_ON_CPU *MUST* be checked before using this helper.
|
||||
*
|
||||
* Note that MPIDR_EL1 for the guest is set by KVM via VMPIDR_EL2 but
|
||||
* should never be listed below, because the MPIDR should only be set
|
||||
* once, before running the VCPU, and never changed later.
|
||||
*/
|
||||
if (!has_vhe())
|
||||
return false;
|
||||
|
||||
switch (reg) {
|
||||
case SCTLR_EL1: write_sysreg_s(val, SYS_SCTLR_EL12); break;
|
||||
case CPACR_EL1: write_sysreg_s(val, SYS_CPACR_EL12); break;
|
||||
case TTBR0_EL1: write_sysreg_s(val, SYS_TTBR0_EL12); break;
|
||||
case TTBR1_EL1: write_sysreg_s(val, SYS_TTBR1_EL12); break;
|
||||
case TCR_EL1: write_sysreg_s(val, SYS_TCR_EL12); break;
|
||||
case TCR2_EL1: write_sysreg_s(val, SYS_TCR2_EL12); break;
|
||||
case PIR_EL1: write_sysreg_s(val, SYS_PIR_EL12); break;
|
||||
case PIRE0_EL1: write_sysreg_s(val, SYS_PIRE0_EL12); break;
|
||||
case POR_EL1: write_sysreg_s(val, SYS_POR_EL12); break;
|
||||
case ESR_EL1: write_sysreg_s(val, SYS_ESR_EL12); break;
|
||||
case AFSR0_EL1: write_sysreg_s(val, SYS_AFSR0_EL12); break;
|
||||
case AFSR1_EL1: write_sysreg_s(val, SYS_AFSR1_EL12); break;
|
||||
case FAR_EL1: write_sysreg_s(val, SYS_FAR_EL12); break;
|
||||
case MAIR_EL1: write_sysreg_s(val, SYS_MAIR_EL12); break;
|
||||
case VBAR_EL1: write_sysreg_s(val, SYS_VBAR_EL12); break;
|
||||
case CONTEXTIDR_EL1: write_sysreg_s(val, SYS_CONTEXTIDR_EL12);break;
|
||||
case TPIDR_EL0: write_sysreg_s(val, SYS_TPIDR_EL0); break;
|
||||
case TPIDRRO_EL0: write_sysreg_s(val, SYS_TPIDRRO_EL0); break;
|
||||
case TPIDR_EL1: write_sysreg_s(val, SYS_TPIDR_EL1); break;
|
||||
case AMAIR_EL1: write_sysreg_s(val, SYS_AMAIR_EL12); break;
|
||||
case CNTKCTL_EL1: write_sysreg_s(val, SYS_CNTKCTL_EL12); break;
|
||||
case ELR_EL1: write_sysreg_s(val, SYS_ELR_EL12); break;
|
||||
case SPSR_EL1: write_sysreg_s(val, SYS_SPSR_EL12); break;
|
||||
case PAR_EL1: write_sysreg_s(val, SYS_PAR_EL1); break;
|
||||
case DACR32_EL2: write_sysreg_s(val, SYS_DACR32_EL2); break;
|
||||
case IFSR32_EL2: write_sysreg_s(val, SYS_IFSR32_EL2); break;
|
||||
case DBGVCR32_EL2: write_sysreg_s(val, SYS_DBGVCR32_EL2); break;
|
||||
case ZCR_EL1: write_sysreg_s(val, SYS_ZCR_EL12); break;
|
||||
case SCTLR2_EL1: write_sysreg_s(val, SYS_SCTLR2_EL12); break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
u64 vcpu_read_sys_reg(const struct kvm_vcpu *, enum vcpu_sysreg);
|
||||
void vcpu_write_sys_reg(struct kvm_vcpu *, u64, enum vcpu_sysreg);
|
||||
|
||||
struct kvm_vm_stat {
|
||||
struct kvm_vm_stat_generic generic;
|
||||
|
||||
@@ -180,6 +180,7 @@ void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu);
|
||||
int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
|
||||
phys_addr_t pa, unsigned long size, bool writable);
|
||||
|
||||
int kvm_handle_guest_sea(struct kvm_vcpu *vcpu);
|
||||
int kvm_handle_guest_abort(struct kvm_vcpu *vcpu);
|
||||
|
||||
phys_addr_t kvm_mmu_get_httbr(void);
|
||||
|
||||
@@ -355,6 +355,11 @@ static inline kvm_pte_t *kvm_dereference_pteref(struct kvm_pgtable_walker *walke
|
||||
return pteref;
|
||||
}
|
||||
|
||||
static inline kvm_pte_t *kvm_dereference_pteref_raw(kvm_pteref_t pteref)
|
||||
{
|
||||
return pteref;
|
||||
}
|
||||
|
||||
static inline int kvm_pgtable_walk_begin(struct kvm_pgtable_walker *walker)
|
||||
{
|
||||
/*
|
||||
@@ -384,6 +389,11 @@ static inline kvm_pte_t *kvm_dereference_pteref(struct kvm_pgtable_walker *walke
|
||||
return rcu_dereference_check(pteref, !(walker->flags & KVM_PGTABLE_WALK_SHARED));
|
||||
}
|
||||
|
||||
static inline kvm_pte_t *kvm_dereference_pteref_raw(kvm_pteref_t pteref)
|
||||
{
|
||||
return rcu_dereference_raw(pteref);
|
||||
}
|
||||
|
||||
static inline int kvm_pgtable_walk_begin(struct kvm_pgtable_walker *walker)
|
||||
{
|
||||
if (walker->flags & KVM_PGTABLE_WALK_SHARED)
|
||||
@@ -551,6 +561,26 @@ static inline int kvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm_s2
|
||||
*/
|
||||
void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt);
|
||||
|
||||
/**
|
||||
* kvm_pgtable_stage2_destroy_range() - Destroy the unlinked range of addresses.
|
||||
* @pgt: Page-table structure initialised by kvm_pgtable_stage2_init*().
|
||||
* @addr: Intermediate physical address at which to place the mapping.
|
||||
* @size: Size of the mapping.
|
||||
*
|
||||
* The page-table is assumed to be unreachable by any hardware walkers prior
|
||||
* to freeing and therefore no TLB invalidation is performed.
|
||||
*/
|
||||
void kvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt,
|
||||
u64 addr, u64 size);
|
||||
|
||||
/**
|
||||
* kvm_pgtable_stage2_destroy_pgd() - Destroy the PGD of guest stage-2 page-table.
|
||||
* @pgt: Page-table structure initialised by kvm_pgtable_stage2_init*().
|
||||
*
|
||||
* It is assumed that the rest of the page-table is freed before this operation.
|
||||
*/
|
||||
void kvm_pgtable_stage2_destroy_pgd(struct kvm_pgtable *pgt);
|
||||
|
||||
/**
|
||||
* kvm_pgtable_stage2_free_unlinked() - Free an unlinked stage-2 paging structure.
|
||||
* @mm_ops: Memory management callbacks.
|
||||
|
||||
@@ -179,7 +179,9 @@ struct pkvm_mapping {
|
||||
|
||||
int pkvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm_s2_mmu *mmu,
|
||||
struct kvm_pgtable_mm_ops *mm_ops);
|
||||
void pkvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt);
|
||||
void pkvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt,
|
||||
u64 addr, u64 size);
|
||||
void pkvm_pgtable_stage2_destroy_pgd(struct kvm_pgtable *pgt);
|
||||
int pkvm_pgtable_stage2_map(struct kvm_pgtable *pgt, u64 addr, u64 size, u64 phys,
|
||||
enum kvm_pgtable_prot prot, void *mc,
|
||||
enum kvm_pgtable_walk_flags flags);
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (C) 2018 - Arm Ltd */
|
||||
|
||||
#ifndef __ARM64_KVM_RAS_H__
|
||||
#define __ARM64_KVM_RAS_H__
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/acpi.h>
|
||||
|
||||
/*
|
||||
* Was this synchronous external abort a RAS notification?
|
||||
* Returns '0' for errors handled by some RAS subsystem, or -ENOENT.
|
||||
*/
|
||||
static inline int kvm_handle_guest_sea(void)
|
||||
{
|
||||
/* apei_claim_sea(NULL) expects to mask interrupts itself */
|
||||
lockdep_assert_irqs_enabled();
|
||||
|
||||
return apei_claim_sea(NULL);
|
||||
}
|
||||
|
||||
#endif /* __ARM64_KVM_RAS_H__ */
|
||||
@@ -1142,9 +1142,6 @@
|
||||
|
||||
#define ARM64_FEATURE_FIELD_BITS 4
|
||||
|
||||
/* Defined for compatibility only, do not add new users. */
|
||||
#define ARM64_FEATURE_MASK(x) (x##_MASK)
|
||||
|
||||
#ifdef __ASSEMBLY__
|
||||
|
||||
.macro mrs_s, rt, sreg
|
||||
|
||||
@@ -2269,6 +2269,24 @@ static void cpu_clear_disr(const struct arm64_cpu_capabilities *__unused)
|
||||
/* Firmware may have left a deferred SError in this register. */
|
||||
write_sysreg_s(0, SYS_DISR_EL1);
|
||||
}
|
||||
static bool has_rasv1p1(const struct arm64_cpu_capabilities *__unused, int scope)
|
||||
{
|
||||
const struct arm64_cpu_capabilities rasv1p1_caps[] = {
|
||||
{
|
||||
ARM64_CPUID_FIELDS(ID_AA64PFR0_EL1, RAS, V1P1)
|
||||
},
|
||||
{
|
||||
ARM64_CPUID_FIELDS(ID_AA64PFR0_EL1, RAS, IMP)
|
||||
},
|
||||
{
|
||||
ARM64_CPUID_FIELDS(ID_AA64PFR1_EL1, RAS_frac, RASv1p1)
|
||||
},
|
||||
};
|
||||
|
||||
return (has_cpuid_feature(&rasv1p1_caps[0], scope) ||
|
||||
(has_cpuid_feature(&rasv1p1_caps[1], scope) &&
|
||||
has_cpuid_feature(&rasv1p1_caps[2], scope)));
|
||||
}
|
||||
#endif /* CONFIG_ARM64_RAS_EXTN */
|
||||
|
||||
#ifdef CONFIG_ARM64_PTR_AUTH
|
||||
@@ -2687,6 +2705,12 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
|
||||
.cpu_enable = cpu_clear_disr,
|
||||
ARM64_CPUID_FIELDS(ID_AA64PFR0_EL1, RAS, IMP)
|
||||
},
|
||||
{
|
||||
.desc = "RASv1p1 Extension Support",
|
||||
.capability = ARM64_HAS_RASV1P1_EXTN,
|
||||
.type = ARM64_CPUCAP_SYSTEM_FEATURE,
|
||||
.matches = has_rasv1p1,
|
||||
},
|
||||
#endif /* CONFIG_ARM64_RAS_EXTN */
|
||||
#ifdef CONFIG_ARM64_AMU_EXTN
|
||||
{
|
||||
|
||||
@@ -2408,12 +2408,12 @@ static u64 get_hyp_id_aa64pfr0_el1(void)
|
||||
*/
|
||||
u64 val = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
|
||||
|
||||
val &= ~(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV2) |
|
||||
ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV3));
|
||||
val &= ~(ID_AA64PFR0_EL1_CSV2 |
|
||||
ID_AA64PFR0_EL1_CSV3);
|
||||
|
||||
val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV2),
|
||||
val |= FIELD_PREP(ID_AA64PFR0_EL1_CSV2,
|
||||
arm64_get_spectre_v2_state() == SPECTRE_UNAFFECTED);
|
||||
val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV3),
|
||||
val |= FIELD_PREP(ID_AA64PFR0_EL1_CSV3,
|
||||
arm64_get_meltdown_state() == SPECTRE_UNAFFECTED);
|
||||
|
||||
return val;
|
||||
|
||||
+3
-3
@@ -1420,10 +1420,10 @@ void __kvm_at_s12(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If we only have a single stage of translation (E2H=0 or
|
||||
* TGE=1), exit early. Same thing if {VM,DC}=={0,0}.
|
||||
* If we only have a single stage of translation (EL2&0), exit
|
||||
* early. Same thing if {VM,DC}=={0,0}.
|
||||
*/
|
||||
if (!vcpu_el2_e2h_is_set(vcpu) || vcpu_el2_tge_is_set(vcpu) ||
|
||||
if (compute_translation_regime(vcpu, op) == TR_EL20 ||
|
||||
!(vcpu_read_sys_reg(vcpu, HCR_EL2) & (HCR_VM | HCR_DC)))
|
||||
return;
|
||||
|
||||
|
||||
@@ -2833,7 +2833,7 @@ int kvm_inject_nested_sea(struct kvm_vcpu *vcpu, bool iabt, u64 addr)
|
||||
iabt ? ESR_ELx_EC_IABT_LOW : ESR_ELx_EC_DABT_LOW);
|
||||
esr |= ESR_ELx_FSC_EXTABT | ESR_ELx_IL;
|
||||
|
||||
vcpu_write_sys_reg(vcpu, FAR_EL2, addr);
|
||||
vcpu_write_sys_reg(vcpu, addr, FAR_EL2);
|
||||
|
||||
if (__vcpu_sys_reg(vcpu, SCTLR2_EL2) & SCTLR2_EL1_EASE)
|
||||
return kvm_inject_nested(vcpu, esr, except_type_serror);
|
||||
|
||||
@@ -22,36 +22,28 @@
|
||||
|
||||
static inline u64 __vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg)
|
||||
{
|
||||
u64 val;
|
||||
|
||||
if (unlikely(vcpu_has_nv(vcpu)))
|
||||
if (has_vhe())
|
||||
return vcpu_read_sys_reg(vcpu, reg);
|
||||
else if (vcpu_get_flag(vcpu, SYSREGS_ON_CPU) &&
|
||||
__vcpu_read_sys_reg_from_cpu(reg, &val))
|
||||
return val;
|
||||
|
||||
return __vcpu_sys_reg(vcpu, reg);
|
||||
}
|
||||
|
||||
static inline void __vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg)
|
||||
{
|
||||
if (unlikely(vcpu_has_nv(vcpu)))
|
||||
if (has_vhe())
|
||||
vcpu_write_sys_reg(vcpu, val, reg);
|
||||
else if (!vcpu_get_flag(vcpu, SYSREGS_ON_CPU) ||
|
||||
!__vcpu_write_sys_reg_to_cpu(val, reg))
|
||||
else
|
||||
__vcpu_assign_sys_reg(vcpu, reg, val);
|
||||
}
|
||||
|
||||
static void __vcpu_write_spsr(struct kvm_vcpu *vcpu, unsigned long target_mode,
|
||||
u64 val)
|
||||
{
|
||||
if (unlikely(vcpu_has_nv(vcpu))) {
|
||||
if (has_vhe()) {
|
||||
if (target_mode == PSR_MODE_EL1h)
|
||||
vcpu_write_sys_reg(vcpu, val, SPSR_EL1);
|
||||
else
|
||||
vcpu_write_sys_reg(vcpu, val, SPSR_EL2);
|
||||
} else if (has_vhe()) {
|
||||
write_sysreg_el1(val, SYS_SPSR);
|
||||
} else {
|
||||
__vcpu_assign_sys_reg(vcpu, SPSR_EL1, val);
|
||||
}
|
||||
@@ -59,7 +51,7 @@ static void __vcpu_write_spsr(struct kvm_vcpu *vcpu, unsigned long target_mode,
|
||||
|
||||
static void __vcpu_write_spsr_abt(struct kvm_vcpu *vcpu, u64 val)
|
||||
{
|
||||
if (has_vhe())
|
||||
if (has_vhe() && vcpu_get_flag(vcpu, SYSREGS_ON_CPU))
|
||||
write_sysreg(val, spsr_abt);
|
||||
else
|
||||
vcpu->arch.ctxt.spsr_abt = val;
|
||||
@@ -67,7 +59,7 @@ static void __vcpu_write_spsr_abt(struct kvm_vcpu *vcpu, u64 val)
|
||||
|
||||
static void __vcpu_write_spsr_und(struct kvm_vcpu *vcpu, u64 val)
|
||||
{
|
||||
if (has_vhe())
|
||||
if (has_vhe() && vcpu_get_flag(vcpu, SYSREGS_ON_CPU))
|
||||
write_sysreg(val, spsr_und);
|
||||
else
|
||||
vcpu->arch.ctxt.spsr_und = val;
|
||||
|
||||
@@ -17,7 +17,7 @@ static inline __must_check bool nvhe_check_data_corruption(bool v)
|
||||
bool corruption = unlikely(condition); \
|
||||
if (corruption) { \
|
||||
if (IS_ENABLED(CONFIG_BUG_ON_DATA_CORRUPTION)) { \
|
||||
BUG_ON(1); \
|
||||
BUG(); \
|
||||
} else \
|
||||
WARN_ON(1); \
|
||||
} \
|
||||
|
||||
@@ -253,6 +253,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
|
||||
|
||||
*vcpu_pc(vcpu) = read_sysreg_el2(SYS_ELR);
|
||||
*vcpu_cpsr(vcpu) = read_sysreg_el2(SYS_SPSR);
|
||||
__vcpu_assign_sys_reg(vcpu, read_sysreg_el1(SYS_VBAR), VBAR_EL1);
|
||||
|
||||
kvm_pend_exception(vcpu, EXCEPT_AA64_EL1_SYNC);
|
||||
|
||||
@@ -372,6 +373,9 @@ static const struct sys_reg_desc pvm_sys_reg_descs[] = {
|
||||
|
||||
/* Debug and Trace Registers are restricted. */
|
||||
|
||||
/* Group 1 ID registers */
|
||||
HOST_HANDLED(SYS_REVIDR_EL1),
|
||||
|
||||
/* AArch64 mappings of the AArch32 ID registers */
|
||||
/* CRm=1 */
|
||||
AARCH32(SYS_ID_PFR0_EL1),
|
||||
@@ -460,6 +464,7 @@ static const struct sys_reg_desc pvm_sys_reg_descs[] = {
|
||||
|
||||
HOST_HANDLED(SYS_CCSIDR_EL1),
|
||||
HOST_HANDLED(SYS_CLIDR_EL1),
|
||||
HOST_HANDLED(SYS_AIDR_EL1),
|
||||
HOST_HANDLED(SYS_CSSELR_EL1),
|
||||
HOST_HANDLED(SYS_CTR_EL0),
|
||||
|
||||
|
||||
@@ -1551,21 +1551,38 @@ static int stage2_free_walker(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt)
|
||||
void kvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt,
|
||||
u64 addr, u64 size)
|
||||
{
|
||||
size_t pgd_sz;
|
||||
struct kvm_pgtable_walker walker = {
|
||||
.cb = stage2_free_walker,
|
||||
.flags = KVM_PGTABLE_WALK_LEAF |
|
||||
KVM_PGTABLE_WALK_TABLE_POST,
|
||||
};
|
||||
|
||||
WARN_ON(kvm_pgtable_walk(pgt, 0, BIT(pgt->ia_bits), &walker));
|
||||
WARN_ON(kvm_pgtable_walk(pgt, addr, size, &walker));
|
||||
}
|
||||
|
||||
void kvm_pgtable_stage2_destroy_pgd(struct kvm_pgtable *pgt)
|
||||
{
|
||||
size_t pgd_sz;
|
||||
|
||||
pgd_sz = kvm_pgd_pages(pgt->ia_bits, pgt->start_level) * PAGE_SIZE;
|
||||
pgt->mm_ops->free_pages_exact(kvm_dereference_pteref(&walker, pgt->pgd), pgd_sz);
|
||||
|
||||
/*
|
||||
* Since the pgtable is unlinked at this point, and not shared with
|
||||
* other walkers, safely deference pgd with kvm_dereference_pteref_raw()
|
||||
*/
|
||||
pgt->mm_ops->free_pages_exact(kvm_dereference_pteref_raw(pgt->pgd), pgd_sz);
|
||||
pgt->pgd = NULL;
|
||||
}
|
||||
|
||||
void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt)
|
||||
{
|
||||
kvm_pgtable_stage2_destroy_range(pgt, 0, BIT(pgt->ia_bits));
|
||||
kvm_pgtable_stage2_destroy_pgd(pgt);
|
||||
}
|
||||
|
||||
void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, s8 level)
|
||||
{
|
||||
kvm_pteref_t ptep = (kvm_pteref_t)pgtable;
|
||||
|
||||
@@ -20,7 +20,7 @@ static bool __is_be(struct kvm_vcpu *vcpu)
|
||||
if (vcpu_mode_is_32bit(vcpu))
|
||||
return !!(read_sysreg_el2(SYS_SPSR) & PSR_AA32_E_BIT);
|
||||
|
||||
return !!(read_sysreg(SCTLR_EL1) & SCTLR_ELx_EE);
|
||||
return !!(read_sysreg_el1(SYS_SCTLR) & SCTLR_ELx_EE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -43,8 +43,11 @@ DEFINE_PER_CPU(unsigned long, kvm_hyp_vector);
|
||||
*
|
||||
* - API/APK: they are already accounted for by vcpu_load(), and can
|
||||
* only take effect across a load/put cycle (such as ERET)
|
||||
*
|
||||
* - FIEN: no way we let a guest have access to the RAS "Common Fault
|
||||
* Injection" thing, whatever that does
|
||||
*/
|
||||
#define NV_HCR_GUEST_EXCLUDE (HCR_TGE | HCR_API | HCR_APK)
|
||||
#define NV_HCR_GUEST_EXCLUDE (HCR_TGE | HCR_API | HCR_APK | HCR_FIEN)
|
||||
|
||||
static u64 __compute_hcr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
|
||||
+51
-14
@@ -4,19 +4,20 @@
|
||||
* Author: Christoffer Dall <c.dall@virtualopensystems.com>
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/mman.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/hugetlb.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <trace/events/kvm.h>
|
||||
#include <asm/acpi.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/kvm_arm.h>
|
||||
#include <asm/kvm_mmu.h>
|
||||
#include <asm/kvm_pgtable.h>
|
||||
#include <asm/kvm_pkvm.h>
|
||||
#include <asm/kvm_ras.h>
|
||||
#include <asm/kvm_asm.h>
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <asm/virt.h>
|
||||
@@ -903,6 +904,38 @@ static int kvm_init_ipa_range(struct kvm_s2_mmu *mmu, unsigned long type)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Assume that @pgt is valid and unlinked from the KVM MMU to free the
|
||||
* page-table without taking the kvm_mmu_lock and without performing any
|
||||
* TLB invalidations.
|
||||
*
|
||||
* Also, the range of addresses can be large enough to cause need_resched
|
||||
* warnings, for instance on CONFIG_PREEMPT_NONE kernels. Hence, invoke
|
||||
* cond_resched() periodically to prevent hogging the CPU for a long time
|
||||
* and schedule something else, if required.
|
||||
*/
|
||||
static void stage2_destroy_range(struct kvm_pgtable *pgt, phys_addr_t addr,
|
||||
phys_addr_t end)
|
||||
{
|
||||
u64 next;
|
||||
|
||||
do {
|
||||
next = stage2_range_addr_end(addr, end);
|
||||
KVM_PGT_FN(kvm_pgtable_stage2_destroy_range)(pgt, addr,
|
||||
next - addr);
|
||||
if (next != end)
|
||||
cond_resched();
|
||||
} while (addr = next, addr != end);
|
||||
}
|
||||
|
||||
static void kvm_stage2_destroy(struct kvm_pgtable *pgt)
|
||||
{
|
||||
unsigned int ia_bits = VTCR_EL2_IPA(pgt->mmu->vtcr);
|
||||
|
||||
stage2_destroy_range(pgt, 0, BIT(ia_bits));
|
||||
KVM_PGT_FN(kvm_pgtable_stage2_destroy_pgd)(pgt);
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_init_stage2_mmu - Initialise a S2 MMU structure
|
||||
* @kvm: The pointer to the KVM structure
|
||||
@@ -979,7 +1012,7 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long t
|
||||
return 0;
|
||||
|
||||
out_destroy_pgtable:
|
||||
KVM_PGT_FN(kvm_pgtable_stage2_destroy)(pgt);
|
||||
kvm_stage2_destroy(pgt);
|
||||
out_free_pgtable:
|
||||
kfree(pgt);
|
||||
return err;
|
||||
@@ -1076,7 +1109,7 @@ void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu)
|
||||
write_unlock(&kvm->mmu_lock);
|
||||
|
||||
if (pgt) {
|
||||
KVM_PGT_FN(kvm_pgtable_stage2_destroy)(pgt);
|
||||
kvm_stage2_destroy(pgt);
|
||||
kfree(pgt);
|
||||
}
|
||||
}
|
||||
@@ -1811,6 +1844,19 @@ static void handle_access_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
|
||||
read_unlock(&vcpu->kvm->mmu_lock);
|
||||
}
|
||||
|
||||
int kvm_handle_guest_sea(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/*
|
||||
* Give APEI the opportunity to claim the abort before handling it
|
||||
* within KVM. apei_claim_sea() expects to be called with IRQs enabled.
|
||||
*/
|
||||
lockdep_assert_irqs_enabled();
|
||||
if (apei_claim_sea(NULL) == 0)
|
||||
return 1;
|
||||
|
||||
return kvm_inject_serror(vcpu);
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_handle_guest_abort - handles all 2nd stage aborts
|
||||
* @vcpu: the VCPU pointer
|
||||
@@ -1834,17 +1880,8 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
|
||||
gfn_t gfn;
|
||||
int ret, idx;
|
||||
|
||||
/* Synchronous External Abort? */
|
||||
if (kvm_vcpu_abt_issea(vcpu)) {
|
||||
/*
|
||||
* For RAS the host kernel may handle this abort.
|
||||
* There is no need to pass the error into the guest.
|
||||
*/
|
||||
if (kvm_handle_guest_sea())
|
||||
return kvm_inject_serror(vcpu);
|
||||
|
||||
return 1;
|
||||
}
|
||||
if (kvm_vcpu_abt_issea(vcpu))
|
||||
return kvm_handle_guest_sea(vcpu);
|
||||
|
||||
esr = kvm_vcpu_get_esr(vcpu);
|
||||
|
||||
|
||||
@@ -1287,7 +1287,10 @@ int kvm_handle_vncr_abort(struct kvm_vcpu *vcpu)
|
||||
struct vncr_tlb *vt = vcpu->arch.vncr_tlb;
|
||||
u64 esr = kvm_vcpu_get_esr(vcpu);
|
||||
|
||||
BUG_ON(!(esr & ESR_ELx_VNCR_SHIFT));
|
||||
WARN_ON_ONCE(!(esr & ESR_ELx_VNCR));
|
||||
|
||||
if (kvm_vcpu_abt_issea(vcpu))
|
||||
return kvm_handle_guest_sea(vcpu);
|
||||
|
||||
if (esr_fsc_is_permission_fault(esr)) {
|
||||
inject_vncr_perm(vcpu);
|
||||
|
||||
@@ -316,9 +316,16 @@ static int __pkvm_pgtable_stage2_unmap(struct kvm_pgtable *pgt, u64 start, u64 e
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pkvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt)
|
||||
void pkvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt,
|
||||
u64 addr, u64 size)
|
||||
{
|
||||
__pkvm_pgtable_stage2_unmap(pgt, 0, ~(0ULL));
|
||||
__pkvm_pgtable_stage2_unmap(pgt, addr, addr + size);
|
||||
}
|
||||
|
||||
void pkvm_pgtable_stage2_destroy_pgd(struct kvm_pgtable *pgt)
|
||||
{
|
||||
/* Expected to be called after all pKVM mappings have been released. */
|
||||
WARN_ON_ONCE(!RB_EMPTY_ROOT(&pgt->pkvm_mappings.rb_root));
|
||||
}
|
||||
|
||||
int pkvm_pgtable_stage2_map(struct kvm_pgtable *pgt, u64 addr, u64 size,
|
||||
|
||||
+293
-138
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user