Hey Marc,
On Sat, Jan 21, 2023 at 12:02:03PM +0000, Marc Zyngier wrote:
On Thu, 19 Jan 2023 19:46:16 +0000, Oliver Upton <oliver.upton@xxxxxxxxx> wrote:
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 459e6d358dab..b6228f7d1d8d 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -148,17 +148,19 @@ static u32 get_ccsidr(struct kvm_vcpu *vcpu, u32 csselr)
static int set_ccsidr(struct kvm_vcpu *vcpu, u32 csselr, u32 val)
{
- u8 line_size = FIELD_GET(CCSIDR_EL1_LineSize, val);
+ u8 line_size = SYS_FIELD_GET(CCSIDR_EL1, LineSize, val);
+ u32 cur = get_ccsidr(vcpu, csselr);
+ u8 min_line_size = SYS_FIELD_GET(CCSIDR_EL1, LineSize, cur);
u32 *ccsidr = vcpu->arch.ccsidr;
u32 i;
- if ((val & CCSIDR_EL1_RES0) || line_size < get_min_cache_line_size(csselr))
+ if (cur == val)
+ return 0;
+
+ if ((val & CCSIDR_EL1_RES0) || line_size < min_line_size)
return -EINVAL;
This doesn't look right. You're comparing the value userspace is
trying to set for a given level with the value that is already set for
that level, and forbid the cache line size to be smaller. It works if
no value has been set yet (you fallback to something derived from
CTR_EL0), but this fails if userspace does multiple writes.
Good catch, I tried to skip over the unit/field conversions by doing this
but it has the consequence of not working as expected for multiple writes.
The original check is against CTR_EL0, which makes absolute sense
because we want to check across the whole hierarchy. It is just that
the original code has two bugs:
- It fails to convert the CCSIDR_EL1.LineSize value to a number of
words (the missing +4). Admire how the architecture is actively
designed to be hostile to SW by providing two different formats for
the cache line size, none of which is in... bytes.
- It passes the full CSSELR value to get_min_cache_line_size(), while
this function wants a bool... Yes, there are times where you'd want
a stronger type system (did anyone say Rust? ;-)
Hey now, if you say it enough times people are going to start getting
ideas ;-P
I propose that we fold something like the patch below in instead
(tested with get-reg-list).
Agreed, I've backed out my diff and applied yours. Pushed (with force!)
to my repo now, PTAL.
--
Thanks,
Oliver