[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v3 4/7] xen/arm: Sanitize cpuinfo ID registers fields
Hi Stefano, > On 3 Sep 2021, at 23:48, Stefano Stabellini <sstabellini@xxxxxxxxxx> wrote: > > On Wed, 25 Aug 2021, Bertrand Marquis wrote: >> Define a sanitize_cpu function to be called on secondary cores to >> sanitize the system cpuinfo structure. >> >> The safest value is taken when possible and the system is marked tainted >> if we encounter values which are incompatible with each other. >> >> Call the update_system_features function on all secondary cores that are >> kept running and taint the system if different midr are found between >> cores but hmp-unsafe=true was passed on Xen command line. >> >> This is only supported on arm64 so update_system_features is an empty >> static inline on arm32. >> >> The patch is adding a new TAINT_CPU_OUT_OF_SPEC to warn the user if >> Xen is running on a system with features differences between cores which >> are not supported. >> >> The patch is disabling CTR_EL0, DCZID_EL0 and ZCRusing #if 0 with a TODO >> as this patch is not handling sanitization of those registers. >> CTR_EL0/DCZID will be handled in a future patch to properly handle >> different cache attributes when possible. >> ZCR should be sanitize once we add support for SVE in Xen. >> >> Signed-off-by: Bertrand Marquis <bertrand.marquis@xxxxxxx> > > Great patch! It looks good I only have a couple of minor questions > below. Thanks > > >> --- >> Changes in v3: >> - in case of different midr but hmp-unsafe passed on the command line, >> enable all cores anyway but taint Xen with CPU_OUT_OF_SPEC. >> - use current core info to sanitize cpu only if we keep it on >> Changes in v2: >> - add compilation of cpufeature.c in this patch instead of previous one >> - remove functions reused from linux code and moved to header >> - rename sanitize_cpu to update_system_features >> - change to Linux coding style >> - remove dev comments >> - surround currently not used Linux structures with #if 0 and adapt the >> commit message >> - add missing aa64dfr1 register >> - add TODO for CTR, DCZID and ZCR >> - add CPU_OUT_OF_SPEC support to print_taint >> - use system_cpuinfo instead of boot_cpu_data >> --- >> xen/arch/arm/arm64/Makefile | 1 + >> xen/arch/arm/arm64/cpufeature.c | 121 +++++++++++++++++++++++++++++++ >> xen/arch/arm/smpboot.c | 34 +++++++-- >> xen/common/kernel.c | 6 +- >> xen/include/asm-arm/cpufeature.h | 9 +++ >> xen/include/xen/lib.h | 1 + >> 6 files changed, 162 insertions(+), 10 deletions(-) >> >> diff --git a/xen/arch/arm/arm64/Makefile b/xen/arch/arm/arm64/Makefile >> index 40642ff574..701d66883d 100644 >> --- a/xen/arch/arm/arm64/Makefile >> +++ b/xen/arch/arm/arm64/Makefile >> @@ -1,6 +1,7 @@ >> obj-y += lib/ >> >> obj-y += cache.o >> +obj-y += cpufeature.o >> obj-$(CONFIG_HARDEN_BRANCH_PREDICTOR) += bpi.o >> obj-$(CONFIG_EARLY_PRINTK) += debug.o >> obj-y += domctl.o >> diff --git a/xen/arch/arm/arm64/cpufeature.c >> b/xen/arch/arm/arm64/cpufeature.c >> index 5777e33e5c..61f629ebaa 100644 >> --- a/xen/arch/arm/arm64/cpufeature.c >> +++ b/xen/arch/arm/arm64/cpufeature.c >> @@ -275,6 +275,9 @@ static const struct arm64_ftr_bits ftr_id_aa64mmfr2[] = { >> ARM64_FTR_END, >> }; >> >> +#if 0 >> +/* TODO: use this to sanitize the cache line size among cores */ >> + >> static const struct arm64_ftr_bits ftr_ctr[] = { >> ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, 31, 1, 1), /* RES1 */ >> ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_DIC_SHIFT, >> 1, 1), >> @@ -291,6 +294,7 @@ static const struct arm64_ftr_bits ftr_ctr[] = { >> ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, >> CTR_IMINLINE_SHIFT, 4, 0), >> ARM64_FTR_END, >> }; >> +#endif >> >> static const struct arm64_ftr_bits ftr_id_mmfr0[] = { >> S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, >> ID_MMFR0_INNERSHR_SHIFT, 4, 0xf), >> @@ -325,11 +329,14 @@ static const struct arm64_ftr_bits ftr_mvfr2[] = { >> ARM64_FTR_END, >> }; >> >> +#if 0 >> +/* TODO: handle this when sanitizing cache related registers */ >> static const struct arm64_ftr_bits ftr_dczid[] = { >> ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, DCZID_DZP_SHIFT, 1, >> 1), >> ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, DCZID_BS_SHIFT, >> 4, 0), >> ARM64_FTR_END, >> }; >> +#endif >> >> static const struct arm64_ftr_bits ftr_id_isar0[] = { >> ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, >> ID_ISAR0_DIVIDE_SHIFT, 4, 0), >> @@ -444,11 +451,15 @@ static const struct arm64_ftr_bits ftr_id_dfr1[] = { >> ARM64_FTR_END, >> }; >> >> +#if 0 >> +/* TODO: use this to sanitize SVE once we support it */ >> + >> static const struct arm64_ftr_bits ftr_zcr[] = { >> ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, >> ZCR_ELx_LEN_SHIFT, ZCR_ELx_LEN_SIZE, 0), /* LEN */ >> ARM64_FTR_END, >> }; >> +#endif >> >> /* >> * Common ftr bits for a 32bit register with all hidden, strict >> @@ -502,3 +513,113 @@ static s64 arm64_ftr_safe_value(const struct >> arm64_ftr_bits *ftrp, s64 new, >> * End of imported linux structures and code >> */ >> >> +static void sanitize_reg(u64 *cur_reg, u64 new_reg, const char *reg_name, >> + const struct arm64_ftr_bits >> *ftrp) >> +{ >> + int taint = 0; >> + u64 old_reg = *cur_reg; >> + >> + for (;ftrp->width != 0;ftrp++) >> + { >> + u64 mask; >> + s64 cur_field = arm64_ftr_value(ftrp, *cur_reg); >> + s64 new_field = arm64_ftr_value(ftrp, new_reg); >> + >> + if (cur_field == new_field) >> + continue; >> + >> + if (ftrp->strict) >> + taint = 1; >> + >> + mask = arm64_ftr_mask(ftrp); >> + >> + *cur_reg &= ~mask; >> + *cur_reg |= (arm64_ftr_safe_value(ftrp, new_field, cur_field) >> + << ftrp->shift) & mask; > > I wonder why you haven't also imported arm64_ftr_set_value? This seems > to be the open-coded version of it. You are right I could have used it instead (no idea why I did not). I will modify that and send an update. Good finding :-) > > >> + } >> + >> + if (old_reg != new_reg) >> + printk(XENLOG_DEBUG "SANITY DIF: %s 0x%"PRIx64" -> >> 0x%"PRIx64"\n", >> + reg_name, old_reg, new_reg); >> + if (old_reg != *cur_reg) >> + printk(XENLOG_DEBUG "SANITY FIX: %s 0x%"PRIx64" -> >> 0x%"PRIx64"\n", >> + reg_name, old_reg, *cur_reg); >> + >> + if (taint) >> + { >> + printk(XENLOG_WARNING "SANITY CHECK: Unexpected variation in >> %s.\n", >> + reg_name); >> + add_taint(TAINT_CPU_OUT_OF_SPEC); >> + } >> +} >> + >> + >> +/* >> + * This function should be called on secondary cores to sanitize the boot >> cpu >> + * cpuinfo. >> + */ >> +void update_system_features(const struct cpuinfo_arm *new) >> +{ >> + >> +#define SANITIZE_REG(field, num, reg) \ >> + sanitize_reg(&system_cpuinfo.field.bits[num], new->field.bits[num], \ >> + #reg, ftr_##reg) >> + >> +#define SANITIZE_ID_REG(field, num, reg) \ >> + sanitize_reg(&system_cpuinfo.field.bits[num], new->field.bits[num], \ >> + #reg, ftr_id_##reg) >> + >> +#define SANITIZE_RAZ_REG(field, num, reg) \ >> + sanitize_reg(&system_cpuinfo.field.bits[num], new->field.bits[num], \ >> + #reg, ftr_raz) >> + >> +#define SANITIZE_GENERIC_REG(field, num, reg) \ >> + sanitize_reg(&system_cpuinfo.field.bits[num], new->field.bits[num], \ >> + #reg, ftr_generic_32bits) >> + >> + SANITIZE_ID_REG(pfr64, 0, aa64pfr0); >> + SANITIZE_ID_REG(pfr64, 1, aa64pfr1); >> + >> + SANITIZE_ID_REG(dbg64, 0, aa64dfr0); >> + SANITIZE_RAZ_REG(dbg64, 1, aa64dfr1); >> + >> + SANITIZE_ID_REG(mm64, 0, aa64mmfr0); >> + SANITIZE_ID_REG(mm64, 1, aa64mmfr1); >> + SANITIZE_ID_REG(mm64, 2, aa64mmfr2); >> + >> + SANITIZE_ID_REG(isa64, 0, aa64isar0); >> + SANITIZE_ID_REG(isa64, 1, aa64isar1); >> + >> + SANITIZE_ID_REG(zfr64, 0, aa64zfr0); >> + >> + if ( cpu_feature64_has_el0_32(&system_cpuinfo) ) >> + { >> + SANITIZE_ID_REG(pfr32, 0, pfr0); >> + SANITIZE_ID_REG(pfr32, 1, pfr1); >> + SANITIZE_ID_REG(pfr32, 2, pfr2); >> + >> + SANITIZE_ID_REG(dbg32, 0, dfr0); >> + SANITIZE_ID_REG(dbg32, 1, dfr1); >> + >> + SANITIZE_ID_REG(mm32, 0, mmfr0); >> + SANITIZE_GENERIC_REG(mm32, 1, mmfr1); >> + SANITIZE_GENERIC_REG(mm32, 2, mmfr2); >> + SANITIZE_GENERIC_REG(mm32, 3, mmfr3); >> + SANITIZE_ID_REG(mm32, 4, mmfr4); >> + SANITIZE_ID_REG(mm32, 5, mmfr5); >> + >> + SANITIZE_ID_REG(isa32, 0, isar0); >> + SANITIZE_GENERIC_REG(isa32, 1, isar1); >> + SANITIZE_GENERIC_REG(isa32, 2, isar2); >> + SANITIZE_GENERIC_REG(isa32, 3, isar3); >> + SANITIZE_ID_REG(isa32, 4, isar4); >> + SANITIZE_ID_REG(isa32, 5, isar5); >> + SANITIZE_ID_REG(isa32, 6, isar6); >> + >> + SANITIZE_GENERIC_REG(mvfr, 0, mvfr0); >> + SANITIZE_GENERIC_REG(mvfr, 1, mvfr1); >> +#ifndef MVFR2_MAYBE_UNDEFINED >> + SANITIZE_REG(mvfr, 2, mvfr2); >> +#endif >> + } >> +} > > Looking at the list of registers we are sanitizing here we are only > missing aux32 and aux64 compared to struct cpuinfo_arm. Is that because > there is nothing to sanitize there? Aux registers have no standard bit definition and as such cannot be treated. Linux is doing the same. Cheers Bertrand
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |