mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-10 13:28:57 -04:00
KVM: arm64: Add a helper providing an inlined literal value for ICH_VTR_EL2
We already have two ways to deal with ICH_VTR_EL2: - directly read the system register - read a cached copy in the vgic global state Add a third way, in the form of an inlined literal value that will eventually replace all of the above. This literal value is computed at boot time, and patched in the relevant code locations. Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://patch.msgid.link/20260721170754.3150521-4-maz@kernel.org Signed-off-by: Oliver Upton <oupton@kernel.org>
This commit is contained in:
committed by
Oliver Upton
parent
27a263e1a0
commit
4edfdc8dde
@@ -92,6 +92,7 @@ KVM_NVHE_ALIAS(spectre_bhb_patch_wa3);
|
||||
KVM_NVHE_ALIAS(spectre_bhb_patch_clearbhb);
|
||||
KVM_NVHE_ALIAS(alt_cb_patch_nops);
|
||||
KVM_NVHE_ALIAS(kvm_compute_ich_hcr_trap_bits);
|
||||
KVM_NVHE_ALIAS(kvm_patch_ich_vtr_el2);
|
||||
|
||||
/* Global kernel state accessed by nVHE hyp code. */
|
||||
KVM_NVHE_ALIAS(kvm_vgic_global_state);
|
||||
|
||||
@@ -858,6 +858,61 @@ void noinstr kvm_compute_ich_hcr_trap_bits(struct alt_instr *alt,
|
||||
*updptr = cpu_to_le32(insn);
|
||||
}
|
||||
|
||||
void noinstr kvm_patch_ich_vtr_el2(struct alt_instr *alt,
|
||||
__le32 *origptr, __le32 *updptr,
|
||||
int nr_inst)
|
||||
{
|
||||
struct arm_smccc_res res = {};
|
||||
u32 insn, oinsn, rd, vtr;
|
||||
|
||||
/* No KVM? Nothing to do */
|
||||
if (!is_hyp_mode_available())
|
||||
return;
|
||||
|
||||
/* No v3, compat, nor the fruity erzatz of a GIC? Bugger off */
|
||||
if (!cpus_have_cap(ARM64_HAS_GICV5_LEGACY) &&
|
||||
!cpus_have_cap(ARM64_HAS_GICV3_CPUIF) &&
|
||||
!vgic_v3_broken_seis())
|
||||
return;
|
||||
|
||||
/*
|
||||
* At the point where this is called, we are guaranteed that if
|
||||
* we're running at EL1, then the EL2 stubs are still in place.
|
||||
*/
|
||||
if (is_kernel_in_hyp_mode())
|
||||
res.a1 = read_sysreg_s(SYS_ICH_VTR_EL2);
|
||||
else
|
||||
arm_smccc_1_1_hvc(HVC_GET_ICH_VTR_EL2, &res);
|
||||
|
||||
if (res.a0 == HVC_STUB_ERR)
|
||||
return;
|
||||
|
||||
vtr = res.a1;
|
||||
|
||||
if (vgic_v3_broken_seis())
|
||||
vtr &= ~ICH_VTR_EL2_SEIS;
|
||||
|
||||
/* Compute target register */
|
||||
oinsn = le32_to_cpu(*origptr);
|
||||
rd = aarch64_insn_decode_register(AARCH64_INSN_REGTYPE_RD, oinsn);
|
||||
|
||||
/* movz rd, #(vtr & 0xffff) */
|
||||
insn = aarch64_insn_gen_movewide(rd,
|
||||
(u16)vtr,
|
||||
0,
|
||||
AARCH64_INSN_VARIANT_64BIT,
|
||||
AARCH64_INSN_MOVEWIDE_ZERO);
|
||||
*updptr++ = cpu_to_le32(insn);
|
||||
|
||||
/* movk rd, #((vtr >> 16) & 0xffff), lsl #16 */
|
||||
insn = aarch64_insn_gen_movewide(rd,
|
||||
(u16)(vtr >> 16),
|
||||
16,
|
||||
AARCH64_INSN_VARIANT_64BIT,
|
||||
AARCH64_INSN_MOVEWIDE_KEEP);
|
||||
*updptr++ = cpu_to_le32(insn);
|
||||
}
|
||||
|
||||
void vgic_v3_enable_cpuif_traps(void)
|
||||
{
|
||||
u64 traps = vgic_ich_hcr_trap_bits();
|
||||
|
||||
@@ -71,6 +71,23 @@
|
||||
ICH_VTR_EL2_IDbits)
|
||||
#define KVM_ICH_VTR_EL2_RES1 ICH_VTR_EL2_nV4
|
||||
|
||||
void kvm_patch_ich_vtr_el2(struct alt_instr *alt,
|
||||
__le32 *origptr, __le32 *updptr, int nr_inst);
|
||||
|
||||
static inline u64 vgic_ich_vtr(void)
|
||||
{
|
||||
u64 vtr;
|
||||
|
||||
/* All non-RES0 bits are in the bottom 32bits */
|
||||
asm volatile(ALTERNATIVE_CB("movz %0, #0\n"
|
||||
"movk %0, #0, lsl #16\n",
|
||||
ARM64_ALWAYS_SYSTEM,
|
||||
kvm_patch_ich_vtr_el2)
|
||||
: "=r" (vtr));
|
||||
|
||||
return vtr;
|
||||
}
|
||||
|
||||
static inline u64 kvm_get_guest_vtr_el2(void)
|
||||
{
|
||||
u64 vtr;
|
||||
|
||||
Reference in New Issue
Block a user