mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-29 22:02:02 +00:00
Merge branch kvm-arm64/hvhe into kvmarm/next
* kvm-arm64/hvhe: : Support for running split-hypervisor w/VHE, courtesy of Marc Zyngier : : From the cover letter: : : KVM (on ARMv8.0) and pKVM (on all revisions of the architecture) use : the split hypervisor model that makes the EL2 code more or less : standalone. In the later case, we totally ignore the VHE mode and : stick with the good old v8.0 EL2 setup. : : We introduce a new "mode" for KVM called hVHE, in reference to the : nVHE mode, and indicating that only the hypervisor is using VHE. KVM: arm64: Fix hVHE init on CPUs where HCR_EL2.E2H is not RES1 arm64: Allow arm64_sw.hvhe on command line KVM: arm64: Force HCR_E2H in guest context when ARM64_KVM_HVHE is set KVM: arm64: Program the timer traps with VHE layout in hVHE mode KVM: arm64: Rework CPTR_EL2 programming for HVHE configuration KVM: arm64: Adjust EL2 stage-1 leaf AP bits when ARM64_KVM_HVHE is set KVM: arm64: Disable TTBR1_EL2 when using ARM64_KVM_HVHE KVM: arm64: Force HCR_EL2.E2H when ARM64_KVM_HVHE is set KVM: arm64: Key use of VHE instructions in nVHE code off ARM64_KVM_HVHE KVM: arm64: Remove alternatives from sysreg accessors in VHE hypervisor context arm64: Use CPACR_EL1 format to set CPTR_EL2 when E2H is set arm64: Allow EL1 physical timer access when running VHE arm64: Don't enable VHE for the kernel if OVERRIDE_HVHE is set arm64: Add KVM_HVHE capability and has_hvhe() predicate arm64: Turn kaslr_feature_override into a generic SW feature override arm64: Prevent the use of is_kernel_in_hyp_mode() in hypervisor code KVM: arm64: Drop is_kernel_in_hyp_mode() from __invalidate_icache_guest_page() Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
This commit is contained in:
commit
b710fe0d30
24 changed files with 245 additions and 66 deletions
|
@ -15,6 +15,9 @@
|
|||
#define MAX_CPU_FEATURES 128
|
||||
#define cpu_feature(x) KERNEL_HWCAP_ ## x
|
||||
|
||||
#define ARM64_SW_FEATURE_OVERRIDE_NOKASLR 0
|
||||
#define ARM64_SW_FEATURE_OVERRIDE_HVHE 4
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <linux/bug.h>
|
||||
|
@ -925,6 +928,8 @@ extern struct arm64_ftr_override id_aa64smfr0_override;
|
|||
extern struct arm64_ftr_override id_aa64isar1_override;
|
||||
extern struct arm64_ftr_override id_aa64isar2_override;
|
||||
|
||||
extern struct arm64_ftr_override arm64_sw_feature_override;
|
||||
|
||||
u32 get_kvm_ipa_limit(void);
|
||||
void dump_cpu_features(void);
|
||||
|
||||
|
|
|
@ -34,6 +34,11 @@
|
|||
*/
|
||||
.macro __init_el2_timers
|
||||
mov x0, #3 // Enable EL1 physical timers
|
||||
mrs x1, hcr_el2
|
||||
and x1, x1, #HCR_E2H
|
||||
cbz x1, .LnVHE_\@
|
||||
lsl x0, x0, #10
|
||||
.LnVHE_\@:
|
||||
msr cnthctl_el2, x0
|
||||
msr cntvoff_el2, xzr // Clear virtual offset
|
||||
.endm
|
||||
|
@ -124,8 +129,15 @@
|
|||
.endm
|
||||
|
||||
/* Coprocessor traps */
|
||||
.macro __init_el2_nvhe_cptr
|
||||
.macro __init_el2_cptr
|
||||
mrs x1, hcr_el2
|
||||
and x1, x1, #HCR_E2H
|
||||
cbz x1, .LnVHE_\@
|
||||
mov x0, #(CPACR_EL1_FPEN_EL1EN | CPACR_EL1_FPEN_EL0EN)
|
||||
b .Lset_cptr_\@
|
||||
.LnVHE_\@:
|
||||
mov x0, #0x33ff
|
||||
.Lset_cptr_\@:
|
||||
msr cptr_el2, x0 // Disable copro. traps to EL2
|
||||
.endm
|
||||
|
||||
|
@ -191,9 +203,8 @@
|
|||
__init_el2_gicv3
|
||||
__init_el2_hstr
|
||||
__init_el2_nvhe_idregs
|
||||
__init_el2_nvhe_cptr
|
||||
__init_el2_cptr
|
||||
__init_el2_fgt
|
||||
__init_el2_nvhe_prepare_eret
|
||||
.endm
|
||||
|
||||
#ifndef __KVM_NVHE_HYPERVISOR__
|
||||
|
@ -239,7 +250,17 @@
|
|||
|
||||
.Linit_sve_\@: /* SVE register access */
|
||||
mrs x0, cptr_el2 // Disable SVE traps
|
||||
mrs x1, hcr_el2
|
||||
and x1, x1, #HCR_E2H
|
||||
cbz x1, .Lcptr_nvhe_\@
|
||||
|
||||
// VHE case
|
||||
orr x0, x0, #(CPACR_EL1_ZEN_EL1EN | CPACR_EL1_ZEN_EL0EN)
|
||||
b .Lset_cptr_\@
|
||||
|
||||
.Lcptr_nvhe_\@: // nVHE case
|
||||
bic x0, x0, #CPTR_EL2_TZ
|
||||
.Lset_cptr_\@:
|
||||
msr cptr_el2, x0
|
||||
isb
|
||||
mov x1, #ZCR_ELx_LEN_MASK // SVE: Enable full vector
|
||||
|
|
|
@ -285,7 +285,6 @@
|
|||
#define CPTR_EL2_TFP (1 << CPTR_EL2_TFP_SHIFT)
|
||||
#define CPTR_EL2_TZ (1 << 8)
|
||||
#define CPTR_NVHE_EL2_RES1 0x000032ff /* known RES1 bits in CPTR_EL2 (nVHE) */
|
||||
#define CPTR_EL2_DEFAULT CPTR_NVHE_EL2_RES1
|
||||
#define CPTR_NVHE_EL2_RES0 (GENMASK(63, 32) | \
|
||||
GENMASK(29, 21) | \
|
||||
GENMASK(19, 14) | \
|
||||
|
@ -347,8 +346,7 @@
|
|||
ECN(SOFTSTP_CUR), ECN(WATCHPT_LOW), ECN(WATCHPT_CUR), \
|
||||
ECN(BKPT32), ECN(VECTOR32), ECN(BRK64), ECN(ERET)
|
||||
|
||||
#define CPACR_EL1_DEFAULT (CPACR_EL1_FPEN_EL0EN | CPACR_EL1_FPEN_EL1EN |\
|
||||
CPACR_EL1_ZEN_EL1EN)
|
||||
#define CPACR_EL1_TTA (1 << 28)
|
||||
|
||||
#define kvm_mode_names \
|
||||
{ PSR_MODE_EL0t, "EL0t" }, \
|
||||
|
|
|
@ -74,7 +74,7 @@ static __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
|
|||
static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
|
||||
if (is_kernel_in_hyp_mode())
|
||||
if (has_vhe() || has_hvhe())
|
||||
vcpu->arch.hcr_el2 |= HCR_E2H;
|
||||
if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN)) {
|
||||
/* route synchronous external abort exceptions to EL2 */
|
||||
|
@ -570,4 +570,35 @@ static inline bool vcpu_has_feature(struct kvm_vcpu *vcpu, int feature)
|
|||
return test_bit(feature, vcpu->arch.features);
|
||||
}
|
||||
|
||||
static __always_inline u64 kvm_get_reset_cptr_el2(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 val;
|
||||
|
||||
if (has_vhe()) {
|
||||
val = (CPACR_EL1_FPEN_EL0EN | CPACR_EL1_FPEN_EL1EN |
|
||||
CPACR_EL1_ZEN_EL1EN);
|
||||
} else if (has_hvhe()) {
|
||||
val = (CPACR_EL1_FPEN_EL0EN | CPACR_EL1_FPEN_EL1EN);
|
||||
} else {
|
||||
val = CPTR_NVHE_EL2_RES1;
|
||||
|
||||
if (vcpu_has_sve(vcpu) &&
|
||||
(vcpu->arch.fp_state == FP_STATE_GUEST_OWNED))
|
||||
val |= CPTR_EL2_TZ;
|
||||
if (cpus_have_final_cap(ARM64_SME))
|
||||
val &= ~CPTR_EL2_TSM;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static __always_inline void kvm_reset_cptr_el2(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 val = kvm_get_reset_cptr_el2(vcpu);
|
||||
|
||||
if (has_vhe() || has_hvhe())
|
||||
write_sysreg(val, cpacr_el1);
|
||||
else
|
||||
write_sysreg(val, cptr_el2);
|
||||
}
|
||||
#endif /* __ARM64_KVM_EMULATE_H__ */
|
||||
|
|
|
@ -16,12 +16,35 @@ DECLARE_PER_CPU(struct kvm_cpu_context, kvm_hyp_ctxt);
|
|||
DECLARE_PER_CPU(unsigned long, kvm_hyp_vector);
|
||||
DECLARE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params);
|
||||
|
||||
/*
|
||||
* Unified accessors for registers that have a different encoding
|
||||
* between VHE and non-VHE. They must be specified without their "ELx"
|
||||
* encoding, but with the SYS_ prefix, as defined in asm/sysreg.h.
|
||||
*/
|
||||
|
||||
#if defined(__KVM_VHE_HYPERVISOR__)
|
||||
|
||||
#define read_sysreg_el0(r) read_sysreg_s(r##_EL02)
|
||||
#define write_sysreg_el0(v,r) write_sysreg_s(v, r##_EL02)
|
||||
#define read_sysreg_el1(r) read_sysreg_s(r##_EL12)
|
||||
#define write_sysreg_el1(v,r) write_sysreg_s(v, r##_EL12)
|
||||
#define read_sysreg_el2(r) read_sysreg_s(r##_EL1)
|
||||
#define write_sysreg_el2(v,r) write_sysreg_s(v, r##_EL1)
|
||||
|
||||
#else // !__KVM_VHE_HYPERVISOR__
|
||||
|
||||
#if defined(__KVM_NVHE_HYPERVISOR__)
|
||||
#define VHE_ALT_KEY ARM64_KVM_HVHE
|
||||
#else
|
||||
#define VHE_ALT_KEY ARM64_HAS_VIRT_HOST_EXTN
|
||||
#endif
|
||||
|
||||
#define read_sysreg_elx(r,nvh,vh) \
|
||||
({ \
|
||||
u64 reg; \
|
||||
asm volatile(ALTERNATIVE(__mrs_s("%0", r##nvh), \
|
||||
asm volatile(ALTERNATIVE(__mrs_s("%0", r##nvh), \
|
||||
__mrs_s("%0", r##vh), \
|
||||
ARM64_HAS_VIRT_HOST_EXTN) \
|
||||
VHE_ALT_KEY) \
|
||||
: "=r" (reg)); \
|
||||
reg; \
|
||||
})
|
||||
|
@ -31,16 +54,10 @@ DECLARE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params);
|
|||
u64 __val = (u64)(v); \
|
||||
asm volatile(ALTERNATIVE(__msr_s(r##nvh, "%x0"), \
|
||||
__msr_s(r##vh, "%x0"), \
|
||||
ARM64_HAS_VIRT_HOST_EXTN) \
|
||||
VHE_ALT_KEY) \
|
||||
: : "rZ" (__val)); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Unified accessors for registers that have a different encoding
|
||||
* between VHE and non-VHE. They must be specified without their "ELx"
|
||||
* encoding, but with the SYS_ prefix, as defined in asm/sysreg.h.
|
||||
*/
|
||||
|
||||
#define read_sysreg_el0(r) read_sysreg_elx(r, _EL0, _EL02)
|
||||
#define write_sysreg_el0(v,r) write_sysreg_elx(v, r, _EL0, _EL02)
|
||||
#define read_sysreg_el1(r) read_sysreg_elx(r, _EL1, _EL12)
|
||||
|
@ -48,6 +65,8 @@ DECLARE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params);
|
|||
#define read_sysreg_el2(r) read_sysreg_elx(r, _EL2, _EL1)
|
||||
#define write_sysreg_el2(v,r) write_sysreg_elx(v, r, _EL2, _EL1)
|
||||
|
||||
#endif // __KVM_VHE_HYPERVISOR__
|
||||
|
||||
/*
|
||||
* Without an __arch_swab32(), we fall back to ___constant_swab32(), but the
|
||||
* static inline can allow the compiler to out-of-line this. KVM always wants
|
||||
|
|
|
@ -228,7 +228,8 @@ static inline void __invalidate_icache_guest_page(void *va, size_t size)
|
|||
if (icache_is_aliasing()) {
|
||||
/* any kind of VIPT cache */
|
||||
icache_inval_all_pou();
|
||||
} else if (is_kernel_in_hyp_mode() || !icache_is_vpipt()) {
|
||||
} else if (read_sysreg(CurrentEL) != CurrentEL_EL1 ||
|
||||
!icache_is_vpipt()) {
|
||||
/* PIPT or VPIPT at EL2 (see comment in __kvm_tlb_flush_vmid_ipa) */
|
||||
icache_inval_pou((unsigned long)va, (unsigned long)va + size);
|
||||
}
|
||||
|
|
|
@ -110,8 +110,10 @@ static inline bool is_hyp_mode_mismatched(void)
|
|||
return __boot_cpu_mode[0] != __boot_cpu_mode[1];
|
||||
}
|
||||
|
||||
static inline bool is_kernel_in_hyp_mode(void)
|
||||
static __always_inline bool is_kernel_in_hyp_mode(void)
|
||||
{
|
||||
BUILD_BUG_ON(__is_defined(__KVM_NVHE_HYPERVISOR__) ||
|
||||
__is_defined(__KVM_VHE_HYPERVISOR__));
|
||||
return read_sysreg(CurrentEL) == CurrentEL_EL2;
|
||||
}
|
||||
|
||||
|
@ -140,6 +142,14 @@ static __always_inline bool is_protected_kvm_enabled(void)
|
|||
return cpus_have_final_cap(ARM64_KVM_PROTECTED_MODE);
|
||||
}
|
||||
|
||||
static __always_inline bool has_hvhe(void)
|
||||
{
|
||||
if (is_vhe_hyp_code())
|
||||
return false;
|
||||
|
||||
return cpus_have_final_cap(ARM64_KVM_HVHE);
|
||||
}
|
||||
|
||||
static inline bool is_hyp_nvhe(void)
|
||||
{
|
||||
return is_hyp_mode_available() && !is_kernel_in_hyp_mode();
|
||||
|
|
|
@ -664,6 +664,8 @@ struct arm64_ftr_override __ro_after_init id_aa64smfr0_override;
|
|||
struct arm64_ftr_override __ro_after_init id_aa64isar1_override;
|
||||
struct arm64_ftr_override __ro_after_init id_aa64isar2_override;
|
||||
|
||||
struct arm64_ftr_override arm64_sw_feature_override;
|
||||
|
||||
static const struct __ftr_reg_entry {
|
||||
u32 sys_id;
|
||||
struct arm64_ftr_reg *reg;
|
||||
|
@ -1996,6 +1998,19 @@ static bool has_nested_virt_support(const struct arm64_cpu_capabilities *cap,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool hvhe_possible(const struct arm64_cpu_capabilities *entry,
|
||||
int __unused)
|
||||
{
|
||||
u64 val;
|
||||
|
||||
val = read_sysreg(id_aa64mmfr1_el1);
|
||||
if (!cpuid_feature_extract_unsigned_field(val, ID_AA64MMFR1_EL1_VH_SHIFT))
|
||||
return false;
|
||||
|
||||
val = arm64_sw_feature_override.val & arm64_sw_feature_override.mask;
|
||||
return cpuid_feature_extract_unsigned_field(val, ARM64_SW_FEATURE_OVERRIDE_HVHE);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARM64_PAN
|
||||
static void cpu_enable_pan(const struct arm64_cpu_capabilities *__unused)
|
||||
{
|
||||
|
@ -2641,6 +2656,12 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
|
|||
.cpu_enable = cpu_enable_dit,
|
||||
ARM64_CPUID_FIELDS(ID_AA64PFR0_EL1, DIT, IMP)
|
||||
},
|
||||
{
|
||||
.desc = "VHE for hypervisor only",
|
||||
.capability = ARM64_KVM_HVHE,
|
||||
.type = ARM64_CPUCAP_SYSTEM_FEATURE,
|
||||
.matches = hvhe_possible,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
|
|
|
@ -603,6 +603,8 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
|
|||
msr sctlr_el1, x1
|
||||
mov x2, xzr
|
||||
2:
|
||||
__init_el2_nvhe_prepare_eret
|
||||
|
||||
mov w0, #BOOT_CPU_MODE_EL2
|
||||
orr x0, x0, x2
|
||||
eret
|
||||
|
|
|
@ -82,7 +82,15 @@ SYM_CODE_START_LOCAL(__finalise_el2)
|
|||
tbnz x1, #0, 1f
|
||||
|
||||
// Needs to be VHE capable, obviously
|
||||
check_override id_aa64mmfr1 ID_AA64MMFR1_EL1_VH_SHIFT 2f 1f x1 x2
|
||||
check_override id_aa64mmfr1 ID_AA64MMFR1_EL1_VH_SHIFT 0f 1f x1 x2
|
||||
|
||||
0: // Check whether we only want the hypervisor to run VHE, not the kernel
|
||||
adr_l x1, arm64_sw_feature_override
|
||||
ldr x2, [x1, FTR_OVR_VAL_OFFSET]
|
||||
ldr x1, [x1, FTR_OVR_MASK_OFFSET]
|
||||
and x2, x2, x1
|
||||
ubfx x2, x2, #ARM64_SW_FEATURE_OVERRIDE_HVHE, #4
|
||||
cbz x2, 2f
|
||||
|
||||
1: mov_q x0, HVC_STUB_ERR
|
||||
eret
|
||||
|
|
|
@ -138,15 +138,22 @@ static const struct ftr_set_desc smfr0 __initconst = {
|
|||
},
|
||||
};
|
||||
|
||||
extern struct arm64_ftr_override kaslr_feature_override;
|
||||
static bool __init hvhe_filter(u64 val)
|
||||
{
|
||||
u64 mmfr1 = read_sysreg(id_aa64mmfr1_el1);
|
||||
|
||||
static const struct ftr_set_desc kaslr __initconst = {
|
||||
.name = "kaslr",
|
||||
#ifdef CONFIG_RANDOMIZE_BASE
|
||||
.override = &kaslr_feature_override,
|
||||
#endif
|
||||
return (val == 1 &&
|
||||
lower_32_bits(__boot_status) == BOOT_CPU_MODE_EL2 &&
|
||||
cpuid_feature_extract_unsigned_field(mmfr1,
|
||||
ID_AA64MMFR1_EL1_VH_SHIFT));
|
||||
}
|
||||
|
||||
static const struct ftr_set_desc sw_features __initconst = {
|
||||
.name = "arm64_sw",
|
||||
.override = &arm64_sw_feature_override,
|
||||
.fields = {
|
||||
FIELD("disabled", 0, NULL),
|
||||
FIELD("nokaslr", ARM64_SW_FEATURE_OVERRIDE_NOKASLR, NULL),
|
||||
FIELD("hvhe", ARM64_SW_FEATURE_OVERRIDE_HVHE, hvhe_filter),
|
||||
{}
|
||||
},
|
||||
};
|
||||
|
@ -158,7 +165,7 @@ static const struct ftr_set_desc * const regs[] __initconst = {
|
|||
&isar1,
|
||||
&isar2,
|
||||
&smfr0,
|
||||
&kaslr,
|
||||
&sw_features,
|
||||
};
|
||||
|
||||
static const struct {
|
||||
|
@ -175,7 +182,7 @@ static const struct {
|
|||
"id_aa64isar1.api=0 id_aa64isar1.apa=0 "
|
||||
"id_aa64isar2.gpa3=0 id_aa64isar2.apa3=0" },
|
||||
{ "arm64.nomte", "id_aa64pfr1.mte=0" },
|
||||
{ "nokaslr", "kaslr.disabled=1" },
|
||||
{ "nokaslr", "arm64_sw.nokaslr=1" },
|
||||
};
|
||||
|
||||
static int __init parse_nokaslr(char *unused)
|
||||
|
|
|
@ -23,8 +23,6 @@
|
|||
u64 __ro_after_init module_alloc_base;
|
||||
u16 __initdata memstart_offset_seed;
|
||||
|
||||
struct arm64_ftr_override kaslr_feature_override __initdata;
|
||||
|
||||
static int __init kaslr_init(void)
|
||||
{
|
||||
u64 module_range;
|
||||
|
@ -36,7 +34,9 @@ static int __init kaslr_init(void)
|
|||
*/
|
||||
module_alloc_base = (u64)_etext - MODULES_VSIZE;
|
||||
|
||||
if (kaslr_feature_override.val & kaslr_feature_override.mask & 0xf) {
|
||||
if (cpuid_feature_extract_unsigned_field(arm64_sw_feature_override.val &
|
||||
arm64_sw_feature_override.mask,
|
||||
ARM64_SW_FEATURE_OVERRIDE_NOKASLR)) {
|
||||
pr_info("KASLR disabled on command line\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1268,7 +1268,7 @@ static int kvm_arch_vcpu_ioctl_vcpu_init(struct kvm_vcpu *vcpu,
|
|||
}
|
||||
|
||||
vcpu_reset_hcr(vcpu);
|
||||
vcpu->arch.cptr_el2 = CPTR_EL2_DEFAULT;
|
||||
vcpu->arch.cptr_el2 = kvm_get_reset_cptr_el2(vcpu);
|
||||
|
||||
/*
|
||||
* Handle the "start in power-off" case.
|
||||
|
@ -1694,7 +1694,13 @@ static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits)
|
|||
|
||||
params->mair_el2 = read_sysreg(mair_el1);
|
||||
|
||||
tcr = (read_sysreg(tcr_el1) & TCR_EL2_MASK) | TCR_EL2_RES1;
|
||||
tcr = read_sysreg(tcr_el1);
|
||||
if (cpus_have_final_cap(ARM64_KVM_HVHE)) {
|
||||
tcr |= TCR_EPD1_MASK;
|
||||
} else {
|
||||
tcr &= TCR_EL2_MASK;
|
||||
tcr |= TCR_EL2_RES1;
|
||||
}
|
||||
tcr &= ~TCR_T0SZ_MASK;
|
||||
tcr |= TCR_T0SZ(hyp_va_bits);
|
||||
params->tcr_el2 = tcr;
|
||||
|
@ -1704,6 +1710,8 @@ static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits)
|
|||
params->hcr_el2 = HCR_HOST_NVHE_PROTECTED_FLAGS;
|
||||
else
|
||||
params->hcr_el2 = HCR_HOST_NVHE_FLAGS;
|
||||
if (cpus_have_final_cap(ARM64_KVM_HVHE))
|
||||
params->hcr_el2 |= HCR_E2H;
|
||||
params->vttbr = params->vtcr = 0;
|
||||
|
||||
/*
|
||||
|
|
|
@ -180,7 +180,7 @@ void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
|
|||
|
||||
/*
|
||||
* If we have VHE then the Hyp code will reset CPACR_EL1 to
|
||||
* CPACR_EL1_DEFAULT and we need to reenable SME.
|
||||
* the default value and we need to reenable SME.
|
||||
*/
|
||||
if (has_vhe() && system_supports_sme()) {
|
||||
/* Also restore EL0 state seen on entry */
|
||||
|
@ -210,7 +210,7 @@ void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
|
|||
/*
|
||||
* The FPSIMD/SVE state in the CPU has not been touched, and we
|
||||
* have SVE (and VHE): CPACR_EL1 (alias CPTR_EL2) has been
|
||||
* reset to CPACR_EL1_DEFAULT by the Hyp code, disabling SVE
|
||||
* reset by kvm_reset_cptr_el2() in the Hyp code, disabling SVE
|
||||
* for EL0. To avoid spurious traps, restore the trap state
|
||||
* seen by kvm_arch_vcpu_load_fp():
|
||||
*/
|
||||
|
|
|
@ -192,7 +192,7 @@ static bool kvm_hyp_handle_fpsimd(struct kvm_vcpu *vcpu, u64 *exit_code)
|
|||
/* Valid trap. Switch the context: */
|
||||
|
||||
/* First disable enough traps to allow us to update the registers */
|
||||
if (has_vhe()) {
|
||||
if (has_vhe() || has_hvhe()) {
|
||||
reg = CPACR_EL1_FPEN_EL0EN | CPACR_EL1_FPEN_EL1EN;
|
||||
if (sve_guest)
|
||||
reg |= CPACR_EL1_ZEN_EL0EN | CPACR_EL1_ZEN_EL1EN;
|
||||
|
|
|
@ -83,9 +83,6 @@ SYM_CODE_END(__kvm_hyp_init)
|
|||
* x0: struct kvm_nvhe_init_params PA
|
||||
*/
|
||||
SYM_CODE_START_LOCAL(___kvm_hyp_init)
|
||||
ldr x1, [x0, #NVHE_INIT_TPIDR_EL2]
|
||||
msr tpidr_el2, x1
|
||||
|
||||
ldr x1, [x0, #NVHE_INIT_STACK_HYP_VA]
|
||||
mov sp, x1
|
||||
|
||||
|
@ -95,6 +92,22 @@ SYM_CODE_START_LOCAL(___kvm_hyp_init)
|
|||
ldr x1, [x0, #NVHE_INIT_HCR_EL2]
|
||||
msr hcr_el2, x1
|
||||
|
||||
mov x2, #HCR_E2H
|
||||
and x2, x1, x2
|
||||
cbz x2, 1f
|
||||
|
||||
// hVHE: Replay the EL2 setup to account for the E2H bit
|
||||
// TPIDR_EL2 is used to preserve x0 across the macro maze...
|
||||
isb
|
||||
msr tpidr_el2, x0
|
||||
init_el2_state
|
||||
finalise_el2_state
|
||||
mrs x0, tpidr_el2
|
||||
|
||||
1:
|
||||
ldr x1, [x0, #NVHE_INIT_TPIDR_EL2]
|
||||
msr tpidr_el2, x1
|
||||
|
||||
ldr x1, [x0, #NVHE_INIT_VTTBR]
|
||||
msr vttbr_el2, x1
|
||||
|
||||
|
@ -184,6 +197,7 @@ SYM_CODE_START_LOCAL(__kvm_hyp_init_cpu)
|
|||
/* Initialize EL2 CPU state to sane values. */
|
||||
init_el2_state // Clobbers x0..x2
|
||||
finalise_el2_state
|
||||
__init_el2_nvhe_prepare_eret
|
||||
|
||||
/* Enable MMU, set vectors and stack. */
|
||||
mov x0, x28
|
||||
|
|
|
@ -405,7 +405,11 @@ void handle_trap(struct kvm_cpu_context *host_ctxt)
|
|||
handle_host_smc(host_ctxt);
|
||||
break;
|
||||
case ESR_ELx_EC_SVE:
|
||||
sysreg_clear_set(cptr_el2, CPTR_EL2_TZ, 0);
|
||||
if (has_hvhe())
|
||||
sysreg_clear_set(cpacr_el1, 0, (CPACR_EL1_ZEN_EL1EN |
|
||||
CPACR_EL1_ZEN_EL0EN));
|
||||
else
|
||||
sysreg_clear_set(cptr_el2, CPTR_EL2_TZ, 0);
|
||||
isb();
|
||||
sve_cond_update_zcr_vq(ZCR_ELx_LEN_MASK, SYS_ZCR_EL2);
|
||||
break;
|
||||
|
|
|
@ -27,6 +27,7 @@ static void pvm_init_traps_aa64pfr0(struct kvm_vcpu *vcpu)
|
|||
u64 hcr_set = HCR_RW;
|
||||
u64 hcr_clear = 0;
|
||||
u64 cptr_set = 0;
|
||||
u64 cptr_clear = 0;
|
||||
|
||||
/* Protected KVM does not support AArch32 guests. */
|
||||
BUILD_BUG_ON(FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_EL0),
|
||||
|
@ -43,6 +44,9 @@ static void pvm_init_traps_aa64pfr0(struct kvm_vcpu *vcpu)
|
|||
BUILD_BUG_ON(!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_AdvSIMD),
|
||||
PVM_ID_AA64PFR0_ALLOW));
|
||||
|
||||
if (has_hvhe())
|
||||
hcr_set |= HCR_E2H;
|
||||
|
||||
/* Trap RAS unless all current versions are supported */
|
||||
if (FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_RAS), feature_ids) <
|
||||
ID_AA64PFR0_EL1_RAS_V1P1) {
|
||||
|
@ -57,12 +61,17 @@ static void pvm_init_traps_aa64pfr0(struct kvm_vcpu *vcpu)
|
|||
}
|
||||
|
||||
/* Trap SVE */
|
||||
if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_SVE), feature_ids))
|
||||
cptr_set |= CPTR_EL2_TZ;
|
||||
if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_SVE), feature_ids)) {
|
||||
if (has_hvhe())
|
||||
cptr_clear |= CPACR_EL1_ZEN_EL0EN | CPACR_EL1_ZEN_EL1EN;
|
||||
else
|
||||
cptr_set |= CPTR_EL2_TZ;
|
||||
}
|
||||
|
||||
vcpu->arch.hcr_el2 |= hcr_set;
|
||||
vcpu->arch.hcr_el2 &= ~hcr_clear;
|
||||
vcpu->arch.cptr_el2 |= cptr_set;
|
||||
vcpu->arch.cptr_el2 &= ~cptr_clear;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -120,8 +129,12 @@ static void pvm_init_traps_aa64dfr0(struct kvm_vcpu *vcpu)
|
|||
mdcr_set |= MDCR_EL2_TTRF;
|
||||
|
||||
/* Trap Trace */
|
||||
if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_TraceVer), feature_ids))
|
||||
cptr_set |= CPTR_EL2_TTA;
|
||||
if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_TraceVer), feature_ids)) {
|
||||
if (has_hvhe())
|
||||
cptr_set |= CPACR_EL1_TTA;
|
||||
else
|
||||
cptr_set |= CPTR_EL2_TTA;
|
||||
}
|
||||
|
||||
vcpu->arch.mdcr_el2 |= mdcr_set;
|
||||
vcpu->arch.mdcr_el2 &= ~mdcr_clear;
|
||||
|
@ -176,8 +189,10 @@ static void pvm_init_trap_regs(struct kvm_vcpu *vcpu)
|
|||
/* Clear res0 and set res1 bits to trap potential new features. */
|
||||
vcpu->arch.hcr_el2 &= ~(HCR_RES0);
|
||||
vcpu->arch.mdcr_el2 &= ~(MDCR_EL2_RES0);
|
||||
vcpu->arch.cptr_el2 |= CPTR_NVHE_EL2_RES1;
|
||||
vcpu->arch.cptr_el2 &= ~(CPTR_NVHE_EL2_RES0);
|
||||
if (!has_hvhe()) {
|
||||
vcpu->arch.cptr_el2 |= CPTR_NVHE_EL2_RES1;
|
||||
vcpu->arch.cptr_el2 &= ~(CPTR_NVHE_EL2_RES0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -44,13 +44,24 @@ static void __activate_traps(struct kvm_vcpu *vcpu)
|
|||
__activate_traps_common(vcpu);
|
||||
|
||||
val = vcpu->arch.cptr_el2;
|
||||
val |= CPTR_EL2_TTA | CPTR_EL2_TAM;
|
||||
val |= CPTR_EL2_TAM; /* Same bit irrespective of E2H */
|
||||
val |= has_hvhe() ? CPACR_EL1_TTA : CPTR_EL2_TTA;
|
||||
if (cpus_have_final_cap(ARM64_SME)) {
|
||||
if (has_hvhe())
|
||||
val &= ~(CPACR_EL1_SMEN_EL1EN | CPACR_EL1_SMEN_EL0EN);
|
||||
else
|
||||
val |= CPTR_EL2_TSM;
|
||||
}
|
||||
|
||||
if (!guest_owns_fp_regs(vcpu)) {
|
||||
val |= CPTR_EL2_TFP | CPTR_EL2_TZ;
|
||||
if (has_hvhe())
|
||||
val &= ~(CPACR_EL1_FPEN_EL0EN | CPACR_EL1_FPEN_EL1EN |
|
||||
CPACR_EL1_ZEN_EL0EN | CPACR_EL1_ZEN_EL1EN);
|
||||
else
|
||||
val |= CPTR_EL2_TFP | CPTR_EL2_TZ;
|
||||
|
||||
__activate_traps_fpsimd32(vcpu);
|
||||
}
|
||||
if (cpus_have_final_cap(ARM64_SME))
|
||||
val |= CPTR_EL2_TSM;
|
||||
|
||||
write_sysreg(val, cptr_el2);
|
||||
write_sysreg(__this_cpu_read(kvm_hyp_vector), vbar_el2);
|
||||
|
@ -73,7 +84,6 @@ static void __activate_traps(struct kvm_vcpu *vcpu)
|
|||
static void __deactivate_traps(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
extern char __kvm_hyp_host_vector[];
|
||||
u64 cptr;
|
||||
|
||||
___deactivate_traps(vcpu);
|
||||
|
||||
|
@ -98,13 +108,7 @@ static void __deactivate_traps(struct kvm_vcpu *vcpu)
|
|||
|
||||
write_sysreg(this_cpu_ptr(&kvm_init_params)->hcr_el2, hcr_el2);
|
||||
|
||||
cptr = CPTR_EL2_DEFAULT;
|
||||
if (vcpu_has_sve(vcpu) && (vcpu->arch.fp_state == FP_STATE_GUEST_OWNED))
|
||||
cptr |= CPTR_EL2_TZ;
|
||||
if (cpus_have_final_cap(ARM64_SME))
|
||||
cptr &= ~CPTR_EL2_TSM;
|
||||
|
||||
write_sysreg(cptr, cptr_el2);
|
||||
kvm_reset_cptr_el2(vcpu);
|
||||
write_sysreg(__kvm_hyp_host_vector, vbar_el2);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,21 +17,24 @@ void __kvm_timer_set_cntvoff(u64 cntvoff)
|
|||
}
|
||||
|
||||
/*
|
||||
* Should only be called on non-VHE systems.
|
||||
* Should only be called on non-VHE or hVHE setups.
|
||||
* VHE systems use EL2 timers and configure EL1 timers in kvm_timer_init_vhe().
|
||||
*/
|
||||
void __timer_disable_traps(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 val;
|
||||
u64 val, shift = 0;
|
||||
|
||||
if (has_hvhe())
|
||||
shift = 10;
|
||||
|
||||
/* Allow physical timer/counter access for the host */
|
||||
val = read_sysreg(cnthctl_el2);
|
||||
val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN;
|
||||
val |= (CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN) << shift;
|
||||
write_sysreg(val, cnthctl_el2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Should only be called on non-VHE systems.
|
||||
* Should only be called on non-VHE or hVHE setups.
|
||||
* VHE systems use EL2 timers and configure EL1 timers in kvm_timer_init_vhe().
|
||||
*/
|
||||
void __timer_enable_traps(struct kvm_vcpu *vcpu)
|
||||
|
@ -50,5 +53,10 @@ void __timer_enable_traps(struct kvm_vcpu *vcpu)
|
|||
else
|
||||
clr |= CNTHCTL_EL1PCTEN;
|
||||
|
||||
if (has_hvhe()) {
|
||||
clr <<= 10;
|
||||
set <<= 10;
|
||||
}
|
||||
|
||||
sysreg_clear_set(cnthctl_el2, clr, set);
|
||||
}
|
||||
|
|
|
@ -21,8 +21,10 @@
|
|||
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_ATTRIDX GENMASK(4, 2)
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_AP GENMASK(7, 6)
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_AP_RO 3
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_AP_RW 1
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_AP_RO \
|
||||
({ cpus_have_final_cap(ARM64_KVM_HVHE) ? 2 : 3; })
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_AP_RW \
|
||||
({ cpus_have_final_cap(ARM64_KVM_HVHE) ? 0 : 1; })
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_SH GENMASK(9, 8)
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_SH_IS 3
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_AF BIT(10)
|
||||
|
|
|
@ -84,7 +84,7 @@ static void __deactivate_traps(struct kvm_vcpu *vcpu)
|
|||
*/
|
||||
asm(ALTERNATIVE("nop", "isb", ARM64_WORKAROUND_SPECULATIVE_AT));
|
||||
|
||||
write_sysreg(CPACR_EL1_DEFAULT, cpacr_el1);
|
||||
kvm_reset_cptr_el2(vcpu);
|
||||
|
||||
if (!arm64_kernel_unmapped_at_el0())
|
||||
host_vectors = __this_cpu_read(this_cpu_vector);
|
||||
|
|
|
@ -2180,7 +2180,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
|||
EL2_REG(ACTLR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(HCR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(MDCR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(CPTR_EL2, access_rw, reset_val, CPTR_EL2_DEFAULT ),
|
||||
EL2_REG(CPTR_EL2, access_rw, reset_val, CPTR_NVHE_EL2_RES1),
|
||||
EL2_REG(HSTR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(HACR_EL2, access_rw, reset_val, 0),
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ HAS_TLB_RANGE
|
|||
HAS_VIRT_HOST_EXTN
|
||||
HAS_WFXT
|
||||
HW_DBM
|
||||
KVM_HVHE
|
||||
KVM_PROTECTED_MODE
|
||||
MISMATCHED_CACHE_TYPE
|
||||
MTE
|
||||
|
|
Loading…
Reference in a new issue