Skip to content

Commit 89a734b

Browse files
committed
Merge branch kvm-arm64/configurable-id-regs into kvmarm/next
* kvm-arm64/configurable-id-regs: : Configurable ID register infrastructure, courtesy of Jing Zhang : : Create generalized infrastructure for allowing userspace to select the : supported feature set for a VM, so long as the feature set is a subset : of what hardware + KVM allows. This does not add any new features that : are user-configurable, and instead focuses on the necessary refactoring : to enable future work. : : As a consequence of the series, feature asymmetry is now deliberately : disallowed for KVM. It is unlikely that VMMs ever configured VMs with : asymmetry, nor does it align with the kernel's overall stance that : features must be uniform across all cores in the system. : : Furthermore, KVM incorrectly advertised an IMP_DEF PMU to guests for : some time. Migrations from affected kernels was supported by explicitly : allowing such an ID register value from userspace, and forwarding that : along to the guest. KVM now allows an IMP_DEF PMU version to be restored : through the ID register interface, but reinterprets the user value as : not implemented (0). KVM: arm64: Rip out the vestiges of the 'old' ID register scheme KVM: arm64: Handle ID register reads using the VM-wide values KVM: arm64: Use generic sanitisation for ID_AA64PFR0_EL1 KVM: arm64: Use generic sanitisation for ID_(AA64)DFR0_EL1 KVM: arm64: Use arm64_ftr_bits to sanitise ID register writes KVM: arm64: Save ID registers' sanitized value per guest KVM: arm64: Reuse fields of sys_reg_desc for idreg KVM: arm64: Rewrite IMPDEF PMU version as NI KVM: arm64: Make vCPU feature flags consistent VM-wide KVM: arm64: Relax invariance of KVM_ARM_VCPU_POWER_OFF KVM: arm64: Separate out feature sanitisation and initialisation Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
2 parents acfdf34 + 6866724 commit 89a734b

9 files changed

Lines changed: 488 additions & 292 deletions

File tree

arch/arm64/include/asm/cpufeature.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,7 @@ static inline unsigned int get_vmid_bits(u64 mmfr1)
918918
return 8;
919919
}
920920

921+
s64 arm64_ftr_safe_value(const struct arm64_ftr_bits *ftrp, s64 new, s64 cur);
921922
struct arm64_ftr_reg *get_arm64_ftr_reg(u32 sys_id);
922923

923924
extern struct arm64_ftr_override id_aa64mmfr1_override;

arch/arm64/include/asm/kvm_emulate.h

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,7 @@ static __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
6262
#else
6363
static __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
6464
{
65-
struct kvm *kvm = vcpu->kvm;
66-
67-
WARN_ON_ONCE(!test_bit(KVM_ARCH_FLAG_REG_WIDTH_CONFIGURED,
68-
&kvm->arch.flags));
69-
70-
return test_bit(KVM_ARCH_FLAG_EL1_32BIT, &kvm->arch.flags);
65+
return test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features);
7166
}
7267
#endif
7368

arch/arm64/include/asm/kvm_host.h

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
4040

4141
#define KVM_VCPU_MAX_FEATURES 7
42+
#define KVM_VCPU_VALID_FEATURES (BIT(KVM_VCPU_MAX_FEATURES) - 1)
4243

4344
#define KVM_REQ_SLEEP \
4445
KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
@@ -229,25 +230,23 @@ struct kvm_arch {
229230
#define KVM_ARCH_FLAG_MTE_ENABLED 1
230231
/* At least one vCPU has ran in the VM */
231232
#define KVM_ARCH_FLAG_HAS_RAN_ONCE 2
232-
/*
233-
* The following two bits are used to indicate the guest's EL1
234-
* register width configuration. A value of KVM_ARCH_FLAG_EL1_32BIT
235-
* bit is valid only when KVM_ARCH_FLAG_REG_WIDTH_CONFIGURED is set.
236-
* Otherwise, the guest's EL1 register width has not yet been
237-
* determined yet.
238-
*/
239-
#define KVM_ARCH_FLAG_REG_WIDTH_CONFIGURED 3
240-
#define KVM_ARCH_FLAG_EL1_32BIT 4
233+
/* The vCPU feature set for the VM is configured */
234+
#define KVM_ARCH_FLAG_VCPU_FEATURES_CONFIGURED 3
241235
/* PSCI SYSTEM_SUSPEND enabled for the guest */
242-
#define KVM_ARCH_FLAG_SYSTEM_SUSPEND_ENABLED 5
236+
#define KVM_ARCH_FLAG_SYSTEM_SUSPEND_ENABLED 4
243237
/* VM counter offset */
244-
#define KVM_ARCH_FLAG_VM_COUNTER_OFFSET 6
238+
#define KVM_ARCH_FLAG_VM_COUNTER_OFFSET 5
245239
/* Timer PPIs made immutable */
246-
#define KVM_ARCH_FLAG_TIMER_PPIS_IMMUTABLE 7
240+
#define KVM_ARCH_FLAG_TIMER_PPIS_IMMUTABLE 6
247241
/* SMCCC filter initialized for the VM */
248-
#define KVM_ARCH_FLAG_SMCCC_FILTER_CONFIGURED 8
242+
#define KVM_ARCH_FLAG_SMCCC_FILTER_CONFIGURED 7
243+
/* Initial ID reg values loaded */
244+
#define KVM_ARCH_FLAG_ID_REGS_INITIALIZED 8
249245
unsigned long flags;
250246

247+
/* VM-wide vCPU feature set */
248+
DECLARE_BITMAP(vcpu_features, KVM_VCPU_MAX_FEATURES);
249+
251250
/*
252251
* VM-wide PMU filter, implemented as a bitmap and big enough for
253252
* up to 2^10 events (ARMv8.0) or 2^16 events (ARMv8.1+).
@@ -257,17 +256,23 @@ struct kvm_arch {
257256

258257
cpumask_var_t supported_cpus;
259258

260-
u8 pfr0_csv2;
261-
u8 pfr0_csv3;
262-
struct {
263-
u8 imp:4;
264-
u8 unimp:4;
265-
} dfr0_pmuver;
266-
267259
/* Hypercall features firmware registers' descriptor */
268260
struct kvm_smccc_features smccc_feat;
269261
struct maple_tree smccc_filter;
270262

263+
/*
264+
* Emulated CPU ID registers per VM
265+
* (Op0, Op1, CRn, CRm, Op2) of the ID registers to be saved in it
266+
* is (3, 0, 0, crm, op2), where 1<=crm<8, 0<=op2<8.
267+
*
268+
* These emulated idregs are VM-wide, but accessed from the context of a vCPU.
269+
* Atomic access to multiple idregs are guarded by kvm_arch.config_lock.
270+
*/
271+
#define IDREG_IDX(id) (((sys_reg_CRm(id) - 1) << 3) | sys_reg_Op2(id))
272+
#define IDREG(kvm, id) ((kvm)->arch.id_regs[IDREG_IDX(id)])
273+
#define KVM_ARM_ID_REG_NUM (IDREG_IDX(sys_reg(3, 0, 0, 7, 7)) + 1)
274+
u64 id_regs[KVM_ARM_ID_REG_NUM];
275+
271276
/*
272277
* For an untrusted host VM, 'pkvm.handle' is used to lookup
273278
* the associated pKVM instance in the hypervisor.

arch/arm64/kernel/cpufeature.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -800,7 +800,7 @@ static u64 arm64_ftr_set_value(const struct arm64_ftr_bits *ftrp, s64 reg,
800800
return reg;
801801
}
802802

803-
static s64 arm64_ftr_safe_value(const struct arm64_ftr_bits *ftrp, s64 new,
803+
s64 arm64_ftr_safe_value(const struct arm64_ftr_bits *ftrp, s64 new,
804804
s64 cur)
805805
{
806806
s64 ret = 0;

arch/arm64/kvm/arm.c

Lines changed: 85 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -121,22 +121,6 @@ static int kvm_arm_default_max_vcpus(void)
121121
return vgic_present ? kvm_vgic_get_max_vcpus() : KVM_MAX_VCPUS;
122122
}
123123

124-
static void set_default_spectre(struct kvm *kvm)
125-
{
126-
/*
127-
* The default is to expose CSV2 == 1 if the HW isn't affected.
128-
* Although this is a per-CPU feature, we make it global because
129-
* asymmetric systems are just a nuisance.
130-
*
131-
* Userspace can override this as long as it doesn't promise
132-
* the impossible.
133-
*/
134-
if (arm64_get_spectre_v2_state() == SPECTRE_UNAFFECTED)
135-
kvm->arch.pfr0_csv2 = 1;
136-
if (arm64_get_meltdown_state() == SPECTRE_UNAFFECTED)
137-
kvm->arch.pfr0_csv3 = 1;
138-
}
139-
140124
/**
141125
* kvm_arch_init_vm - initializes a VM data structure
142126
* @kvm: pointer to the KVM struct
@@ -180,14 +164,9 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
180164
/* The maximum number of VCPUs is limited by the host's GIC model */
181165
kvm->max_vcpus = kvm_arm_default_max_vcpus();
182166

183-
set_default_spectre(kvm);
184167
kvm_arm_init_hypercalls(kvm);
185168

186-
/*
187-
* Initialise the default PMUver before there is a chance to
188-
* create an actual PMU.
189-
*/
190-
kvm->arch.dfr0_pmuver.imp = kvm_arm_pmu_get_pmuver_limit();
169+
bitmap_zero(kvm->arch.vcpu_features, KVM_VCPU_MAX_FEATURES);
191170

192171
return 0;
193172

@@ -1195,58 +1174,115 @@ int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level,
11951174
return -EINVAL;
11961175
}
11971176

1198-
static int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
1199-
const struct kvm_vcpu_init *init)
1177+
static int kvm_vcpu_init_check_features(struct kvm_vcpu *vcpu,
1178+
const struct kvm_vcpu_init *init)
12001179
{
1201-
unsigned int i, ret;
1202-
u32 phys_target = kvm_target_cpu();
1180+
unsigned long features = init->features[0];
1181+
int i;
1182+
1183+
if (features & ~KVM_VCPU_VALID_FEATURES)
1184+
return -ENOENT;
1185+
1186+
for (i = 1; i < ARRAY_SIZE(init->features); i++) {
1187+
if (init->features[i])
1188+
return -ENOENT;
1189+
}
1190+
1191+
if (!test_bit(KVM_ARM_VCPU_EL1_32BIT, &features))
1192+
return 0;
12031193

1204-
if (init->target != phys_target)
1194+
if (!cpus_have_const_cap(ARM64_HAS_32BIT_EL1))
12051195
return -EINVAL;
12061196

1207-
/*
1208-
* Secondary and subsequent calls to KVM_ARM_VCPU_INIT must
1209-
* use the same target.
1210-
*/
1211-
if (vcpu->arch.target != -1 && vcpu->arch.target != init->target)
1197+
/* MTE is incompatible with AArch32 */
1198+
if (kvm_has_mte(vcpu->kvm))
12121199
return -EINVAL;
12131200

1214-
/* -ENOENT for unknown features, -EINVAL for invalid combinations. */
1215-
for (i = 0; i < sizeof(init->features) * 8; i++) {
1216-
bool set = (init->features[i / 32] & (1 << (i % 32)));
1201+
/* NV is incompatible with AArch32 */
1202+
if (test_bit(KVM_ARM_VCPU_HAS_EL2, &features))
1203+
return -EINVAL;
12171204

1218-
if (set && i >= KVM_VCPU_MAX_FEATURES)
1219-
return -ENOENT;
1205+
return 0;
1206+
}
12201207

1221-
/*
1222-
* Secondary and subsequent calls to KVM_ARM_VCPU_INIT must
1223-
* use the same feature set.
1224-
*/
1225-
if (vcpu->arch.target != -1 && i < KVM_VCPU_MAX_FEATURES &&
1226-
test_bit(i, vcpu->arch.features) != set)
1227-
return -EINVAL;
1208+
static bool kvm_vcpu_init_changed(struct kvm_vcpu *vcpu,
1209+
const struct kvm_vcpu_init *init)
1210+
{
1211+
unsigned long features = init->features[0];
12281212

1229-
if (set)
1230-
set_bit(i, vcpu->arch.features);
1231-
}
1213+
return !bitmap_equal(vcpu->arch.features, &features, KVM_VCPU_MAX_FEATURES) ||
1214+
vcpu->arch.target != init->target;
1215+
}
1216+
1217+
static int __kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
1218+
const struct kvm_vcpu_init *init)
1219+
{
1220+
unsigned long features = init->features[0];
1221+
struct kvm *kvm = vcpu->kvm;
1222+
int ret = -EINVAL;
1223+
1224+
mutex_lock(&kvm->arch.config_lock);
1225+
1226+
if (test_bit(KVM_ARCH_FLAG_VCPU_FEATURES_CONFIGURED, &kvm->arch.flags) &&
1227+
!bitmap_equal(kvm->arch.vcpu_features, &features, KVM_VCPU_MAX_FEATURES))
1228+
goto out_unlock;
12321229

1233-
vcpu->arch.target = phys_target;
1230+
vcpu->arch.target = init->target;
1231+
bitmap_copy(vcpu->arch.features, &features, KVM_VCPU_MAX_FEATURES);
12341232

12351233
/* Now we know what it is, we can reset it. */
12361234
ret = kvm_reset_vcpu(vcpu);
12371235
if (ret) {
12381236
vcpu->arch.target = -1;
12391237
bitmap_zero(vcpu->arch.features, KVM_VCPU_MAX_FEATURES);
1238+
goto out_unlock;
12401239
}
12411240

1241+
bitmap_copy(kvm->arch.vcpu_features, &features, KVM_VCPU_MAX_FEATURES);
1242+
set_bit(KVM_ARCH_FLAG_VCPU_FEATURES_CONFIGURED, &kvm->arch.flags);
1243+
1244+
out_unlock:
1245+
mutex_unlock(&kvm->arch.config_lock);
12421246
return ret;
12431247
}
12441248

1249+
static int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
1250+
const struct kvm_vcpu_init *init)
1251+
{
1252+
int ret;
1253+
1254+
if (init->target != kvm_target_cpu())
1255+
return -EINVAL;
1256+
1257+
ret = kvm_vcpu_init_check_features(vcpu, init);
1258+
if (ret)
1259+
return ret;
1260+
1261+
if (vcpu->arch.target == -1)
1262+
return __kvm_vcpu_set_target(vcpu, init);
1263+
1264+
if (kvm_vcpu_init_changed(vcpu, init))
1265+
return -EINVAL;
1266+
1267+
return kvm_reset_vcpu(vcpu);
1268+
}
1269+
12451270
static int kvm_arch_vcpu_ioctl_vcpu_init(struct kvm_vcpu *vcpu,
12461271
struct kvm_vcpu_init *init)
12471272
{
1273+
bool power_off = false;
12481274
int ret;
12491275

1276+
/*
1277+
* Treat the power-off vCPU feature as ephemeral. Clear the bit to avoid
1278+
* reflecting it in the finalized feature set, thus limiting its scope
1279+
* to a single KVM_ARM_VCPU_INIT call.
1280+
*/
1281+
if (init->features[0] & KVM_ARM_VCPU_POWER_OFF) {
1282+
init->features[0] &= ~KVM_ARM_VCPU_POWER_OFF;
1283+
power_off = true;
1284+
}
1285+
12501286
ret = kvm_vcpu_set_target(vcpu, init);
12511287
if (ret)
12521288
return ret;
@@ -1275,7 +1311,7 @@ static int kvm_arch_vcpu_ioctl_vcpu_init(struct kvm_vcpu *vcpu,
12751311
*/
12761312
spin_lock(&vcpu->arch.mp_state_lock);
12771313

1278-
if (test_bit(KVM_ARM_VCPU_POWER_OFF, vcpu->arch.features))
1314+
if (power_off)
12791315
__kvm_arm_vcpu_power_off(vcpu);
12801316
else
12811317
WRITE_ONCE(vcpu->arch.mp_state.mp_state, KVM_MP_STATE_RUNNABLE);

arch/arm64/kvm/reset.c

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -186,57 +186,6 @@ static int kvm_vcpu_enable_ptrauth(struct kvm_vcpu *vcpu)
186186
return 0;
187187
}
188188

189-
/**
190-
* kvm_set_vm_width() - set the register width for the guest
191-
* @vcpu: Pointer to the vcpu being configured
192-
*
193-
* Set both KVM_ARCH_FLAG_EL1_32BIT and KVM_ARCH_FLAG_REG_WIDTH_CONFIGURED
194-
* in the VM flags based on the vcpu's requested register width, the HW
195-
* capabilities and other options (such as MTE).
196-
* When REG_WIDTH_CONFIGURED is already set, the vcpu settings must be
197-
* consistent with the value of the FLAG_EL1_32BIT bit in the flags.
198-
*
199-
* Return: 0 on success, negative error code on failure.
200-
*/
201-
static int kvm_set_vm_width(struct kvm_vcpu *vcpu)
202-
{
203-
struct kvm *kvm = vcpu->kvm;
204-
bool is32bit;
205-
206-
is32bit = vcpu_has_feature(vcpu, KVM_ARM_VCPU_EL1_32BIT);
207-
208-
lockdep_assert_held(&kvm->arch.config_lock);
209-
210-
if (test_bit(KVM_ARCH_FLAG_REG_WIDTH_CONFIGURED, &kvm->arch.flags)) {
211-
/*
212-
* The guest's register width is already configured.
213-
* Make sure that the vcpu is consistent with it.
214-
*/
215-
if (is32bit == test_bit(KVM_ARCH_FLAG_EL1_32BIT, &kvm->arch.flags))
216-
return 0;
217-
218-
return -EINVAL;
219-
}
220-
221-
if (!cpus_have_const_cap(ARM64_HAS_32BIT_EL1) && is32bit)
222-
return -EINVAL;
223-
224-
/* MTE is incompatible with AArch32 */
225-
if (kvm_has_mte(kvm) && is32bit)
226-
return -EINVAL;
227-
228-
/* NV is incompatible with AArch32 */
229-
if (vcpu_has_nv(vcpu) && is32bit)
230-
return -EINVAL;
231-
232-
if (is32bit)
233-
set_bit(KVM_ARCH_FLAG_EL1_32BIT, &kvm->arch.flags);
234-
235-
set_bit(KVM_ARCH_FLAG_REG_WIDTH_CONFIGURED, &kvm->arch.flags);
236-
237-
return 0;
238-
}
239-
240189
/**
241190
* kvm_reset_vcpu - sets core registers and sys_regs to reset value
242191
* @vcpu: The VCPU pointer
@@ -262,13 +211,6 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
262211
bool loaded;
263212
u32 pstate;
264213

265-
mutex_lock(&vcpu->kvm->arch.config_lock);
266-
ret = kvm_set_vm_width(vcpu);
267-
mutex_unlock(&vcpu->kvm->arch.config_lock);
268-
269-
if (ret)
270-
return ret;
271-
272214
spin_lock(&vcpu->arch.mp_state_lock);
273215
reset_state = vcpu->arch.reset_state;
274216
vcpu->arch.reset_state.reset = false;

0 commit comments

Comments
 (0)