On Wed, Jun 11, 2025 at 11:48:19AM +0100, Steven Price wrote: > The RMM only allows setting the GPRS (x0-x30) and PC for a realm > guest. Check this in kvm_arm_set_reg() so that the VMM can receive a > suitable error return if other registers are written to. > > The RMM makes similar restrictions for reading of the guest's registers > (this is *confidential* compute after all), however we don't impose the > restriction here. This allows the VMM to read (stale) values from the > registers which might be useful to read back the initial values even if > the RMM doesn't provide the latest version. For migration of a realm VM, > a new interface will be needed so that the VMM can receive an > (encrypted) blob of the VM's state. > > Reviewed-by: Gavin Shan <gshan@xxxxxxxxxx> > Reviewed-by: Suzuki K Poulose <suzuki.poulose@xxxxxxx> > Signed-off-by: Steven Price <steven.price@xxxxxxx> Reviewed-by: Joey Gouly <joey.gouly@xxxxxxx> > --- > Changes since v5: > * Upper GPRS can be set as part of a HOST_CALL return, so fix up the > test to allow them. > --- > arch/arm64/kvm/guest.c | 41 +++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 41 insertions(+) > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c > index 2196979a24a3..a114b9e15eec 100644 > --- a/arch/arm64/kvm/guest.c > +++ b/arch/arm64/kvm/guest.c > @@ -73,6 +73,25 @@ static u64 core_reg_offset_from_id(u64 id) > return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE); > } > > +static bool kvm_realm_validate_core_reg(u64 off) > +{ > + /* > + * Note that GPRs can only sometimes be controlled by the VMM. > + * For PSCI only X0-X6 are used, higher registers are ignored (restored > + * from the REC). > + * For HOST_CALL all of X0-X30 are copied to the RsiHostCall structure. > + * For emulated MMIO X0 is always used. > + * PC can only be set before the realm is activated. > + */ > + switch (off) { > + case KVM_REG_ARM_CORE_REG(regs.regs[0]) ... > + KVM_REG_ARM_CORE_REG(regs.regs[30]): > + case KVM_REG_ARM_CORE_REG(regs.pc): > + return true; > + } > + return false; > +} > + > static int core_reg_size_from_offset(const struct kvm_vcpu *vcpu, u64 off) > { > int size; > @@ -783,12 +802,34 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) > return kvm_arm_sys_reg_get_reg(vcpu, reg); > } > > +/* > + * The RMI ABI only enables setting some GPRs and PC. The selection of GPRs > + * that are available depends on the Realm state and the reason for the last > + * exit. All other registers are reset to architectural or otherwise defined > + * reset values by the RMM, except for a few configuration fields that > + * correspond to Realm parameters. > + */ > +static bool validate_realm_set_reg(struct kvm_vcpu *vcpu, > + const struct kvm_one_reg *reg) > +{ > + if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) { > + u64 off = core_reg_offset_from_id(reg->id); > + > + return kvm_realm_validate_core_reg(off); > + } > + > + return false; > +} > + > int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) > { > /* We currently use nothing arch-specific in upper 32 bits */ > if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32) > return -EINVAL; > > + if (kvm_is_realm(vcpu->kvm) && !validate_realm_set_reg(vcpu, reg)) > + return -EINVAL; > + > switch (reg->id & KVM_REG_ARM_COPROC_MASK) { > case KVM_REG_ARM_CORE: return set_core_reg(vcpu, reg); > case KVM_REG_ARM_FW: > -- > 2.43.0 >