Merge tag 'kvmarm-6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD
KVM/arm64 updates for Linux 6.8 - LPA2 support, adding 52bit IPA/PA capability for 4kB and 16kB base granule sizes. Branch shared with the arm64 tree. - Large Fine-Grained Trap rework, bringing some sanity to the feature, although there is more to come. This comes with a prefix branch shared with the arm64 tree. - Some additional Nested Virtualization groundwork, mostly introducing the NV2 VNCR support and retargetting the NV support to that version of the architecture. - A small set of vgic fixes and associated cleanups.
This commit is contained in:
@@ -819,6 +819,11 @@ static inline bool system_supports_tlb_range(void)
|
||||
return alternative_has_cap_unlikely(ARM64_HAS_TLB_RANGE);
|
||||
}
|
||||
|
||||
static inline bool system_supports_lpa2(void)
|
||||
{
|
||||
return cpus_have_final_cap(ARM64_HAS_LPA2);
|
||||
}
|
||||
|
||||
int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt);
|
||||
bool try_emulate_mrs(struct pt_regs *regs, u32 isn);
|
||||
|
||||
|
||||
@@ -392,6 +392,21 @@ static inline bool esr_is_data_abort(unsigned long esr)
|
||||
return ec == ESR_ELx_EC_DABT_LOW || ec == ESR_ELx_EC_DABT_CUR;
|
||||
}
|
||||
|
||||
static inline bool esr_fsc_is_translation_fault(unsigned long esr)
|
||||
{
|
||||
return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_FAULT;
|
||||
}
|
||||
|
||||
static inline bool esr_fsc_is_permission_fault(unsigned long esr)
|
||||
{
|
||||
return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_PERM;
|
||||
}
|
||||
|
||||
static inline bool esr_fsc_is_access_flag_fault(unsigned long esr)
|
||||
{
|
||||
return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_ACCESS;
|
||||
}
|
||||
|
||||
const char *esr_get_class_string(unsigned long esr);
|
||||
#endif /* __ASSEMBLY */
|
||||
|
||||
|
||||
@@ -108,6 +108,7 @@
|
||||
#define HCRX_HOST_FLAGS (HCRX_EL2_MSCEn | HCRX_EL2_TCR2En)
|
||||
|
||||
/* TCR_EL2 Registers bits */
|
||||
#define TCR_EL2_DS (1UL << 32)
|
||||
#define TCR_EL2_RES1 ((1U << 31) | (1 << 23))
|
||||
#define TCR_EL2_TBI (1 << 20)
|
||||
#define TCR_EL2_PS_SHIFT 16
|
||||
@@ -122,6 +123,7 @@
|
||||
TCR_EL2_ORGN0_MASK | TCR_EL2_IRGN0_MASK | TCR_EL2_T0SZ_MASK)
|
||||
|
||||
/* VTCR_EL2 Registers bits */
|
||||
#define VTCR_EL2_DS TCR_EL2_DS
|
||||
#define VTCR_EL2_RES1 (1U << 31)
|
||||
#define VTCR_EL2_HD (1 << 22)
|
||||
#define VTCR_EL2_HA (1 << 21)
|
||||
@@ -344,36 +346,47 @@
|
||||
* Once we get to a point where the two describe the same thing, we'll
|
||||
* merge the definitions. One day.
|
||||
*/
|
||||
#define __HFGRTR_EL2_RES0 (GENMASK(63, 56) | GENMASK(53, 51))
|
||||
#define __HFGRTR_EL2_RES0 HFGxTR_EL2_RES0
|
||||
#define __HFGRTR_EL2_MASK GENMASK(49, 0)
|
||||
#define __HFGRTR_EL2_nMASK (GENMASK(58, 57) | GENMASK(55, 54) | BIT(50))
|
||||
#define __HFGRTR_EL2_nMASK ~(__HFGRTR_EL2_RES0 | __HFGRTR_EL2_MASK)
|
||||
|
||||
#define __HFGWTR_EL2_RES0 (GENMASK(63, 56) | GENMASK(53, 51) | \
|
||||
BIT(46) | BIT(42) | BIT(40) | BIT(28) | \
|
||||
GENMASK(26, 25) | BIT(21) | BIT(18) | \
|
||||
/*
|
||||
* The HFGWTR bits are a subset of HFGRTR bits. To ensure we don't miss any
|
||||
* future additions, define __HFGWTR* macros relative to __HFGRTR* ones.
|
||||
*/
|
||||
#define __HFGRTR_ONLY_MASK (BIT(46) | BIT(42) | BIT(40) | BIT(28) | \
|
||||
GENMASK(26, 25) | BIT(21) | BIT(18) | \
|
||||
GENMASK(15, 14) | GENMASK(10, 9) | BIT(2))
|
||||
#define __HFGWTR_EL2_MASK GENMASK(49, 0)
|
||||
#define __HFGWTR_EL2_nMASK (GENMASK(58, 57) | GENMASK(55, 54) | BIT(50))
|
||||
#define __HFGWTR_EL2_RES0 (__HFGRTR_EL2_RES0 | __HFGRTR_ONLY_MASK)
|
||||
#define __HFGWTR_EL2_MASK (__HFGRTR_EL2_MASK & ~__HFGRTR_ONLY_MASK)
|
||||
#define __HFGWTR_EL2_nMASK ~(__HFGWTR_EL2_RES0 | __HFGWTR_EL2_MASK)
|
||||
|
||||
#define __HFGITR_EL2_RES0 GENMASK(63, 57)
|
||||
#define __HFGITR_EL2_MASK GENMASK(54, 0)
|
||||
#define __HFGITR_EL2_nMASK GENMASK(56, 55)
|
||||
#define __HFGITR_EL2_RES0 HFGITR_EL2_RES0
|
||||
#define __HFGITR_EL2_MASK (BIT(62) | BIT(60) | GENMASK(54, 0))
|
||||
#define __HFGITR_EL2_nMASK ~(__HFGITR_EL2_RES0 | __HFGITR_EL2_MASK)
|
||||
|
||||
#define __HDFGRTR_EL2_RES0 (BIT(49) | BIT(42) | GENMASK(39, 38) | \
|
||||
GENMASK(21, 20) | BIT(8))
|
||||
#define __HDFGRTR_EL2_MASK ~__HDFGRTR_EL2_nMASK
|
||||
#define __HDFGRTR_EL2_nMASK GENMASK(62, 59)
|
||||
#define __HDFGRTR_EL2_RES0 HDFGRTR_EL2_RES0
|
||||
#define __HDFGRTR_EL2_MASK (BIT(63) | GENMASK(58, 50) | GENMASK(48, 43) | \
|
||||
GENMASK(41, 40) | GENMASK(37, 22) | \
|
||||
GENMASK(19, 9) | GENMASK(7, 0))
|
||||
#define __HDFGRTR_EL2_nMASK ~(__HDFGRTR_EL2_RES0 | __HDFGRTR_EL2_MASK)
|
||||
|
||||
#define __HDFGWTR_EL2_RES0 (BIT(63) | GENMASK(59, 58) | BIT(51) | BIT(47) | \
|
||||
BIT(43) | GENMASK(40, 38) | BIT(34) | BIT(30) | \
|
||||
BIT(22) | BIT(9) | BIT(6))
|
||||
#define __HDFGWTR_EL2_MASK ~__HDFGWTR_EL2_nMASK
|
||||
#define __HDFGWTR_EL2_nMASK GENMASK(62, 60)
|
||||
#define __HDFGWTR_EL2_RES0 HDFGWTR_EL2_RES0
|
||||
#define __HDFGWTR_EL2_MASK (GENMASK(57, 52) | GENMASK(50, 48) | \
|
||||
GENMASK(46, 44) | GENMASK(42, 41) | \
|
||||
GENMASK(37, 35) | GENMASK(33, 31) | \
|
||||
GENMASK(29, 23) | GENMASK(21, 10) | \
|
||||
GENMASK(8, 7) | GENMASK(5, 0))
|
||||
#define __HDFGWTR_EL2_nMASK ~(__HDFGWTR_EL2_RES0 | __HDFGWTR_EL2_MASK)
|
||||
|
||||
#define __HAFGRTR_EL2_RES0 HAFGRTR_EL2_RES0
|
||||
#define __HAFGRTR_EL2_MASK (GENMASK(49, 17) | GENMASK(4, 0))
|
||||
#define __HAFGRTR_EL2_nMASK ~(__HAFGRTR_EL2_RES0 | __HAFGRTR_EL2_MASK)
|
||||
|
||||
/* Similar definitions for HCRX_EL2 */
|
||||
#define __HCRX_EL2_RES0 (GENMASK(63, 16) | GENMASK(13, 12))
|
||||
#define __HCRX_EL2_MASK (0)
|
||||
#define __HCRX_EL2_nMASK (GENMASK(15, 14) | GENMASK(4, 0))
|
||||
#define __HCRX_EL2_RES0 HCRX_EL2_RES0
|
||||
#define __HCRX_EL2_MASK (BIT(6))
|
||||
#define __HCRX_EL2_nMASK ~(__HCRX_EL2_RES0 | __HCRX_EL2_MASK)
|
||||
|
||||
/* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
|
||||
#define HPFAR_MASK (~UL(0xf))
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <asm/esr.h>
|
||||
#include <asm/kvm_arm.h>
|
||||
#include <asm/kvm_hyp.h>
|
||||
#include <asm/kvm_nested.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/virt.h>
|
||||
@@ -54,11 +55,6 @@ void kvm_emulate_nested_eret(struct kvm_vcpu *vcpu);
|
||||
int kvm_inject_nested_sync(struct kvm_vcpu *vcpu, u64 esr_el2);
|
||||
int kvm_inject_nested_irq(struct kvm_vcpu *vcpu);
|
||||
|
||||
static inline bool vcpu_has_feature(const struct kvm_vcpu *vcpu, int feature)
|
||||
{
|
||||
return test_bit(feature, vcpu->kvm->arch.vcpu_features);
|
||||
}
|
||||
|
||||
#if defined(__KVM_VHE_HYPERVISOR__) || defined(__KVM_NVHE_HYPERVISOR__)
|
||||
static __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
@@ -248,7 +244,7 @@ static inline bool __is_hyp_ctxt(const struct kvm_cpu_context *ctxt)
|
||||
|
||||
static inline bool is_hyp_ctxt(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return __is_hyp_ctxt(&vcpu->arch.ctxt);
|
||||
return vcpu_has_nv(vcpu) && __is_hyp_ctxt(&vcpu->arch.ctxt);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -404,14 +400,25 @@ static __always_inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)
|
||||
return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC;
|
||||
}
|
||||
|
||||
static __always_inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vcpu)
|
||||
static inline
|
||||
bool kvm_vcpu_trap_is_permission_fault(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_TYPE;
|
||||
return esr_fsc_is_permission_fault(kvm_vcpu_get_esr(vcpu));
|
||||
}
|
||||
|
||||
static __always_inline u8 kvm_vcpu_trap_get_fault_level(const struct kvm_vcpu *vcpu)
|
||||
static inline
|
||||
bool kvm_vcpu_trap_is_translation_fault(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_LEVEL;
|
||||
return esr_fsc_is_translation_fault(kvm_vcpu_get_esr(vcpu));
|
||||
}
|
||||
|
||||
static inline
|
||||
u64 kvm_vcpu_trap_get_perm_fault_granule(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long esr = kvm_vcpu_get_esr(vcpu);
|
||||
|
||||
BUG_ON(!esr_fsc_is_permission_fault(esr));
|
||||
return BIT(ARM64_HW_PGTABLE_LEVEL_SHIFT(esr & ESR_ELx_FSC_LEVEL));
|
||||
}
|
||||
|
||||
static __always_inline bool kvm_vcpu_abt_issea(const struct kvm_vcpu *vcpu)
|
||||
@@ -454,12 +461,7 @@ static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
|
||||
* first), then a permission fault to allow the flags
|
||||
* to be set.
|
||||
*/
|
||||
switch (kvm_vcpu_trap_get_fault_type(vcpu)) {
|
||||
case ESR_ELx_FSC_PERM:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return kvm_vcpu_trap_is_permission_fault(vcpu);
|
||||
}
|
||||
|
||||
if (kvm_vcpu_trap_is_iabt(vcpu))
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <asm/fpsimd.h>
|
||||
#include <asm/kvm.h>
|
||||
#include <asm/kvm_asm.h>
|
||||
#include <asm/vncr_mapping.h>
|
||||
|
||||
#define __KVM_HAVE_ARCH_INTC_INITIALIZED
|
||||
|
||||
@@ -306,6 +307,7 @@ struct kvm_arch {
|
||||
* Atomic access to multiple idregs are guarded by kvm_arch.config_lock.
|
||||
*/
|
||||
#define IDREG_IDX(id) (((sys_reg_CRm(id) - 1) << 3) | sys_reg_Op2(id))
|
||||
#define IDX_IDREG(idx) sys_reg(3, 0, 0, ((idx) >> 3) + 1, (idx) & Op2_mask)
|
||||
#define IDREG(kvm, id) ((kvm)->arch.id_regs[IDREG_IDX(id)])
|
||||
#define KVM_ARM_ID_REG_NUM (IDREG_IDX(sys_reg(3, 0, 0, 7, 7)) + 1)
|
||||
u64 id_regs[KVM_ARM_ID_REG_NUM];
|
||||
@@ -324,33 +326,33 @@ struct kvm_vcpu_fault_info {
|
||||
u64 disr_el1; /* Deferred [SError] Status Register */
|
||||
};
|
||||
|
||||
/*
|
||||
* VNCR() just places the VNCR_capable registers in the enum after
|
||||
* __VNCR_START__, and the value (after correction) to be an 8-byte offset
|
||||
* from the VNCR base. As we don't require the enum to be otherwise ordered,
|
||||
* we need the terrible hack below to ensure that we correctly size the
|
||||
* sys_regs array, no matter what.
|
||||
*
|
||||
* The __MAX__ macro has been lifted from Sean Eron Anderson's wonderful
|
||||
* treasure trove of bit hacks:
|
||||
* https://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
|
||||
*/
|
||||
#define __MAX__(x,y) ((x) ^ (((x) ^ (y)) & -((x) < (y))))
|
||||
#define VNCR(r) \
|
||||
__before_##r, \
|
||||
r = __VNCR_START__ + ((VNCR_ ## r) / 8), \
|
||||
__after_##r = __MAX__(__before_##r - 1, r)
|
||||
|
||||
enum vcpu_sysreg {
|
||||
__INVALID_SYSREG__, /* 0 is reserved as an invalid value */
|
||||
MPIDR_EL1, /* MultiProcessor Affinity Register */
|
||||
CLIDR_EL1, /* Cache Level ID Register */
|
||||
CSSELR_EL1, /* Cache Size Selection Register */
|
||||
SCTLR_EL1, /* System Control Register */
|
||||
ACTLR_EL1, /* Auxiliary Control Register */
|
||||
CPACR_EL1, /* Coprocessor Access Control */
|
||||
ZCR_EL1, /* SVE Control */
|
||||
TTBR0_EL1, /* Translation Table Base Register 0 */
|
||||
TTBR1_EL1, /* Translation Table Base Register 1 */
|
||||
TCR_EL1, /* Translation Control Register */
|
||||
TCR2_EL1, /* Extended Translation Control Register */
|
||||
ESR_EL1, /* Exception Syndrome Register */
|
||||
AFSR0_EL1, /* Auxiliary Fault Status Register 0 */
|
||||
AFSR1_EL1, /* Auxiliary Fault Status Register 1 */
|
||||
FAR_EL1, /* Fault Address Register */
|
||||
MAIR_EL1, /* Memory Attribute Indirection Register */
|
||||
VBAR_EL1, /* Vector Base Address Register */
|
||||
CONTEXTIDR_EL1, /* Context ID Register */
|
||||
TPIDR_EL0, /* Thread ID, User R/W */
|
||||
TPIDRRO_EL0, /* Thread ID, User R/O */
|
||||
TPIDR_EL1, /* Thread ID, Privileged */
|
||||
AMAIR_EL1, /* Aux Memory Attribute Indirection Register */
|
||||
CNTKCTL_EL1, /* Timer Control Register (EL1) */
|
||||
PAR_EL1, /* Physical Address Register */
|
||||
MDSCR_EL1, /* Monitor Debug System Control Register */
|
||||
MDCCINT_EL1, /* Monitor Debug Comms Channel Interrupt Enable Reg */
|
||||
OSLSR_EL1, /* OS Lock Status Register */
|
||||
DISR_EL1, /* Deferred Interrupt Status Register */
|
||||
@@ -381,26 +383,11 @@ enum vcpu_sysreg {
|
||||
APGAKEYLO_EL1,
|
||||
APGAKEYHI_EL1,
|
||||
|
||||
ELR_EL1,
|
||||
SP_EL1,
|
||||
SPSR_EL1,
|
||||
|
||||
CNTVOFF_EL2,
|
||||
CNTV_CVAL_EL0,
|
||||
CNTV_CTL_EL0,
|
||||
CNTP_CVAL_EL0,
|
||||
CNTP_CTL_EL0,
|
||||
|
||||
/* Memory Tagging Extension registers */
|
||||
RGSR_EL1, /* Random Allocation Tag Seed Register */
|
||||
GCR_EL1, /* Tag Control Register */
|
||||
TFSR_EL1, /* Tag Fault Status Register (EL1) */
|
||||
TFSRE0_EL1, /* Tag Fault Status Register (EL0) */
|
||||
|
||||
/* Permission Indirection Extension registers */
|
||||
PIR_EL1, /* Permission Indirection Register 1 (EL1) */
|
||||
PIRE0_EL1, /* Permission Indirection Register 0 (EL1) */
|
||||
|
||||
/* 32bit specific registers. */
|
||||
DACR32_EL2, /* Domain Access Control Register */
|
||||
IFSR32_EL2, /* Instruction Fault Status Register */
|
||||
@@ -408,21 +395,14 @@ enum vcpu_sysreg {
|
||||
DBGVCR32_EL2, /* Debug Vector Catch Register */
|
||||
|
||||
/* EL2 registers */
|
||||
VPIDR_EL2, /* Virtualization Processor ID Register */
|
||||
VMPIDR_EL2, /* Virtualization Multiprocessor ID Register */
|
||||
SCTLR_EL2, /* System Control Register (EL2) */
|
||||
ACTLR_EL2, /* Auxiliary Control Register (EL2) */
|
||||
HCR_EL2, /* Hypervisor Configuration Register */
|
||||
MDCR_EL2, /* Monitor Debug Configuration Register (EL2) */
|
||||
CPTR_EL2, /* Architectural Feature Trap Register (EL2) */
|
||||
HSTR_EL2, /* Hypervisor System Trap Register */
|
||||
HACR_EL2, /* Hypervisor Auxiliary Control Register */
|
||||
HCRX_EL2, /* Extended Hypervisor Configuration Register */
|
||||
TTBR0_EL2, /* Translation Table Base Register 0 (EL2) */
|
||||
TTBR1_EL2, /* Translation Table Base Register 1 (EL2) */
|
||||
TCR_EL2, /* Translation Control Register (EL2) */
|
||||
VTTBR_EL2, /* Virtualization Translation Table Base Register */
|
||||
VTCR_EL2, /* Virtualization Translation Control Register */
|
||||
SPSR_EL2, /* EL2 saved program status register */
|
||||
ELR_EL2, /* EL2 exception link register */
|
||||
AFSR0_EL2, /* Auxiliary Fault Status Register 0 (EL2) */
|
||||
@@ -435,19 +415,62 @@ enum vcpu_sysreg {
|
||||
VBAR_EL2, /* Vector Base Address Register (EL2) */
|
||||
RVBAR_EL2, /* Reset Vector Base Address Register */
|
||||
CONTEXTIDR_EL2, /* Context ID Register (EL2) */
|
||||
TPIDR_EL2, /* EL2 Software Thread ID Register */
|
||||
CNTHCTL_EL2, /* Counter-timer Hypervisor Control register */
|
||||
SP_EL2, /* EL2 Stack Pointer */
|
||||
HFGRTR_EL2,
|
||||
HFGWTR_EL2,
|
||||
HFGITR_EL2,
|
||||
HDFGRTR_EL2,
|
||||
HDFGWTR_EL2,
|
||||
CNTHP_CTL_EL2,
|
||||
CNTHP_CVAL_EL2,
|
||||
CNTHV_CTL_EL2,
|
||||
CNTHV_CVAL_EL2,
|
||||
|
||||
__VNCR_START__, /* Any VNCR-capable reg goes after this point */
|
||||
|
||||
VNCR(SCTLR_EL1),/* System Control Register */
|
||||
VNCR(ACTLR_EL1),/* Auxiliary Control Register */
|
||||
VNCR(CPACR_EL1),/* Coprocessor Access Control */
|
||||
VNCR(ZCR_EL1), /* SVE Control */
|
||||
VNCR(TTBR0_EL1),/* Translation Table Base Register 0 */
|
||||
VNCR(TTBR1_EL1),/* Translation Table Base Register 1 */
|
||||
VNCR(TCR_EL1), /* Translation Control Register */
|
||||
VNCR(TCR2_EL1), /* Extended Translation Control Register */
|
||||
VNCR(ESR_EL1), /* Exception Syndrome Register */
|
||||
VNCR(AFSR0_EL1),/* Auxiliary Fault Status Register 0 */
|
||||
VNCR(AFSR1_EL1),/* Auxiliary Fault Status Register 1 */
|
||||
VNCR(FAR_EL1), /* Fault Address Register */
|
||||
VNCR(MAIR_EL1), /* Memory Attribute Indirection Register */
|
||||
VNCR(VBAR_EL1), /* Vector Base Address Register */
|
||||
VNCR(CONTEXTIDR_EL1), /* Context ID Register */
|
||||
VNCR(AMAIR_EL1),/* Aux Memory Attribute Indirection Register */
|
||||
VNCR(MDSCR_EL1),/* Monitor Debug System Control Register */
|
||||
VNCR(ELR_EL1),
|
||||
VNCR(SP_EL1),
|
||||
VNCR(SPSR_EL1),
|
||||
VNCR(TFSR_EL1), /* Tag Fault Status Register (EL1) */
|
||||
VNCR(VPIDR_EL2),/* Virtualization Processor ID Register */
|
||||
VNCR(VMPIDR_EL2),/* Virtualization Multiprocessor ID Register */
|
||||
VNCR(HCR_EL2), /* Hypervisor Configuration Register */
|
||||
VNCR(HSTR_EL2), /* Hypervisor System Trap Register */
|
||||
VNCR(VTTBR_EL2),/* Virtualization Translation Table Base Register */
|
||||
VNCR(VTCR_EL2), /* Virtualization Translation Control Register */
|
||||
VNCR(TPIDR_EL2),/* EL2 Software Thread ID Register */
|
||||
VNCR(HCRX_EL2), /* Extended Hypervisor Configuration Register */
|
||||
|
||||
/* Permission Indirection Extension registers */
|
||||
VNCR(PIR_EL1), /* Permission Indirection Register 1 (EL1) */
|
||||
VNCR(PIRE0_EL1), /* Permission Indirection Register 0 (EL1) */
|
||||
|
||||
VNCR(HFGRTR_EL2),
|
||||
VNCR(HFGWTR_EL2),
|
||||
VNCR(HFGITR_EL2),
|
||||
VNCR(HDFGRTR_EL2),
|
||||
VNCR(HDFGWTR_EL2),
|
||||
VNCR(HAFGRTR_EL2),
|
||||
|
||||
VNCR(CNTVOFF_EL2),
|
||||
VNCR(CNTV_CVAL_EL0),
|
||||
VNCR(CNTV_CTL_EL0),
|
||||
VNCR(CNTP_CVAL_EL0),
|
||||
VNCR(CNTP_CTL_EL0),
|
||||
|
||||
NR_SYS_REGS /* Nothing after this line! */
|
||||
};
|
||||
|
||||
@@ -464,6 +487,9 @@ struct kvm_cpu_context {
|
||||
u64 sys_regs[NR_SYS_REGS];
|
||||
|
||||
struct kvm_vcpu *__hyp_running_vcpu;
|
||||
|
||||
/* This pointer has to be 4kB aligned. */
|
||||
u64 *vncr_array;
|
||||
};
|
||||
|
||||
struct kvm_host_data {
|
||||
@@ -826,8 +852,19 @@ struct kvm_vcpu_arch {
|
||||
* accessed by a running VCPU. For example, for userspace access or
|
||||
* for system registers that are never context switched, but only
|
||||
* emulated.
|
||||
*
|
||||
* Don't bother with VNCR-based accesses in the nVHE code, it has no
|
||||
* business dealing with NV.
|
||||
*/
|
||||
#define __ctxt_sys_reg(c,r) (&(c)->sys_regs[(r)])
|
||||
static inline u64 *__ctxt_sys_reg(const struct kvm_cpu_context *ctxt, int r)
|
||||
{
|
||||
#if !defined (__KVM_NVHE_HYPERVISOR__)
|
||||
if (unlikely(cpus_have_final_cap(ARM64_HAS_NESTED_VIRT) &&
|
||||
r >= __VNCR_START__ && ctxt->vncr_array))
|
||||
return &ctxt->vncr_array[r - __VNCR_START__];
|
||||
#endif
|
||||
return (u64 *)&ctxt->sys_regs[r];
|
||||
}
|
||||
|
||||
#define ctxt_sys_reg(c,r) (*__ctxt_sys_reg(c,r))
|
||||
|
||||
@@ -871,6 +908,7 @@ static inline bool __vcpu_read_sys_reg_from_cpu(int reg, u64 *val)
|
||||
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;
|
||||
@@ -915,6 +953,7 @@ static inline bool __vcpu_write_sys_reg_to_cpu(u64 val, int reg)
|
||||
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;
|
||||
@@ -1175,6 +1214,13 @@ bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
|
||||
#define kvm_vm_has_ran_once(kvm) \
|
||||
(test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &(kvm)->arch.flags))
|
||||
|
||||
static inline bool __vcpu_has_feature(const struct kvm_arch *ka, int feature)
|
||||
{
|
||||
return test_bit(feature, ka->vcpu_features);
|
||||
}
|
||||
|
||||
#define vcpu_has_feature(v, f) __vcpu_has_feature(&(v)->kvm->arch, (f))
|
||||
|
||||
int kvm_trng_call(struct kvm_vcpu *vcpu);
|
||||
#ifdef CONFIG_KVM
|
||||
extern phys_addr_t hyp_mem_base;
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
#ifndef __ARM64_KVM_NESTED_H
|
||||
#define __ARM64_KVM_NESTED_H
|
||||
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <asm/kvm_emulate.h>
|
||||
|
||||
static inline bool vcpu_has_nv(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
@@ -12,12 +13,55 @@ static inline bool vcpu_has_nv(const struct kvm_vcpu *vcpu)
|
||||
vcpu_has_feature(vcpu, KVM_ARM_VCPU_HAS_EL2));
|
||||
}
|
||||
|
||||
/* Translation helpers from non-VHE EL2 to EL1 */
|
||||
static inline u64 tcr_el2_ps_to_tcr_el1_ips(u64 tcr_el2)
|
||||
{
|
||||
return (u64)FIELD_GET(TCR_EL2_PS_MASK, tcr_el2) << TCR_IPS_SHIFT;
|
||||
}
|
||||
|
||||
static inline u64 translate_tcr_el2_to_tcr_el1(u64 tcr)
|
||||
{
|
||||
return TCR_EPD1_MASK | /* disable TTBR1_EL1 */
|
||||
((tcr & TCR_EL2_TBI) ? TCR_TBI0 : 0) |
|
||||
tcr_el2_ps_to_tcr_el1_ips(tcr) |
|
||||
(tcr & TCR_EL2_TG0_MASK) |
|
||||
(tcr & TCR_EL2_ORGN0_MASK) |
|
||||
(tcr & TCR_EL2_IRGN0_MASK) |
|
||||
(tcr & TCR_EL2_T0SZ_MASK);
|
||||
}
|
||||
|
||||
static inline u64 translate_cptr_el2_to_cpacr_el1(u64 cptr_el2)
|
||||
{
|
||||
u64 cpacr_el1 = 0;
|
||||
|
||||
if (cptr_el2 & CPTR_EL2_TTA)
|
||||
cpacr_el1 |= CPACR_ELx_TTA;
|
||||
if (!(cptr_el2 & CPTR_EL2_TFP))
|
||||
cpacr_el1 |= CPACR_ELx_FPEN;
|
||||
if (!(cptr_el2 & CPTR_EL2_TZ))
|
||||
cpacr_el1 |= CPACR_ELx_ZEN;
|
||||
|
||||
return cpacr_el1;
|
||||
}
|
||||
|
||||
static inline u64 translate_sctlr_el2_to_sctlr_el1(u64 val)
|
||||
{
|
||||
/* Only preserve the minimal set of bits we support */
|
||||
val &= (SCTLR_ELx_M | SCTLR_ELx_A | SCTLR_ELx_C | SCTLR_ELx_SA |
|
||||
SCTLR_ELx_I | SCTLR_ELx_IESB | SCTLR_ELx_WXN | SCTLR_ELx_EE);
|
||||
val |= SCTLR_EL1_RES1;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline u64 translate_ttbr0_el2_to_ttbr0_el1(u64 ttbr0)
|
||||
{
|
||||
/* Clear the ASID field */
|
||||
return ttbr0 & ~GENMASK_ULL(63, 48);
|
||||
}
|
||||
|
||||
extern bool __check_nv_sr_forward(struct kvm_vcpu *vcpu);
|
||||
|
||||
struct sys_reg_params;
|
||||
struct sys_reg_desc;
|
||||
|
||||
void access_nested_id_reg(struct kvm_vcpu *v, struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r);
|
||||
int kvm_init_nv_sysregs(struct kvm *kvm);
|
||||
|
||||
#endif /* __ARM64_KVM_NESTED_H */
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define KVM_PGTABLE_MAX_LEVELS 4U
|
||||
#define KVM_PGTABLE_FIRST_LEVEL -1
|
||||
#define KVM_PGTABLE_LAST_LEVEL 3
|
||||
|
||||
/*
|
||||
* The largest supported block sizes for KVM (no 52-bit PA support):
|
||||
@@ -20,17 +21,29 @@
|
||||
* - 64K (level 2): 512MB
|
||||
*/
|
||||
#ifdef CONFIG_ARM64_4K_PAGES
|
||||
#define KVM_PGTABLE_MIN_BLOCK_LEVEL 1U
|
||||
#define KVM_PGTABLE_MIN_BLOCK_LEVEL 1
|
||||
#else
|
||||
#define KVM_PGTABLE_MIN_BLOCK_LEVEL 2U
|
||||
#define KVM_PGTABLE_MIN_BLOCK_LEVEL 2
|
||||
#endif
|
||||
|
||||
#define kvm_lpa2_is_enabled() system_supports_lpa2()
|
||||
|
||||
static inline u64 kvm_get_parange_max(void)
|
||||
{
|
||||
if (kvm_lpa2_is_enabled() ||
|
||||
(IS_ENABLED(CONFIG_ARM64_PA_BITS_52) && PAGE_SHIFT == 16))
|
||||
return ID_AA64MMFR0_EL1_PARANGE_52;
|
||||
else
|
||||
return ID_AA64MMFR0_EL1_PARANGE_48;
|
||||
}
|
||||
|
||||
static inline u64 kvm_get_parange(u64 mmfr0)
|
||||
{
|
||||
u64 parange_max = kvm_get_parange_max();
|
||||
u64 parange = cpuid_feature_extract_unsigned_field(mmfr0,
|
||||
ID_AA64MMFR0_EL1_PARANGE_SHIFT);
|
||||
if (parange > ID_AA64MMFR0_EL1_PARANGE_MAX)
|
||||
parange = ID_AA64MMFR0_EL1_PARANGE_MAX;
|
||||
if (parange > parange_max)
|
||||
parange = parange_max;
|
||||
|
||||
return parange;
|
||||
}
|
||||
@@ -41,6 +54,8 @@ typedef u64 kvm_pte_t;
|
||||
|
||||
#define KVM_PTE_ADDR_MASK GENMASK(47, PAGE_SHIFT)
|
||||
#define KVM_PTE_ADDR_51_48 GENMASK(15, 12)
|
||||
#define KVM_PTE_ADDR_MASK_LPA2 GENMASK(49, PAGE_SHIFT)
|
||||
#define KVM_PTE_ADDR_51_50_LPA2 GENMASK(9, 8)
|
||||
|
||||
#define KVM_PHYS_INVALID (-1ULL)
|
||||
|
||||
@@ -51,21 +66,34 @@ static inline bool kvm_pte_valid(kvm_pte_t pte)
|
||||
|
||||
static inline u64 kvm_pte_to_phys(kvm_pte_t pte)
|
||||
{
|
||||
u64 pa = pte & KVM_PTE_ADDR_MASK;
|
||||
u64 pa;
|
||||
|
||||
if (PAGE_SHIFT == 16)
|
||||
pa |= FIELD_GET(KVM_PTE_ADDR_51_48, pte) << 48;
|
||||
if (kvm_lpa2_is_enabled()) {
|
||||
pa = pte & KVM_PTE_ADDR_MASK_LPA2;
|
||||
pa |= FIELD_GET(KVM_PTE_ADDR_51_50_LPA2, pte) << 50;
|
||||
} else {
|
||||
pa = pte & KVM_PTE_ADDR_MASK;
|
||||
if (PAGE_SHIFT == 16)
|
||||
pa |= FIELD_GET(KVM_PTE_ADDR_51_48, pte) << 48;
|
||||
}
|
||||
|
||||
return pa;
|
||||
}
|
||||
|
||||
static inline kvm_pte_t kvm_phys_to_pte(u64 pa)
|
||||
{
|
||||
kvm_pte_t pte = pa & KVM_PTE_ADDR_MASK;
|
||||
kvm_pte_t pte;
|
||||
|
||||
if (PAGE_SHIFT == 16) {
|
||||
pa &= GENMASK(51, 48);
|
||||
pte |= FIELD_PREP(KVM_PTE_ADDR_51_48, pa >> 48);
|
||||
if (kvm_lpa2_is_enabled()) {
|
||||
pte = pa & KVM_PTE_ADDR_MASK_LPA2;
|
||||
pa &= GENMASK(51, 50);
|
||||
pte |= FIELD_PREP(KVM_PTE_ADDR_51_50_LPA2, pa >> 50);
|
||||
} else {
|
||||
pte = pa & KVM_PTE_ADDR_MASK;
|
||||
if (PAGE_SHIFT == 16) {
|
||||
pa &= GENMASK(51, 48);
|
||||
pte |= FIELD_PREP(KVM_PTE_ADDR_51_48, pa >> 48);
|
||||
}
|
||||
}
|
||||
|
||||
return pte;
|
||||
@@ -76,28 +104,28 @@ static inline kvm_pfn_t kvm_pte_to_pfn(kvm_pte_t pte)
|
||||
return __phys_to_pfn(kvm_pte_to_phys(pte));
|
||||
}
|
||||
|
||||
static inline u64 kvm_granule_shift(u32 level)
|
||||
static inline u64 kvm_granule_shift(s8 level)
|
||||
{
|
||||
/* Assumes KVM_PGTABLE_MAX_LEVELS is 4 */
|
||||
/* Assumes KVM_PGTABLE_LAST_LEVEL is 3 */
|
||||
return ARM64_HW_PGTABLE_LEVEL_SHIFT(level);
|
||||
}
|
||||
|
||||
static inline u64 kvm_granule_size(u32 level)
|
||||
static inline u64 kvm_granule_size(s8 level)
|
||||
{
|
||||
return BIT(kvm_granule_shift(level));
|
||||
}
|
||||
|
||||
static inline bool kvm_level_supports_block_mapping(u32 level)
|
||||
static inline bool kvm_level_supports_block_mapping(s8 level)
|
||||
{
|
||||
return level >= KVM_PGTABLE_MIN_BLOCK_LEVEL;
|
||||
}
|
||||
|
||||
static inline u32 kvm_supported_block_sizes(void)
|
||||
{
|
||||
u32 level = KVM_PGTABLE_MIN_BLOCK_LEVEL;
|
||||
s8 level = KVM_PGTABLE_MIN_BLOCK_LEVEL;
|
||||
u32 r = 0;
|
||||
|
||||
for (; level < KVM_PGTABLE_MAX_LEVELS; level++)
|
||||
for (; level <= KVM_PGTABLE_LAST_LEVEL; level++)
|
||||
r |= BIT(kvm_granule_shift(level));
|
||||
|
||||
return r;
|
||||
@@ -142,7 +170,7 @@ struct kvm_pgtable_mm_ops {
|
||||
void* (*zalloc_page)(void *arg);
|
||||
void* (*zalloc_pages_exact)(size_t size);
|
||||
void (*free_pages_exact)(void *addr, size_t size);
|
||||
void (*free_unlinked_table)(void *addr, u32 level);
|
||||
void (*free_unlinked_table)(void *addr, s8 level);
|
||||
void (*get_page)(void *addr);
|
||||
void (*put_page)(void *addr);
|
||||
int (*page_count)(void *addr);
|
||||
@@ -238,7 +266,7 @@ struct kvm_pgtable_visit_ctx {
|
||||
u64 start;
|
||||
u64 addr;
|
||||
u64 end;
|
||||
u32 level;
|
||||
s8 level;
|
||||
enum kvm_pgtable_walk_flags flags;
|
||||
};
|
||||
|
||||
@@ -341,7 +369,7 @@ static inline bool kvm_pgtable_walk_lock_held(void)
|
||||
*/
|
||||
struct kvm_pgtable {
|
||||
u32 ia_bits;
|
||||
u32 start_level;
|
||||
s8 start_level;
|
||||
kvm_pteref_t pgd;
|
||||
struct kvm_pgtable_mm_ops *mm_ops;
|
||||
|
||||
@@ -475,7 +503,7 @@ void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt);
|
||||
* 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_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, u32 level);
|
||||
void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, s8 level);
|
||||
|
||||
/**
|
||||
* kvm_pgtable_stage2_create_unlinked() - Create an unlinked stage-2 paging structure.
|
||||
@@ -499,7 +527,7 @@ void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *p
|
||||
* an ERR_PTR(error) on failure.
|
||||
*/
|
||||
kvm_pte_t *kvm_pgtable_stage2_create_unlinked(struct kvm_pgtable *pgt,
|
||||
u64 phys, u32 level,
|
||||
u64 phys, s8 level,
|
||||
enum kvm_pgtable_prot prot,
|
||||
void *mc, bool force_pte);
|
||||
|
||||
@@ -725,7 +753,7 @@ int kvm_pgtable_walk(struct kvm_pgtable *pgt, u64 addr, u64 size,
|
||||
* Return: 0 on success, negative error code on failure.
|
||||
*/
|
||||
int kvm_pgtable_get_leaf(struct kvm_pgtable *pgt, u64 addr,
|
||||
kvm_pte_t *ptep, u32 *level);
|
||||
kvm_pte_t *ptep, s8 *level);
|
||||
|
||||
/**
|
||||
* kvm_pgtable_stage2_pte_prot() - Retrieve the protection attributes of a
|
||||
|
||||
@@ -56,10 +56,11 @@ static inline unsigned long hyp_vm_table_pages(void)
|
||||
|
||||
static inline unsigned long __hyp_pgtable_max_pages(unsigned long nr_pages)
|
||||
{
|
||||
unsigned long total = 0, i;
|
||||
unsigned long total = 0;
|
||||
int i;
|
||||
|
||||
/* Provision the worst case scenario */
|
||||
for (i = 0; i < KVM_PGTABLE_MAX_LEVELS; i++) {
|
||||
for (i = KVM_PGTABLE_FIRST_LEVEL; i <= KVM_PGTABLE_LAST_LEVEL; i++) {
|
||||
nr_pages = DIV_ROUND_UP(nr_pages, PTRS_PER_PTE);
|
||||
total += nr_pages;
|
||||
}
|
||||
|
||||
@@ -71,6 +71,8 @@ extern bool arm64_use_ng_mappings;
|
||||
#define PTE_MAYBE_NG (arm64_use_ng_mappings ? PTE_NG : 0)
|
||||
#define PMD_MAYBE_NG (arm64_use_ng_mappings ? PMD_SECT_NG : 0)
|
||||
|
||||
#define lpa2_is_enabled() false
|
||||
|
||||
/*
|
||||
* If we have userspace only BTI we don't want to mark kernel pages
|
||||
* guarded even if the system does support BTI.
|
||||
|
||||
@@ -645,6 +645,7 @@
|
||||
#define OP_AT_S1E0W sys_insn(AT_Op0, 0, AT_CRn, 8, 3)
|
||||
#define OP_AT_S1E1RP sys_insn(AT_Op0, 0, AT_CRn, 9, 0)
|
||||
#define OP_AT_S1E1WP sys_insn(AT_Op0, 0, AT_CRn, 9, 1)
|
||||
#define OP_AT_S1E1A sys_insn(AT_Op0, 0, AT_CRn, 9, 2)
|
||||
#define OP_AT_S1E2R sys_insn(AT_Op0, 4, AT_CRn, 8, 0)
|
||||
#define OP_AT_S1E2W sys_insn(AT_Op0, 4, AT_CRn, 8, 1)
|
||||
#define OP_AT_S12E1R sys_insn(AT_Op0, 4, AT_CRn, 8, 4)
|
||||
@@ -781,10 +782,16 @@
|
||||
#define OP_TLBI_VMALLS12E1NXS sys_insn(1, 4, 9, 7, 6)
|
||||
|
||||
/* Misc instructions */
|
||||
#define OP_GCSPUSHX sys_insn(1, 0, 7, 7, 4)
|
||||
#define OP_GCSPOPCX sys_insn(1, 0, 7, 7, 5)
|
||||
#define OP_GCSPOPX sys_insn(1, 0, 7, 7, 6)
|
||||
#define OP_GCSPUSHM sys_insn(1, 3, 7, 7, 0)
|
||||
|
||||
#define OP_BRB_IALL sys_insn(1, 1, 7, 2, 4)
|
||||
#define OP_BRB_INJ sys_insn(1, 1, 7, 2, 5)
|
||||
#define OP_CFP_RCTX sys_insn(1, 3, 7, 3, 4)
|
||||
#define OP_DVP_RCTX sys_insn(1, 3, 7, 3, 5)
|
||||
#define OP_COSP_RCTX sys_insn(1, 3, 7, 3, 6)
|
||||
#define OP_CPP_RCTX sys_insn(1, 3, 7, 3, 7)
|
||||
|
||||
/* Common SCTLR_ELx flags. */
|
||||
@@ -871,10 +878,12 @@
|
||||
|
||||
/* id_aa64mmfr0 */
|
||||
#define ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MIN 0x0
|
||||
#define ID_AA64MMFR0_EL1_TGRAN4_LPA2 ID_AA64MMFR0_EL1_TGRAN4_52_BIT
|
||||
#define ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MAX 0x7
|
||||
#define ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED_MIN 0x0
|
||||
#define ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED_MAX 0x7
|
||||
#define ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MIN 0x1
|
||||
#define ID_AA64MMFR0_EL1_TGRAN16_LPA2 ID_AA64MMFR0_EL1_TGRAN16_52_BIT
|
||||
#define ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MAX 0xf
|
||||
|
||||
#define ARM64_MIN_PARANGE_BITS 32
|
||||
@@ -882,6 +891,7 @@
|
||||
#define ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_DEFAULT 0x0
|
||||
#define ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_NONE 0x1
|
||||
#define ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_MIN 0x2
|
||||
#define ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_LPA2 0x3
|
||||
#define ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_MAX 0x7
|
||||
|
||||
#ifdef CONFIG_ARM64_PA_BITS_52
|
||||
@@ -892,11 +902,13 @@
|
||||
|
||||
#if defined(CONFIG_ARM64_4K_PAGES)
|
||||
#define ID_AA64MMFR0_EL1_TGRAN_SHIFT ID_AA64MMFR0_EL1_TGRAN4_SHIFT
|
||||
#define ID_AA64MMFR0_EL1_TGRAN_LPA2 ID_AA64MMFR0_EL1_TGRAN4_52_BIT
|
||||
#define ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MIN ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MIN
|
||||
#define ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MAX ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MAX
|
||||
#define ID_AA64MMFR0_EL1_TGRAN_2_SHIFT ID_AA64MMFR0_EL1_TGRAN4_2_SHIFT
|
||||
#elif defined(CONFIG_ARM64_16K_PAGES)
|
||||
#define ID_AA64MMFR0_EL1_TGRAN_SHIFT ID_AA64MMFR0_EL1_TGRAN16_SHIFT
|
||||
#define ID_AA64MMFR0_EL1_TGRAN_LPA2 ID_AA64MMFR0_EL1_TGRAN16_52_BIT
|
||||
#define ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MIN ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MIN
|
||||
#define ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MAX ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MAX
|
||||
#define ID_AA64MMFR0_EL1_TGRAN_2_SHIFT ID_AA64MMFR0_EL1_TGRAN16_2_SHIFT
|
||||
@@ -1039,6 +1051,19 @@
|
||||
|
||||
#define PIRx_ELx_PERM(idx, perm) ((perm) << ((idx) * 4))
|
||||
|
||||
/*
|
||||
* Permission Overlay Extension (POE) permission encodings.
|
||||
*/
|
||||
#define POE_NONE UL(0x0)
|
||||
#define POE_R UL(0x1)
|
||||
#define POE_X UL(0x2)
|
||||
#define POE_RX UL(0x3)
|
||||
#define POE_W UL(0x4)
|
||||
#define POE_RW UL(0x5)
|
||||
#define POE_XW UL(0x6)
|
||||
#define POE_RXW UL(0x7)
|
||||
#define POE_MASK UL(0xf)
|
||||
|
||||
#define ARM64_FEATURE_FIELD_BITS 4
|
||||
|
||||
/* Defined for compatibility only, do not add new users. */
|
||||
|
||||
@@ -22,15 +22,15 @@ static void tlb_flush(struct mmu_gather *tlb);
|
||||
#include <asm-generic/tlb.h>
|
||||
|
||||
/*
|
||||
* get the tlbi levels in arm64. Default value is 0 if more than one
|
||||
* of cleared_* is set or neither is set.
|
||||
* Arm64 doesn't support p4ds now.
|
||||
* get the tlbi levels in arm64. Default value is TLBI_TTL_UNKNOWN if more than
|
||||
* one of cleared_* is set or neither is set - this elides the level hinting to
|
||||
* the hardware.
|
||||
*/
|
||||
static inline int tlb_get_level(struct mmu_gather *tlb)
|
||||
{
|
||||
/* The TTL field is only valid for the leaf entry. */
|
||||
if (tlb->freed_tables)
|
||||
return 0;
|
||||
return TLBI_TTL_UNKNOWN;
|
||||
|
||||
if (tlb->cleared_ptes && !(tlb->cleared_pmds ||
|
||||
tlb->cleared_puds ||
|
||||
@@ -47,7 +47,12 @@ static inline int tlb_get_level(struct mmu_gather *tlb)
|
||||
tlb->cleared_p4ds))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
if (tlb->cleared_p4ds && !(tlb->cleared_ptes ||
|
||||
tlb->cleared_pmds ||
|
||||
tlb->cleared_puds))
|
||||
return 0;
|
||||
|
||||
return TLBI_TTL_UNKNOWN;
|
||||
}
|
||||
|
||||
static inline void tlb_flush(struct mmu_gather *tlb)
|
||||
|
||||
@@ -94,19 +94,22 @@ static inline unsigned long get_trans_granule(void)
|
||||
* When ARMv8.4-TTL exists, TLBI operations take an additional hint for
|
||||
* the level at which the invalidation must take place. If the level is
|
||||
* wrong, no invalidation may take place. In the case where the level
|
||||
* cannot be easily determined, a 0 value for the level parameter will
|
||||
* perform a non-hinted invalidation.
|
||||
* cannot be easily determined, the value TLBI_TTL_UNKNOWN will perform
|
||||
* a non-hinted invalidation. Any provided level outside the hint range
|
||||
* will also cause fall-back to non-hinted invalidation.
|
||||
*
|
||||
* For Stage-2 invalidation, use the level values provided to that effect
|
||||
* in asm/stage2_pgtable.h.
|
||||
*/
|
||||
#define TLBI_TTL_MASK GENMASK_ULL(47, 44)
|
||||
|
||||
#define TLBI_TTL_UNKNOWN INT_MAX
|
||||
|
||||
#define __tlbi_level(op, addr, level) do { \
|
||||
u64 arg = addr; \
|
||||
\
|
||||
if (alternative_has_cap_unlikely(ARM64_HAS_ARMv8_4_TTL) && \
|
||||
level) { \
|
||||
level >= 0 && level <= 3) { \
|
||||
u64 ttl = level & 3; \
|
||||
ttl |= get_trans_granule() << 2; \
|
||||
arg &= ~TLBI_TTL_MASK; \
|
||||
@@ -122,28 +125,34 @@ static inline unsigned long get_trans_granule(void)
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* This macro creates a properly formatted VA operand for the TLB RANGE.
|
||||
* The value bit assignments are:
|
||||
* This macro creates a properly formatted VA operand for the TLB RANGE. The
|
||||
* value bit assignments are:
|
||||
*
|
||||
* +----------+------+-------+-------+-------+----------------------+
|
||||
* | ASID | TG | SCALE | NUM | TTL | BADDR |
|
||||
* +-----------------+-------+-------+-------+----------------------+
|
||||
* |63 48|47 46|45 44|43 39|38 37|36 0|
|
||||
*
|
||||
* The address range is determined by below formula:
|
||||
* [BADDR, BADDR + (NUM + 1) * 2^(5*SCALE + 1) * PAGESIZE)
|
||||
* The address range is determined by below formula: [BADDR, BADDR + (NUM + 1) *
|
||||
* 2^(5*SCALE + 1) * PAGESIZE)
|
||||
*
|
||||
* Note that the first argument, baddr, is pre-shifted; If LPA2 is in use, BADDR
|
||||
* holds addr[52:16]. Else BADDR holds page number. See for example ARM DDI
|
||||
* 0487J.a section C5.5.60 "TLBI VAE1IS, TLBI VAE1ISNXS, TLB Invalidate by VA,
|
||||
* EL1, Inner Shareable".
|
||||
*
|
||||
*/
|
||||
#define __TLBI_VADDR_RANGE(addr, asid, scale, num, ttl) \
|
||||
({ \
|
||||
unsigned long __ta = (addr) >> PAGE_SHIFT; \
|
||||
__ta &= GENMASK_ULL(36, 0); \
|
||||
__ta |= (unsigned long)(ttl) << 37; \
|
||||
__ta |= (unsigned long)(num) << 39; \
|
||||
__ta |= (unsigned long)(scale) << 44; \
|
||||
__ta |= get_trans_granule() << 46; \
|
||||
__ta |= (unsigned long)(asid) << 48; \
|
||||
__ta; \
|
||||
#define __TLBI_VADDR_RANGE(baddr, asid, scale, num, ttl) \
|
||||
({ \
|
||||
unsigned long __ta = (baddr); \
|
||||
unsigned long __ttl = (ttl >= 1 && ttl <= 3) ? ttl : 0; \
|
||||
__ta &= GENMASK_ULL(36, 0); \
|
||||
__ta |= __ttl << 37; \
|
||||
__ta |= (unsigned long)(num) << 39; \
|
||||
__ta |= (unsigned long)(scale) << 44; \
|
||||
__ta |= get_trans_granule() << 46; \
|
||||
__ta |= (unsigned long)(asid) << 48; \
|
||||
__ta; \
|
||||
})
|
||||
|
||||
/* These macros are used by the TLBI RANGE feature. */
|
||||
@@ -216,12 +225,16 @@ static inline unsigned long get_trans_granule(void)
|
||||
* CPUs, ensuring that any walk-cache entries associated with the
|
||||
* translation are also invalidated.
|
||||
*
|
||||
* __flush_tlb_range(vma, start, end, stride, last_level)
|
||||
* __flush_tlb_range(vma, start, end, stride, last_level, tlb_level)
|
||||
* Invalidate the virtual-address range '[start, end)' on all
|
||||
* CPUs for the user address space corresponding to 'vma->mm'.
|
||||
* The invalidation operations are issued at a granularity
|
||||
* determined by 'stride' and only affect any walk-cache entries
|
||||
* if 'last_level' is equal to false.
|
||||
* if 'last_level' is equal to false. tlb_level is the level at
|
||||
* which the invalidation must take place. If the level is wrong,
|
||||
* no invalidation may take place. In the case where the level
|
||||
* cannot be easily determined, the value TLBI_TTL_UNKNOWN will
|
||||
* perform a non-hinted invalidation.
|
||||
*
|
||||
*
|
||||
* Finally, take a look at asm/tlb.h to see how tlb_flush() is implemented
|
||||
@@ -345,34 +358,44 @@ static inline void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
|
||||
* @tlb_level: Translation Table level hint, if known
|
||||
* @tlbi_user: If 'true', call an additional __tlbi_user()
|
||||
* (typically for user ASIDs). 'flase' for IPA instructions
|
||||
* @lpa2: If 'true', the lpa2 scheme is used as set out below
|
||||
*
|
||||
* When the CPU does not support TLB range operations, flush the TLB
|
||||
* entries one by one at the granularity of 'stride'. If the TLB
|
||||
* range ops are supported, then:
|
||||
*
|
||||
* 1. If 'pages' is odd, flush the first page through non-range
|
||||
* operations;
|
||||
* 1. If FEAT_LPA2 is in use, the start address of a range operation must be
|
||||
* 64KB aligned, so flush pages one by one until the alignment is reached
|
||||
* using the non-range operations. This step is skipped if LPA2 is not in
|
||||
* use.
|
||||
*
|
||||
* 2. For remaining pages: the minimum range granularity is decided
|
||||
* by 'scale', so multiple range TLBI operations may be required.
|
||||
* Start from scale = 0, flush the corresponding number of pages
|
||||
* ((num+1)*2^(5*scale+1) starting from 'addr'), then increase it
|
||||
* until no pages left.
|
||||
* 2. The minimum range granularity is decided by 'scale', so multiple range
|
||||
* TLBI operations may be required. Start from scale = 3, flush the largest
|
||||
* possible number of pages ((num+1)*2^(5*scale+1)) that fit into the
|
||||
* requested range, then decrement scale and continue until one or zero pages
|
||||
* are left. We must start from highest scale to ensure 64KB start alignment
|
||||
* is maintained in the LPA2 case.
|
||||
*
|
||||
* 3. If there is 1 page remaining, flush it through non-range operations. Range
|
||||
* operations can only span an even number of pages. We save this for last to
|
||||
* ensure 64KB start alignment is maintained for the LPA2 case.
|
||||
*
|
||||
* Note that certain ranges can be represented by either num = 31 and
|
||||
* scale or num = 0 and scale + 1. The loop below favours the latter
|
||||
* since num is limited to 30 by the __TLBI_RANGE_NUM() macro.
|
||||
*/
|
||||
#define __flush_tlb_range_op(op, start, pages, stride, \
|
||||
asid, tlb_level, tlbi_user) \
|
||||
asid, tlb_level, tlbi_user, lpa2) \
|
||||
do { \
|
||||
int num = 0; \
|
||||
int scale = 0; \
|
||||
int scale = 3; \
|
||||
int shift = lpa2 ? 16 : PAGE_SHIFT; \
|
||||
unsigned long addr; \
|
||||
\
|
||||
while (pages > 0) { \
|
||||
if (!system_supports_tlb_range() || \
|
||||
pages % 2 == 1) { \
|
||||
pages == 1 || \
|
||||
(lpa2 && start != ALIGN(start, SZ_64K))) { \
|
||||
addr = __TLBI_VADDR(start, asid); \
|
||||
__tlbi_level(op, addr, tlb_level); \
|
||||
if (tlbi_user) \
|
||||
@@ -384,20 +407,20 @@ do { \
|
||||
\
|
||||
num = __TLBI_RANGE_NUM(pages, scale); \
|
||||
if (num >= 0) { \
|
||||
addr = __TLBI_VADDR_RANGE(start, asid, scale, \
|
||||
num, tlb_level); \
|
||||
addr = __TLBI_VADDR_RANGE(start >> shift, asid, \
|
||||
scale, num, tlb_level); \
|
||||
__tlbi(r##op, addr); \
|
||||
if (tlbi_user) \
|
||||
__tlbi_user(r##op, addr); \
|
||||
start += __TLBI_RANGE_PAGES(num, scale) << PAGE_SHIFT; \
|
||||
pages -= __TLBI_RANGE_PAGES(num, scale); \
|
||||
} \
|
||||
scale++; \
|
||||
scale--; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define __flush_s2_tlb_range_op(op, start, pages, stride, tlb_level) \
|
||||
__flush_tlb_range_op(op, start, pages, stride, 0, tlb_level, false)
|
||||
__flush_tlb_range_op(op, start, pages, stride, 0, tlb_level, false, kvm_lpa2_is_enabled());
|
||||
|
||||
static inline void __flush_tlb_range(struct vm_area_struct *vma,
|
||||
unsigned long start, unsigned long end,
|
||||
@@ -427,9 +450,11 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma,
|
||||
asid = ASID(vma->vm_mm);
|
||||
|
||||
if (last_level)
|
||||
__flush_tlb_range_op(vale1is, start, pages, stride, asid, tlb_level, true);
|
||||
__flush_tlb_range_op(vale1is, start, pages, stride, asid,
|
||||
tlb_level, true, lpa2_is_enabled());
|
||||
else
|
||||
__flush_tlb_range_op(vae1is, start, pages, stride, asid, tlb_level, true);
|
||||
__flush_tlb_range_op(vae1is, start, pages, stride, asid,
|
||||
tlb_level, true, lpa2_is_enabled());
|
||||
|
||||
dsb(ish);
|
||||
mmu_notifier_arch_invalidate_secondary_tlbs(vma->vm_mm, start, end);
|
||||
@@ -441,9 +466,10 @@ static inline void flush_tlb_range(struct vm_area_struct *vma,
|
||||
/*
|
||||
* We cannot use leaf-only invalidation here, since we may be invalidating
|
||||
* table entries as part of collapsing hugepages or moving page tables.
|
||||
* Set the tlb_level to 0 because we can not get enough information here.
|
||||
* Set the tlb_level to TLBI_TTL_UNKNOWN because we can not get enough
|
||||
* information here.
|
||||
*/
|
||||
__flush_tlb_range(vma, start, end, PAGE_SIZE, false, 0);
|
||||
__flush_tlb_range(vma, start, end, PAGE_SIZE, false, TLBI_TTL_UNKNOWN);
|
||||
}
|
||||
|
||||
static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* System register offsets in the VNCR page
|
||||
* All offsets are *byte* displacements!
|
||||
*/
|
||||
|
||||
#ifndef __ARM64_VNCR_MAPPING_H__
|
||||
#define __ARM64_VNCR_MAPPING_H__
|
||||
|
||||
#define VNCR_VTTBR_EL2 0x020
|
||||
#define VNCR_VTCR_EL2 0x040
|
||||
#define VNCR_VMPIDR_EL2 0x050
|
||||
#define VNCR_CNTVOFF_EL2 0x060
|
||||
#define VNCR_HCR_EL2 0x078
|
||||
#define VNCR_HSTR_EL2 0x080
|
||||
#define VNCR_VPIDR_EL2 0x088
|
||||
#define VNCR_TPIDR_EL2 0x090
|
||||
#define VNCR_HCRX_EL2 0x0A0
|
||||
#define VNCR_VNCR_EL2 0x0B0
|
||||
#define VNCR_CPACR_EL1 0x100
|
||||
#define VNCR_CONTEXTIDR_EL1 0x108
|
||||
#define VNCR_SCTLR_EL1 0x110
|
||||
#define VNCR_ACTLR_EL1 0x118
|
||||
#define VNCR_TCR_EL1 0x120
|
||||
#define VNCR_AFSR0_EL1 0x128
|
||||
#define VNCR_AFSR1_EL1 0x130
|
||||
#define VNCR_ESR_EL1 0x138
|
||||
#define VNCR_MAIR_EL1 0x140
|
||||
#define VNCR_AMAIR_EL1 0x148
|
||||
#define VNCR_MDSCR_EL1 0x158
|
||||
#define VNCR_SPSR_EL1 0x160
|
||||
#define VNCR_CNTV_CVAL_EL0 0x168
|
||||
#define VNCR_CNTV_CTL_EL0 0x170
|
||||
#define VNCR_CNTP_CVAL_EL0 0x178
|
||||
#define VNCR_CNTP_CTL_EL0 0x180
|
||||
#define VNCR_SCXTNUM_EL1 0x188
|
||||
#define VNCR_TFSR_EL1 0x190
|
||||
#define VNCR_HFGRTR_EL2 0x1B8
|
||||
#define VNCR_HFGWTR_EL2 0x1C0
|
||||
#define VNCR_HFGITR_EL2 0x1C8
|
||||
#define VNCR_HDFGRTR_EL2 0x1D0
|
||||
#define VNCR_HDFGWTR_EL2 0x1D8
|
||||
#define VNCR_ZCR_EL1 0x1E0
|
||||
#define VNCR_HAFGRTR_EL2 0x1E8
|
||||
#define VNCR_TTBR0_EL1 0x200
|
||||
#define VNCR_TTBR1_EL1 0x210
|
||||
#define VNCR_FAR_EL1 0x220
|
||||
#define VNCR_ELR_EL1 0x230
|
||||
#define VNCR_SP_EL1 0x240
|
||||
#define VNCR_VBAR_EL1 0x250
|
||||
#define VNCR_TCR2_EL1 0x270
|
||||
#define VNCR_PIRE0_EL1 0x290
|
||||
#define VNCR_PIRE0_EL2 0x298
|
||||
#define VNCR_PIR_EL1 0x2A0
|
||||
#define VNCR_ICH_LR0_EL2 0x400
|
||||
#define VNCR_ICH_LR1_EL2 0x408
|
||||
#define VNCR_ICH_LR2_EL2 0x410
|
||||
#define VNCR_ICH_LR3_EL2 0x418
|
||||
#define VNCR_ICH_LR4_EL2 0x420
|
||||
#define VNCR_ICH_LR5_EL2 0x428
|
||||
#define VNCR_ICH_LR6_EL2 0x430
|
||||
#define VNCR_ICH_LR7_EL2 0x438
|
||||
#define VNCR_ICH_LR8_EL2 0x440
|
||||
#define VNCR_ICH_LR9_EL2 0x448
|
||||
#define VNCR_ICH_LR10_EL2 0x450
|
||||
#define VNCR_ICH_LR11_EL2 0x458
|
||||
#define VNCR_ICH_LR12_EL2 0x460
|
||||
#define VNCR_ICH_LR13_EL2 0x468
|
||||
#define VNCR_ICH_LR14_EL2 0x470
|
||||
#define VNCR_ICH_LR15_EL2 0x478
|
||||
#define VNCR_ICH_AP0R0_EL2 0x480
|
||||
#define VNCR_ICH_AP0R1_EL2 0x488
|
||||
#define VNCR_ICH_AP0R2_EL2 0x490
|
||||
#define VNCR_ICH_AP0R3_EL2 0x498
|
||||
#define VNCR_ICH_AP1R0_EL2 0x4A0
|
||||
#define VNCR_ICH_AP1R1_EL2 0x4A8
|
||||
#define VNCR_ICH_AP1R2_EL2 0x4B0
|
||||
#define VNCR_ICH_AP1R3_EL2 0x4B8
|
||||
#define VNCR_ICH_HCR_EL2 0x4C0
|
||||
#define VNCR_ICH_VMCR_EL2 0x4C8
|
||||
#define VNCR_VDISR_EL2 0x500
|
||||
#define VNCR_PMBLIMITR_EL1 0x800
|
||||
#define VNCR_PMBPTR_EL1 0x810
|
||||
#define VNCR_PMBSR_EL1 0x820
|
||||
#define VNCR_PMSCR_EL1 0x828
|
||||
#define VNCR_PMSEVFR_EL1 0x830
|
||||
#define VNCR_PMSICR_EL1 0x838
|
||||
#define VNCR_PMSIRR_EL1 0x840
|
||||
#define VNCR_PMSLATFR_EL1 0x848
|
||||
#define VNCR_TRFCR_EL1 0x880
|
||||
#define VNCR_MPAM1_EL1 0x900
|
||||
#define VNCR_MPAMHCR_EL2 0x930
|
||||
#define VNCR_MPAMVPMV_EL2 0x938
|
||||
#define VNCR_MPAMVPM0_EL2 0x940
|
||||
#define VNCR_MPAMVPM1_EL2 0x948
|
||||
#define VNCR_MPAMVPM2_EL2 0x950
|
||||
#define VNCR_MPAMVPM3_EL2 0x958
|
||||
#define VNCR_MPAMVPM4_EL2 0x960
|
||||
#define VNCR_MPAMVPM5_EL2 0x968
|
||||
#define VNCR_MPAMVPM6_EL2 0x970
|
||||
#define VNCR_MPAMVPM7_EL2 0x978
|
||||
|
||||
#endif /* __ARM64_VNCR_MAPPING_H__ */
|
||||
@@ -1768,6 +1768,39 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry,
|
||||
return !meltdown_safe;
|
||||
}
|
||||
|
||||
#if defined(ID_AA64MMFR0_EL1_TGRAN_LPA2) && defined(ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_LPA2)
|
||||
static bool has_lpa2_at_stage1(u64 mmfr0)
|
||||
{
|
||||
unsigned int tgran;
|
||||
|
||||
tgran = cpuid_feature_extract_unsigned_field(mmfr0,
|
||||
ID_AA64MMFR0_EL1_TGRAN_SHIFT);
|
||||
return tgran == ID_AA64MMFR0_EL1_TGRAN_LPA2;
|
||||
}
|
||||
|
||||
static bool has_lpa2_at_stage2(u64 mmfr0)
|
||||
{
|
||||
unsigned int tgran;
|
||||
|
||||
tgran = cpuid_feature_extract_unsigned_field(mmfr0,
|
||||
ID_AA64MMFR0_EL1_TGRAN_2_SHIFT);
|
||||
return tgran == ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_LPA2;
|
||||
}
|
||||
|
||||
static bool has_lpa2(const struct arm64_cpu_capabilities *entry, int scope)
|
||||
{
|
||||
u64 mmfr0;
|
||||
|
||||
mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
|
||||
return has_lpa2_at_stage1(mmfr0) && has_lpa2_at_stage2(mmfr0);
|
||||
}
|
||||
#else
|
||||
static bool has_lpa2(const struct arm64_cpu_capabilities *entry, int scope)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
|
||||
#define KPTI_NG_TEMP_VA (-(1UL << PMD_SHIFT))
|
||||
|
||||
@@ -2343,7 +2376,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
|
||||
.capability = ARM64_HAS_NESTED_VIRT,
|
||||
.type = ARM64_CPUCAP_SYSTEM_FEATURE,
|
||||
.matches = has_nested_virt_support,
|
||||
ARM64_CPUID_FIELDS(ID_AA64MMFR2_EL1, NV, IMP)
|
||||
ARM64_CPUID_FIELDS(ID_AA64MMFR2_EL1, NV, NV2)
|
||||
},
|
||||
{
|
||||
.capability = ARM64_HAS_32BIT_EL0_DO_NOT_USE,
|
||||
@@ -2735,6 +2768,12 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
|
||||
.matches = has_cpuid_feature,
|
||||
ARM64_CPUID_FIELDS(ID_AA64MMFR2_EL1, EVT, IMP)
|
||||
},
|
||||
{
|
||||
.desc = "52-bit Virtual Addressing for KVM (LPA2)",
|
||||
.capability = ARM64_HAS_LPA2,
|
||||
.type = ARM64_CPUCAP_SYSTEM_FEATURE,
|
||||
.matches = has_lpa2,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
|
||||
@@ -295,8 +295,7 @@ static u64 wfit_delay_ns(struct kvm_vcpu *vcpu)
|
||||
u64 val = vcpu_get_reg(vcpu, kvm_vcpu_sys_get_rt(vcpu));
|
||||
struct arch_timer_context *ctx;
|
||||
|
||||
ctx = (vcpu_has_nv(vcpu) && is_hyp_ctxt(vcpu)) ? vcpu_hvtimer(vcpu)
|
||||
: vcpu_vtimer(vcpu);
|
||||
ctx = is_hyp_ctxt(vcpu) ? vcpu_hvtimer(vcpu) : vcpu_vtimer(vcpu);
|
||||
|
||||
return kvm_counter_compute_delta(ctx, val);
|
||||
}
|
||||
|
||||
@@ -669,6 +669,12 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (vcpu_has_nv(vcpu)) {
|
||||
ret = kvm_init_nv_sysregs(vcpu->kvm);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = kvm_timer_enable(vcpu);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1837,6 +1843,7 @@ static int kvm_init_vector_slots(void)
|
||||
static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits)
|
||||
{
|
||||
struct kvm_nvhe_init_params *params = per_cpu_ptr_nvhe_sym(kvm_init_params, cpu);
|
||||
u64 mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
|
||||
unsigned long tcr;
|
||||
|
||||
/*
|
||||
@@ -1859,6 +1866,10 @@ static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits)
|
||||
}
|
||||
tcr &= ~TCR_T0SZ_MASK;
|
||||
tcr |= TCR_T0SZ(hyp_va_bits);
|
||||
tcr &= ~TCR_EL2_PS_MASK;
|
||||
tcr |= FIELD_PREP(TCR_EL2_PS_MASK, kvm_get_parange(mmfr0));
|
||||
if (kvm_lpa2_is_enabled())
|
||||
tcr |= TCR_EL2_DS;
|
||||
params->tcr_el2 = tcr;
|
||||
|
||||
params->pgd_pa = kvm_mmu_get_httbr();
|
||||
|
||||
@@ -1012,6 +1012,7 @@ enum fgt_group_id {
|
||||
HDFGRTR_GROUP,
|
||||
HDFGWTR_GROUP,
|
||||
HFGITR_GROUP,
|
||||
HAFGRTR_GROUP,
|
||||
|
||||
/* Must be last */
|
||||
__NR_FGT_GROUP_IDS__
|
||||
@@ -1042,10 +1043,20 @@ enum fg_filter_id {
|
||||
|
||||
static const struct encoding_to_trap_config encoding_to_fgt[] __initconst = {
|
||||
/* HFGRTR_EL2, HFGWTR_EL2 */
|
||||
SR_FGT(SYS_AMAIR2_EL1, HFGxTR, nAMAIR2_EL1, 0),
|
||||
SR_FGT(SYS_MAIR2_EL1, HFGxTR, nMAIR2_EL1, 0),
|
||||
SR_FGT(SYS_S2POR_EL1, HFGxTR, nS2POR_EL1, 0),
|
||||
SR_FGT(SYS_POR_EL1, HFGxTR, nPOR_EL1, 0),
|
||||
SR_FGT(SYS_POR_EL0, HFGxTR, nPOR_EL0, 0),
|
||||
SR_FGT(SYS_PIR_EL1, HFGxTR, nPIR_EL1, 0),
|
||||
SR_FGT(SYS_PIRE0_EL1, HFGxTR, nPIRE0_EL1, 0),
|
||||
SR_FGT(SYS_RCWMASK_EL1, HFGxTR, nRCWMASK_EL1, 0),
|
||||
SR_FGT(SYS_TPIDR2_EL0, HFGxTR, nTPIDR2_EL0, 0),
|
||||
SR_FGT(SYS_SMPRI_EL1, HFGxTR, nSMPRI_EL1, 0),
|
||||
SR_FGT(SYS_GCSCR_EL1, HFGxTR, nGCS_EL1, 0),
|
||||
SR_FGT(SYS_GCSPR_EL1, HFGxTR, nGCS_EL1, 0),
|
||||
SR_FGT(SYS_GCSCRE0_EL1, HFGxTR, nGCS_EL0, 0),
|
||||
SR_FGT(SYS_GCSPR_EL0, HFGxTR, nGCS_EL0, 0),
|
||||
SR_FGT(SYS_ACCDATA_EL1, HFGxTR, nACCDATA_EL1, 0),
|
||||
SR_FGT(SYS_ERXADDR_EL1, HFGxTR, ERXADDR_EL1, 1),
|
||||
SR_FGT(SYS_ERXPFGCDN_EL1, HFGxTR, ERXPFGCDN_EL1, 1),
|
||||
@@ -1107,6 +1118,11 @@ static const struct encoding_to_trap_config encoding_to_fgt[] __initconst = {
|
||||
SR_FGT(SYS_AFSR1_EL1, HFGxTR, AFSR1_EL1, 1),
|
||||
SR_FGT(SYS_AFSR0_EL1, HFGxTR, AFSR0_EL1, 1),
|
||||
/* HFGITR_EL2 */
|
||||
SR_FGT(OP_AT_S1E1A, HFGITR, ATS1E1A, 1),
|
||||
SR_FGT(OP_COSP_RCTX, HFGITR, COSPRCTX, 1),
|
||||
SR_FGT(OP_GCSPUSHX, HFGITR, nGCSEPP, 0),
|
||||
SR_FGT(OP_GCSPOPX, HFGITR, nGCSEPP, 0),
|
||||
SR_FGT(OP_GCSPUSHM, HFGITR, nGCSPUSHM_EL1, 0),
|
||||
SR_FGT(OP_BRB_IALL, HFGITR, nBRBIALL, 0),
|
||||
SR_FGT(OP_BRB_INJ, HFGITR, nBRBINJ, 0),
|
||||
SR_FGT(SYS_DC_CVAC, HFGITR, DCCVAC, 1),
|
||||
@@ -1674,6 +1690,49 @@ static const struct encoding_to_trap_config encoding_to_fgt[] __initconst = {
|
||||
SR_FGT(SYS_PMCR_EL0, HDFGWTR, PMCR_EL0, 1),
|
||||
SR_FGT(SYS_PMSWINC_EL0, HDFGWTR, PMSWINC_EL0, 1),
|
||||
SR_FGT(SYS_OSLAR_EL1, HDFGWTR, OSLAR_EL1, 1),
|
||||
/*
|
||||
* HAFGRTR_EL2
|
||||
*/
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(15), HAFGRTR, AMEVTYPER115_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(14), HAFGRTR, AMEVTYPER114_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(13), HAFGRTR, AMEVTYPER113_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(12), HAFGRTR, AMEVTYPER112_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(11), HAFGRTR, AMEVTYPER111_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(10), HAFGRTR, AMEVTYPER110_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(9), HAFGRTR, AMEVTYPER19_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(8), HAFGRTR, AMEVTYPER18_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(7), HAFGRTR, AMEVTYPER17_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(6), HAFGRTR, AMEVTYPER16_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(5), HAFGRTR, AMEVTYPER15_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(4), HAFGRTR, AMEVTYPER14_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(3), HAFGRTR, AMEVTYPER13_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(2), HAFGRTR, AMEVTYPER12_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(1), HAFGRTR, AMEVTYPER11_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(0), HAFGRTR, AMEVTYPER10_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(15), HAFGRTR, AMEVCNTR115_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(14), HAFGRTR, AMEVCNTR114_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(13), HAFGRTR, AMEVCNTR113_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(12), HAFGRTR, AMEVCNTR112_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(11), HAFGRTR, AMEVCNTR111_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(10), HAFGRTR, AMEVCNTR110_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(9), HAFGRTR, AMEVCNTR19_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(8), HAFGRTR, AMEVCNTR18_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(7), HAFGRTR, AMEVCNTR17_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(6), HAFGRTR, AMEVCNTR16_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(5), HAFGRTR, AMEVCNTR15_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(4), HAFGRTR, AMEVCNTR14_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(3), HAFGRTR, AMEVCNTR13_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(2), HAFGRTR, AMEVCNTR12_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(1), HAFGRTR, AMEVCNTR11_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(0), HAFGRTR, AMEVCNTR10_EL0, 1),
|
||||
SR_FGT(SYS_AMCNTENCLR1_EL0, HAFGRTR, AMCNTEN1, 1),
|
||||
SR_FGT(SYS_AMCNTENSET1_EL0, HAFGRTR, AMCNTEN1, 1),
|
||||
SR_FGT(SYS_AMCNTENCLR0_EL0, HAFGRTR, AMCNTEN0, 1),
|
||||
SR_FGT(SYS_AMCNTENSET0_EL0, HAFGRTR, AMCNTEN0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR0_EL0(3), HAFGRTR, AMEVCNTR03_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR0_EL0(2), HAFGRTR, AMEVCNTR02_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR0_EL0(1), HAFGRTR, AMEVCNTR01_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR0_EL0(0), HAFGRTR, AMEVCNTR00_EL0, 1),
|
||||
};
|
||||
|
||||
static union trap_config get_trap_config(u32 sysreg)
|
||||
@@ -1894,6 +1953,10 @@ bool __check_nv_sr_forward(struct kvm_vcpu *vcpu)
|
||||
val = sanitised_sys_reg(vcpu, HDFGWTR_EL2);
|
||||
break;
|
||||
|
||||
case HAFGRTR_GROUP:
|
||||
val = sanitised_sys_reg(vcpu, HAFGRTR_EL2);
|
||||
break;
|
||||
|
||||
case HFGITR_GROUP:
|
||||
val = sanitised_sys_reg(vcpu, HFGITR_EL2);
|
||||
switch (tc.fgf) {
|
||||
|
||||
@@ -60,7 +60,7 @@ static inline bool __get_fault_info(u64 esr, struct kvm_vcpu_fault_info *fault)
|
||||
*/
|
||||
if (!(esr & ESR_ELx_S1PTW) &&
|
||||
(cpus_have_final_cap(ARM64_WORKAROUND_834220) ||
|
||||
(esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_PERM)) {
|
||||
esr_fsc_is_permission_fault(esr))) {
|
||||
if (!__translate_far_to_hpfar(far, &hpfar))
|
||||
return false;
|
||||
} else {
|
||||
|
||||
@@ -79,6 +79,45 @@ static inline void __activate_traps_fpsimd32(struct kvm_vcpu *vcpu)
|
||||
clr |= ~hfg & __ ## reg ## _nMASK; \
|
||||
} while(0)
|
||||
|
||||
#define update_fgt_traps_cs(vcpu, reg, clr, set) \
|
||||
do { \
|
||||
struct kvm_cpu_context *hctxt = \
|
||||
&this_cpu_ptr(&kvm_host_data)->host_ctxt; \
|
||||
u64 c = 0, s = 0; \
|
||||
\
|
||||
ctxt_sys_reg(hctxt, reg) = read_sysreg_s(SYS_ ## reg); \
|
||||
compute_clr_set(vcpu, reg, c, s); \
|
||||
s |= set; \
|
||||
c |= clr; \
|
||||
if (c || s) { \
|
||||
u64 val = __ ## reg ## _nMASK; \
|
||||
val |= s; \
|
||||
val &= ~c; \
|
||||
write_sysreg_s(val, SYS_ ## reg); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define update_fgt_traps(vcpu, reg) \
|
||||
update_fgt_traps_cs(vcpu, reg, 0, 0)
|
||||
|
||||
/*
|
||||
* Validate the fine grain trap masks.
|
||||
* Check that the masks do not overlap and that all bits are accounted for.
|
||||
*/
|
||||
#define CHECK_FGT_MASKS(reg) \
|
||||
do { \
|
||||
BUILD_BUG_ON((__ ## reg ## _MASK) & (__ ## reg ## _nMASK)); \
|
||||
BUILD_BUG_ON(~((__ ## reg ## _RES0) ^ (__ ## reg ## _MASK) ^ \
|
||||
(__ ## reg ## _nMASK))); \
|
||||
} while(0)
|
||||
|
||||
static inline bool cpu_has_amu(void)
|
||||
{
|
||||
u64 pfr0 = read_sysreg_s(SYS_ID_AA64PFR0_EL1);
|
||||
|
||||
return cpuid_feature_extract_unsigned_field(pfr0,
|
||||
ID_AA64PFR0_EL1_AMU_SHIFT);
|
||||
}
|
||||
|
||||
static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
@@ -86,6 +125,14 @@ static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu)
|
||||
u64 r_clr = 0, w_clr = 0, r_set = 0, w_set = 0, tmp;
|
||||
u64 r_val, w_val;
|
||||
|
||||
CHECK_FGT_MASKS(HFGRTR_EL2);
|
||||
CHECK_FGT_MASKS(HFGWTR_EL2);
|
||||
CHECK_FGT_MASKS(HFGITR_EL2);
|
||||
CHECK_FGT_MASKS(HDFGRTR_EL2);
|
||||
CHECK_FGT_MASKS(HDFGWTR_EL2);
|
||||
CHECK_FGT_MASKS(HAFGRTR_EL2);
|
||||
CHECK_FGT_MASKS(HCRX_EL2);
|
||||
|
||||
if (!cpus_have_final_cap(ARM64_HAS_FGT))
|
||||
return;
|
||||
|
||||
@@ -110,12 +157,15 @@ static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu)
|
||||
compute_clr_set(vcpu, HFGWTR_EL2, w_clr, w_set);
|
||||
}
|
||||
|
||||
/* The default is not to trap anything but ACCDATA_EL1 */
|
||||
r_val = __HFGRTR_EL2_nMASK & ~HFGxTR_EL2_nACCDATA_EL1;
|
||||
/* The default to trap everything not handled or supported in KVM. */
|
||||
tmp = HFGxTR_EL2_nAMAIR2_EL1 | HFGxTR_EL2_nMAIR2_EL1 | HFGxTR_EL2_nS2POR_EL1 |
|
||||
HFGxTR_EL2_nPOR_EL1 | HFGxTR_EL2_nPOR_EL0 | HFGxTR_EL2_nACCDATA_EL1;
|
||||
|
||||
r_val = __HFGRTR_EL2_nMASK & ~tmp;
|
||||
r_val |= r_set;
|
||||
r_val &= ~r_clr;
|
||||
|
||||
w_val = __HFGWTR_EL2_nMASK & ~HFGxTR_EL2_nACCDATA_EL1;
|
||||
w_val = __HFGWTR_EL2_nMASK & ~tmp;
|
||||
w_val |= w_set;
|
||||
w_val &= ~w_clr;
|
||||
|
||||
@@ -125,34 +175,12 @@ static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu)
|
||||
if (!vcpu_has_nv(vcpu) || is_hyp_ctxt(vcpu))
|
||||
return;
|
||||
|
||||
ctxt_sys_reg(hctxt, HFGITR_EL2) = read_sysreg_s(SYS_HFGITR_EL2);
|
||||
update_fgt_traps(vcpu, HFGITR_EL2);
|
||||
update_fgt_traps(vcpu, HDFGRTR_EL2);
|
||||
update_fgt_traps(vcpu, HDFGWTR_EL2);
|
||||
|
||||
r_set = r_clr = 0;
|
||||
compute_clr_set(vcpu, HFGITR_EL2, r_clr, r_set);
|
||||
r_val = __HFGITR_EL2_nMASK;
|
||||
r_val |= r_set;
|
||||
r_val &= ~r_clr;
|
||||
|
||||
write_sysreg_s(r_val, SYS_HFGITR_EL2);
|
||||
|
||||
ctxt_sys_reg(hctxt, HDFGRTR_EL2) = read_sysreg_s(SYS_HDFGRTR_EL2);
|
||||
ctxt_sys_reg(hctxt, HDFGWTR_EL2) = read_sysreg_s(SYS_HDFGWTR_EL2);
|
||||
|
||||
r_clr = r_set = w_clr = w_set = 0;
|
||||
|
||||
compute_clr_set(vcpu, HDFGRTR_EL2, r_clr, r_set);
|
||||
compute_clr_set(vcpu, HDFGWTR_EL2, w_clr, w_set);
|
||||
|
||||
r_val = __HDFGRTR_EL2_nMASK;
|
||||
r_val |= r_set;
|
||||
r_val &= ~r_clr;
|
||||
|
||||
w_val = __HDFGWTR_EL2_nMASK;
|
||||
w_val |= w_set;
|
||||
w_val &= ~w_clr;
|
||||
|
||||
write_sysreg_s(r_val, SYS_HDFGRTR_EL2);
|
||||
write_sysreg_s(w_val, SYS_HDFGWTR_EL2);
|
||||
if (cpu_has_amu())
|
||||
update_fgt_traps(vcpu, HAFGRTR_EL2);
|
||||
}
|
||||
|
||||
static inline void __deactivate_traps_hfgxtr(struct kvm_vcpu *vcpu)
|
||||
@@ -171,6 +199,9 @@ static inline void __deactivate_traps_hfgxtr(struct kvm_vcpu *vcpu)
|
||||
write_sysreg_s(ctxt_sys_reg(hctxt, HFGITR_EL2), SYS_HFGITR_EL2);
|
||||
write_sysreg_s(ctxt_sys_reg(hctxt, HDFGRTR_EL2), SYS_HDFGRTR_EL2);
|
||||
write_sysreg_s(ctxt_sys_reg(hctxt, HDFGWTR_EL2), SYS_HDFGWTR_EL2);
|
||||
|
||||
if (cpu_has_amu())
|
||||
write_sysreg_s(ctxt_sys_reg(hctxt, HAFGRTR_EL2), SYS_HAFGRTR_EL2);
|
||||
}
|
||||
|
||||
static inline void __activate_traps_common(struct kvm_vcpu *vcpu)
|
||||
@@ -591,7 +622,7 @@ static bool kvm_hyp_handle_dabt_low(struct kvm_vcpu *vcpu, u64 *exit_code)
|
||||
if (static_branch_unlikely(&vgic_v2_cpuif_trap)) {
|
||||
bool valid;
|
||||
|
||||
valid = kvm_vcpu_trap_get_fault_type(vcpu) == ESR_ELx_FSC_FAULT &&
|
||||
valid = kvm_vcpu_trap_is_translation_fault(vcpu) &&
|
||||
kvm_vcpu_dabt_isvalid(vcpu) &&
|
||||
!kvm_vcpu_abt_issea(vcpu) &&
|
||||
!kvm_vcpu_abt_iss1tw(vcpu);
|
||||
|
||||
@@ -69,6 +69,8 @@
|
||||
ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_SSBS) \
|
||||
)
|
||||
|
||||
#define PVM_ID_AA64PFR2_ALLOW 0ULL
|
||||
|
||||
/*
|
||||
* Allow for protected VMs:
|
||||
* - Mixed-endian
|
||||
@@ -101,6 +103,7 @@
|
||||
* - 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) | \
|
||||
@@ -108,7 +111,8 @@
|
||||
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_ETS) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_CMOW) \
|
||||
)
|
||||
|
||||
/*
|
||||
@@ -133,6 +137,8 @@
|
||||
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
|
||||
@@ -178,10 +184,18 @@
|
||||
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_APA) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_API) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_JSCVT) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_FCMA) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_LRCPC) | \
|
||||
@@ -196,8 +210,8 @@
|
||||
)
|
||||
|
||||
#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_APA3) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_MOPS) \
|
||||
)
|
||||
|
||||
|
||||
@@ -122,11 +122,7 @@ alternative_if ARM64_HAS_CNP
|
||||
alternative_else_nop_endif
|
||||
msr ttbr0_el2, x2
|
||||
|
||||
/*
|
||||
* Set the PS bits in TCR_EL2.
|
||||
*/
|
||||
ldr x0, [x0, #NVHE_INIT_TCR_EL2]
|
||||
tcr_compute_pa_size x0, #TCR_EL2_PS_SHIFT, x1, x2
|
||||
msr tcr_el2, x0
|
||||
|
||||
isb
|
||||
@@ -292,6 +288,8 @@ alternative_else_nop_endif
|
||||
mov sp, x0
|
||||
|
||||
/* And turn the MMU back on! */
|
||||
dsb nsh
|
||||
isb
|
||||
set_sctlr_el2 x2
|
||||
ret x1
|
||||
SYM_FUNC_END(__pkvm_init_switch_pgd)
|
||||
|
||||
@@ -91,7 +91,7 @@ static void host_s2_put_page(void *addr)
|
||||
hyp_put_page(&host_s2_pool, addr);
|
||||
}
|
||||
|
||||
static void host_s2_free_unlinked_table(void *addr, u32 level)
|
||||
static void host_s2_free_unlinked_table(void *addr, s8 level)
|
||||
{
|
||||
kvm_pgtable_stage2_free_unlinked(&host_mmu.mm_ops, addr, level);
|
||||
}
|
||||
@@ -443,7 +443,7 @@ static int host_stage2_adjust_range(u64 addr, struct kvm_mem_range *range)
|
||||
{
|
||||
struct kvm_mem_range cur;
|
||||
kvm_pte_t pte;
|
||||
u32 level;
|
||||
s8 level;
|
||||
int ret;
|
||||
|
||||
hyp_assert_lock_held(&host_mmu.lock);
|
||||
@@ -462,7 +462,7 @@ static int host_stage2_adjust_range(u64 addr, struct kvm_mem_range *range)
|
||||
cur.start = ALIGN_DOWN(addr, granule);
|
||||
cur.end = cur.start + granule;
|
||||
level++;
|
||||
} while ((level < KVM_PGTABLE_MAX_LEVELS) &&
|
||||
} while ((level <= KVM_PGTABLE_LAST_LEVEL) &&
|
||||
!(kvm_level_supports_block_mapping(level) &&
|
||||
range_included(&cur, range)));
|
||||
|
||||
|
||||
@@ -260,7 +260,7 @@ static void fixmap_clear_slot(struct hyp_fixmap_slot *slot)
|
||||
* https://lore.kernel.org/kvm/20221017115209.2099-1-will@kernel.org/T/#mf10dfbaf1eaef9274c581b81c53758918c1d0f03
|
||||
*/
|
||||
dsb(ishst);
|
||||
__tlbi_level(vale2is, __TLBI_VADDR(addr, 0), (KVM_PGTABLE_MAX_LEVELS - 1));
|
||||
__tlbi_level(vale2is, __TLBI_VADDR(addr, 0), KVM_PGTABLE_LAST_LEVEL);
|
||||
dsb(ish);
|
||||
isb();
|
||||
}
|
||||
@@ -275,7 +275,7 @@ static int __create_fixmap_slot_cb(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
{
|
||||
struct hyp_fixmap_slot *slot = per_cpu_ptr(&fixmap_slots, (u64)ctx->arg);
|
||||
|
||||
if (!kvm_pte_valid(ctx->old) || ctx->level != KVM_PGTABLE_MAX_LEVELS - 1)
|
||||
if (!kvm_pte_valid(ctx->old) || ctx->level != KVM_PGTABLE_LAST_LEVEL)
|
||||
return -EINVAL;
|
||||
|
||||
slot->addr = ctx->addr;
|
||||
|
||||
@@ -136,6 +136,10 @@ static void pvm_init_traps_aa64dfr0(struct kvm_vcpu *vcpu)
|
||||
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 << MDCR_EL2_E2TB_SHIFT;
|
||||
|
||||
vcpu->arch.mdcr_el2 |= mdcr_set;
|
||||
vcpu->arch.mdcr_el2 &= ~mdcr_clear;
|
||||
vcpu->arch.cptr_el2 |= cptr_set;
|
||||
|
||||
@@ -181,7 +181,7 @@ static int fix_host_ownership_walker(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
if (!kvm_pte_valid(ctx->old))
|
||||
return 0;
|
||||
|
||||
if (ctx->level != (KVM_PGTABLE_MAX_LEVELS - 1))
|
||||
if (ctx->level != KVM_PGTABLE_LAST_LEVEL)
|
||||
return -EINVAL;
|
||||
|
||||
phys = kvm_pte_to_phys(ctx->old);
|
||||
|
||||
@@ -79,7 +79,10 @@ static bool kvm_pgtable_walk_skip_cmo(const struct kvm_pgtable_visit_ctx *ctx)
|
||||
|
||||
static bool kvm_phys_is_valid(u64 phys)
|
||||
{
|
||||
return phys < BIT(id_aa64mmfr0_parange_to_phys_shift(ID_AA64MMFR0_EL1_PARANGE_MAX));
|
||||
u64 parange_max = kvm_get_parange_max();
|
||||
u8 shift = id_aa64mmfr0_parange_to_phys_shift(parange_max);
|
||||
|
||||
return phys < BIT(shift);
|
||||
}
|
||||
|
||||
static bool kvm_block_mapping_supported(const struct kvm_pgtable_visit_ctx *ctx, u64 phys)
|
||||
@@ -98,7 +101,7 @@ static bool kvm_block_mapping_supported(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
return IS_ALIGNED(ctx->addr, granule);
|
||||
}
|
||||
|
||||
static u32 kvm_pgtable_idx(struct kvm_pgtable_walk_data *data, u32 level)
|
||||
static u32 kvm_pgtable_idx(struct kvm_pgtable_walk_data *data, s8 level)
|
||||
{
|
||||
u64 shift = kvm_granule_shift(level);
|
||||
u64 mask = BIT(PAGE_SHIFT - 3) - 1;
|
||||
@@ -114,7 +117,7 @@ static u32 kvm_pgd_page_idx(struct kvm_pgtable *pgt, u64 addr)
|
||||
return (addr & mask) >> shift;
|
||||
}
|
||||
|
||||
static u32 kvm_pgd_pages(u32 ia_bits, u32 start_level)
|
||||
static u32 kvm_pgd_pages(u32 ia_bits, s8 start_level)
|
||||
{
|
||||
struct kvm_pgtable pgt = {
|
||||
.ia_bits = ia_bits,
|
||||
@@ -124,9 +127,9 @@ static u32 kvm_pgd_pages(u32 ia_bits, u32 start_level)
|
||||
return kvm_pgd_page_idx(&pgt, -1ULL) + 1;
|
||||
}
|
||||
|
||||
static bool kvm_pte_table(kvm_pte_t pte, u32 level)
|
||||
static bool kvm_pte_table(kvm_pte_t pte, s8 level)
|
||||
{
|
||||
if (level == KVM_PGTABLE_MAX_LEVELS - 1)
|
||||
if (level == KVM_PGTABLE_LAST_LEVEL)
|
||||
return false;
|
||||
|
||||
if (!kvm_pte_valid(pte))
|
||||
@@ -154,11 +157,11 @@ static kvm_pte_t kvm_init_table_pte(kvm_pte_t *childp, struct kvm_pgtable_mm_ops
|
||||
return pte;
|
||||
}
|
||||
|
||||
static kvm_pte_t kvm_init_valid_leaf_pte(u64 pa, kvm_pte_t attr, u32 level)
|
||||
static kvm_pte_t kvm_init_valid_leaf_pte(u64 pa, kvm_pte_t attr, s8 level)
|
||||
{
|
||||
kvm_pte_t pte = kvm_phys_to_pte(pa);
|
||||
u64 type = (level == KVM_PGTABLE_MAX_LEVELS - 1) ? KVM_PTE_TYPE_PAGE :
|
||||
KVM_PTE_TYPE_BLOCK;
|
||||
u64 type = (level == KVM_PGTABLE_LAST_LEVEL) ? KVM_PTE_TYPE_PAGE :
|
||||
KVM_PTE_TYPE_BLOCK;
|
||||
|
||||
pte |= attr & (KVM_PTE_LEAF_ATTR_LO | KVM_PTE_LEAF_ATTR_HI);
|
||||
pte |= FIELD_PREP(KVM_PTE_TYPE, type);
|
||||
@@ -203,11 +206,11 @@ static bool kvm_pgtable_walk_continue(const struct kvm_pgtable_walker *walker,
|
||||
}
|
||||
|
||||
static int __kvm_pgtable_walk(struct kvm_pgtable_walk_data *data,
|
||||
struct kvm_pgtable_mm_ops *mm_ops, kvm_pteref_t pgtable, u32 level);
|
||||
struct kvm_pgtable_mm_ops *mm_ops, kvm_pteref_t pgtable, s8 level);
|
||||
|
||||
static inline int __kvm_pgtable_visit(struct kvm_pgtable_walk_data *data,
|
||||
struct kvm_pgtable_mm_ops *mm_ops,
|
||||
kvm_pteref_t pteref, u32 level)
|
||||
kvm_pteref_t pteref, s8 level)
|
||||
{
|
||||
enum kvm_pgtable_walk_flags flags = data->walker->flags;
|
||||
kvm_pte_t *ptep = kvm_dereference_pteref(data->walker, pteref);
|
||||
@@ -272,12 +275,13 @@ out:
|
||||
}
|
||||
|
||||
static int __kvm_pgtable_walk(struct kvm_pgtable_walk_data *data,
|
||||
struct kvm_pgtable_mm_ops *mm_ops, kvm_pteref_t pgtable, u32 level)
|
||||
struct kvm_pgtable_mm_ops *mm_ops, kvm_pteref_t pgtable, s8 level)
|
||||
{
|
||||
u32 idx;
|
||||
int ret = 0;
|
||||
|
||||
if (WARN_ON_ONCE(level >= KVM_PGTABLE_MAX_LEVELS))
|
||||
if (WARN_ON_ONCE(level < KVM_PGTABLE_FIRST_LEVEL ||
|
||||
level > KVM_PGTABLE_LAST_LEVEL))
|
||||
return -EINVAL;
|
||||
|
||||
for (idx = kvm_pgtable_idx(data, level); idx < PTRS_PER_PTE; ++idx) {
|
||||
@@ -340,7 +344,7 @@ int kvm_pgtable_walk(struct kvm_pgtable *pgt, u64 addr, u64 size,
|
||||
|
||||
struct leaf_walk_data {
|
||||
kvm_pte_t pte;
|
||||
u32 level;
|
||||
s8 level;
|
||||
};
|
||||
|
||||
static int leaf_walker(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
@@ -355,7 +359,7 @@ static int leaf_walker(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
}
|
||||
|
||||
int kvm_pgtable_get_leaf(struct kvm_pgtable *pgt, u64 addr,
|
||||
kvm_pte_t *ptep, u32 *level)
|
||||
kvm_pte_t *ptep, s8 *level)
|
||||
{
|
||||
struct leaf_walk_data data;
|
||||
struct kvm_pgtable_walker walker = {
|
||||
@@ -408,7 +412,8 @@ static int hyp_set_prot_attr(enum kvm_pgtable_prot prot, kvm_pte_t *ptep)
|
||||
}
|
||||
|
||||
attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_AP, ap);
|
||||
attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_SH, sh);
|
||||
if (!kvm_lpa2_is_enabled())
|
||||
attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_SH, sh);
|
||||
attr |= KVM_PTE_LEAF_ATTR_LO_S1_AF;
|
||||
attr |= prot & KVM_PTE_LEAF_ATTR_HI_SW;
|
||||
*ptep = attr;
|
||||
@@ -467,7 +472,7 @@ static int hyp_map_walker(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
if (hyp_map_walker_try_leaf(ctx, data))
|
||||
return 0;
|
||||
|
||||
if (WARN_ON(ctx->level == KVM_PGTABLE_MAX_LEVELS - 1))
|
||||
if (WARN_ON(ctx->level == KVM_PGTABLE_LAST_LEVEL))
|
||||
return -EINVAL;
|
||||
|
||||
childp = (kvm_pte_t *)mm_ops->zalloc_page(NULL);
|
||||
@@ -563,14 +568,19 @@ u64 kvm_pgtable_hyp_unmap(struct kvm_pgtable *pgt, u64 addr, u64 size)
|
||||
int kvm_pgtable_hyp_init(struct kvm_pgtable *pgt, u32 va_bits,
|
||||
struct kvm_pgtable_mm_ops *mm_ops)
|
||||
{
|
||||
u64 levels = ARM64_HW_PGTABLE_LEVELS(va_bits);
|
||||
s8 start_level = KVM_PGTABLE_LAST_LEVEL + 1 -
|
||||
ARM64_HW_PGTABLE_LEVELS(va_bits);
|
||||
|
||||
if (start_level < KVM_PGTABLE_FIRST_LEVEL ||
|
||||
start_level > KVM_PGTABLE_LAST_LEVEL)
|
||||
return -EINVAL;
|
||||
|
||||
pgt->pgd = (kvm_pteref_t)mm_ops->zalloc_page(NULL);
|
||||
if (!pgt->pgd)
|
||||
return -ENOMEM;
|
||||
|
||||
pgt->ia_bits = va_bits;
|
||||
pgt->start_level = KVM_PGTABLE_MAX_LEVELS - levels;
|
||||
pgt->start_level = start_level;
|
||||
pgt->mm_ops = mm_ops;
|
||||
pgt->mmu = NULL;
|
||||
pgt->force_pte_cb = NULL;
|
||||
@@ -624,7 +634,7 @@ struct stage2_map_data {
|
||||
u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
|
||||
{
|
||||
u64 vtcr = VTCR_EL2_FLAGS;
|
||||
u8 lvls;
|
||||
s8 lvls;
|
||||
|
||||
vtcr |= kvm_get_parange(mmfr0) << VTCR_EL2_PS_SHIFT;
|
||||
vtcr |= VTCR_EL2_T0SZ(phys_shift);
|
||||
@@ -635,6 +645,15 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
|
||||
lvls = stage2_pgtable_levels(phys_shift);
|
||||
if (lvls < 2)
|
||||
lvls = 2;
|
||||
|
||||
/*
|
||||
* When LPA2 is enabled, the HW supports an extra level of translation
|
||||
* (for 5 in total) when using 4K pages. It also introduces VTCR_EL2.SL2
|
||||
* to as an addition to SL0 to enable encoding this extra start level.
|
||||
* However, since we always use concatenated pages for the first level
|
||||
* lookup, we will never need this extra level and therefore do not need
|
||||
* to touch SL2.
|
||||
*/
|
||||
vtcr |= VTCR_EL2_LVLS_TO_SL0(lvls);
|
||||
|
||||
#ifdef CONFIG_ARM64_HW_AFDBM
|
||||
@@ -654,6 +673,9 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
|
||||
vtcr |= VTCR_EL2_HA;
|
||||
#endif /* CONFIG_ARM64_HW_AFDBM */
|
||||
|
||||
if (kvm_lpa2_is_enabled())
|
||||
vtcr |= VTCR_EL2_DS;
|
||||
|
||||
/* Set the vmid bits */
|
||||
vtcr |= (get_vmid_bits(mmfr1) == 16) ?
|
||||
VTCR_EL2_VS_16BIT :
|
||||
@@ -711,7 +733,9 @@ static int stage2_set_prot_attr(struct kvm_pgtable *pgt, enum kvm_pgtable_prot p
|
||||
if (prot & KVM_PGTABLE_PROT_W)
|
||||
attr |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W;
|
||||
|
||||
attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S2_SH, sh);
|
||||
if (!kvm_lpa2_is_enabled())
|
||||
attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S2_SH, sh);
|
||||
|
||||
attr |= KVM_PTE_LEAF_ATTR_LO_S2_AF;
|
||||
attr |= prot & KVM_PTE_LEAF_ATTR_HI_SW;
|
||||
*ptep = attr;
|
||||
@@ -902,7 +926,7 @@ static bool stage2_leaf_mapping_allowed(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
{
|
||||
u64 phys = stage2_map_walker_phys_addr(ctx, data);
|
||||
|
||||
if (data->force_pte && (ctx->level < (KVM_PGTABLE_MAX_LEVELS - 1)))
|
||||
if (data->force_pte && ctx->level < KVM_PGTABLE_LAST_LEVEL)
|
||||
return false;
|
||||
|
||||
return kvm_block_mapping_supported(ctx, phys);
|
||||
@@ -981,7 +1005,7 @@ static int stage2_map_walk_leaf(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
if (ret != -E2BIG)
|
||||
return ret;
|
||||
|
||||
if (WARN_ON(ctx->level == KVM_PGTABLE_MAX_LEVELS - 1))
|
||||
if (WARN_ON(ctx->level == KVM_PGTABLE_LAST_LEVEL))
|
||||
return -EINVAL;
|
||||
|
||||
if (!data->memcache)
|
||||
@@ -1151,7 +1175,7 @@ struct stage2_attr_data {
|
||||
kvm_pte_t attr_set;
|
||||
kvm_pte_t attr_clr;
|
||||
kvm_pte_t pte;
|
||||
u32 level;
|
||||
s8 level;
|
||||
};
|
||||
|
||||
static int stage2_attr_walker(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
@@ -1194,7 +1218,7 @@ static int stage2_attr_walker(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
static int stage2_update_leaf_attrs(struct kvm_pgtable *pgt, u64 addr,
|
||||
u64 size, kvm_pte_t attr_set,
|
||||
kvm_pte_t attr_clr, kvm_pte_t *orig_pte,
|
||||
u32 *level, enum kvm_pgtable_walk_flags flags)
|
||||
s8 *level, enum kvm_pgtable_walk_flags flags)
|
||||
{
|
||||
int ret;
|
||||
kvm_pte_t attr_mask = KVM_PTE_LEAF_ATTR_LO | KVM_PTE_LEAF_ATTR_HI;
|
||||
@@ -1296,7 +1320,7 @@ int kvm_pgtable_stage2_relax_perms(struct kvm_pgtable *pgt, u64 addr,
|
||||
enum kvm_pgtable_prot prot)
|
||||
{
|
||||
int ret;
|
||||
u32 level;
|
||||
s8 level;
|
||||
kvm_pte_t set = 0, clr = 0;
|
||||
|
||||
if (prot & KVM_PTE_LEAF_ATTR_HI_SW)
|
||||
@@ -1349,7 +1373,7 @@ int kvm_pgtable_stage2_flush(struct kvm_pgtable *pgt, u64 addr, u64 size)
|
||||
}
|
||||
|
||||
kvm_pte_t *kvm_pgtable_stage2_create_unlinked(struct kvm_pgtable *pgt,
|
||||
u64 phys, u32 level,
|
||||
u64 phys, s8 level,
|
||||
enum kvm_pgtable_prot prot,
|
||||
void *mc, bool force_pte)
|
||||
{
|
||||
@@ -1407,7 +1431,7 @@ kvm_pte_t *kvm_pgtable_stage2_create_unlinked(struct kvm_pgtable *pgt,
|
||||
* fully populated tree up to the PTE entries. Note that @level is
|
||||
* interpreted as in "level @level entry".
|
||||
*/
|
||||
static int stage2_block_get_nr_page_tables(u32 level)
|
||||
static int stage2_block_get_nr_page_tables(s8 level)
|
||||
{
|
||||
switch (level) {
|
||||
case 1:
|
||||
@@ -1418,7 +1442,7 @@ static int stage2_block_get_nr_page_tables(u32 level)
|
||||
return 0;
|
||||
default:
|
||||
WARN_ON_ONCE(level < KVM_PGTABLE_MIN_BLOCK_LEVEL ||
|
||||
level >= KVM_PGTABLE_MAX_LEVELS);
|
||||
level > KVM_PGTABLE_LAST_LEVEL);
|
||||
return -EINVAL;
|
||||
};
|
||||
}
|
||||
@@ -1431,13 +1455,13 @@ static int stage2_split_walker(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
struct kvm_s2_mmu *mmu;
|
||||
kvm_pte_t pte = ctx->old, new, *childp;
|
||||
enum kvm_pgtable_prot prot;
|
||||
u32 level = ctx->level;
|
||||
s8 level = ctx->level;
|
||||
bool force_pte;
|
||||
int nr_pages;
|
||||
u64 phys;
|
||||
|
||||
/* No huge-pages exist at the last level */
|
||||
if (level == KVM_PGTABLE_MAX_LEVELS - 1)
|
||||
if (level == KVM_PGTABLE_LAST_LEVEL)
|
||||
return 0;
|
||||
|
||||
/* We only split valid block mappings */
|
||||
@@ -1514,7 +1538,7 @@ int __kvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm_s2_mmu *mmu,
|
||||
u64 vtcr = mmu->vtcr;
|
||||
u32 ia_bits = VTCR_EL2_IPA(vtcr);
|
||||
u32 sl0 = FIELD_GET(VTCR_EL2_SL0_MASK, vtcr);
|
||||
u32 start_level = VTCR_EL2_TGRAN_SL0_BASE - sl0;
|
||||
s8 start_level = VTCR_EL2_TGRAN_SL0_BASE - sl0;
|
||||
|
||||
pgd_sz = kvm_pgd_pages(ia_bits, start_level) * PAGE_SIZE;
|
||||
pgt->pgd = (kvm_pteref_t)mm_ops->zalloc_pages_exact(pgd_sz);
|
||||
@@ -1537,7 +1561,7 @@ size_t kvm_pgtable_stage2_pgd_size(u64 vtcr)
|
||||
{
|
||||
u32 ia_bits = VTCR_EL2_IPA(vtcr);
|
||||
u32 sl0 = FIELD_GET(VTCR_EL2_SL0_MASK, vtcr);
|
||||
u32 start_level = VTCR_EL2_TGRAN_SL0_BASE - sl0;
|
||||
s8 start_level = VTCR_EL2_TGRAN_SL0_BASE - sl0;
|
||||
|
||||
return kvm_pgd_pages(ia_bits, start_level) * PAGE_SIZE;
|
||||
}
|
||||
@@ -1573,7 +1597,7 @@ void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt)
|
||||
pgt->pgd = NULL;
|
||||
}
|
||||
|
||||
void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, u32 level)
|
||||
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;
|
||||
struct kvm_pgtable_walker walker = {
|
||||
|
||||
+25
-24
@@ -223,12 +223,12 @@ static void stage2_free_unlinked_table_rcu_cb(struct rcu_head *head)
|
||||
{
|
||||
struct page *page = container_of(head, struct page, rcu_head);
|
||||
void *pgtable = page_to_virt(page);
|
||||
u32 level = page_private(page);
|
||||
s8 level = page_private(page);
|
||||
|
||||
kvm_pgtable_stage2_free_unlinked(&kvm_s2_mm_ops, pgtable, level);
|
||||
}
|
||||
|
||||
static void stage2_free_unlinked_table(void *addr, u32 level)
|
||||
static void stage2_free_unlinked_table(void *addr, s8 level)
|
||||
{
|
||||
struct page *page = virt_to_page(addr);
|
||||
|
||||
@@ -804,13 +804,13 @@ static int get_user_mapping_size(struct kvm *kvm, u64 addr)
|
||||
struct kvm_pgtable pgt = {
|
||||
.pgd = (kvm_pteref_t)kvm->mm->pgd,
|
||||
.ia_bits = vabits_actual,
|
||||
.start_level = (KVM_PGTABLE_MAX_LEVELS -
|
||||
CONFIG_PGTABLE_LEVELS),
|
||||
.start_level = (KVM_PGTABLE_LAST_LEVEL -
|
||||
CONFIG_PGTABLE_LEVELS + 1),
|
||||
.mm_ops = &kvm_user_mm_ops,
|
||||
};
|
||||
unsigned long flags;
|
||||
kvm_pte_t pte = 0; /* Keep GCC quiet... */
|
||||
u32 level = ~0;
|
||||
s8 level = S8_MAX;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
@@ -829,7 +829,9 @@ static int get_user_mapping_size(struct kvm *kvm, u64 addr)
|
||||
* Not seeing an error, but not updating level? Something went
|
||||
* deeply wrong...
|
||||
*/
|
||||
if (WARN_ON(level >= KVM_PGTABLE_MAX_LEVELS))
|
||||
if (WARN_ON(level > KVM_PGTABLE_LAST_LEVEL))
|
||||
return -EFAULT;
|
||||
if (WARN_ON(level < KVM_PGTABLE_FIRST_LEVEL))
|
||||
return -EFAULT;
|
||||
|
||||
/* Oops, the userspace PTs are gone... Replay the fault */
|
||||
@@ -1374,7 +1376,7 @@ static bool kvm_vma_mte_allowed(struct vm_area_struct *vma)
|
||||
|
||||
static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||
struct kvm_memory_slot *memslot, unsigned long hva,
|
||||
unsigned long fault_status)
|
||||
bool fault_is_perm)
|
||||
{
|
||||
int ret = 0;
|
||||
bool write_fault, writable, force_pte = false;
|
||||
@@ -1388,17 +1390,17 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||
gfn_t gfn;
|
||||
kvm_pfn_t pfn;
|
||||
bool logging_active = memslot_is_logging(memslot);
|
||||
unsigned long fault_level = kvm_vcpu_trap_get_fault_level(vcpu);
|
||||
long vma_pagesize, fault_granule;
|
||||
enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_R;
|
||||
struct kvm_pgtable *pgt;
|
||||
|
||||
fault_granule = 1UL << ARM64_HW_PGTABLE_LEVEL_SHIFT(fault_level);
|
||||
if (fault_is_perm)
|
||||
fault_granule = kvm_vcpu_trap_get_perm_fault_granule(vcpu);
|
||||
write_fault = kvm_is_write_fault(vcpu);
|
||||
exec_fault = kvm_vcpu_trap_is_exec_fault(vcpu);
|
||||
VM_BUG_ON(write_fault && exec_fault);
|
||||
|
||||
if (fault_status == ESR_ELx_FSC_PERM && !write_fault && !exec_fault) {
|
||||
if (fault_is_perm && !write_fault && !exec_fault) {
|
||||
kvm_err("Unexpected L2 read permission error\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
@@ -1409,8 +1411,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||
* only exception to this is when dirty logging is enabled at runtime
|
||||
* and a write fault needs to collapse a block entry into a table.
|
||||
*/
|
||||
if (fault_status != ESR_ELx_FSC_PERM ||
|
||||
(logging_active && write_fault)) {
|
||||
if (!fault_is_perm || (logging_active && write_fault)) {
|
||||
ret = kvm_mmu_topup_memory_cache(memcache,
|
||||
kvm_mmu_cache_min_pages(vcpu->arch.hw_mmu));
|
||||
if (ret)
|
||||
@@ -1527,8 +1528,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||
* backed by a THP and thus use block mapping if possible.
|
||||
*/
|
||||
if (vma_pagesize == PAGE_SIZE && !(force_pte || device)) {
|
||||
if (fault_status == ESR_ELx_FSC_PERM &&
|
||||
fault_granule > PAGE_SIZE)
|
||||
if (fault_is_perm && fault_granule > PAGE_SIZE)
|
||||
vma_pagesize = fault_granule;
|
||||
else
|
||||
vma_pagesize = transparent_hugepage_adjust(kvm, memslot,
|
||||
@@ -1541,7 +1541,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||
}
|
||||
}
|
||||
|
||||
if (fault_status != ESR_ELx_FSC_PERM && !device && kvm_has_mte(kvm)) {
|
||||
if (!fault_is_perm && !device && kvm_has_mte(kvm)) {
|
||||
/* Check the VMM hasn't introduced a new disallowed VMA */
|
||||
if (mte_allowed) {
|
||||
sanitise_mte_tags(kvm, pfn, vma_pagesize);
|
||||
@@ -1567,7 +1567,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||
* permissions only if vma_pagesize equals fault_granule. Otherwise,
|
||||
* kvm_pgtable_stage2_map() should be called to change block size.
|
||||
*/
|
||||
if (fault_status == ESR_ELx_FSC_PERM && vma_pagesize == fault_granule)
|
||||
if (fault_is_perm && vma_pagesize == fault_granule)
|
||||
ret = kvm_pgtable_stage2_relax_perms(pgt, fault_ipa, prot);
|
||||
else
|
||||
ret = kvm_pgtable_stage2_map(pgt, fault_ipa, vma_pagesize,
|
||||
@@ -1618,7 +1618,7 @@ static void handle_access_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
|
||||
*/
|
||||
int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long fault_status;
|
||||
unsigned long esr;
|
||||
phys_addr_t fault_ipa;
|
||||
struct kvm_memory_slot *memslot;
|
||||
unsigned long hva;
|
||||
@@ -1626,12 +1626,12 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
|
||||
gfn_t gfn;
|
||||
int ret, idx;
|
||||
|
||||
fault_status = kvm_vcpu_trap_get_fault_type(vcpu);
|
||||
esr = kvm_vcpu_get_esr(vcpu);
|
||||
|
||||
fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
|
||||
is_iabt = kvm_vcpu_trap_is_iabt(vcpu);
|
||||
|
||||
if (fault_status == ESR_ELx_FSC_FAULT) {
|
||||
if (esr_fsc_is_permission_fault(esr)) {
|
||||
/* Beyond sanitised PARange (which is the IPA limit) */
|
||||
if (fault_ipa >= BIT_ULL(get_kvm_ipa_limit())) {
|
||||
kvm_inject_size_fault(vcpu);
|
||||
@@ -1666,9 +1666,9 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
|
||||
kvm_vcpu_get_hfar(vcpu), fault_ipa);
|
||||
|
||||
/* Check the stage-2 fault is trans. fault or write fault */
|
||||
if (fault_status != ESR_ELx_FSC_FAULT &&
|
||||
fault_status != ESR_ELx_FSC_PERM &&
|
||||
fault_status != ESR_ELx_FSC_ACCESS) {
|
||||
if (!esr_fsc_is_translation_fault(esr) &&
|
||||
!esr_fsc_is_permission_fault(esr) &&
|
||||
!esr_fsc_is_access_flag_fault(esr)) {
|
||||
kvm_err("Unsupported FSC: EC=%#x xFSC=%#lx ESR_EL2=%#lx\n",
|
||||
kvm_vcpu_trap_get_class(vcpu),
|
||||
(unsigned long)kvm_vcpu_trap_get_fault(vcpu),
|
||||
@@ -1730,13 +1730,14 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
|
||||
/* Userspace should not be able to register out-of-bounds IPAs */
|
||||
VM_BUG_ON(fault_ipa >= kvm_phys_size(vcpu->arch.hw_mmu));
|
||||
|
||||
if (fault_status == ESR_ELx_FSC_ACCESS) {
|
||||
if (esr_fsc_is_access_flag_fault(esr)) {
|
||||
handle_access_fault(vcpu, fault_ipa);
|
||||
ret = 1;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
ret = user_mem_abort(vcpu, fault_ipa, memslot, hva, fault_status);
|
||||
ret = user_mem_abort(vcpu, fault_ipa, memslot, hva,
|
||||
esr_fsc_is_permission_fault(esr));
|
||||
if (ret == 0)
|
||||
ret = 1;
|
||||
out:
|
||||
|
||||
+15
-7
@@ -23,13 +23,9 @@
|
||||
* This list should get updated as new features get added to the NV
|
||||
* support, and new extension to the architecture.
|
||||
*/
|
||||
void access_nested_id_reg(struct kvm_vcpu *v, struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
static u64 limit_nv_id_reg(u32 id, u64 val)
|
||||
{
|
||||
u32 id = reg_to_encoding(r);
|
||||
u64 val, tmp;
|
||||
|
||||
val = p->regval;
|
||||
u64 tmp;
|
||||
|
||||
switch (id) {
|
||||
case SYS_ID_AA64ISAR0_EL1:
|
||||
@@ -158,5 +154,17 @@ void access_nested_id_reg(struct kvm_vcpu *v, struct sys_reg_params *p,
|
||||
break;
|
||||
}
|
||||
|
||||
p->regval = val;
|
||||
return val;
|
||||
}
|
||||
int kvm_init_nv_sysregs(struct kvm *kvm)
|
||||
{
|
||||
mutex_lock(&kvm->arch.config_lock);
|
||||
|
||||
for (int i = 0; i < KVM_ARM_ID_REG_NUM; i++)
|
||||
kvm->arch.id_regs[i] = limit_nv_id_reg(IDX_IDREG(i),
|
||||
kvm->arch.id_regs[i]);
|
||||
|
||||
mutex_unlock(&kvm->arch.config_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -280,12 +280,11 @@ int __init kvm_set_ipa_limit(void)
|
||||
parange = cpuid_feature_extract_unsigned_field(mmfr0,
|
||||
ID_AA64MMFR0_EL1_PARANGE_SHIFT);
|
||||
/*
|
||||
* IPA size beyond 48 bits could not be supported
|
||||
* on either 4K or 16K page size. Hence let's cap
|
||||
* it to 48 bits, in case it's reported as larger
|
||||
* on the system.
|
||||
* IPA size beyond 48 bits for 4K and 16K page size is only supported
|
||||
* when LPA2 is available. So if we have LPA2, enable it, else cap to 48
|
||||
* bits, in case it's reported as larger on the system.
|
||||
*/
|
||||
if (PAGE_SIZE != SZ_64K)
|
||||
if (!kvm_lpa2_is_enabled() && PAGE_SIZE != SZ_64K)
|
||||
parange = min(parange, (unsigned int)ID_AA64MMFR0_EL1_PARANGE_48);
|
||||
|
||||
/*
|
||||
|
||||
+187
-48
@@ -45,44 +45,170 @@ static u64 sys_reg_to_index(const struct sys_reg_desc *reg);
|
||||
static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
|
||||
u64 val);
|
||||
|
||||
static bool bad_trap(struct kvm_vcpu *vcpu,
|
||||
struct sys_reg_params *params,
|
||||
const struct sys_reg_desc *r,
|
||||
const char *msg)
|
||||
{
|
||||
WARN_ONCE(1, "Unexpected %s\n", msg);
|
||||
print_sys_reg_instr(params);
|
||||
kvm_inject_undefined(vcpu);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool read_from_write_only(struct kvm_vcpu *vcpu,
|
||||
struct sys_reg_params *params,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
WARN_ONCE(1, "Unexpected sys_reg read to write-only register\n");
|
||||
print_sys_reg_instr(params);
|
||||
kvm_inject_undefined(vcpu);
|
||||
return false;
|
||||
return bad_trap(vcpu, params, r,
|
||||
"sys_reg read to write-only register");
|
||||
}
|
||||
|
||||
static bool write_to_read_only(struct kvm_vcpu *vcpu,
|
||||
struct sys_reg_params *params,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
WARN_ONCE(1, "Unexpected sys_reg write to read-only register\n");
|
||||
print_sys_reg_instr(params);
|
||||
kvm_inject_undefined(vcpu);
|
||||
return false;
|
||||
return bad_trap(vcpu, params, r,
|
||||
"sys_reg write to read-only register");
|
||||
}
|
||||
|
||||
#define PURE_EL2_SYSREG(el2) \
|
||||
case el2: { \
|
||||
*el1r = el2; \
|
||||
return true; \
|
||||
}
|
||||
|
||||
#define MAPPED_EL2_SYSREG(el2, el1, fn) \
|
||||
case el2: { \
|
||||
*xlate = fn; \
|
||||
*el1r = el1; \
|
||||
return true; \
|
||||
}
|
||||
|
||||
static bool get_el2_to_el1_mapping(unsigned int reg,
|
||||
unsigned int *el1r, u64 (**xlate)(u64))
|
||||
{
|
||||
switch (reg) {
|
||||
PURE_EL2_SYSREG( VPIDR_EL2 );
|
||||
PURE_EL2_SYSREG( VMPIDR_EL2 );
|
||||
PURE_EL2_SYSREG( ACTLR_EL2 );
|
||||
PURE_EL2_SYSREG( HCR_EL2 );
|
||||
PURE_EL2_SYSREG( MDCR_EL2 );
|
||||
PURE_EL2_SYSREG( HSTR_EL2 );
|
||||
PURE_EL2_SYSREG( HACR_EL2 );
|
||||
PURE_EL2_SYSREG( VTTBR_EL2 );
|
||||
PURE_EL2_SYSREG( VTCR_EL2 );
|
||||
PURE_EL2_SYSREG( RVBAR_EL2 );
|
||||
PURE_EL2_SYSREG( TPIDR_EL2 );
|
||||
PURE_EL2_SYSREG( HPFAR_EL2 );
|
||||
PURE_EL2_SYSREG( CNTHCTL_EL2 );
|
||||
MAPPED_EL2_SYSREG(SCTLR_EL2, SCTLR_EL1,
|
||||
translate_sctlr_el2_to_sctlr_el1 );
|
||||
MAPPED_EL2_SYSREG(CPTR_EL2, CPACR_EL1,
|
||||
translate_cptr_el2_to_cpacr_el1 );
|
||||
MAPPED_EL2_SYSREG(TTBR0_EL2, TTBR0_EL1,
|
||||
translate_ttbr0_el2_to_ttbr0_el1 );
|
||||
MAPPED_EL2_SYSREG(TTBR1_EL2, TTBR1_EL1, NULL );
|
||||
MAPPED_EL2_SYSREG(TCR_EL2, TCR_EL1,
|
||||
translate_tcr_el2_to_tcr_el1 );
|
||||
MAPPED_EL2_SYSREG(VBAR_EL2, VBAR_EL1, NULL );
|
||||
MAPPED_EL2_SYSREG(AFSR0_EL2, AFSR0_EL1, NULL );
|
||||
MAPPED_EL2_SYSREG(AFSR1_EL2, AFSR1_EL1, NULL );
|
||||
MAPPED_EL2_SYSREG(ESR_EL2, ESR_EL1, NULL );
|
||||
MAPPED_EL2_SYSREG(FAR_EL2, FAR_EL1, NULL );
|
||||
MAPPED_EL2_SYSREG(MAIR_EL2, MAIR_EL1, NULL );
|
||||
MAPPED_EL2_SYSREG(AMAIR_EL2, AMAIR_EL1, NULL );
|
||||
MAPPED_EL2_SYSREG(ELR_EL2, ELR_EL1, NULL );
|
||||
MAPPED_EL2_SYSREG(SPSR_EL2, SPSR_EL1, NULL );
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg)
|
||||
{
|
||||
u64 val = 0x8badf00d8badf00d;
|
||||
u64 (*xlate)(u64) = NULL;
|
||||
unsigned int el1r;
|
||||
|
||||
if (vcpu_get_flag(vcpu, SYSREGS_ON_CPU) &&
|
||||
__vcpu_read_sys_reg_from_cpu(reg, &val))
|
||||
if (!vcpu_get_flag(vcpu, SYSREGS_ON_CPU))
|
||||
goto memory_read;
|
||||
|
||||
if (unlikely(get_el2_to_el1_mapping(reg, &el1r, &xlate))) {
|
||||
if (!is_hyp_ctxt(vcpu))
|
||||
goto memory_read;
|
||||
|
||||
/*
|
||||
* If this register does not have an EL1 counterpart,
|
||||
* then read the stored EL2 version.
|
||||
*/
|
||||
if (reg == el1r)
|
||||
goto memory_read;
|
||||
|
||||
/*
|
||||
* If we have a non-VHE guest and that the sysreg
|
||||
* requires translation to be used at EL1, use the
|
||||
* in-memory copy instead.
|
||||
*/
|
||||
if (!vcpu_el2_e2h_is_set(vcpu) && xlate)
|
||||
goto memory_read;
|
||||
|
||||
/* Get the current version of the EL1 counterpart. */
|
||||
WARN_ON(!__vcpu_read_sys_reg_from_cpu(el1r, &val));
|
||||
return val;
|
||||
}
|
||||
|
||||
/* EL1 register can't be on the CPU if the guest is in vEL2. */
|
||||
if (unlikely(is_hyp_ctxt(vcpu)))
|
||||
goto memory_read;
|
||||
|
||||
if (__vcpu_read_sys_reg_from_cpu(reg, &val))
|
||||
return val;
|
||||
|
||||
memory_read:
|
||||
return __vcpu_sys_reg(vcpu, reg);
|
||||
}
|
||||
|
||||
void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg)
|
||||
{
|
||||
if (vcpu_get_flag(vcpu, SYSREGS_ON_CPU) &&
|
||||
__vcpu_write_sys_reg_to_cpu(val, reg))
|
||||
u64 (*xlate)(u64) = NULL;
|
||||
unsigned int el1r;
|
||||
|
||||
if (!vcpu_get_flag(vcpu, SYSREGS_ON_CPU))
|
||||
goto memory_write;
|
||||
|
||||
if (unlikely(get_el2_to_el1_mapping(reg, &el1r, &xlate))) {
|
||||
if (!is_hyp_ctxt(vcpu))
|
||||
goto memory_write;
|
||||
|
||||
/*
|
||||
* Always store a copy of the write to memory to avoid having
|
||||
* to reverse-translate virtual EL2 system registers for a
|
||||
* non-VHE guest hypervisor.
|
||||
*/
|
||||
__vcpu_sys_reg(vcpu, reg) = val;
|
||||
|
||||
/* No EL1 counterpart? We're done here.? */
|
||||
if (reg == el1r)
|
||||
return;
|
||||
|
||||
if (!vcpu_el2_e2h_is_set(vcpu) && xlate)
|
||||
val = xlate(val);
|
||||
|
||||
/* Redirect this to the EL1 version of the register. */
|
||||
WARN_ON(!__vcpu_write_sys_reg_to_cpu(val, el1r));
|
||||
return;
|
||||
}
|
||||
|
||||
/* EL1 register can't be on the CPU if the guest is in vEL2. */
|
||||
if (unlikely(is_hyp_ctxt(vcpu)))
|
||||
goto memory_write;
|
||||
|
||||
if (__vcpu_write_sys_reg_to_cpu(val, reg))
|
||||
return;
|
||||
|
||||
__vcpu_sys_reg(vcpu, reg) = val;
|
||||
memory_write:
|
||||
__vcpu_sys_reg(vcpu, reg) = val;
|
||||
}
|
||||
|
||||
/* CSSELR values; used to index KVM_REG_ARM_DEMUX_ID_CCSIDR */
|
||||
@@ -1505,8 +1631,6 @@ static bool access_id_reg(struct kvm_vcpu *vcpu,
|
||||
return write_to_read_only(vcpu, p, r);
|
||||
|
||||
p->regval = read_id_reg(vcpu, r);
|
||||
if (vcpu_has_nv(vcpu))
|
||||
access_nested_id_reg(vcpu, p, r);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1885,6 +2009,32 @@ static unsigned int el2_visibility(const struct kvm_vcpu *vcpu,
|
||||
return REG_HIDDEN;
|
||||
}
|
||||
|
||||
static bool bad_vncr_trap(struct kvm_vcpu *vcpu,
|
||||
struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
/*
|
||||
* We really shouldn't be here, and this is likely the result
|
||||
* of a misconfigured trap, as this register should target the
|
||||
* VNCR page, and nothing else.
|
||||
*/
|
||||
return bad_trap(vcpu, p, r,
|
||||
"trap of VNCR-backed register");
|
||||
}
|
||||
|
||||
static bool bad_redir_trap(struct kvm_vcpu *vcpu,
|
||||
struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
/*
|
||||
* We really shouldn't be here, and this is likely the result
|
||||
* of a misconfigured trap, as this register should target the
|
||||
* corresponding EL1, and nothing else.
|
||||
*/
|
||||
return bad_trap(vcpu, p, r,
|
||||
"trap of EL2 register redirected to EL1");
|
||||
}
|
||||
|
||||
#define EL2_REG(name, acc, rst, v) { \
|
||||
SYS_DESC(SYS_##name), \
|
||||
.access = acc, \
|
||||
@@ -1894,6 +2044,9 @@ static unsigned int el2_visibility(const struct kvm_vcpu *vcpu,
|
||||
.val = v, \
|
||||
}
|
||||
|
||||
#define EL2_REG_VNCR(name, rst, v) EL2_REG(name, bad_vncr_trap, rst, v)
|
||||
#define EL2_REG_REDIR(name, rst, v) EL2_REG(name, bad_redir_trap, rst, v)
|
||||
|
||||
/*
|
||||
* EL{0,1}2 registers are the EL2 view on an EL0 or EL1 register when
|
||||
* HCR_EL2.E2H==1, and only in the sysreg table for convenience of
|
||||
@@ -2508,32 +2661,33 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
||||
{ PMU_SYS_REG(PMCCFILTR_EL0), .access = access_pmu_evtyper,
|
||||
.reset = reset_val, .reg = PMCCFILTR_EL0, .val = 0 },
|
||||
|
||||
EL2_REG(VPIDR_EL2, access_rw, reset_unknown, 0),
|
||||
EL2_REG(VMPIDR_EL2, access_rw, reset_unknown, 0),
|
||||
EL2_REG_VNCR(VPIDR_EL2, reset_unknown, 0),
|
||||
EL2_REG_VNCR(VMPIDR_EL2, reset_unknown, 0),
|
||||
EL2_REG(SCTLR_EL2, access_rw, reset_val, SCTLR_EL2_RES1),
|
||||
EL2_REG(ACTLR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(HCR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG_VNCR(HCR_EL2, reset_val, 0),
|
||||
EL2_REG(MDCR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(CPTR_EL2, access_rw, reset_val, CPTR_NVHE_EL2_RES1),
|
||||
EL2_REG(HSTR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(HFGRTR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(HFGWTR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(HFGITR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(HACR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG_VNCR(HSTR_EL2, reset_val, 0),
|
||||
EL2_REG_VNCR(HFGRTR_EL2, reset_val, 0),
|
||||
EL2_REG_VNCR(HFGWTR_EL2, reset_val, 0),
|
||||
EL2_REG_VNCR(HFGITR_EL2, reset_val, 0),
|
||||
EL2_REG_VNCR(HACR_EL2, reset_val, 0),
|
||||
|
||||
EL2_REG(HCRX_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG_VNCR(HCRX_EL2, reset_val, 0),
|
||||
|
||||
EL2_REG(TTBR0_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(TTBR1_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(TCR_EL2, access_rw, reset_val, TCR_EL2_RES1),
|
||||
EL2_REG(VTTBR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(VTCR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG_VNCR(VTTBR_EL2, reset_val, 0),
|
||||
EL2_REG_VNCR(VTCR_EL2, reset_val, 0),
|
||||
|
||||
{ SYS_DESC(SYS_DACR32_EL2), trap_undef, reset_unknown, DACR32_EL2 },
|
||||
EL2_REG(HDFGRTR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(HDFGWTR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(SPSR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(ELR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG_VNCR(HDFGRTR_EL2, reset_val, 0),
|
||||
EL2_REG_VNCR(HDFGWTR_EL2, reset_val, 0),
|
||||
EL2_REG_VNCR(HAFGRTR_EL2, reset_val, 0),
|
||||
EL2_REG_REDIR(SPSR_EL2, reset_val, 0),
|
||||
EL2_REG_REDIR(ELR_EL2, reset_val, 0),
|
||||
{ SYS_DESC(SYS_SP_EL1), access_sp_el1},
|
||||
|
||||
/* AArch32 SPSR_* are RES0 if trapped from a NV guest */
|
||||
@@ -2549,10 +2703,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
||||
{ SYS_DESC(SYS_IFSR32_EL2), trap_undef, reset_unknown, IFSR32_EL2 },
|
||||
EL2_REG(AFSR0_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(AFSR1_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(ESR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG_REDIR(ESR_EL2, reset_val, 0),
|
||||
{ SYS_DESC(SYS_FPEXC32_EL2), trap_undef, reset_val, FPEXC32_EL2, 0x700 },
|
||||
|
||||
EL2_REG(FAR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG_REDIR(FAR_EL2, reset_val, 0),
|
||||
EL2_REG(HPFAR_EL2, access_rw, reset_val, 0),
|
||||
|
||||
EL2_REG(MAIR_EL2, access_rw, reset_val, 0),
|
||||
@@ -2565,24 +2719,9 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
||||
EL2_REG(CONTEXTIDR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(TPIDR_EL2, access_rw, reset_val, 0),
|
||||
|
||||
EL2_REG(CNTVOFF_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG_VNCR(CNTVOFF_EL2, reset_val, 0),
|
||||
EL2_REG(CNTHCTL_EL2, access_rw, reset_val, 0),
|
||||
|
||||
EL12_REG(SCTLR, access_vm_reg, reset_val, 0x00C50078),
|
||||
EL12_REG(CPACR, access_rw, reset_val, 0),
|
||||
EL12_REG(TTBR0, access_vm_reg, reset_unknown, 0),
|
||||
EL12_REG(TTBR1, access_vm_reg, reset_unknown, 0),
|
||||
EL12_REG(TCR, access_vm_reg, reset_val, 0),
|
||||
{ SYS_DESC(SYS_SPSR_EL12), access_spsr},
|
||||
{ SYS_DESC(SYS_ELR_EL12), access_elr},
|
||||
EL12_REG(AFSR0, access_vm_reg, reset_unknown, 0),
|
||||
EL12_REG(AFSR1, access_vm_reg, reset_unknown, 0),
|
||||
EL12_REG(ESR, access_vm_reg, reset_unknown, 0),
|
||||
EL12_REG(FAR, access_vm_reg, reset_unknown, 0),
|
||||
EL12_REG(MAIR, access_vm_reg, reset_unknown, 0),
|
||||
EL12_REG(AMAIR, access_vm_reg, reset_amair_el1, 0),
|
||||
EL12_REG(VBAR, access_rw, reset_val, 0),
|
||||
EL12_REG(CONTEXTIDR, access_vm_reg, reset_val, 0),
|
||||
EL12_REG(CNTKCTL, access_rw, reset_val, 0),
|
||||
|
||||
EL2_REG(SP_EL2, NULL, reset_unknown, 0),
|
||||
|
||||
@@ -590,7 +590,11 @@ static struct vgic_irq *vgic_its_check_cache(struct kvm *kvm, phys_addr_t db,
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&dist->lpi_list_lock, flags);
|
||||
|
||||
irq = __vgic_its_check_cache(dist, db, devid, eventid);
|
||||
if (irq)
|
||||
vgic_get_irq_kref(irq);
|
||||
|
||||
raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags);
|
||||
|
||||
return irq;
|
||||
@@ -769,6 +773,7 @@ int vgic_its_inject_cached_translation(struct kvm *kvm, struct kvm_msi *msi)
|
||||
raw_spin_lock_irqsave(&irq->irq_lock, flags);
|
||||
irq->pending_latch = true;
|
||||
vgic_queue_irq_unlock(kvm, irq, flags);
|
||||
vgic_put_irq(kvm, irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -357,31 +357,13 @@ static int vgic_v3_uaccess_write_pending(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val)
|
||||
{
|
||||
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
|
||||
int i;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < len * 8; i++) {
|
||||
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
|
||||
ret = vgic_uaccess_write_spending(vcpu, addr, len, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
raw_spin_lock_irqsave(&irq->irq_lock, flags);
|
||||
if (test_bit(i, &val)) {
|
||||
/*
|
||||
* pending_latch is set irrespective of irq type
|
||||
* (level or edge) to avoid dependency that VM should
|
||||
* restore irq config before pending info.
|
||||
*/
|
||||
irq->pending_latch = true;
|
||||
vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
|
||||
} else {
|
||||
irq->pending_latch = false;
|
||||
raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
|
||||
}
|
||||
|
||||
vgic_put_irq(vcpu->kvm, irq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return vgic_uaccess_write_cpending(vcpu, addr, len, ~val);
|
||||
}
|
||||
|
||||
/* We want to avoid outer shareable. */
|
||||
|
||||
@@ -301,9 +301,8 @@ static bool is_vgic_v2_sgi(struct kvm_vcpu *vcpu, struct vgic_irq *irq)
|
||||
vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2);
|
||||
}
|
||||
|
||||
void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val)
|
||||
static void __set_pending(struct kvm_vcpu *vcpu, gpa_t addr, unsigned int len,
|
||||
unsigned long val, bool is_user)
|
||||
{
|
||||
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
|
||||
int i;
|
||||
@@ -312,14 +311,22 @@ void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
|
||||
for_each_set_bit(i, &val, len * 8) {
|
||||
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
|
||||
|
||||
/* GICD_ISPENDR0 SGI bits are WI */
|
||||
if (is_vgic_v2_sgi(vcpu, irq)) {
|
||||
/* GICD_ISPENDR0 SGI bits are WI when written from the guest. */
|
||||
if (is_vgic_v2_sgi(vcpu, irq) && !is_user) {
|
||||
vgic_put_irq(vcpu->kvm, irq);
|
||||
continue;
|
||||
}
|
||||
|
||||
raw_spin_lock_irqsave(&irq->irq_lock, flags);
|
||||
|
||||
/*
|
||||
* GICv2 SGIs are terribly broken. We can't restore
|
||||
* the source of the interrupt, so just pick the vcpu
|
||||
* itself as the source...
|
||||
*/
|
||||
if (is_vgic_v2_sgi(vcpu, irq))
|
||||
irq->source |= BIT(vcpu->vcpu_id);
|
||||
|
||||
if (irq->hw && vgic_irq_is_sgi(irq->intid)) {
|
||||
/* HW SGI? Ask the GIC to inject it */
|
||||
int err;
|
||||
@@ -335,7 +342,7 @@ void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
|
||||
}
|
||||
|
||||
irq->pending_latch = true;
|
||||
if (irq->hw)
|
||||
if (irq->hw && !is_user)
|
||||
vgic_irq_set_phys_active(irq, true);
|
||||
|
||||
vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
|
||||
@@ -343,33 +350,18 @@ void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
|
||||
}
|
||||
}
|
||||
|
||||
void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val)
|
||||
{
|
||||
__set_pending(vcpu, addr, len, val, false);
|
||||
}
|
||||
|
||||
int vgic_uaccess_write_spending(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val)
|
||||
{
|
||||
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
for_each_set_bit(i, &val, len * 8) {
|
||||
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
|
||||
|
||||
raw_spin_lock_irqsave(&irq->irq_lock, flags);
|
||||
irq->pending_latch = true;
|
||||
|
||||
/*
|
||||
* GICv2 SGIs are terribly broken. We can't restore
|
||||
* the source of the interrupt, so just pick the vcpu
|
||||
* itself as the source...
|
||||
*/
|
||||
if (is_vgic_v2_sgi(vcpu, irq))
|
||||
irq->source |= BIT(vcpu->vcpu_id);
|
||||
|
||||
vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
|
||||
|
||||
vgic_put_irq(vcpu->kvm, irq);
|
||||
}
|
||||
|
||||
__set_pending(vcpu, addr, len, val, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -394,9 +386,9 @@ static void vgic_hw_irq_cpending(struct kvm_vcpu *vcpu, struct vgic_irq *irq)
|
||||
vgic_irq_set_phys_active(irq, false);
|
||||
}
|
||||
|
||||
void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val)
|
||||
static void __clear_pending(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val, bool is_user)
|
||||
{
|
||||
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
|
||||
int i;
|
||||
@@ -405,14 +397,22 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
|
||||
for_each_set_bit(i, &val, len * 8) {
|
||||
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
|
||||
|
||||
/* GICD_ICPENDR0 SGI bits are WI */
|
||||
if (is_vgic_v2_sgi(vcpu, irq)) {
|
||||
/* GICD_ICPENDR0 SGI bits are WI when written from the guest. */
|
||||
if (is_vgic_v2_sgi(vcpu, irq) && !is_user) {
|
||||
vgic_put_irq(vcpu->kvm, irq);
|
||||
continue;
|
||||
}
|
||||
|
||||
raw_spin_lock_irqsave(&irq->irq_lock, flags);
|
||||
|
||||
/*
|
||||
* More fun with GICv2 SGIs! If we're clearing one of them
|
||||
* from userspace, which source vcpu to clear? Let's not
|
||||
* even think of it, and blow the whole set.
|
||||
*/
|
||||
if (is_vgic_v2_sgi(vcpu, irq))
|
||||
irq->source = 0;
|
||||
|
||||
if (irq->hw && vgic_irq_is_sgi(irq->intid)) {
|
||||
/* HW SGI? Ask the GIC to clear its pending bit */
|
||||
int err;
|
||||
@@ -427,7 +427,7 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (irq->hw)
|
||||
if (irq->hw && !is_user)
|
||||
vgic_hw_irq_cpending(vcpu, irq);
|
||||
else
|
||||
irq->pending_latch = false;
|
||||
@@ -437,33 +437,18 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
|
||||
}
|
||||
}
|
||||
|
||||
void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val)
|
||||
{
|
||||
__clear_pending(vcpu, addr, len, val, false);
|
||||
}
|
||||
|
||||
int vgic_uaccess_write_cpending(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val)
|
||||
{
|
||||
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
for_each_set_bit(i, &val, len * 8) {
|
||||
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
|
||||
|
||||
raw_spin_lock_irqsave(&irq->irq_lock, flags);
|
||||
/*
|
||||
* More fun with GICv2 SGIs! If we're clearing one of them
|
||||
* from userspace, which source vcpu to clear? Let's not
|
||||
* even think of it, and blow the whole set.
|
||||
*/
|
||||
if (is_vgic_v2_sgi(vcpu, irq))
|
||||
irq->source = 0;
|
||||
|
||||
irq->pending_latch = false;
|
||||
|
||||
raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
|
||||
|
||||
vgic_put_irq(vcpu->kvm, irq);
|
||||
}
|
||||
|
||||
__clear_pending(vcpu, addr, len, val, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ HAS_GIC_PRIO_MASKING
|
||||
HAS_GIC_PRIO_RELAXED_SYNC
|
||||
HAS_HCX
|
||||
HAS_LDAPR
|
||||
HAS_LPA2
|
||||
HAS_LSE_ATOMICS
|
||||
HAS_MOPS
|
||||
HAS_NESTED_VIRT
|
||||
|
||||
+309
-11
@@ -1002,6 +1002,27 @@ UnsignedEnum 3:0 BT
|
||||
EndEnum
|
||||
EndSysreg
|
||||
|
||||
Sysreg ID_AA64PFR2_EL1 3 0 0 4 2
|
||||
Res0 63:36
|
||||
UnsignedEnum 35:32 FPMR
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
EndEnum
|
||||
Res0 31:12
|
||||
UnsignedEnum 11:8 MTEFAR
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
EndEnum
|
||||
UnsignedEnum 7:4 MTESTOREONLY
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
EndEnum
|
||||
UnsignedEnum 3:0 MTEPERM
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
EndEnum
|
||||
EndSysreg
|
||||
|
||||
Sysreg ID_AA64ZFR0_EL1 3 0 0 4 4
|
||||
Res0 63:60
|
||||
UnsignedEnum 59:56 F64MM
|
||||
@@ -1058,7 +1079,11 @@ UnsignedEnum 63 FA64
|
||||
0b0 NI
|
||||
0b1 IMP
|
||||
EndEnum
|
||||
Res0 62:60
|
||||
Res0 62:61
|
||||
UnsignedEnum 60 LUTv2
|
||||
0b0 NI
|
||||
0b1 IMP
|
||||
EndEnum
|
||||
UnsignedEnum 59:56 SMEver
|
||||
0b0000 SME
|
||||
0b0001 SME2
|
||||
@@ -1086,7 +1111,14 @@ UnsignedEnum 42 F16F16
|
||||
0b0 NI
|
||||
0b1 IMP
|
||||
EndEnum
|
||||
Res0 41:40
|
||||
UnsignedEnum 41 F8F16
|
||||
0b0 NI
|
||||
0b1 IMP
|
||||
EndEnum
|
||||
UnsignedEnum 40 F8F32
|
||||
0b0 NI
|
||||
0b1 IMP
|
||||
EndEnum
|
||||
UnsignedEnum 39:36 I8I32
|
||||
0b0000 NI
|
||||
0b1111 IMP
|
||||
@@ -1107,7 +1139,49 @@ UnsignedEnum 32 F32F32
|
||||
0b0 NI
|
||||
0b1 IMP
|
||||
EndEnum
|
||||
Res0 31:0
|
||||
Res0 31
|
||||
UnsignedEnum 30 SF8FMA
|
||||
0b0 NI
|
||||
0b1 IMP
|
||||
EndEnum
|
||||
UnsignedEnum 29 SF8DP4
|
||||
0b0 NI
|
||||
0b1 IMP
|
||||
EndEnum
|
||||
UnsignedEnum 28 SF8DP2
|
||||
0b0 NI
|
||||
0b1 IMP
|
||||
EndEnum
|
||||
Res0 27:0
|
||||
EndSysreg
|
||||
|
||||
Sysreg ID_AA64FPFR0_EL1 3 0 0 4 7
|
||||
Res0 63:32
|
||||
UnsignedEnum 31 F8CVT
|
||||
0b0 NI
|
||||
0b1 IMP
|
||||
EndEnum
|
||||
UnsignedEnum 30 F8FMA
|
||||
0b0 NI
|
||||
0b1 IMP
|
||||
EndEnum
|
||||
UnsignedEnum 29 F8DP4
|
||||
0b0 NI
|
||||
0b1 IMP
|
||||
EndEnum
|
||||
UnsignedEnum 28 F8DP2
|
||||
0b0 NI
|
||||
0b1 IMP
|
||||
EndEnum
|
||||
Res0 27:2
|
||||
UnsignedEnum 1 F8E4M3
|
||||
0b0 NI
|
||||
0b1 IMP
|
||||
EndEnum
|
||||
UnsignedEnum 0 F8E5M2
|
||||
0b0 NI
|
||||
0b1 IMP
|
||||
EndEnum
|
||||
EndSysreg
|
||||
|
||||
Sysreg ID_AA64DFR0_EL1 3 0 0 5 0
|
||||
@@ -1115,7 +1189,10 @@ Enum 63:60 HPMN0
|
||||
0b0000 UNPREDICTABLE
|
||||
0b0001 DEF
|
||||
EndEnum
|
||||
Res0 59:56
|
||||
UnsignedEnum 59:56 ExtTrcBuff
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
EndEnum
|
||||
UnsignedEnum 55:52 BRBE
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
@@ -1327,6 +1404,7 @@ UnsignedEnum 11:8 API
|
||||
0b0011 PAuth2
|
||||
0b0100 FPAC
|
||||
0b0101 FPACCOMBINE
|
||||
0b0110 PAuth_LR
|
||||
EndEnum
|
||||
UnsignedEnum 7:4 APA
|
||||
0b0000 NI
|
||||
@@ -1335,6 +1413,7 @@ UnsignedEnum 7:4 APA
|
||||
0b0011 PAuth2
|
||||
0b0100 FPAC
|
||||
0b0101 FPACCOMBINE
|
||||
0b0110 PAuth_LR
|
||||
EndEnum
|
||||
UnsignedEnum 3:0 DPB
|
||||
0b0000 NI
|
||||
@@ -1344,7 +1423,14 @@ EndEnum
|
||||
EndSysreg
|
||||
|
||||
Sysreg ID_AA64ISAR2_EL1 3 0 0 6 2
|
||||
Res0 63:56
|
||||
UnsignedEnum 63:60 ATS1A
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
EndEnum
|
||||
UnsignedEnum 59:56 LUT
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
EndEnum
|
||||
UnsignedEnum 55:52 CSSC
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
@@ -1353,7 +1439,19 @@ UnsignedEnum 51:48 RPRFM
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
EndEnum
|
||||
Res0 47:32
|
||||
Res0 47:44
|
||||
UnsignedEnum 43:40 PRFMSLC
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
EndEnum
|
||||
UnsignedEnum 39:36 SYSINSTR_128
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
EndEnum
|
||||
UnsignedEnum 35:32 SYSREG_128
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
EndEnum
|
||||
UnsignedEnum 31:28 CLRBHB
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
@@ -1377,6 +1475,7 @@ UnsignedEnum 15:12 APA3
|
||||
0b0011 PAuth2
|
||||
0b0100 FPAC
|
||||
0b0101 FPACCOMBINE
|
||||
0b0110 PAuth_LR
|
||||
EndEnum
|
||||
UnsignedEnum 11:8 GPA3
|
||||
0b0000 NI
|
||||
@@ -1392,6 +1491,23 @@ UnsignedEnum 3:0 WFxT
|
||||
EndEnum
|
||||
EndSysreg
|
||||
|
||||
Sysreg ID_AA64ISAR3_EL1 3 0 0 6 3
|
||||
Res0 63:12
|
||||
UnsignedEnum 11:8 TLBIW
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
EndEnum
|
||||
UnsignedEnum 7:4 FAMINMAX
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
EndEnum
|
||||
UnsignedEnum 3:0 CPA
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
0b0010 CPA2
|
||||
EndEnum
|
||||
EndSysreg
|
||||
|
||||
Sysreg ID_AA64MMFR0_EL1 3 0 0 7 0
|
||||
UnsignedEnum 63:60 ECV
|
||||
0b0000 NI
|
||||
@@ -1680,7 +1796,8 @@ Field 63 TIDCP
|
||||
Field 62 SPINTMASK
|
||||
Field 61 NMI
|
||||
Field 60 EnTP2
|
||||
Res0 59:58
|
||||
Field 59 TCSO
|
||||
Field 58 TCSO0
|
||||
Field 57 EPAN
|
||||
Field 56 EnALS
|
||||
Field 55 EnAS0
|
||||
@@ -1709,7 +1826,7 @@ EndEnum
|
||||
Field 37 ITFSB
|
||||
Field 36 BT1
|
||||
Field 35 BT0
|
||||
Res0 34
|
||||
Field 34 EnFPM
|
||||
Field 33 MSCEn
|
||||
Field 32 CMOW
|
||||
Field 31 EnIA
|
||||
@@ -1747,7 +1864,8 @@ Field 0 M
|
||||
EndSysreg
|
||||
|
||||
SysregFields CPACR_ELx
|
||||
Res0 63:29
|
||||
Res0 63:30
|
||||
Field 29 E0POE
|
||||
Field 28 TTA
|
||||
Res0 27:26
|
||||
Field 25:24 SMEN
|
||||
@@ -1790,6 +1908,41 @@ Sysreg SMCR_EL1 3 0 1 2 6
|
||||
Fields SMCR_ELx
|
||||
EndSysreg
|
||||
|
||||
SysregFields GCSCR_ELx
|
||||
Res0 63:10
|
||||
Field 9 STREn
|
||||
Field 8 PUSHMEn
|
||||
Res0 7
|
||||
Field 6 EXLOCKEN
|
||||
Field 5 RVCHKEN
|
||||
Res0 4:1
|
||||
Field 0 PCRSEL
|
||||
EndSysregFields
|
||||
|
||||
Sysreg GCSCR_EL1 3 0 2 5 0
|
||||
Fields GCSCR_ELx
|
||||
EndSysreg
|
||||
|
||||
SysregFields GCSPR_ELx
|
||||
Field 63:3 PTR
|
||||
Res0 2:0
|
||||
EndSysregFields
|
||||
|
||||
Sysreg GCSPR_EL1 3 0 2 5 1
|
||||
Fields GCSPR_ELx
|
||||
EndSysreg
|
||||
|
||||
Sysreg GCSCRE0_EL1 3 0 2 5 2
|
||||
Res0 63:11
|
||||
Field 10 nTR
|
||||
Field 9 STREn
|
||||
Field 8 PUSHMEn
|
||||
Res0 7:6
|
||||
Field 5 RVCHKEN
|
||||
Res0 4:1
|
||||
Field 0 PCRSEL
|
||||
EndSysreg
|
||||
|
||||
Sysreg ALLINT 3 0 4 3 0
|
||||
Res0 63:14
|
||||
Field 13 ALLINT
|
||||
@@ -1933,10 +2086,18 @@ Sysreg CONTEXTIDR_EL1 3 0 13 0 1
|
||||
Fields CONTEXTIDR_ELx
|
||||
EndSysreg
|
||||
|
||||
Sysreg RCWSMASK_EL1 3 0 13 0 3
|
||||
Field 63:0 RCWSMASK
|
||||
EndSysreg
|
||||
|
||||
Sysreg TPIDR_EL1 3 0 13 0 4
|
||||
Field 63:0 ThreadID
|
||||
EndSysreg
|
||||
|
||||
Sysreg RCWMASK_EL1 3 0 13 0 6
|
||||
Field 63:0 RCWMASK
|
||||
EndSysreg
|
||||
|
||||
Sysreg SCXTNUM_EL1 3 0 13 0 7
|
||||
Field 63:0 SoftwareContextNumber
|
||||
EndSysreg
|
||||
@@ -2020,12 +2181,39 @@ Field 4 DZP
|
||||
Field 3:0 BS
|
||||
EndSysreg
|
||||
|
||||
Sysreg GCSPR_EL0 3 3 2 5 1
|
||||
Fields GCSPR_ELx
|
||||
EndSysreg
|
||||
|
||||
Sysreg SVCR 3 3 4 2 2
|
||||
Res0 63:2
|
||||
Field 1 ZA
|
||||
Field 0 SM
|
||||
EndSysreg
|
||||
|
||||
Sysreg FPMR 3 3 4 4 2
|
||||
Res0 63:38
|
||||
Field 37:32 LSCALE2
|
||||
Field 31:24 NSCALE
|
||||
Res0 23
|
||||
Field 22:16 LSCALE
|
||||
Field 15 OSC
|
||||
Field 14 OSM
|
||||
Res0 13:9
|
||||
UnsignedEnum 8:6 F8D
|
||||
0b000 E5M2
|
||||
0b001 E4M3
|
||||
EndEnum
|
||||
UnsignedEnum 5:3 F8S2
|
||||
0b000 E5M2
|
||||
0b001 E4M3
|
||||
EndEnum
|
||||
UnsignedEnum 2:0 F8S1
|
||||
0b000 E5M2
|
||||
0b001 E4M3
|
||||
EndEnum
|
||||
EndSysreg
|
||||
|
||||
SysregFields HFGxTR_EL2
|
||||
Field 63 nAMAIR2_EL1
|
||||
Field 62 nMAIR2_EL1
|
||||
@@ -2102,7 +2290,9 @@ Fields HFGxTR_EL2
|
||||
EndSysreg
|
||||
|
||||
Sysreg HFGITR_EL2 3 4 1 1 6
|
||||
Res0 63:61
|
||||
Res0 63
|
||||
Field 62 ATS1E1A
|
||||
Res0 61
|
||||
Field 60 COSPRCTX
|
||||
Field 59 nGCSEPP
|
||||
Field 58 nGCSSTR_EL1
|
||||
@@ -2295,12 +2485,57 @@ Field 1 DBGBVRn_EL1
|
||||
Field 0 DBGBCRn_EL1
|
||||
EndSysreg
|
||||
|
||||
Sysreg HAFGRTR_EL2 3 4 3 1 6
|
||||
Res0 63:50
|
||||
Field 49 AMEVTYPER115_EL0
|
||||
Field 48 AMEVCNTR115_EL0
|
||||
Field 47 AMEVTYPER114_EL0
|
||||
Field 46 AMEVCNTR114_EL0
|
||||
Field 45 AMEVTYPER113_EL0
|
||||
Field 44 AMEVCNTR113_EL0
|
||||
Field 43 AMEVTYPER112_EL0
|
||||
Field 42 AMEVCNTR112_EL0
|
||||
Field 41 AMEVTYPER111_EL0
|
||||
Field 40 AMEVCNTR111_EL0
|
||||
Field 39 AMEVTYPER110_EL0
|
||||
Field 38 AMEVCNTR110_EL0
|
||||
Field 37 AMEVTYPER19_EL0
|
||||
Field 36 AMEVCNTR19_EL0
|
||||
Field 35 AMEVTYPER18_EL0
|
||||
Field 34 AMEVCNTR18_EL0
|
||||
Field 33 AMEVTYPER17_EL0
|
||||
Field 32 AMEVCNTR17_EL0
|
||||
Field 31 AMEVTYPER16_EL0
|
||||
Field 30 AMEVCNTR16_EL0
|
||||
Field 29 AMEVTYPER15_EL0
|
||||
Field 28 AMEVCNTR15_EL0
|
||||
Field 27 AMEVTYPER14_EL0
|
||||
Field 26 AMEVCNTR14_EL0
|
||||
Field 25 AMEVTYPER13_EL0
|
||||
Field 24 AMEVCNTR13_EL0
|
||||
Field 23 AMEVTYPER12_EL0
|
||||
Field 22 AMEVCNTR12_EL0
|
||||
Field 21 AMEVTYPER11_EL0
|
||||
Field 20 AMEVCNTR11_EL0
|
||||
Field 19 AMEVTYPER10_EL0
|
||||
Field 18 AMEVCNTR10_EL0
|
||||
Field 17 AMCNTEN1
|
||||
Res0 16:5
|
||||
Field 4 AMEVCNTR03_EL0
|
||||
Field 3 AMEVCNTR02_EL0
|
||||
Field 2 AMEVCNTR01_EL0
|
||||
Field 1 AMEVCNTR00_EL0
|
||||
Field 0 AMCNTEN0
|
||||
EndSysreg
|
||||
|
||||
Sysreg ZCR_EL2 3 4 1 2 0
|
||||
Fields ZCR_ELx
|
||||
EndSysreg
|
||||
|
||||
Sysreg HCRX_EL2 3 4 1 2 2
|
||||
Res0 63:23
|
||||
Res0 63:25
|
||||
Field 24 PACMEn
|
||||
Field 23 EnFPM
|
||||
Field 22 GCSEn
|
||||
Field 21 EnIDCP128
|
||||
Field 20 EnSDERR
|
||||
@@ -2348,6 +2583,14 @@ Sysreg SMCR_EL2 3 4 1 2 6
|
||||
Fields SMCR_ELx
|
||||
EndSysreg
|
||||
|
||||
Sysreg GCSCR_EL2 3 4 2 5 0
|
||||
Fields GCSCR_ELx
|
||||
EndSysreg
|
||||
|
||||
Sysreg GCSPR_EL2 3 4 2 5 1
|
||||
Fields GCSPR_ELx
|
||||
EndSysreg
|
||||
|
||||
Sysreg DACR32_EL2 3 4 3 0 0
|
||||
Res0 63:32
|
||||
Field 31:30 D15
|
||||
@@ -2407,6 +2650,14 @@ Sysreg SMCR_EL12 3 5 1 2 6
|
||||
Fields SMCR_ELx
|
||||
EndSysreg
|
||||
|
||||
Sysreg GCSCR_EL12 3 5 2 5 0
|
||||
Fields GCSCR_ELx
|
||||
EndSysreg
|
||||
|
||||
Sysreg GCSPR_EL12 3 5 2 5 1
|
||||
Fields GCSPR_ELx
|
||||
EndSysreg
|
||||
|
||||
Sysreg FAR_EL12 3 5 6 0 0
|
||||
Field 63:0 ADDR
|
||||
EndSysreg
|
||||
@@ -2471,6 +2722,33 @@ Field 1 PIE
|
||||
Field 0 PnCH
|
||||
EndSysreg
|
||||
|
||||
SysregFields MAIR2_ELx
|
||||
Field 63:56 Attr7
|
||||
Field 55:48 Attr6
|
||||
Field 47:40 Attr5
|
||||
Field 39:32 Attr4
|
||||
Field 31:24 Attr3
|
||||
Field 23:16 Attr2
|
||||
Field 15:8 Attr1
|
||||
Field 7:0 Attr0
|
||||
EndSysregFields
|
||||
|
||||
Sysreg MAIR2_EL1 3 0 10 2 1
|
||||
Fields MAIR2_ELx
|
||||
EndSysreg
|
||||
|
||||
Sysreg MAIR2_EL2 3 4 10 1 1
|
||||
Fields MAIR2_ELx
|
||||
EndSysreg
|
||||
|
||||
Sysreg AMAIR2_EL1 3 0 10 3 1
|
||||
Field 63:0 ImpDef
|
||||
EndSysreg
|
||||
|
||||
Sysreg AMAIR2_EL2 3 4 10 3 1
|
||||
Field 63:0 ImpDef
|
||||
EndSysreg
|
||||
|
||||
SysregFields PIRx_ELx
|
||||
Field 63:60 Perm15
|
||||
Field 59:56 Perm14
|
||||
@@ -2510,6 +2788,26 @@ Sysreg PIR_EL2 3 4 10 2 3
|
||||
Fields PIRx_ELx
|
||||
EndSysreg
|
||||
|
||||
Sysreg POR_EL0 3 3 10 2 4
|
||||
Fields PIRx_ELx
|
||||
EndSysreg
|
||||
|
||||
Sysreg POR_EL1 3 0 10 2 4
|
||||
Fields PIRx_ELx
|
||||
EndSysreg
|
||||
|
||||
Sysreg POR_EL12 3 5 10 2 4
|
||||
Fields PIRx_ELx
|
||||
EndSysreg
|
||||
|
||||
Sysreg S2POR_EL1 3 0 10 2 5
|
||||
Fields PIRx_ELx
|
||||
EndSysreg
|
||||
|
||||
Sysreg S2PIR_EL2 3 4 10 2 5
|
||||
Fields PIRx_ELx
|
||||
EndSysreg
|
||||
|
||||
Sysreg LORSA_EL1 3 0 10 4 0
|
||||
Res0 63:52
|
||||
Field 51:16 SA
|
||||
|
||||
@@ -119,8 +119,8 @@ enum {
|
||||
/* Access flag update enable/disable */
|
||||
#define TCR_EL1_HA (1ULL << 39)
|
||||
|
||||
void aarch64_get_supported_page_sizes(uint32_t ipa,
|
||||
bool *ps4k, bool *ps16k, bool *ps64k);
|
||||
void aarch64_get_supported_page_sizes(uint32_t ipa, uint32_t *ipa4k,
|
||||
uint32_t *ipa16k, uint32_t *ipa64k);
|
||||
|
||||
void vm_init_descriptor_tables(struct kvm_vm *vm);
|
||||
void vcpu_init_descriptor_tables(struct kvm_vcpu *vcpu);
|
||||
|
||||
@@ -11,8 +11,8 @@ struct guest_mode {
|
||||
|
||||
extern struct guest_mode guest_modes[NUM_VM_MODES];
|
||||
|
||||
#define guest_mode_append(mode, supported, enabled) ({ \
|
||||
guest_modes[mode] = (struct guest_mode){ supported, enabled }; \
|
||||
#define guest_mode_append(mode, enabled) ({ \
|
||||
guest_modes[mode] = (struct guest_mode){ (enabled), (enabled) }; \
|
||||
})
|
||||
|
||||
void guest_modes_append_default(void);
|
||||
|
||||
@@ -172,6 +172,7 @@ static inline struct userspace_mem_region *vm_get_mem_region(struct kvm_vm *vm,
|
||||
|
||||
enum vm_guest_mode {
|
||||
VM_MODE_P52V48_4K,
|
||||
VM_MODE_P52V48_16K,
|
||||
VM_MODE_P52V48_64K,
|
||||
VM_MODE_P48V48_4K,
|
||||
VM_MODE_P48V48_16K,
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "kvm_util.h"
|
||||
#include "processor.h"
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
#define DEFAULT_ARM64_GUEST_STACK_VADDR_MIN 0xac0000
|
||||
|
||||
@@ -58,13 +59,25 @@ static uint64_t pte_index(struct kvm_vm *vm, vm_vaddr_t gva)
|
||||
return (gva >> vm->page_shift) & mask;
|
||||
}
|
||||
|
||||
static inline bool use_lpa2_pte_format(struct kvm_vm *vm)
|
||||
{
|
||||
return (vm->page_size == SZ_4K || vm->page_size == SZ_16K) &&
|
||||
(vm->pa_bits > 48 || vm->va_bits > 48);
|
||||
}
|
||||
|
||||
static uint64_t addr_pte(struct kvm_vm *vm, uint64_t pa, uint64_t attrs)
|
||||
{
|
||||
uint64_t pte;
|
||||
|
||||
pte = pa & GENMASK(47, vm->page_shift);
|
||||
if (vm->page_shift == 16)
|
||||
pte |= FIELD_GET(GENMASK(51, 48), pa) << 12;
|
||||
if (use_lpa2_pte_format(vm)) {
|
||||
pte = pa & GENMASK(49, vm->page_shift);
|
||||
pte |= FIELD_GET(GENMASK(51, 50), pa) << 8;
|
||||
attrs &= ~GENMASK(9, 8);
|
||||
} else {
|
||||
pte = pa & GENMASK(47, vm->page_shift);
|
||||
if (vm->page_shift == 16)
|
||||
pte |= FIELD_GET(GENMASK(51, 48), pa) << 12;
|
||||
}
|
||||
pte |= attrs;
|
||||
|
||||
return pte;
|
||||
@@ -74,9 +87,14 @@ static uint64_t pte_addr(struct kvm_vm *vm, uint64_t pte)
|
||||
{
|
||||
uint64_t pa;
|
||||
|
||||
pa = pte & GENMASK(47, vm->page_shift);
|
||||
if (vm->page_shift == 16)
|
||||
pa |= FIELD_GET(GENMASK(15, 12), pte) << 48;
|
||||
if (use_lpa2_pte_format(vm)) {
|
||||
pa = pte & GENMASK(49, vm->page_shift);
|
||||
pa |= FIELD_GET(GENMASK(9, 8), pte) << 50;
|
||||
} else {
|
||||
pa = pte & GENMASK(47, vm->page_shift);
|
||||
if (vm->page_shift == 16)
|
||||
pa |= FIELD_GET(GENMASK(15, 12), pte) << 48;
|
||||
}
|
||||
|
||||
return pa;
|
||||
}
|
||||
@@ -266,9 +284,6 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
|
||||
|
||||
/* Configure base granule size */
|
||||
switch (vm->mode) {
|
||||
case VM_MODE_P52V48_4K:
|
||||
TEST_FAIL("AArch64 does not support 4K sized pages "
|
||||
"with 52-bit physical address ranges");
|
||||
case VM_MODE_PXXV48_4K:
|
||||
TEST_FAIL("AArch64 does not support 4K sized pages "
|
||||
"with ANY-bit physical address ranges");
|
||||
@@ -278,12 +293,14 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
|
||||
case VM_MODE_P36V48_64K:
|
||||
tcr_el1 |= 1ul << 14; /* TG0 = 64KB */
|
||||
break;
|
||||
case VM_MODE_P52V48_16K:
|
||||
case VM_MODE_P48V48_16K:
|
||||
case VM_MODE_P40V48_16K:
|
||||
case VM_MODE_P36V48_16K:
|
||||
case VM_MODE_P36V47_16K:
|
||||
tcr_el1 |= 2ul << 14; /* TG0 = 16KB */
|
||||
break;
|
||||
case VM_MODE_P52V48_4K:
|
||||
case VM_MODE_P48V48_4K:
|
||||
case VM_MODE_P40V48_4K:
|
||||
case VM_MODE_P36V48_4K:
|
||||
@@ -297,6 +314,8 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
|
||||
|
||||
/* Configure output size */
|
||||
switch (vm->mode) {
|
||||
case VM_MODE_P52V48_4K:
|
||||
case VM_MODE_P52V48_16K:
|
||||
case VM_MODE_P52V48_64K:
|
||||
tcr_el1 |= 6ul << 32; /* IPS = 52 bits */
|
||||
ttbr0_el1 |= FIELD_GET(GENMASK(51, 48), vm->pgd) << 2;
|
||||
@@ -325,6 +344,8 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
|
||||
/* TCR_EL1 |= IRGN0:WBWA | ORGN0:WBWA | SH0:Inner-Shareable */;
|
||||
tcr_el1 |= (1 << 8) | (1 << 10) | (3 << 12);
|
||||
tcr_el1 |= (64 - vm->va_bits) /* T0SZ */;
|
||||
if (use_lpa2_pte_format(vm))
|
||||
tcr_el1 |= (1ul << 59) /* DS */;
|
||||
|
||||
vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_SCTLR_EL1), sctlr_el1);
|
||||
vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_TCR_EL1), tcr_el1);
|
||||
@@ -492,12 +513,24 @@ uint32_t guest_get_vcpuid(void)
|
||||
return read_sysreg(tpidr_el1);
|
||||
}
|
||||
|
||||
void aarch64_get_supported_page_sizes(uint32_t ipa,
|
||||
bool *ps4k, bool *ps16k, bool *ps64k)
|
||||
static uint32_t max_ipa_for_page_size(uint32_t vm_ipa, uint32_t gran,
|
||||
uint32_t not_sup_val, uint32_t ipa52_min_val)
|
||||
{
|
||||
if (gran == not_sup_val)
|
||||
return 0;
|
||||
else if (gran >= ipa52_min_val && vm_ipa >= 52)
|
||||
return 52;
|
||||
else
|
||||
return min(vm_ipa, 48U);
|
||||
}
|
||||
|
||||
void aarch64_get_supported_page_sizes(uint32_t ipa, uint32_t *ipa4k,
|
||||
uint32_t *ipa16k, uint32_t *ipa64k)
|
||||
{
|
||||
struct kvm_vcpu_init preferred_init;
|
||||
int kvm_fd, vm_fd, vcpu_fd, err;
|
||||
uint64_t val;
|
||||
uint32_t gran;
|
||||
struct kvm_one_reg reg = {
|
||||
.id = KVM_ARM64_SYS_REG(SYS_ID_AA64MMFR0_EL1),
|
||||
.addr = (uint64_t)&val,
|
||||
@@ -518,9 +551,17 @@ void aarch64_get_supported_page_sizes(uint32_t ipa,
|
||||
err = ioctl(vcpu_fd, KVM_GET_ONE_REG, ®);
|
||||
TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_GET_ONE_REG, vcpu_fd));
|
||||
|
||||
*ps4k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN4), val) != 0xf;
|
||||
*ps64k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN64), val) == 0;
|
||||
*ps16k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN16), val) != 0;
|
||||
gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN4), val);
|
||||
*ipa4k = max_ipa_for_page_size(ipa, gran, ID_AA64MMFR0_EL1_TGRAN4_NI,
|
||||
ID_AA64MMFR0_EL1_TGRAN4_52_BIT);
|
||||
|
||||
gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN64), val);
|
||||
*ipa64k = max_ipa_for_page_size(ipa, gran, ID_AA64MMFR0_EL1_TGRAN64_NI,
|
||||
ID_AA64MMFR0_EL1_TGRAN64_IMP);
|
||||
|
||||
gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN16), val);
|
||||
*ipa16k = max_ipa_for_page_size(ipa, gran, ID_AA64MMFR0_EL1_TGRAN16_NI,
|
||||
ID_AA64MMFR0_EL1_TGRAN16_52_BIT);
|
||||
|
||||
close(vcpu_fd);
|
||||
close(vm_fd);
|
||||
|
||||
@@ -14,37 +14,33 @@ struct guest_mode guest_modes[NUM_VM_MODES];
|
||||
void guest_modes_append_default(void)
|
||||
{
|
||||
#ifndef __aarch64__
|
||||
guest_mode_append(VM_MODE_DEFAULT, true, true);
|
||||
guest_mode_append(VM_MODE_DEFAULT, true);
|
||||
#else
|
||||
{
|
||||
unsigned int limit = kvm_check_cap(KVM_CAP_ARM_VM_IPA_SIZE);
|
||||
bool ps4k, ps16k, ps64k;
|
||||
uint32_t ipa4k, ipa16k, ipa64k;
|
||||
int i;
|
||||
|
||||
aarch64_get_supported_page_sizes(limit, &ps4k, &ps16k, &ps64k);
|
||||
aarch64_get_supported_page_sizes(limit, &ipa4k, &ipa16k, &ipa64k);
|
||||
|
||||
vm_mode_default = NUM_VM_MODES;
|
||||
guest_mode_append(VM_MODE_P52V48_4K, ipa4k >= 52);
|
||||
guest_mode_append(VM_MODE_P52V48_16K, ipa16k >= 52);
|
||||
guest_mode_append(VM_MODE_P52V48_64K, ipa64k >= 52);
|
||||
|
||||
if (limit >= 52)
|
||||
guest_mode_append(VM_MODE_P52V48_64K, ps64k, ps64k);
|
||||
if (limit >= 48) {
|
||||
guest_mode_append(VM_MODE_P48V48_4K, ps4k, ps4k);
|
||||
guest_mode_append(VM_MODE_P48V48_16K, ps16k, ps16k);
|
||||
guest_mode_append(VM_MODE_P48V48_64K, ps64k, ps64k);
|
||||
}
|
||||
if (limit >= 40) {
|
||||
guest_mode_append(VM_MODE_P40V48_4K, ps4k, ps4k);
|
||||
guest_mode_append(VM_MODE_P40V48_16K, ps16k, ps16k);
|
||||
guest_mode_append(VM_MODE_P40V48_64K, ps64k, ps64k);
|
||||
if (ps4k)
|
||||
vm_mode_default = VM_MODE_P40V48_4K;
|
||||
}
|
||||
if (limit >= 36) {
|
||||
guest_mode_append(VM_MODE_P36V48_4K, ps4k, ps4k);
|
||||
guest_mode_append(VM_MODE_P36V48_16K, ps16k, ps16k);
|
||||
guest_mode_append(VM_MODE_P36V48_64K, ps64k, ps64k);
|
||||
guest_mode_append(VM_MODE_P36V47_16K, ps16k, ps16k);
|
||||
}
|
||||
guest_mode_append(VM_MODE_P48V48_4K, ipa4k >= 48);
|
||||
guest_mode_append(VM_MODE_P48V48_16K, ipa16k >= 48);
|
||||
guest_mode_append(VM_MODE_P48V48_64K, ipa64k >= 48);
|
||||
|
||||
guest_mode_append(VM_MODE_P40V48_4K, ipa4k >= 40);
|
||||
guest_mode_append(VM_MODE_P40V48_16K, ipa16k >= 40);
|
||||
guest_mode_append(VM_MODE_P40V48_64K, ipa64k >= 40);
|
||||
|
||||
guest_mode_append(VM_MODE_P36V48_4K, ipa4k >= 36);
|
||||
guest_mode_append(VM_MODE_P36V48_16K, ipa16k >= 36);
|
||||
guest_mode_append(VM_MODE_P36V48_64K, ipa64k >= 36);
|
||||
guest_mode_append(VM_MODE_P36V47_16K, ipa16k >= 36);
|
||||
|
||||
vm_mode_default = ipa4k >= 40 ? VM_MODE_P40V48_4K : NUM_VM_MODES;
|
||||
|
||||
/*
|
||||
* Pick the first supported IPA size if the default
|
||||
@@ -72,7 +68,7 @@ void guest_modes_append_default(void)
|
||||
close(kvm_fd);
|
||||
/* Starting with z13 we have 47bits of physical address */
|
||||
if (info.ibc >= 0x30)
|
||||
guest_mode_append(VM_MODE_P47V64_4K, true, true);
|
||||
guest_mode_append(VM_MODE_P47V64_4K, true);
|
||||
}
|
||||
#endif
|
||||
#ifdef __riscv
|
||||
@@ -80,9 +76,9 @@ void guest_modes_append_default(void)
|
||||
unsigned int sz = kvm_check_cap(KVM_CAP_VM_GPA_BITS);
|
||||
|
||||
if (sz >= 52)
|
||||
guest_mode_append(VM_MODE_P52V48_4K, true, true);
|
||||
guest_mode_append(VM_MODE_P52V48_4K, true);
|
||||
if (sz >= 48)
|
||||
guest_mode_append(VM_MODE_P48V48_4K, true, true);
|
||||
guest_mode_append(VM_MODE_P48V48_4K, true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -148,6 +148,7 @@ const char *vm_guest_mode_string(uint32_t i)
|
||||
{
|
||||
static const char * const strings[] = {
|
||||
[VM_MODE_P52V48_4K] = "PA-bits:52, VA-bits:48, 4K pages",
|
||||
[VM_MODE_P52V48_16K] = "PA-bits:52, VA-bits:48, 16K pages",
|
||||
[VM_MODE_P52V48_64K] = "PA-bits:52, VA-bits:48, 64K pages",
|
||||
[VM_MODE_P48V48_4K] = "PA-bits:48, VA-bits:48, 4K pages",
|
||||
[VM_MODE_P48V48_16K] = "PA-bits:48, VA-bits:48, 16K pages",
|
||||
@@ -173,6 +174,7 @@ const char *vm_guest_mode_string(uint32_t i)
|
||||
|
||||
const struct vm_guest_mode_params vm_guest_mode_params[] = {
|
||||
[VM_MODE_P52V48_4K] = { 52, 48, 0x1000, 12 },
|
||||
[VM_MODE_P52V48_16K] = { 52, 48, 0x4000, 14 },
|
||||
[VM_MODE_P52V48_64K] = { 52, 48, 0x10000, 16 },
|
||||
[VM_MODE_P48V48_4K] = { 48, 48, 0x1000, 12 },
|
||||
[VM_MODE_P48V48_16K] = { 48, 48, 0x4000, 14 },
|
||||
@@ -251,6 +253,7 @@ struct kvm_vm *____vm_create(struct vm_shape shape)
|
||||
case VM_MODE_P36V48_64K:
|
||||
vm->pgtable_levels = 3;
|
||||
break;
|
||||
case VM_MODE_P52V48_16K:
|
||||
case VM_MODE_P48V48_16K:
|
||||
case VM_MODE_P40V48_16K:
|
||||
case VM_MODE_P36V48_16K:
|
||||
|
||||
Reference in New Issue
Block a user