To emulate ID registers, we need to validate the value of the register defined by user space. For most ID registers, we need to check whether each field defined by user space is no more than that of host (whether host support the corresponding features) and whether the fields are supposed to be exposed to guest. Introduce check_features to do those jobs. Signed-off-by: zhanghailiang <zhang.zhanghailiang@xxxxxxxxxx> Signed-off-by: Peng Liang <liangpeng10@xxxxxxxxxx> --- arch/arm64/include/asm/cpufeature.h | 2 ++ arch/arm64/kernel/cpufeature.c | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 2ba7c4f11d8a..954adc5ca72f 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -579,6 +579,8 @@ void check_local_cpu_capabilities(void); u64 read_sanitised_ftr_reg(u32 id); +int check_features(u32 sys_reg, u64 val); + static inline bool cpu_supports_mixed_endian_el0(void) { return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1)); diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 698b32705544..e58926992a70 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -2850,3 +2850,26 @@ ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, return sprintf(buf, "Vulnerable\n"); } + +int check_features(u32 sys_reg, u64 val) +{ + struct arm64_ftr_reg *reg = get_arm64_ftr_reg(sys_reg); + const struct arm64_ftr_bits *ftrp; + u64 exposed_mask = 0; + + if (!reg) + return -ENOENT; + + for (ftrp = reg->ftr_bits; ftrp->width; ftrp++) { + if (arm64_ftr_value(ftrp, reg->sys_val) < + arm64_ftr_value(ftrp, val)) { + return -EINVAL; + } + exposed_mask |= arm64_ftr_mask(ftrp); + } + + if (val & ~exposed_mask) + return -EINVAL; + + return 0; +} -- 2.26.2