Skip to content

Commit 3adaee7

Browse files
Sebastian Ottoupton
authored andcommitted
KVM: arm64: Allow userspace to change the implementation ID registers
KVM's treatment of the ID registers that describe the implementation (MIDR, REVIDR, and AIDR) is interesting, to say the least. On the userspace-facing end of it, KVM presents the values of the boot CPU on all vCPUs and treats them as invariant. On the guest side of things KVM presents the hardware values of the local CPU, which can change during CPU migration in a big-little system. While one may call this fragile, there is at least some degree of predictability around it. For example, if a VMM wanted to present big-little to a guest, it could affine vCPUs accordingly to the correct clusters. All of this makes a giant mess out of adding support for making these implementation ID registers writable. Avoid breaking the rather subtle ABI around the old way of doing things by requiring opt-in from userspace to make the registers writable. When the cap is enabled, allow userspace to set MIDR, REVIDR, and AIDR to any non-reserved value and present those values consistently across all vCPUs. Signed-off-by: Sebastian Ott <sebott@redhat.com> [oliver: changelog, capability] Link: https://lore.kernel.org/r/20250225005401.679536-5-oliver.upton@linux.dev Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
1 parent d0d81e0 commit 3adaee7

File tree

6 files changed

+77
-6
lines changed

6 files changed

+77
-6
lines changed

Documentation/virt/kvm/api.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8258,6 +8258,24 @@ KVM exits with the register state of either the L1 or L2 guest
82588258
depending on which executed at the time of an exit. Userspace must
82598259
take care to differentiate between these cases.
82608260

8261+
7.37 KVM_CAP_ARM_WRITABLE_IMP_ID_REGS
8262+
-------------------------------------
8263+
8264+
:Architectures: arm64
8265+
:Target: VM
8266+
:Parameters: None
8267+
:Returns: 0 on success, -EBUSY if vCPUs have been created before enabling this
8268+
capability.
8269+
8270+
This capability changes the behavior of the registers that identify a PE
8271+
implementation of the Arm architecture: MIDR_EL1, REVIDR_EL1, and AIDR_EL1.
8272+
By default, these registers are visible to userspace but treated as invariant.
8273+
8274+
When this capability is enabled, KVM allows userspace to change the
8275+
aforementioned registers before the first KVM_RUN. These registers are VM
8276+
scoped, meaning that the same set of values are presented on all vCPUs in a
8277+
given VM.
8278+
82618279
8. Other capabilities.
82628280
======================
82638281

arch/arm64/include/asm/kvm_host.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,8 @@ struct kvm_arch {
334334
#define KVM_ARCH_FLAG_FGU_INITIALIZED 8
335335
/* SVE exposed to guest */
336336
#define KVM_ARCH_FLAG_GUEST_HAS_SVE 9
337+
/* MIDR_EL1, REVIDR_EL1, and AIDR_EL1 are writable from userspace */
338+
#define KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS 10
337339
unsigned long flags;
338340

339341
/* VM-wide vCPU feature set */

arch/arm64/kvm/arm.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,14 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
125125
}
126126
mutex_unlock(&kvm->slots_lock);
127127
break;
128+
case KVM_CAP_ARM_WRITABLE_IMP_ID_REGS:
129+
mutex_lock(&kvm->lock);
130+
if (!kvm->created_vcpus) {
131+
r = 0;
132+
set_bit(KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS, &kvm->arch.flags);
133+
}
134+
mutex_unlock(&kvm->lock);
135+
break;
128136
default:
129137
break;
130138
}
@@ -313,6 +321,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
313321
case KVM_CAP_ARM_SYSTEM_SUSPEND:
314322
case KVM_CAP_IRQFD_RESAMPLE:
315323
case KVM_CAP_COUNTER_OFFSET:
324+
case KVM_CAP_ARM_WRITABLE_IMP_ID_REGS:
316325
r = 1;
317326
break;
318327
case KVM_CAP_SET_GUEST_DEBUG2:

arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,13 @@ static inline u64 *ctxt_mdscr_el1(struct kvm_cpu_context *ctxt)
4545

4646
static inline u64 ctxt_midr_el1(struct kvm_cpu_context *ctxt)
4747
{
48-
return read_cpuid_id();
48+
struct kvm *kvm = kern_hyp_va(ctxt_to_vcpu(ctxt)->kvm);
49+
50+
if (!(ctxt_is_guest(ctxt) &&
51+
test_bit(KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS, &kvm->arch.flags)))
52+
return read_cpuid_id();
53+
54+
return kvm_read_vm_id_reg(kvm, SYS_MIDR_EL1);
4955
}
5056

5157
static inline void __sysreg_save_common_state(struct kvm_cpu_context *ctxt)

arch/arm64/kvm/sys_regs.c

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2524,6 +2524,17 @@ static bool access_imp_id_reg(struct kvm_vcpu *vcpu,
25242524
if (p->is_write)
25252525
return write_to_read_only(vcpu, p, r);
25262526

2527+
/*
2528+
* Return the VM-scoped implementation ID register values if userspace
2529+
* has made them writable.
2530+
*/
2531+
if (test_bit(KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS, &vcpu->kvm->arch.flags))
2532+
return access_id_reg(vcpu, p, r);
2533+
2534+
/*
2535+
* Otherwise, fall back to the old behavior of returning the value of
2536+
* the current CPU.
2537+
*/
25272538
switch (reg_to_encoding(r)) {
25282539
case SYS_REVIDR_EL1:
25292540
p->regval = read_sysreg(revidr_el1);
@@ -2567,19 +2578,43 @@ static u64 reset_imp_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
25672578
static int set_imp_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
25682579
u64 val)
25692580
{
2581+
struct kvm *kvm = vcpu->kvm;
25702582
u64 expected;
25712583

2584+
guard(mutex)(&kvm->arch.config_lock);
2585+
25722586
expected = read_id_reg(vcpu, r);
2587+
if (expected == val)
2588+
return 0;
25732589

2574-
return (expected == val) ? 0 : -EINVAL;
2590+
if (!test_bit(KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS, &kvm->arch.flags))
2591+
return -EINVAL;
2592+
2593+
/*
2594+
* Once the VM has started the ID registers are immutable. Reject the
2595+
* write if userspace tries to change it.
2596+
*/
2597+
if (kvm_vm_has_ran_once(kvm))
2598+
return -EBUSY;
2599+
2600+
/*
2601+
* Any value is allowed for the implementation ID registers so long as
2602+
* it is within the writable mask.
2603+
*/
2604+
if ((val & r->val) != val)
2605+
return -EINVAL;
2606+
2607+
kvm_set_vm_id_reg(kvm, reg_to_encoding(r), val);
2608+
return 0;
25752609
}
25762610

2577-
#define IMPLEMENTATION_ID(reg) { \
2611+
#define IMPLEMENTATION_ID(reg, mask) { \
25782612
SYS_DESC(SYS_##reg), \
25792613
.access = access_imp_id_reg, \
25802614
.get_user = get_id_reg, \
25812615
.set_user = set_imp_id_reg, \
25822616
.reset = reset_imp_id_reg, \
2617+
.val = mask, \
25832618
}
25842619

25852620
/*
@@ -2630,9 +2665,9 @@ static const struct sys_reg_desc sys_reg_descs[] = {
26302665

26312666
{ SYS_DESC(SYS_DBGVCR32_EL2), undef_access, reset_val, DBGVCR32_EL2, 0 },
26322667

2633-
IMPLEMENTATION_ID(MIDR_EL1),
2668+
IMPLEMENTATION_ID(MIDR_EL1, GENMASK_ULL(31, 0)),
26342669
{ SYS_DESC(SYS_MPIDR_EL1), NULL, reset_mpidr, MPIDR_EL1 },
2635-
IMPLEMENTATION_ID(REVIDR_EL1),
2670+
IMPLEMENTATION_ID(REVIDR_EL1, GENMASK_ULL(63, 0)),
26362671

26372672
/*
26382673
* ID regs: all ID_SANITISED() entries here must have corresponding
@@ -2904,7 +2939,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
29042939
.set_user = set_clidr, .val = ~CLIDR_EL1_RES0 },
29052940
{ SYS_DESC(SYS_CCSIDR2_EL1), undef_access },
29062941
{ SYS_DESC(SYS_SMIDR_EL1), undef_access },
2907-
IMPLEMENTATION_ID(AIDR_EL1),
2942+
IMPLEMENTATION_ID(AIDR_EL1, GENMASK_ULL(63, 0)),
29082943
{ SYS_DESC(SYS_CSSELR_EL1), access_csselr, reset_unknown, CSSELR_EL1 },
29092944
ID_FILTERED(CTR_EL0, ctr_el0,
29102945
CTR_EL0_DIC_MASK |

include/uapi/linux/kvm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -929,6 +929,7 @@ struct kvm_enable_cap {
929929
#define KVM_CAP_PRE_FAULT_MEMORY 236
930930
#define KVM_CAP_X86_APIC_BUS_CYCLES_NS 237
931931
#define KVM_CAP_X86_GUEST_MODE 238
932+
#define KVM_CAP_ARM_WRITABLE_IMP_ID_REGS 239
932933

933934
struct kvm_irq_routing_irqchip {
934935
__u32 irqchip;

0 commit comments

Comments
 (0)