Commit 4f2774c5 authored by Oliver Upton's avatar Oliver Upton
Browse files

Merge branch 'kvm-arm64/writable-midr' into kvmarm/next



* kvm-arm64/writable-midr:
  : Writable implementation ID registers, courtesy of Sebastian Ott
  :
  : Introduce a new capability that allows userspace to set the
  : ID registers that identify a CPU implementation: MIDR_EL1, REVIDR_EL1,
  : and AIDR_EL1. Also plug a hole in KVM's trap configuration where
  : SMIDR_EL1 was readable at EL1, despite the fact that KVM does not
  : support SME.
  KVM: arm64: Fix documentation for KVM_CAP_ARM_WRITABLE_IMP_ID_REGS
  KVM: arm64: Copy MIDR_EL1 into hyp VM when it is writable
  KVM: arm64: Copy guest CTR_EL0 into hyp VM
  KVM: selftests: arm64: Test writes to MIDR,REVIDR,AIDR
  KVM: arm64: Allow userspace to change the implementation ID registers
  KVM: arm64: Load VPIDR_EL2 with the VM's MIDR_EL1 value
  KVM: arm64: Maintain per-VM copy of implementation ID regs
  KVM: arm64: Set HCR_EL2.TID1 unconditionally

Signed-off-by: default avatarOliver Upton <oliver.upton@linux.dev>
parents 1b1d1b17 5980a693
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -8258,6 +8258,24 @@ KVM exits with the register state of either the L1 or L2 guest
depending on which executed at the time of an exit. Userspace must
take care to differentiate between these cases.

7.37 KVM_CAP_ARM_WRITABLE_IMP_ID_REGS
-------------------------------------

:Architectures: arm64
:Target: VM
:Parameters: None
:Returns: 0 on success, -EINVAL if vCPUs have been created before enabling this
          capability.

This capability changes the behavior of the registers that identify a PE
implementation of the Arm architecture: MIDR_EL1, REVIDR_EL1, and AIDR_EL1.
By default, these registers are visible to userspace but treated as invariant.

When this capability is enabled, KVM allows userspace to change the
aforementioned registers before the first KVM_RUN. These registers are VM
scoped, meaning that the same set of values are presented on all vCPUs in a
given VM.

8. Other capabilities.
======================

+2 −2
Original line number Diff line number Diff line
@@ -92,12 +92,12 @@
 * SWIO:	Turn set/way invalidates into set/way clean+invalidate
 * PTW:		Take a stage2 fault if a stage1 walk steps in device memory
 * TID3:	Trap EL1 reads of group 3 ID registers
 * TID2:	Trap CTR_EL0, CCSIDR2_EL1, CLIDR_EL1, and CSSELR_EL1
 * TID1:	Trap REVIDR_EL1, AIDR_EL1, and SMIDR_EL1
 */
#define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \
			 HCR_BSU_IS | HCR_FB | HCR_TACR | \
			 HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW | HCR_TLOR | \
			 HCR_FMO | HCR_IMO | HCR_PTW | HCR_TID3)
			 HCR_FMO | HCR_IMO | HCR_PTW | HCR_TID3 | HCR_TID1)
#define HCR_HOST_NVHE_FLAGS (HCR_RW | HCR_API | HCR_APK | HCR_ATA)
#define HCR_HOST_NVHE_PROTECTED_FLAGS (HCR_HOST_NVHE_FLAGS | HCR_TSC)
#define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H)
+11 −0
Original line number Diff line number Diff line
@@ -336,6 +336,8 @@ struct kvm_arch {
#define KVM_ARCH_FLAG_FGU_INITIALIZED			8
	/* SVE exposed to guest */
#define KVM_ARCH_FLAG_GUEST_HAS_SVE			9
	/* MIDR_EL1, REVIDR_EL1, and AIDR_EL1 are writable from userspace */
#define KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS		10
	unsigned long flags;

	/* VM-wide vCPU feature set */
@@ -375,6 +377,9 @@ struct kvm_arch {
#define KVM_ARM_ID_REG_NUM	(IDREG_IDX(sys_reg(3, 0, 0, 7, 7)) + 1)
	u64 id_regs[KVM_ARM_ID_REG_NUM];

	u64 midr_el1;
	u64 revidr_el1;
	u64 aidr_el1;
	u64 ctr_el0;

	/* Masks for VNCR-backed and general EL2 sysregs */
@@ -1489,6 +1494,12 @@ static inline u64 *__vm_id_reg(struct kvm_arch *ka, u32 reg)
		return &ka->id_regs[IDREG_IDX(reg)];
	case SYS_CTR_EL0:
		return &ka->ctr_el0;
	case SYS_MIDR_EL1:
		return &ka->midr_el1;
	case SYS_REVIDR_EL1:
		return &ka->revidr_el1;
	case SYS_AIDR_EL1:
		return &ka->aidr_el1;
	default:
		WARN_ON_ONCE(1);
		return NULL;
+9 −0
Original line number Diff line number Diff line
@@ -125,6 +125,14 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
		}
		mutex_unlock(&kvm->slots_lock);
		break;
	case KVM_CAP_ARM_WRITABLE_IMP_ID_REGS:
		mutex_lock(&kvm->lock);
		if (!kvm->created_vcpus) {
			r = 0;
			set_bit(KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS, &kvm->arch.flags);
		}
		mutex_unlock(&kvm->lock);
		break;
	default:
		break;
	}
@@ -313,6 +321,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
	case KVM_CAP_ARM_SYSTEM_SUSPEND:
	case KVM_CAP_IRQFD_RESAMPLE:
	case KVM_CAP_COUNTER_OFFSET:
	case KVM_CAP_ARM_WRITABLE_IMP_ID_REGS:
		r = 1;
		break;
	case KVM_CAP_SET_GUEST_DEBUG2:
+13 −1
Original line number Diff line number Diff line
@@ -43,6 +43,17 @@ static inline u64 *ctxt_mdscr_el1(struct kvm_cpu_context *ctxt)
	return &ctxt_sys_reg(ctxt, MDSCR_EL1);
}

static inline u64 ctxt_midr_el1(struct kvm_cpu_context *ctxt)
{
	struct kvm *kvm = kern_hyp_va(ctxt_to_vcpu(ctxt)->kvm);

	if (!(ctxt_is_guest(ctxt) &&
	      test_bit(KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS, &kvm->arch.flags)))
		return read_cpuid_id();

	return kvm_read_vm_id_reg(kvm, SYS_MIDR_EL1);
}

static inline void __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
{
	*ctxt_mdscr_el1(ctxt)	= read_sysreg(mdscr_el1);
@@ -168,8 +179,9 @@ static inline void __sysreg_restore_user_state(struct kvm_cpu_context *ctxt)
}

static inline void __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt,
					      u64 mpidr)
					      u64 midr, u64 mpidr)
{
	write_sysreg(midr,				vpidr_el2);
	write_sysreg(mpidr,				vmpidr_el2);

	if (has_vhe() ||
Loading