arm64: cpufeature: Force HWCAP to be based on the sysreg visible to user-space
[ Upstream commit 237405ebef
]
arm64 advertises hardware features to user-space via HWCAPs, and by
emulating access to the CPUs id registers. The cpufeature code has a
sanitised system-wide view of an id register, and a sanitised user-space
view of an id register, where some features use their 'safe' value
instead of the hardware value.
It is currently possible for a HWCAP to be advertised where the user-space
view of the id register does not show the feature as supported.
Erratum workaround need to remove both the HWCAP, and the feature from
the user-space view of the id register. This involves duplicating the
code, and spreading it over cpufeature.c and cpu_errata.c.
Make the HWCAP code use the user-space view of id registers. This ensures
the values never diverge, and allows erratum workaround to remove HWCAP
by modifying the user-space view of the id register.
Signed-off-by: James Morse <james.morse@arm.com>
Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Link: https://lore.kernel.org/r/20220909165938.3931307-2-james.morse@arm.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
[ Mark: fixup lack of 'width' parameter ]
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Родитель
f07bf04fbf
Коммит
77137d50c9
|
@ -1319,17 +1319,39 @@ feature_matches(u64 reg, const struct arm64_cpu_capabilities *entry)
|
|||
return val >= entry->min_field_value;
|
||||
}
|
||||
|
||||
static u64
|
||||
read_scoped_sysreg(const struct arm64_cpu_capabilities *entry, int scope)
|
||||
{
|
||||
WARN_ON(scope == SCOPE_LOCAL_CPU && preemptible());
|
||||
if (scope == SCOPE_SYSTEM)
|
||||
return read_sanitised_ftr_reg(entry->sys_reg);
|
||||
else
|
||||
return __read_sysreg_by_encoding(entry->sys_reg);
|
||||
}
|
||||
|
||||
static bool
|
||||
has_user_cpuid_feature(const struct arm64_cpu_capabilities *entry, int scope)
|
||||
{
|
||||
int mask;
|
||||
struct arm64_ftr_reg *regp;
|
||||
u64 val = read_scoped_sysreg(entry, scope);
|
||||
|
||||
regp = get_arm64_ftr_reg(entry->sys_reg);
|
||||
if (!regp)
|
||||
return false;
|
||||
|
||||
mask = cpuid_feature_extract_unsigned_field(regp->user_mask,
|
||||
entry->field_pos);
|
||||
if (!mask)
|
||||
return false;
|
||||
|
||||
return feature_matches(val, entry);
|
||||
}
|
||||
|
||||
static bool
|
||||
has_cpuid_feature(const struct arm64_cpu_capabilities *entry, int scope)
|
||||
{
|
||||
u64 val;
|
||||
|
||||
WARN_ON(scope == SCOPE_LOCAL_CPU && preemptible());
|
||||
if (scope == SCOPE_SYSTEM)
|
||||
val = read_sanitised_ftr_reg(entry->sys_reg);
|
||||
else
|
||||
val = __read_sysreg_by_encoding(entry->sys_reg);
|
||||
|
||||
u64 val = read_scoped_sysreg(entry, scope);
|
||||
return feature_matches(val, entry);
|
||||
}
|
||||
|
||||
|
@ -2376,7 +2398,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
|
|||
};
|
||||
|
||||
#define HWCAP_CPUID_MATCH(reg, field, s, min_value) \
|
||||
.matches = has_cpuid_feature, \
|
||||
.matches = has_user_cpuid_feature, \
|
||||
.sys_reg = reg, \
|
||||
.field_pos = field, \
|
||||
.sign = s, \
|
||||
|
|
Загрузка…
Ссылка в новой задаче