mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 18:13:41 +02:00
Merge branch kvm-arm64/pkvm-fixed-features-6.14 into kvmarm-master/next
* kvm-arm64/pkvm-fixed-features-6.14: (24 commits) : . : Complete rework of the pKVM handling of features, catching up : with the rest of the code deals with it these days. : Patches courtesy of Fuad Tabba. From the cover letter: : : "This patch series uses the vm's feature id registers to track the : supported features, a framework similar to nested virt to set the : trap values, and removes the need to store cptr_el2 per vcpu in : favor of setting its value when traps are activated, as VHE mode : does." : : This branch drags the arm64/for-next/cpufeature branch to solve : ugly conflicts in -next. : . KVM: arm64: Fix FEAT_MTE in pKVM KVM: arm64: Use kvm_vcpu_has_feature() directly for struct kvm KVM: arm64: Convert the SVE guest vcpu flag to a vm flag KVM: arm64: Remove PtrAuth guest vcpu flag KVM: arm64: Fix the value of the CPTR_EL2 RES1 bitmask for nVHE KVM: arm64: Refactor kvm_reset_cptr_el2() KVM: arm64: Calculate cptr_el2 traps on activating traps KVM: arm64: Remove redundant setting of HCR_EL2 trap bit KVM: arm64: Remove fixed_config.h header KVM: arm64: Rework specifying restricted features for protected VMs KVM: arm64: Set protected VM traps based on its view of feature registers KVM: arm64: Fix RAS trapping in pKVM for protected VMs KVM: arm64: Initialize feature id registers for protected VMs KVM: arm64: Use KVM extension checks for allowed protected VM capabilities KVM: arm64: Remove KVM_ARM_VCPU_POWER_OFF from protected VMs allowed features in pKVM KVM: arm64: Move checking protected vcpu features to a separate function KVM: arm64: Group setting traps for protected VMs by control register KVM: arm64: Consolidate allowed and restricted VM feature checks arm64/sysreg: Get rid of CPACR_ELx SysregFields arm64/sysreg: Convert *_EL12 accessors to Mapping ... Signed-off-by: Marc Zyngier <maz@kernel.org> # Conflicts: # arch/arm64/kvm/fpsimd.c # arch/arm64/kvm/hyp/nvhe/pkvm.c
This commit is contained in:
commit
e880b16efb
|
|
@ -46,6 +46,8 @@ cpucap_is_possible(const unsigned int cap)
|
|||
return IS_ENABLED(CONFIG_ARM64_POE);
|
||||
case ARM64_HAS_GCS:
|
||||
return IS_ENABLED(CONFIG_ARM64_GCS);
|
||||
case ARM64_HAFT:
|
||||
return IS_ENABLED(CONFIG_ARM64_HAFT);
|
||||
case ARM64_UNMAP_KERNEL_AT_EL0:
|
||||
return IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0);
|
||||
case ARM64_WORKAROUND_843419:
|
||||
|
|
|
|||
|
|
@ -852,8 +852,7 @@ static inline bool system_supports_gcs(void)
|
|||
|
||||
static inline bool system_supports_haft(void)
|
||||
{
|
||||
return IS_ENABLED(CONFIG_ARM64_HAFT) &&
|
||||
cpus_have_final_cap(ARM64_HAFT);
|
||||
return cpus_have_final_cap(ARM64_HAFT);
|
||||
}
|
||||
|
||||
static __always_inline bool system_supports_mpam(void)
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@
|
|||
/* Coprocessor traps */
|
||||
.macro __init_el2_cptr
|
||||
__check_hvhe .LnVHE_\@, x1
|
||||
mov x0, #CPACR_ELx_FPEN
|
||||
mov x0, #CPACR_EL1_FPEN
|
||||
msr cpacr_el1, x0
|
||||
b .Lskip_set_cptr_\@
|
||||
.LnVHE_\@:
|
||||
|
|
@ -332,7 +332,7 @@
|
|||
|
||||
// (h)VHE case
|
||||
mrs x0, cpacr_el1 // Disable SVE traps
|
||||
orr x0, x0, #CPACR_ELx_ZEN
|
||||
orr x0, x0, #CPACR_EL1_ZEN
|
||||
msr cpacr_el1, x0
|
||||
b .Lskip_set_cptr_\@
|
||||
|
||||
|
|
@ -353,7 +353,7 @@
|
|||
|
||||
// (h)VHE case
|
||||
mrs x0, cpacr_el1 // Disable SME traps
|
||||
orr x0, x0, #CPACR_ELx_SMEN
|
||||
orr x0, x0, #CPACR_EL1_SMEN
|
||||
msr cpacr_el1, x0
|
||||
b .Lskip_set_cptr_sme_\@
|
||||
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@
|
|||
#define CPTR_EL2_TSM (1 << 12)
|
||||
#define CPTR_EL2_TFP (1 << CPTR_EL2_TFP_SHIFT)
|
||||
#define CPTR_EL2_TZ (1 << 8)
|
||||
#define CPTR_NVHE_EL2_RES1 0x000032ff /* known RES1 bits in CPTR_EL2 (nVHE) */
|
||||
#define CPTR_NVHE_EL2_RES1 (BIT(13) | BIT(9) | GENMASK(7, 0))
|
||||
#define CPTR_NVHE_EL2_RES0 (GENMASK(63, 32) | \
|
||||
GENMASK(29, 21) | \
|
||||
GENMASK(19, 14) | \
|
||||
|
|
@ -391,8 +391,6 @@
|
|||
ECN(SOFTSTP_CUR), ECN(WATCHPT_LOW), ECN(WATCHPT_CUR), \
|
||||
ECN(BKPT32), ECN(VECTOR32), ECN(BRK64), ECN(ERET)
|
||||
|
||||
#define CPACR_EL1_TTA (1 << 28)
|
||||
|
||||
#define kvm_mode_names \
|
||||
{ PSR_MODE_EL0t, "EL0t" }, \
|
||||
{ PSR_MODE_EL1t, "EL1t" }, \
|
||||
|
|
|
|||
|
|
@ -556,13 +556,13 @@ static __always_inline void kvm_incr_pc(struct kvm_vcpu *vcpu)
|
|||
({ \
|
||||
u64 cptr = 0; \
|
||||
\
|
||||
if ((set) & CPACR_ELx_FPEN) \
|
||||
if ((set) & CPACR_EL1_FPEN) \
|
||||
cptr |= CPTR_EL2_TFP; \
|
||||
if ((set) & CPACR_ELx_ZEN) \
|
||||
if ((set) & CPACR_EL1_ZEN) \
|
||||
cptr |= CPTR_EL2_TZ; \
|
||||
if ((set) & CPACR_ELx_SMEN) \
|
||||
if ((set) & CPACR_EL1_SMEN) \
|
||||
cptr |= CPTR_EL2_TSM; \
|
||||
if ((clr) & CPACR_ELx_TTA) \
|
||||
if ((clr) & CPACR_EL1_TTA) \
|
||||
cptr |= CPTR_EL2_TTA; \
|
||||
if ((clr) & CPTR_EL2_TAM) \
|
||||
cptr |= CPTR_EL2_TAM; \
|
||||
|
|
@ -576,13 +576,13 @@ static __always_inline void kvm_incr_pc(struct kvm_vcpu *vcpu)
|
|||
({ \
|
||||
u64 cptr = 0; \
|
||||
\
|
||||
if ((clr) & CPACR_ELx_FPEN) \
|
||||
if ((clr) & CPACR_EL1_FPEN) \
|
||||
cptr |= CPTR_EL2_TFP; \
|
||||
if ((clr) & CPACR_ELx_ZEN) \
|
||||
if ((clr) & CPACR_EL1_ZEN) \
|
||||
cptr |= CPTR_EL2_TZ; \
|
||||
if ((clr) & CPACR_ELx_SMEN) \
|
||||
if ((clr) & CPACR_EL1_SMEN) \
|
||||
cptr |= CPTR_EL2_TSM; \
|
||||
if ((set) & CPACR_ELx_TTA) \
|
||||
if ((set) & CPACR_EL1_TTA) \
|
||||
cptr |= CPTR_EL2_TTA; \
|
||||
if ((set) & CPTR_EL2_TAM) \
|
||||
cptr |= CPTR_EL2_TAM; \
|
||||
|
|
@ -595,13 +595,13 @@ static __always_inline void kvm_incr_pc(struct kvm_vcpu *vcpu)
|
|||
#define cpacr_clear_set(clr, set) \
|
||||
do { \
|
||||
BUILD_BUG_ON((set) & CPTR_VHE_EL2_RES0); \
|
||||
BUILD_BUG_ON((clr) & CPACR_ELx_E0POE); \
|
||||
__build_check_all_or_none((clr), CPACR_ELx_FPEN); \
|
||||
__build_check_all_or_none((set), CPACR_ELx_FPEN); \
|
||||
__build_check_all_or_none((clr), CPACR_ELx_ZEN); \
|
||||
__build_check_all_or_none((set), CPACR_ELx_ZEN); \
|
||||
__build_check_all_or_none((clr), CPACR_ELx_SMEN); \
|
||||
__build_check_all_or_none((set), CPACR_ELx_SMEN); \
|
||||
BUILD_BUG_ON((clr) & CPACR_EL1_E0POE); \
|
||||
__build_check_all_or_none((clr), CPACR_EL1_FPEN); \
|
||||
__build_check_all_or_none((set), CPACR_EL1_FPEN); \
|
||||
__build_check_all_or_none((clr), CPACR_EL1_ZEN); \
|
||||
__build_check_all_or_none((set), CPACR_EL1_ZEN); \
|
||||
__build_check_all_or_none((clr), CPACR_EL1_SMEN); \
|
||||
__build_check_all_or_none((set), CPACR_EL1_SMEN); \
|
||||
\
|
||||
if (has_vhe() || has_hvhe()) \
|
||||
sysreg_clear_set(cpacr_el1, clr, set); \
|
||||
|
|
@ -619,40 +619,40 @@ static __always_inline void kvm_write_cptr_el2(u64 val)
|
|||
write_sysreg(val, cptr_el2);
|
||||
}
|
||||
|
||||
static __always_inline u64 kvm_get_reset_cptr_el2(struct kvm_vcpu *vcpu)
|
||||
/* Resets the value of cptr_el2 when returning to the host. */
|
||||
static __always_inline void __kvm_reset_cptr_el2(struct kvm *kvm)
|
||||
{
|
||||
u64 val;
|
||||
|
||||
if (has_vhe()) {
|
||||
val = (CPACR_ELx_FPEN | CPACR_EL1_ZEN_EL1EN);
|
||||
val = (CPACR_EL1_FPEN | CPACR_EL1_ZEN_EL1EN);
|
||||
if (cpus_have_final_cap(ARM64_SME))
|
||||
val |= CPACR_EL1_SMEN_EL1EN;
|
||||
} else if (has_hvhe()) {
|
||||
val = CPACR_ELx_FPEN;
|
||||
val = CPACR_EL1_FPEN;
|
||||
|
||||
if (!vcpu_has_sve(vcpu) || !guest_owns_fp_regs())
|
||||
val |= CPACR_ELx_ZEN;
|
||||
if (!kvm_has_sve(kvm) || !guest_owns_fp_regs())
|
||||
val |= CPACR_EL1_ZEN;
|
||||
if (cpus_have_final_cap(ARM64_SME))
|
||||
val |= CPACR_ELx_SMEN;
|
||||
val |= CPACR_EL1_SMEN;
|
||||
} else {
|
||||
val = CPTR_NVHE_EL2_RES1;
|
||||
|
||||
if (vcpu_has_sve(vcpu) && guest_owns_fp_regs())
|
||||
if (kvm_has_sve(kvm) && guest_owns_fp_regs())
|
||||
val |= CPTR_EL2_TZ;
|
||||
if (cpus_have_final_cap(ARM64_SME))
|
||||
val &= ~CPTR_EL2_TSM;
|
||||
if (!cpus_have_final_cap(ARM64_SME))
|
||||
val |= CPTR_EL2_TSM;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static __always_inline void kvm_reset_cptr_el2(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 val = kvm_get_reset_cptr_el2(vcpu);
|
||||
|
||||
kvm_write_cptr_el2(val);
|
||||
}
|
||||
|
||||
#ifdef __KVM_NVHE_HYPERVISOR__
|
||||
#define kvm_reset_cptr_el2(v) __kvm_reset_cptr_el2(kern_hyp_va((v)->kvm))
|
||||
#else
|
||||
#define kvm_reset_cptr_el2(v) __kvm_reset_cptr_el2((v)->kvm)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Returns a 'sanitised' view of CPTR_EL2, translating from nVHE to the VHE
|
||||
* format if E2H isn't set.
|
||||
|
|
@ -685,7 +685,7 @@ static inline bool ____cptr_xen_trap_enabled(const struct kvm_vcpu *vcpu,
|
|||
#define __guest_hyp_cptr_xen_trap_enabled(vcpu, xen) \
|
||||
(!vcpu_has_nv(vcpu) ? false : \
|
||||
____cptr_xen_trap_enabled(vcpu, \
|
||||
SYS_FIELD_GET(CPACR_ELx, xen, \
|
||||
SYS_FIELD_GET(CPACR_EL1, xen, \
|
||||
vcpu_sanitised_cptr_el2(vcpu))))
|
||||
|
||||
static inline bool guest_hyp_fpsimd_traps_enabled(const struct kvm_vcpu *vcpu)
|
||||
|
|
@ -697,9 +697,4 @@ static inline bool guest_hyp_sve_traps_enabled(const struct kvm_vcpu *vcpu)
|
|||
{
|
||||
return __guest_hyp_cptr_xen_trap_enabled(vcpu, ZEN);
|
||||
}
|
||||
|
||||
static inline void kvm_vcpu_enable_ptrauth(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
vcpu_set_flag(vcpu, GUEST_HAS_PTRAUTH);
|
||||
}
|
||||
#endif /* __ARM64_KVM_EMULATE_H__ */
|
||||
|
|
|
|||
|
|
@ -332,6 +332,8 @@ struct kvm_arch {
|
|||
#define KVM_ARCH_FLAG_ID_REGS_INITIALIZED 7
|
||||
/* Fine-Grained UNDEF initialised */
|
||||
#define KVM_ARCH_FLAG_FGU_INITIALIZED 8
|
||||
/* SVE exposed to guest */
|
||||
#define KVM_ARCH_FLAG_GUEST_HAS_SVE 9
|
||||
unsigned long flags;
|
||||
|
||||
/* VM-wide vCPU feature set */
|
||||
|
|
@ -722,7 +724,6 @@ struct kvm_vcpu_arch {
|
|||
u64 hcr_el2;
|
||||
u64 hcrx_el2;
|
||||
u64 mdcr_el2;
|
||||
u64 cptr_el2;
|
||||
|
||||
/* Exception Information */
|
||||
struct kvm_vcpu_fault_info fault;
|
||||
|
|
@ -871,14 +872,10 @@ struct kvm_vcpu_arch {
|
|||
#define vcpu_set_flag(v, ...) __vcpu_set_flag((v), __VA_ARGS__)
|
||||
#define vcpu_clear_flag(v, ...) __vcpu_clear_flag((v), __VA_ARGS__)
|
||||
|
||||
/* SVE exposed to guest */
|
||||
#define GUEST_HAS_SVE __vcpu_single_flag(cflags, BIT(0))
|
||||
/* KVM_ARM_VCPU_INIT completed */
|
||||
#define VCPU_INITIALIZED __vcpu_single_flag(cflags, BIT(0))
|
||||
/* SVE config completed */
|
||||
#define VCPU_SVE_FINALIZED __vcpu_single_flag(cflags, BIT(1))
|
||||
/* PTRAUTH exposed to guest */
|
||||
#define GUEST_HAS_PTRAUTH __vcpu_single_flag(cflags, BIT(2))
|
||||
/* KVM_ARM_VCPU_INIT completed */
|
||||
#define VCPU_INITIALIZED __vcpu_single_flag(cflags, BIT(3))
|
||||
|
||||
/* Exception pending */
|
||||
#define PENDING_EXCEPTION __vcpu_single_flag(iflags, BIT(0))
|
||||
|
|
@ -959,14 +956,21 @@ struct kvm_vcpu_arch {
|
|||
KVM_GUESTDBG_USE_HW | \
|
||||
KVM_GUESTDBG_SINGLESTEP)
|
||||
|
||||
#define vcpu_has_sve(vcpu) (system_supports_sve() && \
|
||||
vcpu_get_flag(vcpu, GUEST_HAS_SVE))
|
||||
#define kvm_has_sve(kvm) (system_supports_sve() && \
|
||||
test_bit(KVM_ARCH_FLAG_GUEST_HAS_SVE, &(kvm)->arch.flags))
|
||||
|
||||
#ifdef __KVM_NVHE_HYPERVISOR__
|
||||
#define vcpu_has_sve(vcpu) kvm_has_sve(kern_hyp_va((vcpu)->kvm))
|
||||
#else
|
||||
#define vcpu_has_sve(vcpu) kvm_has_sve((vcpu)->kvm)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARM64_PTR_AUTH
|
||||
#define vcpu_has_ptrauth(vcpu) \
|
||||
((cpus_have_final_cap(ARM64_HAS_ADDRESS_AUTH) || \
|
||||
cpus_have_final_cap(ARM64_HAS_GENERIC_AUTH)) && \
|
||||
vcpu_get_flag(vcpu, GUEST_HAS_PTRAUTH))
|
||||
(vcpu_has_feature(vcpu, KVM_ARM_VCPU_PTRAUTH_ADDRESS) || \
|
||||
vcpu_has_feature(vcpu, KVM_ARM_VCPU_PTRAUTH_GENERIC)))
|
||||
#else
|
||||
#define vcpu_has_ptrauth(vcpu) false
|
||||
#endif
|
||||
|
|
@ -1432,6 +1436,7 @@ static inline bool __vcpu_has_feature(const struct kvm_arch *ka, int feature)
|
|||
return test_bit(feature, ka->vcpu_features);
|
||||
}
|
||||
|
||||
#define kvm_vcpu_has_feature(k, f) __vcpu_has_feature(&(k)->arch, (f))
|
||||
#define vcpu_has_feature(v, f) __vcpu_has_feature(&(v)->kvm->arch, (f))
|
||||
|
||||
#define kvm_vcpu_initialized(v) vcpu_get_flag(vcpu, VCPU_INITIALIZED)
|
||||
|
|
|
|||
|
|
@ -33,14 +33,14 @@ static inline u64 translate_tcr_el2_to_tcr_el1(u64 tcr)
|
|||
|
||||
static inline u64 translate_cptr_el2_to_cpacr_el1(u64 cptr_el2)
|
||||
{
|
||||
u64 cpacr_el1 = CPACR_ELx_RES1;
|
||||
u64 cpacr_el1 = CPACR_EL1_RES1;
|
||||
|
||||
if (cptr_el2 & CPTR_EL2_TTA)
|
||||
cpacr_el1 |= CPACR_ELx_TTA;
|
||||
cpacr_el1 |= CPACR_EL1_TTA;
|
||||
if (!(cptr_el2 & CPTR_EL2_TFP))
|
||||
cpacr_el1 |= CPACR_ELx_FPEN;
|
||||
cpacr_el1 |= CPACR_EL1_FPEN;
|
||||
if (!(cptr_el2 & CPTR_EL2_TZ))
|
||||
cpacr_el1 |= CPACR_ELx_ZEN;
|
||||
cpacr_el1 |= CPACR_EL1_ZEN;
|
||||
|
||||
cpacr_el1 |= cptr_el2 & (CPTR_EL2_TCPAC | CPTR_EL2_TAM);
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,31 @@ int pkvm_init_host_vm(struct kvm *kvm);
|
|||
int pkvm_create_hyp_vm(struct kvm *kvm);
|
||||
void pkvm_destroy_hyp_vm(struct kvm *kvm);
|
||||
|
||||
/*
|
||||
* This functions as an allow-list of protected VM capabilities.
|
||||
* Features not explicitly allowed by this function are denied.
|
||||
*/
|
||||
static inline bool kvm_pvm_ext_allowed(long ext)
|
||||
{
|
||||
switch (ext) {
|
||||
case KVM_CAP_IRQCHIP:
|
||||
case KVM_CAP_ARM_PSCI:
|
||||
case KVM_CAP_ARM_PSCI_0_2:
|
||||
case KVM_CAP_NR_VCPUS:
|
||||
case KVM_CAP_MAX_VCPUS:
|
||||
case KVM_CAP_MAX_VCPU_ID:
|
||||
case KVM_CAP_MSI_DEVID:
|
||||
case KVM_CAP_ARM_VM_IPA_SIZE:
|
||||
case KVM_CAP_ARM_PMU_V3:
|
||||
case KVM_CAP_ARM_SVE:
|
||||
case KVM_CAP_ARM_PTRAUTH_ADDRESS:
|
||||
case KVM_CAP_ARM_PTRAUTH_GENERIC:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
extern struct memblock_region kvm_nvhe_sym(hyp_memory)[];
|
||||
extern unsigned int kvm_nvhe_sym(hyp_memblock_nr);
|
||||
|
||||
|
|
|
|||
|
|
@ -1004,17 +1004,16 @@ static void init_cpu_ftr_reg(u32 sys_reg, u64 new)
|
|||
/* Override was valid */
|
||||
ftr_new = tmp;
|
||||
str = "forced";
|
||||
} else if (ftr_ovr == tmp) {
|
||||
} else {
|
||||
/* Override was the safe value */
|
||||
str = "already set";
|
||||
}
|
||||
|
||||
if (str)
|
||||
pr_warn("%s[%d:%d]: %s to %llx\n",
|
||||
reg->name,
|
||||
ftrp->shift + ftrp->width - 1,
|
||||
ftrp->shift, str,
|
||||
tmp & (BIT(ftrp->width) - 1));
|
||||
pr_warn("%s[%d:%d]: %s to %llx\n",
|
||||
reg->name,
|
||||
ftrp->shift + ftrp->width - 1,
|
||||
ftrp->shift, str,
|
||||
tmp & (BIT(ftrp->width) - 1));
|
||||
} else if ((ftr_mask & reg->override->val) == ftr_mask) {
|
||||
reg->override->val &= ~ftr_mask;
|
||||
pr_warn("%s[%d:%d]: impossible override, ignored\n",
|
||||
|
|
@ -2376,8 +2375,8 @@ static void cpu_enable_mops(const struct arm64_cpu_capabilities *__unused)
|
|||
#ifdef CONFIG_ARM64_POE
|
||||
static void cpu_enable_poe(const struct arm64_cpu_capabilities *__unused)
|
||||
{
|
||||
sysreg_clear_set(REG_TCR2_EL1, 0, TCR2_EL1x_E0POE);
|
||||
sysreg_clear_set(CPACR_EL1, 0, CPACR_ELx_E0POE);
|
||||
sysreg_clear_set(REG_TCR2_EL1, 0, TCR2_EL1_E0POE);
|
||||
sysreg_clear_set(CPACR_EL1, 0, CPACR_EL1_E0POE);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -80,31 +80,6 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
|
|||
return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
|
||||
}
|
||||
|
||||
/*
|
||||
* This functions as an allow-list of protected VM capabilities.
|
||||
* Features not explicitly allowed by this function are denied.
|
||||
*/
|
||||
static bool pkvm_ext_allowed(struct kvm *kvm, long ext)
|
||||
{
|
||||
switch (ext) {
|
||||
case KVM_CAP_IRQCHIP:
|
||||
case KVM_CAP_ARM_PSCI:
|
||||
case KVM_CAP_ARM_PSCI_0_2:
|
||||
case KVM_CAP_NR_VCPUS:
|
||||
case KVM_CAP_MAX_VCPUS:
|
||||
case KVM_CAP_MAX_VCPU_ID:
|
||||
case KVM_CAP_MSI_DEVID:
|
||||
case KVM_CAP_ARM_VM_IPA_SIZE:
|
||||
case KVM_CAP_ARM_PMU_V3:
|
||||
case KVM_CAP_ARM_SVE:
|
||||
case KVM_CAP_ARM_PTRAUTH_ADDRESS:
|
||||
case KVM_CAP_ARM_PTRAUTH_GENERIC:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
|
||||
struct kvm_enable_cap *cap)
|
||||
{
|
||||
|
|
@ -113,7 +88,7 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
|
|||
if (cap->flags)
|
||||
return -EINVAL;
|
||||
|
||||
if (kvm_vm_is_protected(kvm) && !pkvm_ext_allowed(kvm, cap->cap))
|
||||
if (kvm_vm_is_protected(kvm) && !kvm_pvm_ext_allowed(cap->cap))
|
||||
return -EINVAL;
|
||||
|
||||
switch (cap->cap) {
|
||||
|
|
@ -311,7 +286,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
|||
{
|
||||
int r;
|
||||
|
||||
if (kvm && kvm_vm_is_protected(kvm) && !pkvm_ext_allowed(kvm, ext))
|
||||
if (kvm && kvm_vm_is_protected(kvm) && !kvm_pvm_ext_allowed(ext))
|
||||
return 0;
|
||||
|
||||
switch (ext) {
|
||||
|
|
@ -1584,7 +1559,6 @@ static int kvm_arch_vcpu_ioctl_vcpu_init(struct kvm_vcpu *vcpu,
|
|||
}
|
||||
|
||||
vcpu_reset_hcr(vcpu);
|
||||
vcpu->arch.cptr_el2 = kvm_get_reset_cptr_el2(vcpu);
|
||||
|
||||
/*
|
||||
* Handle the "start in power-off" case.
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ static bool s1pie_enabled(struct kvm_vcpu *vcpu, enum trans_regime regime)
|
|||
return vcpu_read_sys_reg(vcpu, TCR2_EL2) & TCR2_EL2_PIE;
|
||||
case TR_EL10:
|
||||
return (__vcpu_sys_reg(vcpu, HCRX_EL2) & HCRX_EL2_TCR2En) &&
|
||||
(__vcpu_sys_reg(vcpu, TCR2_EL1) & TCR2_EL1x_PIE);
|
||||
(__vcpu_sys_reg(vcpu, TCR2_EL1) & TCR2_EL1_PIE);
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
|
@ -140,8 +140,8 @@ static void compute_s1poe(struct kvm_vcpu *vcpu, struct s1_walk_info *wi)
|
|||
}
|
||||
|
||||
val = __vcpu_sys_reg(vcpu, TCR2_EL1);
|
||||
wi->poe = val & TCR2_EL1x_POE;
|
||||
wi->e0poe = val & TCR2_EL1x_E0POE;
|
||||
wi->poe = val & TCR2_EL1_POE;
|
||||
wi->e0poe = val & TCR2_EL1_E0POE;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -494,7 +494,7 @@ static enum trap_behaviour check_cptr_tta(struct kvm_vcpu *vcpu)
|
|||
if (!vcpu_el2_e2h_is_set(vcpu))
|
||||
val = translate_cptr_el2_to_cpacr_el1(val);
|
||||
|
||||
if (val & CPACR_ELx_TTA)
|
||||
if (val & CPACR_EL1_TTA)
|
||||
return BEHAVE_FORWARD_RW;
|
||||
|
||||
return BEHAVE_HANDLE_LOCALLY;
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
|
|||
if (has_vhe() && system_supports_sme()) {
|
||||
/* Also restore EL0 state seen on entry */
|
||||
if (host_data_test_flag(HOST_SME_ENABLED))
|
||||
sysreg_clear_set(CPACR_EL1, 0, CPACR_ELx_SMEN);
|
||||
sysreg_clear_set(CPACR_EL1, 0, CPACR_EL1_SMEN);
|
||||
else
|
||||
sysreg_clear_set(CPACR_EL1,
|
||||
CPACR_EL1_SMEN_EL0EN,
|
||||
|
|
|
|||
|
|
@ -419,9 +419,9 @@ static bool kvm_hyp_handle_fpsimd(struct kvm_vcpu *vcpu, u64 *exit_code)
|
|||
|
||||
/* First disable enough traps to allow us to update the registers */
|
||||
if (sve_guest || (is_protected_kvm_enabled() && system_supports_sve()))
|
||||
cpacr_clear_set(0, CPACR_ELx_FPEN | CPACR_ELx_ZEN);
|
||||
cpacr_clear_set(0, CPACR_EL1_FPEN | CPACR_EL1_ZEN);
|
||||
else
|
||||
cpacr_clear_set(0, CPACR_ELx_FPEN);
|
||||
cpacr_clear_set(0, CPACR_EL1_FPEN);
|
||||
isb();
|
||||
|
||||
/* Write out the host state if it's in the registers */
|
||||
|
|
|
|||
|
|
@ -1,223 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2021 Google LLC
|
||||
* Author: Fuad Tabba <tabba@google.com>
|
||||
*/
|
||||
|
||||
#ifndef __ARM64_KVM_FIXED_CONFIG_H__
|
||||
#define __ARM64_KVM_FIXED_CONFIG_H__
|
||||
|
||||
#include <asm/sysreg.h>
|
||||
|
||||
/*
|
||||
* This file contains definitions for features to be allowed or restricted for
|
||||
* guest virtual machines, depending on the mode KVM is running in and on the
|
||||
* type of guest that is running.
|
||||
*
|
||||
* The ALLOW masks represent a bitmask of feature fields that are allowed
|
||||
* without any restrictions as long as they are supported by the system.
|
||||
*
|
||||
* The RESTRICT_UNSIGNED masks, if present, represent unsigned fields for
|
||||
* features that are restricted to support at most the specified feature.
|
||||
*
|
||||
* If a feature field is not present in either, than it is not supported.
|
||||
*
|
||||
* The approach taken for protected VMs is to allow features that are:
|
||||
* - Needed by common Linux distributions (e.g., floating point)
|
||||
* - Trivial to support, e.g., supporting the feature does not introduce or
|
||||
* require tracking of additional state in KVM
|
||||
* - Cannot be trapped or prevent the guest from using anyway
|
||||
*/
|
||||
|
||||
/*
|
||||
* Allow for protected VMs:
|
||||
* - Floating-point and Advanced SIMD
|
||||
* - Data Independent Timing
|
||||
* - Spectre/Meltdown Mitigation
|
||||
*/
|
||||
#define PVM_ID_AA64PFR0_ALLOW (\
|
||||
ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_FP) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_AdvSIMD) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_DIT) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV2) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV3) \
|
||||
)
|
||||
|
||||
/*
|
||||
* Restrict to the following *unsigned* features for protected VMs:
|
||||
* - AArch64 guests only (no support for AArch32 guests):
|
||||
* AArch32 adds complexity in trap handling, emulation, condition codes,
|
||||
* etc...
|
||||
* - RAS (v1)
|
||||
* Supported by KVM
|
||||
*/
|
||||
#define PVM_ID_AA64PFR0_RESTRICT_UNSIGNED (\
|
||||
SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, EL0, IMP) | \
|
||||
SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, EL1, IMP) | \
|
||||
SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, EL2, IMP) | \
|
||||
SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, EL3, IMP) | \
|
||||
SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, RAS, IMP) \
|
||||
)
|
||||
|
||||
/*
|
||||
* Allow for protected VMs:
|
||||
* - Branch Target Identification
|
||||
* - Speculative Store Bypassing
|
||||
*/
|
||||
#define PVM_ID_AA64PFR1_ALLOW (\
|
||||
ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_BT) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_SSBS) \
|
||||
)
|
||||
|
||||
#define PVM_ID_AA64PFR2_ALLOW 0ULL
|
||||
|
||||
/*
|
||||
* Allow for protected VMs:
|
||||
* - Mixed-endian
|
||||
* - Distinction between Secure and Non-secure Memory
|
||||
* - Mixed-endian at EL0 only
|
||||
* - Non-context synchronizing exception entry and exit
|
||||
*/
|
||||
#define PVM_ID_AA64MMFR0_ALLOW (\
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_BIGEND) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_SNSMEM) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_BIGENDEL0) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_EXS) \
|
||||
)
|
||||
|
||||
/*
|
||||
* Restrict to the following *unsigned* features for protected VMs:
|
||||
* - 40-bit IPA
|
||||
* - 16-bit ASID
|
||||
*/
|
||||
#define PVM_ID_AA64MMFR0_RESTRICT_UNSIGNED (\
|
||||
FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_PARANGE), ID_AA64MMFR0_EL1_PARANGE_40) | \
|
||||
FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_ASIDBITS), ID_AA64MMFR0_EL1_ASIDBITS_16) \
|
||||
)
|
||||
|
||||
/*
|
||||
* Allow for protected VMs:
|
||||
* - Hardware translation table updates to Access flag and Dirty state
|
||||
* - Number of VMID bits from CPU
|
||||
* - Hierarchical Permission Disables
|
||||
* - Privileged Access Never
|
||||
* - SError interrupt exceptions from speculative reads
|
||||
* - Enhanced Translation Synchronization
|
||||
* - Control for cache maintenance permission
|
||||
*/
|
||||
#define PVM_ID_AA64MMFR1_ALLOW (\
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_HAFDBS) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_VMIDBits) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_HPDS) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_PAN) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_SpecSEI) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_ETS) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_CMOW) \
|
||||
)
|
||||
|
||||
/*
|
||||
* Allow for protected VMs:
|
||||
* - Common not Private translations
|
||||
* - User Access Override
|
||||
* - IESB bit in the SCTLR_ELx registers
|
||||
* - Unaligned single-copy atomicity and atomic functions
|
||||
* - ESR_ELx.EC value on an exception by read access to feature ID space
|
||||
* - TTL field in address operations.
|
||||
* - Break-before-make sequences when changing translation block size
|
||||
* - E0PDx mechanism
|
||||
*/
|
||||
#define PVM_ID_AA64MMFR2_ALLOW (\
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR2_EL1_CnP) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR2_EL1_UAO) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR2_EL1_IESB) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR2_EL1_AT) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR2_EL1_IDS) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR2_EL1_TTL) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR2_EL1_BBM) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR2_EL1_E0PD) \
|
||||
)
|
||||
|
||||
#define PVM_ID_AA64MMFR3_ALLOW (0ULL)
|
||||
|
||||
/*
|
||||
* No support for Scalable Vectors for protected VMs:
|
||||
* Requires additional support from KVM, e.g., context-switching and
|
||||
* trapping at EL2
|
||||
*/
|
||||
#define PVM_ID_AA64ZFR0_ALLOW (0ULL)
|
||||
|
||||
/*
|
||||
* No support for debug, including breakpoints, and watchpoints for protected
|
||||
* VMs:
|
||||
* The Arm architecture mandates support for at least the Armv8 debug
|
||||
* architecture, which would include at least 2 hardware breakpoints and
|
||||
* watchpoints. Providing that support to protected guests adds
|
||||
* considerable state and complexity. Therefore, the reserved value of 0 is
|
||||
* used for debug-related fields.
|
||||
*/
|
||||
#define PVM_ID_AA64DFR0_ALLOW (0ULL)
|
||||
#define PVM_ID_AA64DFR1_ALLOW (0ULL)
|
||||
|
||||
/*
|
||||
* No support for implementation defined features.
|
||||
*/
|
||||
#define PVM_ID_AA64AFR0_ALLOW (0ULL)
|
||||
#define PVM_ID_AA64AFR1_ALLOW (0ULL)
|
||||
|
||||
/*
|
||||
* No restrictions on instructions implemented in AArch64.
|
||||
*/
|
||||
#define PVM_ID_AA64ISAR0_ALLOW (\
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR0_EL1_AES) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR0_EL1_SHA1) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR0_EL1_SHA2) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR0_EL1_CRC32) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR0_EL1_ATOMIC) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR0_EL1_RDM) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR0_EL1_SHA3) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR0_EL1_SM3) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR0_EL1_SM4) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR0_EL1_DP) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR0_EL1_FHM) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR0_EL1_TS) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR0_EL1_TLB) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR0_EL1_RNDR) \
|
||||
)
|
||||
|
||||
/* Restrict pointer authentication to the basic version. */
|
||||
#define PVM_ID_AA64ISAR1_RESTRICT_UNSIGNED (\
|
||||
FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_APA), ID_AA64ISAR1_EL1_APA_PAuth) | \
|
||||
FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_API), ID_AA64ISAR1_EL1_API_PAuth) \
|
||||
)
|
||||
|
||||
#define PVM_ID_AA64ISAR2_RESTRICT_UNSIGNED (\
|
||||
FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_APA3), ID_AA64ISAR2_EL1_APA3_PAuth) \
|
||||
)
|
||||
|
||||
#define PVM_ID_AA64ISAR1_ALLOW (\
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_DPB) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_JSCVT) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_FCMA) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_LRCPC) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPA) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPI) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_FRINTTS) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_SB) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_SPECRES) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_BF16) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_DGH) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_I8MM) \
|
||||
)
|
||||
|
||||
#define PVM_ID_AA64ISAR2_ALLOW (\
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_ATS1A)| \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_GPA3) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_MOPS) \
|
||||
)
|
||||
|
||||
u64 pvm_read_id_reg(const struct kvm_vcpu *vcpu, u32 id);
|
||||
bool kvm_handle_pvm_sysreg(struct kvm_vcpu *vcpu, u64 *exit_code);
|
||||
bool kvm_handle_pvm_restricted(struct kvm_vcpu *vcpu, u64 *exit_code);
|
||||
int kvm_check_pvm_sysreg_table(void);
|
||||
|
||||
#endif /* __ARM64_KVM_FIXED_CONFIG_H__ */
|
||||
|
|
@ -53,6 +53,8 @@ struct pkvm_hyp_vm {
|
|||
struct pkvm_hyp_vcpu *vcpus[];
|
||||
};
|
||||
|
||||
extern hyp_spinlock_t vm_table_lock;
|
||||
|
||||
static inline struct pkvm_hyp_vm *
|
||||
pkvm_hyp_vcpu_to_hyp_vm(struct pkvm_hyp_vcpu *hyp_vcpu)
|
||||
{
|
||||
|
|
@ -86,4 +88,9 @@ struct pkvm_hyp_vm *get_pkvm_hyp_vm(pkvm_handle_t handle);
|
|||
struct pkvm_hyp_vm *get_np_pkvm_hyp_vm(pkvm_handle_t handle);
|
||||
void put_pkvm_hyp_vm(struct pkvm_hyp_vm *hyp_vm);
|
||||
|
||||
bool kvm_handle_pvm_sysreg(struct kvm_vcpu *vcpu, u64 *exit_code);
|
||||
bool kvm_handle_pvm_restricted(struct kvm_vcpu *vcpu, u64 *exit_code);
|
||||
void kvm_init_pvm_id_regs(struct kvm_vcpu *vcpu);
|
||||
int kvm_check_pvm_sysreg_table(void);
|
||||
|
||||
#endif /* __ARM64_KVM_NVHE_PKVM_H__ */
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ static void fpsimd_sve_sync(struct kvm_vcpu *vcpu)
|
|||
if (!guest_owns_fp_regs())
|
||||
return;
|
||||
|
||||
cpacr_clear_set(0, CPACR_ELx_FPEN | CPACR_ELx_ZEN);
|
||||
cpacr_clear_set(0, CPACR_EL1_FPEN | CPACR_EL1_ZEN);
|
||||
isb();
|
||||
|
||||
if (vcpu_has_sve(vcpu))
|
||||
|
|
@ -652,7 +652,7 @@ void handle_trap(struct kvm_cpu_context *host_ctxt)
|
|||
handle_host_smc(host_ctxt);
|
||||
break;
|
||||
case ESR_ELx_EC_SVE:
|
||||
cpacr_clear_set(0, CPACR_ELx_ZEN);
|
||||
cpacr_clear_set(0, CPACR_EL1_ZEN);
|
||||
isb();
|
||||
sve_cond_update_zcr_vq(sve_vq_from_vl(kvm_host_sve_max_vl) - 1,
|
||||
SYS_ZCR_EL2);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include <asm/kvm_emulate.h>
|
||||
|
||||
#include <nvhe/fixed_config.h>
|
||||
#include <nvhe/mem_protect.h>
|
||||
#include <nvhe/memory.h>
|
||||
#include <nvhe/pkvm.h>
|
||||
|
|
@ -29,187 +28,6 @@ unsigned int kvm_host_sve_max_vl;
|
|||
*/
|
||||
static DEFINE_PER_CPU(struct pkvm_hyp_vcpu *, loaded_hyp_vcpu);
|
||||
|
||||
/*
|
||||
* Set trap register values based on features in ID_AA64PFR0.
|
||||
*/
|
||||
static void pvm_init_traps_aa64pfr0(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
const u64 feature_ids = pvm_read_id_reg(vcpu, SYS_ID_AA64PFR0_EL1);
|
||||
u64 hcr_set = HCR_RW;
|
||||
u64 hcr_clear = 0;
|
||||
u64 cptr_set = 0;
|
||||
u64 cptr_clear = 0;
|
||||
|
||||
/* Protected KVM does not support AArch32 guests. */
|
||||
BUILD_BUG_ON(FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_EL0),
|
||||
PVM_ID_AA64PFR0_RESTRICT_UNSIGNED) != ID_AA64PFR0_EL1_EL0_IMP);
|
||||
BUILD_BUG_ON(FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_EL1),
|
||||
PVM_ID_AA64PFR0_RESTRICT_UNSIGNED) != ID_AA64PFR0_EL1_EL1_IMP);
|
||||
|
||||
/*
|
||||
* Linux guests assume support for floating-point and Advanced SIMD. Do
|
||||
* not change the trapping behavior for these from the KVM default.
|
||||
*/
|
||||
BUILD_BUG_ON(!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_FP),
|
||||
PVM_ID_AA64PFR0_ALLOW));
|
||||
BUILD_BUG_ON(!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_AdvSIMD),
|
||||
PVM_ID_AA64PFR0_ALLOW));
|
||||
|
||||
if (has_hvhe())
|
||||
hcr_set |= HCR_E2H;
|
||||
|
||||
/* Trap RAS unless all current versions are supported */
|
||||
if (FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_RAS), feature_ids) <
|
||||
ID_AA64PFR0_EL1_RAS_V1P1) {
|
||||
hcr_set |= HCR_TERR | HCR_TEA;
|
||||
hcr_clear |= HCR_FIEN;
|
||||
}
|
||||
|
||||
/* Trap AMU */
|
||||
if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_AMU), feature_ids)) {
|
||||
hcr_clear |= HCR_AMVOFFEN;
|
||||
cptr_set |= CPTR_EL2_TAM;
|
||||
}
|
||||
|
||||
/* Trap SVE */
|
||||
if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_SVE), feature_ids)) {
|
||||
if (has_hvhe())
|
||||
cptr_clear |= CPACR_ELx_ZEN;
|
||||
else
|
||||
cptr_set |= CPTR_EL2_TZ;
|
||||
}
|
||||
|
||||
vcpu->arch.hcr_el2 |= hcr_set;
|
||||
vcpu->arch.hcr_el2 &= ~hcr_clear;
|
||||
vcpu->arch.cptr_el2 |= cptr_set;
|
||||
vcpu->arch.cptr_el2 &= ~cptr_clear;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set trap register values based on features in ID_AA64PFR1.
|
||||
*/
|
||||
static void pvm_init_traps_aa64pfr1(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
const u64 feature_ids = pvm_read_id_reg(vcpu, SYS_ID_AA64PFR1_EL1);
|
||||
u64 hcr_set = 0;
|
||||
u64 hcr_clear = 0;
|
||||
|
||||
/* Memory Tagging: Trap and Treat as Untagged if not supported. */
|
||||
if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE), feature_ids)) {
|
||||
hcr_set |= HCR_TID5;
|
||||
hcr_clear |= HCR_DCT | HCR_ATA;
|
||||
}
|
||||
|
||||
vcpu->arch.hcr_el2 |= hcr_set;
|
||||
vcpu->arch.hcr_el2 &= ~hcr_clear;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set trap register values based on features in ID_AA64DFR0.
|
||||
*/
|
||||
static void pvm_init_traps_aa64dfr0(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
const u64 feature_ids = pvm_read_id_reg(vcpu, SYS_ID_AA64DFR0_EL1);
|
||||
u64 mdcr_set = 0;
|
||||
u64 mdcr_clear = 0;
|
||||
u64 cptr_set = 0;
|
||||
|
||||
/* Trap/constrain PMU */
|
||||
if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMUVer), feature_ids)) {
|
||||
mdcr_set |= MDCR_EL2_TPM | MDCR_EL2_TPMCR;
|
||||
mdcr_clear |= MDCR_EL2_HPME | MDCR_EL2_MTPME |
|
||||
MDCR_EL2_HPMN_MASK;
|
||||
}
|
||||
|
||||
/* Trap Debug */
|
||||
if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_DebugVer), feature_ids))
|
||||
mdcr_set |= MDCR_EL2_TDRA | MDCR_EL2_TDA | MDCR_EL2_TDE;
|
||||
|
||||
/* Trap OS Double Lock */
|
||||
if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_DoubleLock), feature_ids))
|
||||
mdcr_set |= MDCR_EL2_TDOSA;
|
||||
|
||||
/* Trap SPE */
|
||||
if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMSVer), feature_ids)) {
|
||||
mdcr_set |= MDCR_EL2_TPMS;
|
||||
mdcr_clear |= MDCR_EL2_E2PB_MASK;
|
||||
}
|
||||
|
||||
/* Trap Trace Filter */
|
||||
if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_TraceFilt), feature_ids))
|
||||
mdcr_set |= MDCR_EL2_TTRF;
|
||||
|
||||
/* Trap Trace */
|
||||
if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_TraceVer), feature_ids)) {
|
||||
if (has_hvhe())
|
||||
cptr_set |= CPACR_EL1_TTA;
|
||||
else
|
||||
cptr_set |= CPTR_EL2_TTA;
|
||||
}
|
||||
|
||||
/* Trap External Trace */
|
||||
if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_ExtTrcBuff), feature_ids))
|
||||
mdcr_clear |= MDCR_EL2_E2TB_MASK;
|
||||
|
||||
vcpu->arch.mdcr_el2 |= mdcr_set;
|
||||
vcpu->arch.mdcr_el2 &= ~mdcr_clear;
|
||||
vcpu->arch.cptr_el2 |= cptr_set;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set trap register values based on features in ID_AA64MMFR0.
|
||||
*/
|
||||
static void pvm_init_traps_aa64mmfr0(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
const u64 feature_ids = pvm_read_id_reg(vcpu, SYS_ID_AA64MMFR0_EL1);
|
||||
u64 mdcr_set = 0;
|
||||
|
||||
/* Trap Debug Communications Channel registers */
|
||||
if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_FGT), feature_ids))
|
||||
mdcr_set |= MDCR_EL2_TDCC;
|
||||
|
||||
vcpu->arch.mdcr_el2 |= mdcr_set;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set trap register values based on features in ID_AA64MMFR1.
|
||||
*/
|
||||
static void pvm_init_traps_aa64mmfr1(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
const u64 feature_ids = pvm_read_id_reg(vcpu, SYS_ID_AA64MMFR1_EL1);
|
||||
u64 hcr_set = 0;
|
||||
|
||||
/* Trap LOR */
|
||||
if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_LO), feature_ids))
|
||||
hcr_set |= HCR_TLOR;
|
||||
|
||||
vcpu->arch.hcr_el2 |= hcr_set;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set baseline trap register values.
|
||||
*/
|
||||
static void pvm_init_trap_regs(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
const u64 hcr_trap_feat_regs = HCR_TID3;
|
||||
const u64 hcr_trap_impdef = HCR_TACR | HCR_TIDCP | HCR_TID1;
|
||||
|
||||
/*
|
||||
* Always trap:
|
||||
* - Feature id registers: to control features exposed to guests
|
||||
* - Implementation-defined features
|
||||
*/
|
||||
vcpu->arch.hcr_el2 |= hcr_trap_feat_regs | hcr_trap_impdef;
|
||||
|
||||
/* Clear res0 and set res1 bits to trap potential new features. */
|
||||
vcpu->arch.hcr_el2 &= ~(HCR_RES0);
|
||||
vcpu->arch.mdcr_el2 &= ~(MDCR_EL2_RES0);
|
||||
if (!has_hvhe()) {
|
||||
vcpu->arch.cptr_el2 |= CPTR_NVHE_EL2_RES1;
|
||||
vcpu->arch.cptr_el2 &= ~(CPTR_NVHE_EL2_RES0);
|
||||
}
|
||||
}
|
||||
|
||||
static void pkvm_vcpu_reset_hcr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
|
||||
|
|
@ -235,27 +53,130 @@ static void pkvm_vcpu_reset_hcr(struct kvm_vcpu *vcpu)
|
|||
|
||||
if (vcpu_has_ptrauth(vcpu))
|
||||
vcpu->arch.hcr_el2 |= (HCR_API | HCR_APK);
|
||||
|
||||
if (kvm_has_mte(vcpu->kvm))
|
||||
vcpu->arch.hcr_el2 |= HCR_ATA;
|
||||
}
|
||||
|
||||
static void pvm_init_traps_hcr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm *kvm = vcpu->kvm;
|
||||
u64 val = vcpu->arch.hcr_el2;
|
||||
|
||||
/* No support for AArch32. */
|
||||
val |= HCR_RW;
|
||||
|
||||
/*
|
||||
* Always trap:
|
||||
* - Feature id registers: to control features exposed to guests
|
||||
* - Implementation-defined features
|
||||
*/
|
||||
val |= HCR_TACR | HCR_TIDCP | HCR_TID3 | HCR_TID1;
|
||||
|
||||
if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, RAS, IMP)) {
|
||||
val |= HCR_TERR | HCR_TEA;
|
||||
val &= ~(HCR_FIEN);
|
||||
}
|
||||
|
||||
if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, AMU, IMP))
|
||||
val &= ~(HCR_AMVOFFEN);
|
||||
|
||||
if (!kvm_has_feat(kvm, ID_AA64PFR1_EL1, MTE, IMP)) {
|
||||
val |= HCR_TID5;
|
||||
val &= ~(HCR_DCT | HCR_ATA);
|
||||
}
|
||||
|
||||
if (!kvm_has_feat(kvm, ID_AA64MMFR1_EL1, LO, IMP))
|
||||
val |= HCR_TLOR;
|
||||
|
||||
vcpu->arch.hcr_el2 = val;
|
||||
}
|
||||
|
||||
static void pvm_init_traps_mdcr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm *kvm = vcpu->kvm;
|
||||
u64 val = vcpu->arch.mdcr_el2;
|
||||
|
||||
if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, PMUVer, IMP)) {
|
||||
val |= MDCR_EL2_TPM | MDCR_EL2_TPMCR;
|
||||
val &= ~(MDCR_EL2_HPME | MDCR_EL2_MTPME | MDCR_EL2_HPMN_MASK);
|
||||
}
|
||||
|
||||
if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, DebugVer, IMP))
|
||||
val |= MDCR_EL2_TDRA | MDCR_EL2_TDA;
|
||||
|
||||
if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, DoubleLock, IMP))
|
||||
val |= MDCR_EL2_TDOSA;
|
||||
|
||||
if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, PMSVer, IMP)) {
|
||||
val |= MDCR_EL2_TPMS;
|
||||
val &= ~MDCR_EL2_E2PB_MASK;
|
||||
}
|
||||
|
||||
if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, TraceFilt, IMP))
|
||||
val |= MDCR_EL2_TTRF;
|
||||
|
||||
if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, ExtTrcBuff, IMP))
|
||||
val |= MDCR_EL2_E2TB_MASK;
|
||||
|
||||
/* Trap Debug Communications Channel registers */
|
||||
if (!kvm_has_feat(kvm, ID_AA64MMFR0_EL1, FGT, IMP))
|
||||
val |= MDCR_EL2_TDCC;
|
||||
|
||||
vcpu->arch.mdcr_el2 = val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that cpu features that are neither trapped nor supported are not
|
||||
* enabled for protected VMs.
|
||||
*/
|
||||
static int pkvm_check_pvm_cpu_features(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm *kvm = vcpu->kvm;
|
||||
|
||||
/* Protected KVM does not support AArch32 guests. */
|
||||
if (kvm_has_feat(kvm, ID_AA64PFR0_EL1, EL0, AARCH32) ||
|
||||
kvm_has_feat(kvm, ID_AA64PFR0_EL1, EL1, AARCH32))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Linux guests assume support for floating-point and Advanced SIMD. Do
|
||||
* not change the trapping behavior for these from the KVM default.
|
||||
*/
|
||||
if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, FP, IMP) ||
|
||||
!kvm_has_feat(kvm, ID_AA64PFR0_EL1, AdvSIMD, IMP))
|
||||
return -EINVAL;
|
||||
|
||||
/* No SME support in KVM right now. Check to catch if it changes. */
|
||||
if (kvm_has_feat(kvm, ID_AA64PFR1_EL1, SME, IMP))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize trap register values in protected mode.
|
||||
*/
|
||||
static void pkvm_vcpu_init_traps(struct kvm_vcpu *vcpu)
|
||||
static int pkvm_vcpu_init_traps(struct pkvm_hyp_vcpu *hyp_vcpu)
|
||||
{
|
||||
vcpu->arch.cptr_el2 = kvm_get_reset_cptr_el2(vcpu);
|
||||
struct kvm_vcpu *vcpu = &hyp_vcpu->vcpu;
|
||||
int ret;
|
||||
|
||||
vcpu->arch.mdcr_el2 = 0;
|
||||
|
||||
pkvm_vcpu_reset_hcr(vcpu);
|
||||
|
||||
if ((!vcpu_is_protected(vcpu)))
|
||||
return;
|
||||
if ((!pkvm_hyp_vcpu_is_protected(hyp_vcpu)))
|
||||
return 0;
|
||||
|
||||
pvm_init_trap_regs(vcpu);
|
||||
pvm_init_traps_aa64pfr0(vcpu);
|
||||
pvm_init_traps_aa64pfr1(vcpu);
|
||||
pvm_init_traps_aa64dfr0(vcpu);
|
||||
pvm_init_traps_aa64mmfr0(vcpu);
|
||||
pvm_init_traps_aa64mmfr1(vcpu);
|
||||
ret = pkvm_check_pvm_cpu_features(vcpu);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pvm_init_traps_hcr(vcpu);
|
||||
pvm_init_traps_mdcr(vcpu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -276,10 +197,10 @@ static pkvm_handle_t idx_to_vm_handle(unsigned int idx)
|
|||
|
||||
/*
|
||||
* Spinlock for protecting state related to the VM table. Protects writes
|
||||
* to 'vm_table' and 'nr_table_entries' as well as reads and writes to
|
||||
* 'last_hyp_vcpu_lookup'.
|
||||
* to 'vm_table', 'nr_table_entries', and other per-vm state on initialization.
|
||||
* Also protects reads and writes to 'last_hyp_vcpu_lookup'.
|
||||
*/
|
||||
static DEFINE_HYP_SPINLOCK(vm_table_lock);
|
||||
DEFINE_HYP_SPINLOCK(vm_table_lock);
|
||||
|
||||
/*
|
||||
* The table of VM entries for protected VMs in hyp.
|
||||
|
|
@ -391,10 +312,16 @@ struct pkvm_hyp_vm *get_np_pkvm_hyp_vm(pkvm_handle_t handle)
|
|||
static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struct kvm *host_kvm)
|
||||
{
|
||||
struct kvm *kvm = &hyp_vm->kvm;
|
||||
unsigned long host_arch_flags = READ_ONCE(host_kvm->arch.flags);
|
||||
DECLARE_BITMAP(allowed_features, KVM_VCPU_MAX_FEATURES);
|
||||
|
||||
if (test_bit(KVM_ARCH_FLAG_MTE_ENABLED, &host_kvm->arch.flags))
|
||||
set_bit(KVM_ARCH_FLAG_MTE_ENABLED, &kvm->arch.flags);
|
||||
|
||||
/* No restrictions for non-protected VMs. */
|
||||
if (!kvm_vm_is_protected(kvm)) {
|
||||
hyp_vm->kvm.arch.flags = host_arch_flags;
|
||||
|
||||
bitmap_copy(kvm->arch.vcpu_features,
|
||||
host_kvm->arch.vcpu_features,
|
||||
KVM_VCPU_MAX_FEATURES);
|
||||
|
|
@ -403,50 +330,26 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
|
|||
|
||||
bitmap_zero(allowed_features, KVM_VCPU_MAX_FEATURES);
|
||||
|
||||
/*
|
||||
* For protected VMs, always allow:
|
||||
* - CPU starting in poweroff state
|
||||
* - PSCI v0.2
|
||||
*/
|
||||
set_bit(KVM_ARM_VCPU_POWER_OFF, allowed_features);
|
||||
set_bit(KVM_ARM_VCPU_PSCI_0_2, allowed_features);
|
||||
|
||||
/*
|
||||
* Check if remaining features are allowed:
|
||||
* - Performance Monitoring
|
||||
* - Scalable Vectors
|
||||
* - Pointer Authentication
|
||||
*/
|
||||
if (FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMUVer), PVM_ID_AA64DFR0_ALLOW))
|
||||
if (kvm_pvm_ext_allowed(KVM_CAP_ARM_PMU_V3))
|
||||
set_bit(KVM_ARM_VCPU_PMU_V3, allowed_features);
|
||||
|
||||
if (FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_SVE), PVM_ID_AA64PFR0_ALLOW))
|
||||
set_bit(KVM_ARM_VCPU_SVE, allowed_features);
|
||||
|
||||
if (FIELD_GET(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_API), PVM_ID_AA64ISAR1_RESTRICT_UNSIGNED) &&
|
||||
FIELD_GET(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_APA), PVM_ID_AA64ISAR1_RESTRICT_UNSIGNED))
|
||||
if (kvm_pvm_ext_allowed(KVM_CAP_ARM_PTRAUTH_ADDRESS))
|
||||
set_bit(KVM_ARM_VCPU_PTRAUTH_ADDRESS, allowed_features);
|
||||
|
||||
if (FIELD_GET(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPI), PVM_ID_AA64ISAR1_ALLOW) &&
|
||||
FIELD_GET(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPA), PVM_ID_AA64ISAR1_ALLOW))
|
||||
if (kvm_pvm_ext_allowed(KVM_CAP_ARM_PTRAUTH_GENERIC))
|
||||
set_bit(KVM_ARM_VCPU_PTRAUTH_GENERIC, allowed_features);
|
||||
|
||||
if (kvm_pvm_ext_allowed(KVM_CAP_ARM_SVE)) {
|
||||
set_bit(KVM_ARM_VCPU_SVE, allowed_features);
|
||||
kvm->arch.flags |= host_arch_flags & BIT(KVM_ARCH_FLAG_GUEST_HAS_SVE);
|
||||
}
|
||||
|
||||
bitmap_and(kvm->arch.vcpu_features, host_kvm->arch.vcpu_features,
|
||||
allowed_features, KVM_VCPU_MAX_FEATURES);
|
||||
}
|
||||
|
||||
static void pkvm_vcpu_init_ptrauth(struct pkvm_hyp_vcpu *hyp_vcpu)
|
||||
{
|
||||
struct kvm_vcpu *vcpu = &hyp_vcpu->vcpu;
|
||||
|
||||
if (vcpu_has_feature(vcpu, KVM_ARM_VCPU_PTRAUTH_ADDRESS) ||
|
||||
vcpu_has_feature(vcpu, KVM_ARM_VCPU_PTRAUTH_GENERIC)) {
|
||||
kvm_vcpu_enable_ptrauth(vcpu);
|
||||
} else {
|
||||
vcpu_clear_flag(&hyp_vcpu->vcpu, GUEST_HAS_PTRAUTH);
|
||||
}
|
||||
}
|
||||
|
||||
static void unpin_host_vcpu(struct kvm_vcpu *host_vcpu)
|
||||
{
|
||||
if (host_vcpu)
|
||||
|
|
@ -469,6 +372,7 @@ static void init_pkvm_hyp_vm(struct kvm *host_kvm, struct pkvm_hyp_vm *hyp_vm,
|
|||
hyp_vm->kvm.created_vcpus = nr_vcpus;
|
||||
hyp_vm->kvm.arch.mmu.vtcr = host_mmu.arch.mmu.vtcr;
|
||||
hyp_vm->kvm.arch.pkvm.enabled = READ_ONCE(host_kvm->arch.pkvm.enabled);
|
||||
hyp_vm->kvm.arch.flags = 0;
|
||||
pkvm_init_features_from_host(hyp_vm, host_kvm);
|
||||
}
|
||||
|
||||
|
|
@ -476,10 +380,8 @@ static void pkvm_vcpu_init_sve(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *
|
|||
{
|
||||
struct kvm_vcpu *vcpu = &hyp_vcpu->vcpu;
|
||||
|
||||
if (!vcpu_has_feature(vcpu, KVM_ARM_VCPU_SVE)) {
|
||||
vcpu_clear_flag(vcpu, GUEST_HAS_SVE);
|
||||
if (!vcpu_has_feature(vcpu, KVM_ARM_VCPU_SVE))
|
||||
vcpu_clear_flag(vcpu, VCPU_SVE_FINALIZED);
|
||||
}
|
||||
}
|
||||
|
||||
static int init_pkvm_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu,
|
||||
|
|
@ -507,9 +409,14 @@ static int init_pkvm_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu,
|
|||
hyp_vcpu->vcpu.arch.cflags = READ_ONCE(host_vcpu->arch.cflags);
|
||||
hyp_vcpu->vcpu.arch.mp_state.mp_state = KVM_MP_STATE_STOPPED;
|
||||
|
||||
if (pkvm_hyp_vcpu_is_protected(hyp_vcpu))
|
||||
kvm_init_pvm_id_regs(&hyp_vcpu->vcpu);
|
||||
|
||||
ret = pkvm_vcpu_init_traps(hyp_vcpu);
|
||||
if (ret)
|
||||
goto done;
|
||||
|
||||
pkvm_vcpu_init_sve(hyp_vcpu, host_vcpu);
|
||||
pkvm_vcpu_init_ptrauth(hyp_vcpu);
|
||||
pkvm_vcpu_init_traps(&hyp_vcpu->vcpu);
|
||||
done:
|
||||
if (ret)
|
||||
unpin_host_vcpu(host_vcpu);
|
||||
|
|
@ -754,8 +661,6 @@ int __pkvm_init_vcpu(pkvm_handle_t handle, struct kvm_vcpu *host_vcpu,
|
|||
return ret;
|
||||
}
|
||||
|
||||
hyp_vcpu->vcpu.arch.cptr_el2 = kvm_get_reset_cptr_el2(&hyp_vcpu->vcpu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
#include <nvhe/early_alloc.h>
|
||||
#include <nvhe/ffa.h>
|
||||
#include <nvhe/fixed_config.h>
|
||||
#include <nvhe/gfp.h>
|
||||
#include <nvhe/memory.h>
|
||||
#include <nvhe/mem_protect.h>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
#include <asm/debug-monitors.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
#include <nvhe/fixed_config.h>
|
||||
#include <nvhe/mem_protect.h>
|
||||
|
||||
/* Non-VHE specific context */
|
||||
|
|
@ -36,33 +35,46 @@ DEFINE_PER_CPU(unsigned long, kvm_hyp_vector);
|
|||
|
||||
extern void kvm_nvhe_prepare_backtrace(unsigned long fp, unsigned long pc);
|
||||
|
||||
static void __activate_traps(struct kvm_vcpu *vcpu)
|
||||
static void __activate_cptr_traps(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 val;
|
||||
u64 val = CPTR_EL2_TAM; /* Same bit irrespective of E2H */
|
||||
|
||||
___activate_traps(vcpu, vcpu->arch.hcr_el2);
|
||||
__activate_traps_common(vcpu);
|
||||
if (has_hvhe()) {
|
||||
val |= CPACR_EL1_TTA;
|
||||
|
||||
val = vcpu->arch.cptr_el2;
|
||||
val |= CPTR_EL2_TAM; /* Same bit irrespective of E2H */
|
||||
val |= has_hvhe() ? CPACR_EL1_TTA : CPTR_EL2_TTA;
|
||||
if (cpus_have_final_cap(ARM64_SME)) {
|
||||
if (has_hvhe())
|
||||
val &= ~CPACR_ELx_SMEN;
|
||||
else
|
||||
val |= CPTR_EL2_TSM;
|
||||
if (guest_owns_fp_regs()) {
|
||||
val |= CPACR_EL1_FPEN;
|
||||
if (vcpu_has_sve(vcpu))
|
||||
val |= CPACR_EL1_ZEN;
|
||||
}
|
||||
} else {
|
||||
val |= CPTR_EL2_TTA | CPTR_NVHE_EL2_RES1;
|
||||
|
||||
/*
|
||||
* Always trap SME since it's not supported in KVM.
|
||||
* TSM is RES1 if SME isn't implemented.
|
||||
*/
|
||||
val |= CPTR_EL2_TSM;
|
||||
|
||||
if (!vcpu_has_sve(vcpu) || !guest_owns_fp_regs())
|
||||
val |= CPTR_EL2_TZ;
|
||||
|
||||
if (!guest_owns_fp_regs())
|
||||
val |= CPTR_EL2_TFP;
|
||||
}
|
||||
|
||||
if (!guest_owns_fp_regs()) {
|
||||
if (has_hvhe())
|
||||
val &= ~(CPACR_ELx_FPEN | CPACR_ELx_ZEN);
|
||||
else
|
||||
val |= CPTR_EL2_TFP | CPTR_EL2_TZ;
|
||||
|
||||
if (!guest_owns_fp_regs())
|
||||
__activate_traps_fpsimd32(vcpu);
|
||||
}
|
||||
|
||||
kvm_write_cptr_el2(val);
|
||||
}
|
||||
|
||||
static void __activate_traps(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
___activate_traps(vcpu, vcpu->arch.hcr_el2);
|
||||
__activate_traps_common(vcpu);
|
||||
__activate_cptr_traps(vcpu);
|
||||
|
||||
write_sysreg(__this_cpu_read(kvm_hyp_vector), vbar_el2);
|
||||
|
||||
if (cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT)) {
|
||||
|
|
@ -192,7 +204,7 @@ static void kvm_hyp_save_fpsimd_host(struct kvm_vcpu *vcpu)
|
|||
|
||||
/* Re-enable SVE traps if not supported for the guest vcpu. */
|
||||
if (!vcpu_has_sve(vcpu))
|
||||
cpacr_clear_set(CPACR_ELx_ZEN, 0);
|
||||
cpacr_clear_set(CPACR_EL1_ZEN, 0);
|
||||
|
||||
} else {
|
||||
__fpsimd_save_state(*host_data_ptr(fpsimd_state));
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include <hyp/adjust_pc.h>
|
||||
|
||||
#include <nvhe/fixed_config.h>
|
||||
#include <nvhe/pkvm.h>
|
||||
|
||||
#include "../../sys_regs.h"
|
||||
|
||||
|
|
@ -28,6 +28,221 @@ u64 id_aa64mmfr1_el1_sys_val;
|
|||
u64 id_aa64mmfr2_el1_sys_val;
|
||||
u64 id_aa64smfr0_el1_sys_val;
|
||||
|
||||
struct pvm_ftr_bits {
|
||||
bool sign;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
u8 max_val;
|
||||
bool (*vm_supported)(const struct kvm *kvm);
|
||||
};
|
||||
|
||||
#define __MAX_FEAT_FUNC(id, fld, max, func, sgn) \
|
||||
{ \
|
||||
.sign = sgn, \
|
||||
.shift = id##_##fld##_SHIFT, \
|
||||
.width = id##_##fld##_WIDTH, \
|
||||
.max_val = id##_##fld##_##max, \
|
||||
.vm_supported = func, \
|
||||
}
|
||||
|
||||
#define MAX_FEAT_FUNC(id, fld, max, func) \
|
||||
__MAX_FEAT_FUNC(id, fld, max, func, id##_##fld##_SIGNED)
|
||||
|
||||
#define MAX_FEAT(id, fld, max) \
|
||||
MAX_FEAT_FUNC(id, fld, max, NULL)
|
||||
|
||||
#define MAX_FEAT_ENUM(id, fld, max) \
|
||||
__MAX_FEAT_FUNC(id, fld, max, NULL, false)
|
||||
|
||||
#define FEAT_END { .width = 0, }
|
||||
|
||||
static bool vm_has_ptrauth(const struct kvm *kvm)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_ARM64_PTR_AUTH))
|
||||
return false;
|
||||
|
||||
return (cpus_have_final_cap(ARM64_HAS_ADDRESS_AUTH) ||
|
||||
cpus_have_final_cap(ARM64_HAS_GENERIC_AUTH)) &&
|
||||
kvm_vcpu_has_feature(kvm, KVM_ARM_VCPU_PTRAUTH_GENERIC);
|
||||
}
|
||||
|
||||
static bool vm_has_sve(const struct kvm *kvm)
|
||||
{
|
||||
return system_supports_sve() && kvm_vcpu_has_feature(kvm, KVM_ARM_VCPU_SVE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Definitions for features to be allowed or restricted for protected guests.
|
||||
*
|
||||
* Each field in the masks represents the highest supported value for the
|
||||
* feature. If a feature field is not present, it is not supported. Moreover,
|
||||
* these are used to generate the guest's view of the feature registers.
|
||||
*
|
||||
* The approach for protected VMs is to at least support features that are:
|
||||
* - Needed by common Linux distributions (e.g., floating point)
|
||||
* - Trivial to support, e.g., supporting the feature does not introduce or
|
||||
* require tracking of additional state in KVM
|
||||
* - Cannot be trapped or prevent the guest from using anyway
|
||||
*/
|
||||
|
||||
static const struct pvm_ftr_bits pvmid_aa64pfr0[] = {
|
||||
MAX_FEAT(ID_AA64PFR0_EL1, EL0, IMP),
|
||||
MAX_FEAT(ID_AA64PFR0_EL1, EL1, IMP),
|
||||
MAX_FEAT(ID_AA64PFR0_EL1, EL2, IMP),
|
||||
MAX_FEAT(ID_AA64PFR0_EL1, EL3, IMP),
|
||||
MAX_FEAT(ID_AA64PFR0_EL1, FP, FP16),
|
||||
MAX_FEAT(ID_AA64PFR0_EL1, AdvSIMD, FP16),
|
||||
MAX_FEAT(ID_AA64PFR0_EL1, GIC, IMP),
|
||||
MAX_FEAT_FUNC(ID_AA64PFR0_EL1, SVE, IMP, vm_has_sve),
|
||||
MAX_FEAT(ID_AA64PFR0_EL1, RAS, IMP),
|
||||
MAX_FEAT(ID_AA64PFR0_EL1, DIT, IMP),
|
||||
MAX_FEAT(ID_AA64PFR0_EL1, CSV2, IMP),
|
||||
MAX_FEAT(ID_AA64PFR0_EL1, CSV3, IMP),
|
||||
FEAT_END
|
||||
};
|
||||
|
||||
static const struct pvm_ftr_bits pvmid_aa64pfr1[] = {
|
||||
MAX_FEAT(ID_AA64PFR1_EL1, BT, IMP),
|
||||
MAX_FEAT(ID_AA64PFR1_EL1, SSBS, SSBS2),
|
||||
MAX_FEAT_ENUM(ID_AA64PFR1_EL1, MTE_frac, NI),
|
||||
FEAT_END
|
||||
};
|
||||
|
||||
static const struct pvm_ftr_bits pvmid_aa64mmfr0[] = {
|
||||
MAX_FEAT_ENUM(ID_AA64MMFR0_EL1, PARANGE, 40),
|
||||
MAX_FEAT_ENUM(ID_AA64MMFR0_EL1, ASIDBITS, 16),
|
||||
MAX_FEAT(ID_AA64MMFR0_EL1, BIGEND, IMP),
|
||||
MAX_FEAT(ID_AA64MMFR0_EL1, SNSMEM, IMP),
|
||||
MAX_FEAT(ID_AA64MMFR0_EL1, BIGENDEL0, IMP),
|
||||
MAX_FEAT(ID_AA64MMFR0_EL1, EXS, IMP),
|
||||
FEAT_END
|
||||
};
|
||||
|
||||
static const struct pvm_ftr_bits pvmid_aa64mmfr1[] = {
|
||||
MAX_FEAT(ID_AA64MMFR1_EL1, HAFDBS, DBM),
|
||||
MAX_FEAT_ENUM(ID_AA64MMFR1_EL1, VMIDBits, 16),
|
||||
MAX_FEAT(ID_AA64MMFR1_EL1, HPDS, HPDS2),
|
||||
MAX_FEAT(ID_AA64MMFR1_EL1, PAN, PAN3),
|
||||
MAX_FEAT(ID_AA64MMFR1_EL1, SpecSEI, IMP),
|
||||
MAX_FEAT(ID_AA64MMFR1_EL1, ETS, IMP),
|
||||
MAX_FEAT(ID_AA64MMFR1_EL1, CMOW, IMP),
|
||||
FEAT_END
|
||||
};
|
||||
|
||||
static const struct pvm_ftr_bits pvmid_aa64mmfr2[] = {
|
||||
MAX_FEAT(ID_AA64MMFR2_EL1, CnP, IMP),
|
||||
MAX_FEAT(ID_AA64MMFR2_EL1, UAO, IMP),
|
||||
MAX_FEAT(ID_AA64MMFR2_EL1, IESB, IMP),
|
||||
MAX_FEAT(ID_AA64MMFR2_EL1, AT, IMP),
|
||||
MAX_FEAT_ENUM(ID_AA64MMFR2_EL1, IDS, 0x18),
|
||||
MAX_FEAT(ID_AA64MMFR2_EL1, TTL, IMP),
|
||||
MAX_FEAT(ID_AA64MMFR2_EL1, BBM, 2),
|
||||
MAX_FEAT(ID_AA64MMFR2_EL1, E0PD, IMP),
|
||||
FEAT_END
|
||||
};
|
||||
|
||||
static const struct pvm_ftr_bits pvmid_aa64isar1[] = {
|
||||
MAX_FEAT(ID_AA64ISAR1_EL1, DPB, DPB2),
|
||||
MAX_FEAT_FUNC(ID_AA64ISAR1_EL1, APA, PAuth, vm_has_ptrauth),
|
||||
MAX_FEAT_FUNC(ID_AA64ISAR1_EL1, API, PAuth, vm_has_ptrauth),
|
||||
MAX_FEAT(ID_AA64ISAR1_EL1, JSCVT, IMP),
|
||||
MAX_FEAT(ID_AA64ISAR1_EL1, FCMA, IMP),
|
||||
MAX_FEAT(ID_AA64ISAR1_EL1, LRCPC, LRCPC3),
|
||||
MAX_FEAT(ID_AA64ISAR1_EL1, GPA, IMP),
|
||||
MAX_FEAT(ID_AA64ISAR1_EL1, GPI, IMP),
|
||||
MAX_FEAT(ID_AA64ISAR1_EL1, FRINTTS, IMP),
|
||||
MAX_FEAT(ID_AA64ISAR1_EL1, SB, IMP),
|
||||
MAX_FEAT(ID_AA64ISAR1_EL1, SPECRES, COSP_RCTX),
|
||||
MAX_FEAT(ID_AA64ISAR1_EL1, BF16, EBF16),
|
||||
MAX_FEAT(ID_AA64ISAR1_EL1, DGH, IMP),
|
||||
MAX_FEAT(ID_AA64ISAR1_EL1, I8MM, IMP),
|
||||
FEAT_END
|
||||
};
|
||||
|
||||
static const struct pvm_ftr_bits pvmid_aa64isar2[] = {
|
||||
MAX_FEAT_FUNC(ID_AA64ISAR2_EL1, GPA3, IMP, vm_has_ptrauth),
|
||||
MAX_FEAT_FUNC(ID_AA64ISAR2_EL1, APA3, PAuth, vm_has_ptrauth),
|
||||
MAX_FEAT(ID_AA64ISAR2_EL1, ATS1A, IMP),
|
||||
FEAT_END
|
||||
};
|
||||
|
||||
/*
|
||||
* None of the features in ID_AA64DFR0_EL1 nor ID_AA64MMFR4_EL1 are supported.
|
||||
* However, both have Not-Implemented values that are non-zero. Define them
|
||||
* so they can be used when getting the value of these registers.
|
||||
*/
|
||||
#define ID_AA64DFR0_EL1_NONZERO_NI \
|
||||
( \
|
||||
SYS_FIELD_PREP_ENUM(ID_AA64DFR0_EL1, DoubleLock, NI) | \
|
||||
SYS_FIELD_PREP_ENUM(ID_AA64DFR0_EL1, MTPMU, NI) \
|
||||
)
|
||||
|
||||
#define ID_AA64MMFR4_EL1_NONZERO_NI \
|
||||
SYS_FIELD_PREP_ENUM(ID_AA64MMFR4_EL1, E2H0, NI)
|
||||
|
||||
/*
|
||||
* Returns the value of the feature registers based on the system register
|
||||
* value, the vcpu support for the revelant features, and the additional
|
||||
* restrictions for protected VMs.
|
||||
*/
|
||||
static u64 get_restricted_features(const struct kvm_vcpu *vcpu,
|
||||
u64 sys_reg_val,
|
||||
const struct pvm_ftr_bits restrictions[])
|
||||
{
|
||||
u64 val = 0UL;
|
||||
int i;
|
||||
|
||||
for (i = 0; restrictions[i].width != 0; i++) {
|
||||
bool (*vm_supported)(const struct kvm *) = restrictions[i].vm_supported;
|
||||
bool sign = restrictions[i].sign;
|
||||
int shift = restrictions[i].shift;
|
||||
int width = restrictions[i].width;
|
||||
u64 min_signed = (1UL << width) - 1UL;
|
||||
u64 sign_bit = 1UL << (width - 1);
|
||||
u64 mask = GENMASK_ULL(width + shift - 1, shift);
|
||||
u64 sys_val = (sys_reg_val & mask) >> shift;
|
||||
u64 pvm_max = restrictions[i].max_val;
|
||||
|
||||
if (vm_supported && !vm_supported(vcpu->kvm))
|
||||
val |= (sign ? min_signed : 0) << shift;
|
||||
else if (sign && (sys_val >= sign_bit || pvm_max >= sign_bit))
|
||||
val |= max(sys_val, pvm_max) << shift;
|
||||
else
|
||||
val |= min(sys_val, pvm_max) << shift;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static u64 pvm_calc_id_reg(const struct kvm_vcpu *vcpu, u32 id)
|
||||
{
|
||||
switch (id) {
|
||||
case SYS_ID_AA64PFR0_EL1:
|
||||
return get_restricted_features(vcpu, id_aa64pfr0_el1_sys_val, pvmid_aa64pfr0);
|
||||
case SYS_ID_AA64PFR1_EL1:
|
||||
return get_restricted_features(vcpu, id_aa64pfr1_el1_sys_val, pvmid_aa64pfr1);
|
||||
case SYS_ID_AA64ISAR0_EL1:
|
||||
return id_aa64isar0_el1_sys_val;
|
||||
case SYS_ID_AA64ISAR1_EL1:
|
||||
return get_restricted_features(vcpu, id_aa64isar1_el1_sys_val, pvmid_aa64isar1);
|
||||
case SYS_ID_AA64ISAR2_EL1:
|
||||
return get_restricted_features(vcpu, id_aa64isar2_el1_sys_val, pvmid_aa64isar2);
|
||||
case SYS_ID_AA64MMFR0_EL1:
|
||||
return get_restricted_features(vcpu, id_aa64mmfr0_el1_sys_val, pvmid_aa64mmfr0);
|
||||
case SYS_ID_AA64MMFR1_EL1:
|
||||
return get_restricted_features(vcpu, id_aa64mmfr1_el1_sys_val, pvmid_aa64mmfr1);
|
||||
case SYS_ID_AA64MMFR2_EL1:
|
||||
return get_restricted_features(vcpu, id_aa64mmfr2_el1_sys_val, pvmid_aa64mmfr2);
|
||||
case SYS_ID_AA64DFR0_EL1:
|
||||
return ID_AA64DFR0_EL1_NONZERO_NI;
|
||||
case SYS_ID_AA64MMFR4_EL1:
|
||||
return ID_AA64MMFR4_EL1_NONZERO_NI;
|
||||
default:
|
||||
/* Unhandled ID register, RAZ */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Inject an unknown/undefined exception to an AArch64 guest while most of its
|
||||
* sysregs are live.
|
||||
|
|
@ -49,201 +264,19 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
|
|||
write_sysreg_el2(*vcpu_cpsr(vcpu), SYS_SPSR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the restricted features values of the feature register based on the
|
||||
* limitations in restrict_fields.
|
||||
* A feature id field value of 0b0000 does not impose any restrictions.
|
||||
* Note: Use only for unsigned feature field values.
|
||||
*/
|
||||
static u64 get_restricted_features_unsigned(u64 sys_reg_val,
|
||||
u64 restrict_fields)
|
||||
{
|
||||
u64 value = 0UL;
|
||||
u64 mask = GENMASK_ULL(ARM64_FEATURE_FIELD_BITS - 1, 0);
|
||||
|
||||
/*
|
||||
* According to the Arm Architecture Reference Manual, feature fields
|
||||
* use increasing values to indicate increases in functionality.
|
||||
* Iterate over the restricted feature fields and calculate the minimum
|
||||
* unsigned value between the one supported by the system, and what the
|
||||
* value is being restricted to.
|
||||
*/
|
||||
while (sys_reg_val && restrict_fields) {
|
||||
value |= min(sys_reg_val & mask, restrict_fields & mask);
|
||||
sys_reg_val &= ~mask;
|
||||
restrict_fields &= ~mask;
|
||||
mask <<= ARM64_FEATURE_FIELD_BITS;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Functions that return the value of feature id registers for protected VMs
|
||||
* based on allowed features, system features, and KVM support.
|
||||
*/
|
||||
|
||||
static u64 get_pvm_id_aa64pfr0(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 set_mask = 0;
|
||||
u64 allow_mask = PVM_ID_AA64PFR0_ALLOW;
|
||||
|
||||
set_mask |= get_restricted_features_unsigned(id_aa64pfr0_el1_sys_val,
|
||||
PVM_ID_AA64PFR0_RESTRICT_UNSIGNED);
|
||||
|
||||
return (id_aa64pfr0_el1_sys_val & allow_mask) | set_mask;
|
||||
}
|
||||
|
||||
static u64 get_pvm_id_aa64pfr1(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
const struct kvm *kvm = (const struct kvm *)kern_hyp_va(vcpu->kvm);
|
||||
u64 allow_mask = PVM_ID_AA64PFR1_ALLOW;
|
||||
|
||||
if (!kvm_has_mte(kvm))
|
||||
allow_mask &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE);
|
||||
|
||||
return id_aa64pfr1_el1_sys_val & allow_mask;
|
||||
}
|
||||
|
||||
static u64 get_pvm_id_aa64zfr0(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/*
|
||||
* No support for Scalable Vectors, therefore, hyp has no sanitized
|
||||
* copy of the feature id register.
|
||||
*/
|
||||
BUILD_BUG_ON(PVM_ID_AA64ZFR0_ALLOW != 0ULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 get_pvm_id_aa64dfr0(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/*
|
||||
* No support for debug, including breakpoints, and watchpoints,
|
||||
* therefore, pKVM has no sanitized copy of the feature id register.
|
||||
*/
|
||||
BUILD_BUG_ON(PVM_ID_AA64DFR0_ALLOW != 0ULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 get_pvm_id_aa64dfr1(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/*
|
||||
* No support for debug, therefore, hyp has no sanitized copy of the
|
||||
* feature id register.
|
||||
*/
|
||||
BUILD_BUG_ON(PVM_ID_AA64DFR1_ALLOW != 0ULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 get_pvm_id_aa64afr0(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/*
|
||||
* No support for implementation defined features, therefore, hyp has no
|
||||
* sanitized copy of the feature id register.
|
||||
*/
|
||||
BUILD_BUG_ON(PVM_ID_AA64AFR0_ALLOW != 0ULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 get_pvm_id_aa64afr1(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/*
|
||||
* No support for implementation defined features, therefore, hyp has no
|
||||
* sanitized copy of the feature id register.
|
||||
*/
|
||||
BUILD_BUG_ON(PVM_ID_AA64AFR1_ALLOW != 0ULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 get_pvm_id_aa64isar0(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return id_aa64isar0_el1_sys_val & PVM_ID_AA64ISAR0_ALLOW;
|
||||
}
|
||||
|
||||
static u64 get_pvm_id_aa64isar1(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 allow_mask = PVM_ID_AA64ISAR1_ALLOW;
|
||||
|
||||
if (!vcpu_has_ptrauth(vcpu))
|
||||
allow_mask &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_APA) |
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_API) |
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPA) |
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPI));
|
||||
|
||||
return id_aa64isar1_el1_sys_val & allow_mask;
|
||||
}
|
||||
|
||||
static u64 get_pvm_id_aa64isar2(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 allow_mask = PVM_ID_AA64ISAR2_ALLOW;
|
||||
|
||||
if (!vcpu_has_ptrauth(vcpu))
|
||||
allow_mask &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_APA3) |
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_GPA3));
|
||||
|
||||
return id_aa64isar2_el1_sys_val & allow_mask;
|
||||
}
|
||||
|
||||
static u64 get_pvm_id_aa64mmfr0(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 set_mask;
|
||||
|
||||
set_mask = get_restricted_features_unsigned(id_aa64mmfr0_el1_sys_val,
|
||||
PVM_ID_AA64MMFR0_RESTRICT_UNSIGNED);
|
||||
|
||||
return (id_aa64mmfr0_el1_sys_val & PVM_ID_AA64MMFR0_ALLOW) | set_mask;
|
||||
}
|
||||
|
||||
static u64 get_pvm_id_aa64mmfr1(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return id_aa64mmfr1_el1_sys_val & PVM_ID_AA64MMFR1_ALLOW;
|
||||
}
|
||||
|
||||
static u64 get_pvm_id_aa64mmfr2(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return id_aa64mmfr2_el1_sys_val & PVM_ID_AA64MMFR2_ALLOW;
|
||||
}
|
||||
|
||||
/* Read a sanitized cpufeature ID register by its encoding */
|
||||
u64 pvm_read_id_reg(const struct kvm_vcpu *vcpu, u32 id)
|
||||
{
|
||||
switch (id) {
|
||||
case SYS_ID_AA64PFR0_EL1:
|
||||
return get_pvm_id_aa64pfr0(vcpu);
|
||||
case SYS_ID_AA64PFR1_EL1:
|
||||
return get_pvm_id_aa64pfr1(vcpu);
|
||||
case SYS_ID_AA64ZFR0_EL1:
|
||||
return get_pvm_id_aa64zfr0(vcpu);
|
||||
case SYS_ID_AA64DFR0_EL1:
|
||||
return get_pvm_id_aa64dfr0(vcpu);
|
||||
case SYS_ID_AA64DFR1_EL1:
|
||||
return get_pvm_id_aa64dfr1(vcpu);
|
||||
case SYS_ID_AA64AFR0_EL1:
|
||||
return get_pvm_id_aa64afr0(vcpu);
|
||||
case SYS_ID_AA64AFR1_EL1:
|
||||
return get_pvm_id_aa64afr1(vcpu);
|
||||
case SYS_ID_AA64ISAR0_EL1:
|
||||
return get_pvm_id_aa64isar0(vcpu);
|
||||
case SYS_ID_AA64ISAR1_EL1:
|
||||
return get_pvm_id_aa64isar1(vcpu);
|
||||
case SYS_ID_AA64ISAR2_EL1:
|
||||
return get_pvm_id_aa64isar2(vcpu);
|
||||
case SYS_ID_AA64MMFR0_EL1:
|
||||
return get_pvm_id_aa64mmfr0(vcpu);
|
||||
case SYS_ID_AA64MMFR1_EL1:
|
||||
return get_pvm_id_aa64mmfr1(vcpu);
|
||||
case SYS_ID_AA64MMFR2_EL1:
|
||||
return get_pvm_id_aa64mmfr2(vcpu);
|
||||
default:
|
||||
/* Unhandled ID register, RAZ */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static u64 read_id_reg(const struct kvm_vcpu *vcpu,
|
||||
struct sys_reg_desc const *r)
|
||||
{
|
||||
return pvm_read_id_reg(vcpu, reg_to_encoding(r));
|
||||
struct kvm *kvm = vcpu->kvm;
|
||||
u32 reg = reg_to_encoding(r);
|
||||
|
||||
if (WARN_ON_ONCE(!test_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags)))
|
||||
return 0;
|
||||
|
||||
if (reg >= sys_reg(3, 0, 0, 1, 0) && reg <= sys_reg(3, 0, 0, 7, 7))
|
||||
return kvm->arch.id_regs[IDREG_IDX(reg)];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Handler to RAZ/WI sysregs */
|
||||
|
|
@ -271,13 +304,6 @@ static bool pvm_access_id_aarch32(struct kvm_vcpu *vcpu,
|
|||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* No support for AArch32 guests, therefore, pKVM has no sanitized copy
|
||||
* of AArch32 feature id registers.
|
||||
*/
|
||||
BUILD_BUG_ON(FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_EL1),
|
||||
PVM_ID_AA64PFR0_RESTRICT_UNSIGNED) > ID_AA64PFR0_EL1_EL1_IMP);
|
||||
|
||||
return pvm_access_raz_wi(vcpu, p, r);
|
||||
}
|
||||
|
||||
|
|
@ -448,6 +474,30 @@ static const struct sys_reg_desc pvm_sys_reg_descs[] = {
|
|||
/* Performance Monitoring Registers are restricted. */
|
||||
};
|
||||
|
||||
/*
|
||||
* Initializes feature registers for protected vms.
|
||||
*/
|
||||
void kvm_init_pvm_id_regs(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm *kvm = vcpu->kvm;
|
||||
struct kvm_arch *ka = &kvm->arch;
|
||||
u32 r;
|
||||
|
||||
hyp_assert_lock_held(&vm_table_lock);
|
||||
|
||||
if (test_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Initialize only AArch64 id registers since AArch32 isn't supported
|
||||
* for protected VMs.
|
||||
*/
|
||||
for (r = sys_reg(3, 0, 0, 4, 0); r <= sys_reg(3, 0, 0, 7, 7); r += sys_reg(0, 0, 0, 0, 1))
|
||||
ka->id_regs[IDREG_IDX(r)] = pvm_calc_id_reg(vcpu, r);
|
||||
|
||||
set_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks that the sysreg table is unique and in-order.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -77,12 +77,12 @@ static void __activate_cptr_traps(struct kvm_vcpu *vcpu)
|
|||
* VHE (HCR.E2H == 1) which allows us to use here the CPTR_EL2.TAM
|
||||
* shift value for trapping the AMU accesses.
|
||||
*/
|
||||
u64 val = CPACR_ELx_TTA | CPTR_EL2_TAM;
|
||||
u64 val = CPACR_EL1_TTA | CPTR_EL2_TAM;
|
||||
|
||||
if (guest_owns_fp_regs()) {
|
||||
val |= CPACR_ELx_FPEN;
|
||||
val |= CPACR_EL1_FPEN;
|
||||
if (vcpu_has_sve(vcpu))
|
||||
val |= CPACR_ELx_ZEN;
|
||||
val |= CPACR_EL1_ZEN;
|
||||
} else {
|
||||
__activate_traps_fpsimd32(vcpu);
|
||||
}
|
||||
|
|
@ -122,13 +122,13 @@ static void __activate_cptr_traps(struct kvm_vcpu *vcpu)
|
|||
* hypervisor has traps enabled to dispel any illusion of something more
|
||||
* complicated taking place.
|
||||
*/
|
||||
if (!(SYS_FIELD_GET(CPACR_ELx, FPEN, cptr) & BIT(0)))
|
||||
val &= ~CPACR_ELx_FPEN;
|
||||
if (!(SYS_FIELD_GET(CPACR_ELx, ZEN, cptr) & BIT(0)))
|
||||
val &= ~CPACR_ELx_ZEN;
|
||||
if (!(SYS_FIELD_GET(CPACR_EL1, FPEN, cptr) & BIT(0)))
|
||||
val &= ~CPACR_EL1_FPEN;
|
||||
if (!(SYS_FIELD_GET(CPACR_EL1, ZEN, cptr) & BIT(0)))
|
||||
val &= ~CPACR_EL1_ZEN;
|
||||
|
||||
if (kvm_has_feat(vcpu->kvm, ID_AA64MMFR3_EL1, S2POE, IMP))
|
||||
val |= cptr & CPACR_ELx_E0POE;
|
||||
val |= cptr & CPACR_EL1_E0POE;
|
||||
|
||||
val |= cptr & CPTR_EL2_TCPAC;
|
||||
|
||||
|
|
|
|||
|
|
@ -1021,8 +1021,8 @@ int kvm_init_nv_sysregs(struct kvm *kvm)
|
|||
res0 |= HCR_NV2;
|
||||
if (!kvm_has_feat(kvm, ID_AA64MMFR2_EL1, NV, IMP))
|
||||
res0 |= (HCR_AT | HCR_NV1 | HCR_NV);
|
||||
if (!(__vcpu_has_feature(&kvm->arch, KVM_ARM_VCPU_PTRAUTH_ADDRESS) &&
|
||||
__vcpu_has_feature(&kvm->arch, KVM_ARM_VCPU_PTRAUTH_GENERIC)))
|
||||
if (!(kvm_vcpu_has_feature(kvm, KVM_ARM_VCPU_PTRAUTH_ADDRESS) &&
|
||||
kvm_vcpu_has_feature(kvm, KVM_ARM_VCPU_PTRAUTH_GENERIC)))
|
||||
res0 |= (HCR_API | HCR_APK);
|
||||
if (!kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TME, IMP))
|
||||
res0 |= BIT(39);
|
||||
|
|
@ -1078,8 +1078,8 @@ int kvm_init_nv_sysregs(struct kvm *kvm)
|
|||
|
||||
/* HFG[RW]TR_EL2 */
|
||||
res0 = res1 = 0;
|
||||
if (!(__vcpu_has_feature(&kvm->arch, KVM_ARM_VCPU_PTRAUTH_ADDRESS) &&
|
||||
__vcpu_has_feature(&kvm->arch, KVM_ARM_VCPU_PTRAUTH_GENERIC)))
|
||||
if (!(kvm_vcpu_has_feature(kvm, KVM_ARM_VCPU_PTRAUTH_ADDRESS) &&
|
||||
kvm_vcpu_has_feature(kvm, KVM_ARM_VCPU_PTRAUTH_GENERIC)))
|
||||
res0 |= (HFGxTR_EL2_APDAKey | HFGxTR_EL2_APDBKey |
|
||||
HFGxTR_EL2_APGAKey | HFGxTR_EL2_APIAKey |
|
||||
HFGxTR_EL2_APIBKey);
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ static void kvm_vcpu_enable_sve(struct kvm_vcpu *vcpu)
|
|||
* KVM_REG_ARM64_SVE_VLS. Allocation is deferred until
|
||||
* kvm_arm_vcpu_finalize(), which freezes the configuration.
|
||||
*/
|
||||
vcpu_set_flag(vcpu, GUEST_HAS_SVE);
|
||||
set_bit(KVM_ARCH_FLAG_GUEST_HAS_SVE, &vcpu->kvm->arch.flags);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -211,10 +211,6 @@ void kvm_reset_vcpu(struct kvm_vcpu *vcpu)
|
|||
kvm_vcpu_reset_sve(vcpu);
|
||||
}
|
||||
|
||||
if (vcpu_has_feature(vcpu, KVM_ARM_VCPU_PTRAUTH_ADDRESS) ||
|
||||
vcpu_has_feature(vcpu, KVM_ARM_VCPU_PTRAUTH_GENERIC))
|
||||
kvm_vcpu_enable_ptrauth(vcpu);
|
||||
|
||||
if (vcpu_el1_is_32bit(vcpu))
|
||||
pstate = VCPU_RESET_PSTATE_SVC;
|
||||
else if (vcpu_has_nv(vcpu))
|
||||
|
|
|
|||
|
|
@ -501,7 +501,7 @@ alternative_else_nop_endif
|
|||
#ifdef CONFIG_ARM64_HAFT
|
||||
cmp x9, ID_AA64MMFR1_EL1_HAFDBS_HAFT
|
||||
b.lt 1f
|
||||
orr tcr2, tcr2, TCR2_EL1x_HAFT
|
||||
orr tcr2, tcr2, TCR2_EL1_HAFT
|
||||
#endif /* CONFIG_ARM64_HAFT */
|
||||
1:
|
||||
#endif /* CONFIG_ARM64_HW_AFDBM */
|
||||
|
|
@ -532,7 +532,8 @@ alternative_else_nop_endif
|
|||
#undef PTE_MAYBE_NG
|
||||
#undef PTE_MAYBE_SHARED
|
||||
|
||||
orr tcr2, tcr2, TCR2_EL1x_PIE
|
||||
orr tcr2, tcr2, TCR2_EL1_PIE
|
||||
msr REG_TCR2_EL1, x0
|
||||
|
||||
.Lskip_indirection:
|
||||
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ END {
|
|||
|
||||
# Currently this is effectivey a comment, in future we may want to emit
|
||||
# defines for the fields.
|
||||
/^Fields/ && block_current() == "Sysreg" {
|
||||
(/^Fields/ || /^Mapping/) && block_current() == "Sysreg" {
|
||||
expect_fields(2)
|
||||
|
||||
if (next_bit != 63)
|
||||
|
|
|
|||
|
|
@ -24,8 +24,16 @@
|
|||
# ...
|
||||
# EndEnum
|
||||
|
||||
# Alternatively if multiple registers share the same layout then
|
||||
# a SysregFields block can be used to describe the shared layout
|
||||
# For VHE aliases (*_EL12, *_EL02) of system registers, a Mapping
|
||||
# entry describes the register the alias actually accesses:
|
||||
|
||||
# Sysreg <name_EL12> <op0> <op1> <crn> <crm> <op2>
|
||||
# Mapping <name_EL1>
|
||||
# EndSysreg
|
||||
|
||||
# Where multiple system regsiters are not VHE aliases but share a
|
||||
# common layout, a SysregFields block can be used to describe the
|
||||
# shared layout:
|
||||
|
||||
# SysregFields <fieldsname>
|
||||
# <field>
|
||||
|
|
@ -1978,7 +1986,7 @@ Field 1 A
|
|||
Field 0 M
|
||||
EndSysreg
|
||||
|
||||
SysregFields CPACR_ELx
|
||||
Sysreg CPACR_EL1 3 0 1 0 2
|
||||
Res0 63:30
|
||||
Field 29 E0POE
|
||||
Field 28 TTA
|
||||
|
|
@ -1989,10 +1997,6 @@ Field 21:20 FPEN
|
|||
Res0 19:18
|
||||
Field 17:16 ZEN
|
||||
Res0 15:0
|
||||
EndSysregFields
|
||||
|
||||
Sysreg CPACR_EL1 3 0 1 0 2
|
||||
Fields CPACR_ELx
|
||||
EndSysreg
|
||||
|
||||
Sysreg SMPRI_EL1 3 0 1 2 4
|
||||
|
|
@ -2947,23 +2951,23 @@ Field 63:0 PhysicalOffset
|
|||
EndSysreg
|
||||
|
||||
Sysreg CPACR_EL12 3 5 1 0 2
|
||||
Fields CPACR_ELx
|
||||
Mapping CPACR_EL1
|
||||
EndSysreg
|
||||
|
||||
Sysreg ZCR_EL12 3 5 1 2 0
|
||||
Fields ZCR_ELx
|
||||
Mapping ZCR_EL1
|
||||
EndSysreg
|
||||
|
||||
Sysreg SMCR_EL12 3 5 1 2 6
|
||||
Fields SMCR_ELx
|
||||
Mapping SMCR_EL1
|
||||
EndSysreg
|
||||
|
||||
Sysreg GCSCR_EL12 3 5 2 5 0
|
||||
Fields GCSCR_ELx
|
||||
Mapping GCSCR_EL1
|
||||
EndSysreg
|
||||
|
||||
Sysreg GCSPR_EL12 3 5 2 5 1
|
||||
Fields GCSPR_ELx
|
||||
Mapping GCSPR_EL1
|
||||
EndSysreg
|
||||
|
||||
Sysreg FAR_EL12 3 5 6 0 0
|
||||
|
|
@ -2975,7 +2979,7 @@ Fields MPAM1_ELx
|
|||
EndSysreg
|
||||
|
||||
Sysreg CONTEXTIDR_EL12 3 5 13 0 1
|
||||
Fields CONTEXTIDR_ELx
|
||||
Mapping CONTEXTIDR_EL1
|
||||
EndSysreg
|
||||
|
||||
SysregFields TTBRx_EL1
|
||||
|
|
@ -2992,7 +2996,7 @@ Sysreg TTBR1_EL1 3 0 2 0 1
|
|||
Fields TTBRx_EL1
|
||||
EndSysreg
|
||||
|
||||
SysregFields TCR2_EL1x
|
||||
Sysreg TCR2_EL1 3 0 2 0 3
|
||||
Res0 63:16
|
||||
Field 15 DisCH1
|
||||
Field 14 DisCH0
|
||||
|
|
@ -3006,14 +3010,10 @@ Field 3 POE
|
|||
Field 2 E0POE
|
||||
Field 1 PIE
|
||||
Field 0 PnCH
|
||||
EndSysregFields
|
||||
|
||||
Sysreg TCR2_EL1 3 0 2 0 3
|
||||
Fields TCR2_EL1x
|
||||
EndSysreg
|
||||
|
||||
Sysreg TCR2_EL12 3 5 2 0 3
|
||||
Fields TCR2_EL1x
|
||||
Mapping TCR2_EL1
|
||||
EndSysreg
|
||||
|
||||
Sysreg TCR2_EL2 3 4 2 0 3
|
||||
|
|
@ -3084,7 +3084,7 @@ Fields PIRx_ELx
|
|||
EndSysreg
|
||||
|
||||
Sysreg PIRE0_EL12 3 5 10 2 2
|
||||
Fields PIRx_ELx
|
||||
Mapping PIRE0_EL1
|
||||
EndSysreg
|
||||
|
||||
Sysreg PIRE0_EL2 3 4 10 2 2
|
||||
|
|
@ -3096,7 +3096,7 @@ Fields PIRx_ELx
|
|||
EndSysreg
|
||||
|
||||
Sysreg PIR_EL12 3 5 10 2 3
|
||||
Fields PIRx_ELx
|
||||
Mapping PIR_EL1
|
||||
EndSysreg
|
||||
|
||||
Sysreg PIR_EL2 3 4 10 2 3
|
||||
|
|
@ -3116,7 +3116,7 @@ Fields PIRx_ELx
|
|||
EndSysreg
|
||||
|
||||
Sysreg POR_EL12 3 5 10 2 4
|
||||
Fields PIRx_ELx
|
||||
Mapping POR_EL1
|
||||
EndSysreg
|
||||
|
||||
Sysreg S2POR_EL1 3 0 10 2 5
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user