Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: arm64: nv: Filter out unsupported features from ID regs

As there is a number of features that we either can't support,
or don't want to support right away with NV, let's add some
basic filtering so that we don't advertize silly things to the
EL2 guest.

Whilst we are at it, advertize FEAT_TTL as well as FEAT_GTG, which
the NV implementation will implement.

Reviewed-by: Ganapatrao Kulkarni <gankulkarni@os.amperecomputing.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20230209175820.1939006-18-maz@kernel.org
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>

authored by

Marc Zyngier and committed by
Oliver Upton
9f75b6d4 280b748e

+172 -1
+6
arch/arm64/include/asm/kvm_nested.h
··· 11 11 test_bit(KVM_ARM_VCPU_HAS_EL2, vcpu->arch.features)); 12 12 } 13 13 14 + struct sys_reg_params; 15 + struct sys_reg_desc; 16 + 17 + void access_nested_id_reg(struct kvm_vcpu *v, struct sys_reg_params *p, 18 + const struct sys_reg_desc *r); 19 + 14 20 #endif /* __ARM64_KVM_NESTED_H */
+1 -1
arch/arm64/kvm/Makefile
··· 14 14 inject_fault.o va_layout.o handle_exit.o \ 15 15 guest.o debug.o reset.o sys_regs.o stacktrace.o \ 16 16 vgic-sys-reg-v3.o fpsimd.o pkvm.o \ 17 - arch_timer.o trng.o vmid.o emulate-nested.o \ 17 + arch_timer.o trng.o vmid.o emulate-nested.o nested.o \ 18 18 vgic/vgic.o vgic/vgic-init.o \ 19 19 vgic/vgic-irqfd.o vgic/vgic-v2.o \ 20 20 vgic/vgic-v3.o vgic/vgic-v4.o \
+162
arch/arm64/kvm/nested.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (C) 2017 - Columbia University and Linaro Ltd. 4 + * Author: Jintack Lim <jintack.lim@linaro.org> 5 + */ 6 + 7 + #include <linux/kvm.h> 8 + #include <linux/kvm_host.h> 9 + 10 + #include <asm/kvm_emulate.h> 11 + #include <asm/kvm_nested.h> 12 + #include <asm/sysreg.h> 13 + 14 + #include "sys_regs.h" 15 + 16 + /* Protection against the sysreg repainting madness... */ 17 + #define NV_FTR(r, f) ID_AA64##r##_EL1_##f 18 + 19 + /* 20 + * Our emulated CPU doesn't support all the possible features. For the 21 + * sake of simplicity (and probably mental sanity), wipe out a number 22 + * of feature bits we don't intend to support for the time being. 23 + * This list should get updated as new features get added to the NV 24 + * support, and new extension to the architecture. 25 + */ 26 + void access_nested_id_reg(struct kvm_vcpu *v, struct sys_reg_params *p, 27 + const struct sys_reg_desc *r) 28 + { 29 + u32 id = sys_reg((u32)r->Op0, (u32)r->Op1, 30 + (u32)r->CRn, (u32)r->CRm, (u32)r->Op2); 31 + u64 val, tmp; 32 + 33 + val = p->regval; 34 + 35 + switch (id) { 36 + case SYS_ID_AA64ISAR0_EL1: 37 + /* Support everything but TME, O.S. and Range TLBIs */ 38 + val &= ~(NV_FTR(ISAR0, TLB) | 39 + NV_FTR(ISAR0, TME)); 40 + break; 41 + 42 + case SYS_ID_AA64ISAR1_EL1: 43 + /* Support everything but PtrAuth and Spec Invalidation */ 44 + val &= ~(GENMASK_ULL(63, 56) | 45 + NV_FTR(ISAR1, SPECRES) | 46 + NV_FTR(ISAR1, GPI) | 47 + NV_FTR(ISAR1, GPA) | 48 + NV_FTR(ISAR1, API) | 49 + NV_FTR(ISAR1, APA)); 50 + break; 51 + 52 + case SYS_ID_AA64PFR0_EL1: 53 + /* No AMU, MPAM, S-EL2, RAS or SVE */ 54 + val &= ~(GENMASK_ULL(55, 52) | 55 + NV_FTR(PFR0, AMU) | 56 + NV_FTR(PFR0, MPAM) | 57 + NV_FTR(PFR0, SEL2) | 58 + NV_FTR(PFR0, RAS) | 59 + NV_FTR(PFR0, SVE) | 60 + NV_FTR(PFR0, EL3) | 61 + NV_FTR(PFR0, EL2) | 62 + NV_FTR(PFR0, EL1)); 63 + /* 64bit EL1/EL2/EL3 only */ 64 + val |= FIELD_PREP(NV_FTR(PFR0, EL1), 0b0001); 65 + val |= FIELD_PREP(NV_FTR(PFR0, EL2), 0b0001); 66 + val |= FIELD_PREP(NV_FTR(PFR0, EL3), 0b0001); 67 + break; 68 + 69 + case SYS_ID_AA64PFR1_EL1: 70 + /* Only support SSBS */ 71 + val &= NV_FTR(PFR1, SSBS); 72 + break; 73 + 74 + case SYS_ID_AA64MMFR0_EL1: 75 + /* Hide ECV, FGT, ExS, Secure Memory */ 76 + val &= ~(GENMASK_ULL(63, 43) | 77 + NV_FTR(MMFR0, TGRAN4_2) | 78 + NV_FTR(MMFR0, TGRAN16_2) | 79 + NV_FTR(MMFR0, TGRAN64_2) | 80 + NV_FTR(MMFR0, SNSMEM)); 81 + 82 + /* Disallow unsupported S2 page sizes */ 83 + switch (PAGE_SIZE) { 84 + case SZ_64K: 85 + val |= FIELD_PREP(NV_FTR(MMFR0, TGRAN16_2), 0b0001); 86 + fallthrough; 87 + case SZ_16K: 88 + val |= FIELD_PREP(NV_FTR(MMFR0, TGRAN4_2), 0b0001); 89 + fallthrough; 90 + case SZ_4K: 91 + /* Support everything */ 92 + break; 93 + } 94 + /* 95 + * Since we can't support a guest S2 page size smaller than 96 + * the host's own page size (due to KVM only populating its 97 + * own S2 using the kernel's page size), advertise the 98 + * limitation using FEAT_GTG. 99 + */ 100 + switch (PAGE_SIZE) { 101 + case SZ_4K: 102 + val |= FIELD_PREP(NV_FTR(MMFR0, TGRAN4_2), 0b0010); 103 + fallthrough; 104 + case SZ_16K: 105 + val |= FIELD_PREP(NV_FTR(MMFR0, TGRAN16_2), 0b0010); 106 + fallthrough; 107 + case SZ_64K: 108 + val |= FIELD_PREP(NV_FTR(MMFR0, TGRAN64_2), 0b0010); 109 + break; 110 + } 111 + /* Cap PARange to 48bits */ 112 + tmp = FIELD_GET(NV_FTR(MMFR0, PARANGE), val); 113 + if (tmp > 0b0101) { 114 + val &= ~NV_FTR(MMFR0, PARANGE); 115 + val |= FIELD_PREP(NV_FTR(MMFR0, PARANGE), 0b0101); 116 + } 117 + break; 118 + 119 + case SYS_ID_AA64MMFR1_EL1: 120 + val &= (NV_FTR(MMFR1, PAN) | 121 + NV_FTR(MMFR1, LO) | 122 + NV_FTR(MMFR1, HPDS) | 123 + NV_FTR(MMFR1, VH) | 124 + NV_FTR(MMFR1, VMIDBits)); 125 + break; 126 + 127 + case SYS_ID_AA64MMFR2_EL1: 128 + val &= ~(NV_FTR(MMFR2, EVT) | 129 + NV_FTR(MMFR2, BBM) | 130 + NV_FTR(MMFR2, TTL) | 131 + GENMASK_ULL(47, 44) | 132 + NV_FTR(MMFR2, ST) | 133 + NV_FTR(MMFR2, CCIDX) | 134 + NV_FTR(MMFR2, VARange)); 135 + 136 + /* Force TTL support */ 137 + val |= FIELD_PREP(NV_FTR(MMFR2, TTL), 0b0001); 138 + break; 139 + 140 + case SYS_ID_AA64DFR0_EL1: 141 + /* Only limited support for PMU, Debug, BPs and WPs */ 142 + val &= (NV_FTR(DFR0, PMUVer) | 143 + NV_FTR(DFR0, WRPs) | 144 + NV_FTR(DFR0, BRPs) | 145 + NV_FTR(DFR0, DebugVer)); 146 + 147 + /* Cap Debug to ARMv8.1 */ 148 + tmp = FIELD_GET(NV_FTR(DFR0, DebugVer), val); 149 + if (tmp > 0b0111) { 150 + val &= ~NV_FTR(DFR0, DebugVer); 151 + val |= FIELD_PREP(NV_FTR(DFR0, DebugVer), 0b0111); 152 + } 153 + break; 154 + 155 + default: 156 + /* Unknown register, just wipe it clean */ 157 + val = 0; 158 + break; 159 + } 160 + 161 + p->regval = val; 162 + }
+3
arch/arm64/kvm/sys_regs.c
··· 1223 1223 return write_to_read_only(vcpu, p, r); 1224 1224 1225 1225 p->regval = read_id_reg(vcpu, r); 1226 + if (vcpu_has_nv(vcpu)) 1227 + access_nested_id_reg(vcpu, p, r); 1228 + 1226 1229 return true; 1227 1230 } 1228 1231