[PATCH v5 3/6] KVM: arm64: Reject attempts to set invalid debug arch version
Jing Zhang
jingzhangos at google.com
Mon Jul 10 13:54:46 PDT 2023
Hi Oliver,
On Mon, Jul 10, 2023 at 1:18 PM Oliver Upton <oliver.upton at linux.dev> wrote:
>
> Jing,
>
> On Mon, Jul 10, 2023 at 07:24:26PM +0000, Jing Zhang wrote:
> > From: Oliver Upton <oliver.upton at linux.dev>
> >
> > The debug architecture is mandatory in ARMv8, so KVM should not allow
> > userspace to configure a vCPU with less than that. Of course, this isn't
> > handled elegantly by the generic ID register plumbing, as the respective
> > ID register fields have a nonzero starting value.
> >
> > Add an explicit check for debug versions less than v8 of the
> > architecture.
> >
> > Signed-off-by: Oliver Upton <oliver.upton at linux.dev>
> > Signed-off-by: Jing Zhang <jingzhangos at google.com>
>
> This patch should be ordered before the change that permits writes to
> the DebugVer field (i.e. the previous patch). While we're at it, there's
> another set of prerequisites for actually making the field writable.
>
> As Suraj pointed out earlier, we need to override the type of the field
> to be FTR_LOWER_SAFE instead of EXACT. Beyond that, KVM limits the field
> to 0x6, which is the minimum value for an ARMv8 implementation. We can
> relax this limitation up to v8p8, as I believe all of the changes are to
> external debug and wouldn't affect a KVM guest.
>
> Below is my (untested) diff on top of your series for both of these
> changes.
>
> --
> Thanks,
> Oliver
>
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index 78ccc95624fa..35c4ab8cb5c8 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -1216,8 +1216,14 @@ static s64 kvm_arm64_ftr_safe_value(u32 id, const struct arm64_ftr_bits *ftrp,
> /* Some features have different safe value type in KVM than host features */
> switch (id) {
> case SYS_ID_AA64DFR0_EL1:
> - if (kvm_ftr.shift == ID_AA64DFR0_EL1_PMUVer_SHIFT)
> + switch (kvm_ftr.shift) {
> + case ID_AA64DFR0_EL1_PMUVer_SHIFT:
> kvm_ftr.type = FTR_LOWER_SAFE;
> + break;
> + case ID_AA64DFR0_EL1_DebugVer_SHIFT:
> + kvm_ftr.type = FTR_LOWER_SAFE;
> + break;
> + }
> break;
> case SYS_ID_DFR0_EL1:
> if (kvm_ftr.shift == ID_DFR0_EL1_PerfMon_SHIFT)
> @@ -1466,14 +1472,22 @@ static u64 read_sanitised_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
> return val;
> }
>
> +#define ID_REG_LIMIT_FIELD_ENUM(val, reg, field, limit) \
> +({ \
> + u64 __f_val = FIELD_GET(reg##_##field##_MASK, val); \
> + (val) &= ~reg##_##field##_MASK; \
> + (val) |= FIELD_PREP(reg##_##field##_MASK, \
> + min(__f_val, (u64)reg##_##field##_##limit)); \
> + (val); \
> +})
> +
> static u64 read_sanitised_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
> const struct sys_reg_desc *rd)
> {
> u64 val = read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1);
>
> /* Limit debug to ARMv8.0 */
> - val &= ~ID_AA64DFR0_EL1_DebugVer_MASK;
> - val |= SYS_FIELD_PREP_ENUM(ID_AA64DFR0_EL1, DebugVer, IMP);
> + val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64DFR0_EL1, DebugVer, V8P8);
>
> /*
> * Only initialize the PMU version if the vCPU was configured with one.
> @@ -1529,6 +1543,8 @@ static u64 read_sanitised_id_dfr0_el1(struct kvm_vcpu *vcpu,
> u8 perfmon = pmuver_to_perfmon(kvm_arm_pmu_get_pmuver_limit());
> u64 val = read_sanitised_ftr_reg(SYS_ID_DFR0_EL1);
>
> + val = ID_REG_LIMIT_FIELD_ENUM(val, ID_DFR0_EL1, CopDbg, Debugv8p8);
> +
> val &= ~ID_DFR0_EL1_PerfMon_MASK;
> if (kvm_vcpu_has_pmu(vcpu))
> val |= SYS_FIELD_PREP(ID_DFR0_EL1, PerfMon, perfmon);
>
Thanks for the details. Will improve it in the next version.
Jing
More information about the linux-arm-kernel
mailing list