NetBSD Problem Report #48710

From www@NetBSD.org  Fri Apr  4 21:56:42 2014
Return-Path: <www@NetBSD.org>
Received: from mail.netbsd.org (mail.netbsd.org [149.20.53.66])
	(using TLSv1 with cipher ECDHE-RSA-AES256-SHA (256/256 bits))
	(Client CN "mail.netbsd.org", Issuer "Postmaster NetBSD.org" (verified OK))
	by mollari.NetBSD.org (Postfix) with ESMTPS id E6D7AA580A
	for <gnats-bugs@gnats.NetBSD.org>; Fri,  4 Apr 2014 21:56:42 +0000 (UTC)
Message-Id: <20140404215641.1C593A580F@mollari.NetBSD.org>
Date: Fri,  4 Apr 2014 21:56:40 +0000 (UTC)
From: jwerner@chromium.org
Reply-To: jwerner@chromium.org
To: gnats-bugs@NetBSD.org
Subject: Fixes for kernel ARMv7 cache invalidation routine
X-Send-Pr-Version: www-1.0

>Number:         48710
>Category:       port-arm
>Synopsis:       Fixes for kernel ARMv7 cache invalidation routine
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    port-arm-maintainer
>State:          closed
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Apr 04 22:00:00 +0000 2014
>Closed-Date:    Mon Jun 09 03:23:12 +0000 2014
>Last-Modified:  Mon Jun 09 03:23:12 +0000 2014
>Originator:     Julius Werner
>Release:        Topmost SVN revision
>Organization:
>Environment:
I never actually built NetBSD, sorry.
>Description:
Hi,

I'm not really interested in NetBSD itself, but I recently needed some BSD-compatible ARMv7 cache invalidation routines for the coreboot project and decided to take yours (the function armv7_dcache_wbinv_all from src/sys/arch/arm/arm/cpufunc_asm_armv7.S). It's a nice piece of code, but it has some bugs in it which you probably want to fix as well:

1. The code uses R3 to store the current cache level, and counts upwards towards the Level of Coherency to iterate through all of them. Unfortunately, it already initializes R3 to LoC, so you are essentially "done" immediately and never really run the main loop. You want to start at 0 instead.

2. At the end of the invalidation loop, you try to extract the set from the way/set/level mask in R0. You shift it left to drop the way (10 highest bits), and then right to drop the level (4 lowest bits), but the second shift didn't account for the fact that the register was already shifted once. It should shift by 14, not 4.

3. Right after that you use conditional execution to check if the leftover set bits are zero or not, but in order to do that (at least in ARM mode) you need to use instructions that explictly set the condition code. The second shift should be LSRS, not just LSR.
>How-To-Repeat:

>Fix:
Here's a diff that should fix all those problems (and some whitespace issues on top). It also reorders the way .Lnext_level_wbinv works to reuse a bit of that code in the initialization part. I have tested this code in coreboot and confirmed that it works as it should, but I have not actually compiled the NetBSD version (it should apply fine, though). You probably also want similar fixes in armv7_dcache_inv_all and armv7_icache_inv_all, but I did not take a close look at them.

--- a/src/sys/arch/arm/arm/cpufunc_asm_armv7.S
+++ b/src/sys/arch/arm/arm/cpufunc_asm_armv7.S
@@ -400,15 +400,20 @@
 /* * LINTSTUB: void armv7_dcache_wbinv_all(void); */
 ENTRY_NP(armv7_dcache_wbinv_all)
+       dsb
+       mov     r3, #-2                 @ initialize level so that we start at 0
+
+.Lnext_level_wbinv:
+       add     r3, r3, #2              @ increment level
+
        mrc     p15, 1, r0, c0, c0, 1   @ read CLIDR
-       ands    r3, r0, #0x07000000
-       beq     .Ldone_wbinv
-       lsr     r3, r3, #23             @ left align loc (low 4 bits)
+       and     ip, r0, #0x07000000     @ narrow to LoC
+       lsr     ip, ip, #23             @ left align LoC (low 4 bits)
+       cmp     r3, ip                  @ compare
+       bge     .Ldone_wbinv            @ else fall through (r0 == CLIDR)

-       mov     r1, #0
-.Lstart_wbinv:
-       add     r2, r3, r3, lsr #1      @ r2 = level * 3 / 2
+       add     r2, r3, r3, lsr #1      @ r2 = (level << 1) * 3 / 2
        mov     r1, r0, lsr r2          @ r1 = cache type
-       bfc     r1, #3, #29
+       and     r1, r1, #7
        cmp     r1, #2                  @ is it data or i&d?
        blt     .Lnext_level_wbinv      @ nope, skip level

@@ -420,14 +425,14 @@ ENTRY_NP(armv7_dcache_wbinv_all)
        add     ip, ip, #4              @ apply bias
        ubfx    r2, r0, #13, #15        @ get numsets - 1 from CCSIDR
        lsl     r2, r2, ip              @ shift to set position
-       orr     r3, r3, r2              @ merge set into way/set/level 
+       orr     r3, r3, r2              @ merge set into way/set/level
        mov     r1, #1
        lsl     r1, r1, ip              @ r1 = set decr

        ubfx    ip, r0, #3, #10         @ get numways - 1 from [to be discarded] CCSIDR
        clz     r2, ip                  @ number of bits to MSB of way
        lsl     ip, ip, r2              @ shift by that into way position
-       mov     r0, #1                  @
+       mov     r0, #1
        lsl     r2, r0, r2              @ r2 now contains the way decr
        mov     r0, r3                  @ get sets/level (no way yet)
        orr     r3, r3, ip              @ merge way into way/set/level
@@ -438,20 +443,12 @@ ENTRY_NP(armv7_dcache_wbinv_all)
 1:     mcr     p15, 0, r3, c7, c14, 2  @ writeback and invalidate line
        cmp     r3, #15                 @ are we done with this level (way/set == 0)
        bls     .Lnext_level_wbinv      @ yes, go to next level
-       lsl     r0, r3, #10             @ clear way bits leaving only set/level bits
-       lsr     r0, r0, #4              @ clear level bits leaving only set bits
+       lsr     r0, r3, #4              @ clear level bits leaving only way/set bits
+       lsls    r0, r0, #14             @ clear way bits leaving only set bits
        subne   r3, r3, r1              @ non-zero?, decrement set #
        subeq   r3, r3, r2              @ zero?, decrement way # and restore set count
        b       1b

-.Lnext_level_wbinv:
-       mrc     p15, 1, r0, c0, c0, 1   @ read CLIDR
-       and     ip, r0, #0x07000000     @ narrow to LoC
-       lsr     ip, ip, #23             @ left align LoC (low 4 bits)
-       add     r3, r3, #2              @ go to next level
-       cmp     r3, ip                  @ compare
-       blt     .Lstart_wbinv           @ not done, next level (r0 == CLIDR)
-
 .Ldone_wbinv:
        mov     r0, #0                  @ default back to cache level 0
        mcr     p15, 2, r0, c0, c0, 0   @ select cache level

>Release-Note:

>Audit-Trail:
From: "Matt Thomas" <matt@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/48710 CVS commit: src/sys/arch/arm/arm
Date: Thu, 10 Apr 2014 02:55:13 +0000

 Module Name:	src
 Committed By:	matt
 Date:		Thu Apr 10 02:55:13 UTC 2014

 Modified Files:
 	src/sys/arch/arm/arm: cpufunc_asm_armv7.S

 Log Message:
 Address PR/48710.
 r3 is not trashed during the routine so the level is preserved.
 The only two real bugs was not initializing r3 to 0 to start with L1 cache
 and the invalid fetching the set count from r3.  The mov r1, #0 should have
 been mov r3, #0 and has been corrected.
 Instead of two shifts, just use ubfx to extract the set bits and then compare
 them to 0.
 Add some other minor optimizations that make the code a little clearer.


 To generate a diff of this commit:
 cvs rdiff -u -r1.16 -r1.17 src/sys/arch/arm/arm/cpufunc_asm_armv7.S

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

State-Changed-From-To: open->feedback
State-Changed-By: dholland@NetBSD.org
State-Changed-When: Mon, 02 Jun 2014 02:00:28 +0000
State-Changed-Why:
fixes were committed, please review if you get a chance


From: Julius Werner <jwerner@chromium.org>
To: gnats-bugs@netbsd.org
Cc: 
Subject: Re: PR/48710 CVS commit: src/sys/arch/arm/arm
Date: Thu, 5 Jun 2014 10:45:47 -0700

 Yes, I think your patch looks good and should fix all reported issues.
 (Is this the right way to respond to one of these PRs?)

State-Changed-From-To: feedback->closed
State-Changed-By: msaitoh@NetBSD.org
State-Changed-When: Mon, 09 Jun 2014 03:23:12 +0000
State-Changed-Why:
The submitter reviewed and said it's good.
>(Is this the right way to respond to one of these PRs?)
Yes, it's right.
Thanks.


>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.