From f1fb1d5c901797b80e17d5c1d2a38aee6b63fcd2 Mon Sep 17 00:00:00 2001 From: Andrew Turner Date: Fri, 18 Oct 2024 10:16:41 +0100 Subject: [PATCH] arm64: Support more ID register field types Add MRS_EXACT_IF_DIFFERENT, MRS_HIGHER_OR_ZERO, and MRS_HIGHER. These will be used to handle the cache CTR_EL0 register, and make some ID register values safer. They are: - MRS_EXACT_IF_DIFFERENT: If the field is the same on all CPUs then use this value, otherwise use the safe value. - MRS_HIGHER_OR_ZERO: Use the highest value, or zero if seen, - MRS_HIGHER: Use the highest value. Reviewed by: imp Sponsored by: Arm Ltd Differential Revision: https://reviews.freebsd.org/D47122 --- sys/arm64/arm64/identcpu.c | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/sys/arm64/arm64/identcpu.c b/sys/arm64/arm64/identcpu.c index 83d934af345e..48ac5c59274d 100644 --- a/sys/arm64/arm64/identcpu.c +++ b/sys/arm64/arm64/identcpu.c @@ -292,7 +292,10 @@ const struct cpu_implementers cpu_implementers[] = { #define MRS_TYPE_MASK 0xf #define MRS_INVALID 0 #define MRS_EXACT 1 -#define MRS_LOWER 2 +#define MRS_EXACT_IF_DIFFERENT 2 +#define MRS_LOWER 3 +#define MRS_HIGHER_OR_ZERO 4 +#define MRS_HIGHER 5 #define MRS_SAFE_SHIFT 4 #define MRS_SAFE_MASK (0xfu << MRS_SAFE_SHIFT) #define MRS_SAFE(x) (((x) << MRS_SAFE_SHIFT) & MRS_SAFE_MASK) @@ -2175,19 +2178,41 @@ static uint64_t update_special_reg_field(uint64_t user_reg, u_int type, uint64_t value, u_int width, u_int shift, bool sign) { + uint64_t cur, mask, new_val; + + mask = ((1ul << width) - 1) << shift; + cur = user_reg & mask; + new_val = value & mask; + switch (type & MRS_TYPE_MASK) { + case MRS_EXACT_IF_DIFFERENT: + if (mrs_field_cmp(cur, new_val, shift, width, sign) != 0) + break; + /* FALLTHROUGH */ case MRS_EXACT: - user_reg &= ~(0xful << shift); - user_reg |= (uint64_t)MRS_SAFE(type) << shift; + cur = (uint64_t)MRS_SAFE_VAL(type) << shift; break; case MRS_LOWER: - user_reg = update_lower_register(user_reg, value, shift, width, - sign); + if (mrs_field_cmp(cur, new_val, shift, width, sign) < 0) + cur = new_val; + break; + case MRS_HIGHER_OR_ZERO: + if (cur == 0 || new_val == 0) { + cur = 0; + break; + } + /* FALLTHROUGH */ + case MRS_HIGHER: + if (mrs_field_cmp(cur, new_val, shift, width, sign) > 0) + cur = new_val; break; default: panic("Invalid field type: %d", type); } + user_reg &= ~mask; + user_reg |= cur; + return (user_reg); }