coreboot-kgpe-d16/payloads/libpayload/arch/arm/cpu.S
Julius Werner 638015b98b arm: Fix minor mistake in cache maintenance assembly
Turns out that when you clear 28 bits starting with bit 3, you leave bit
31 standing. Ooops...

This shouldn't really matter since that bit is reserved/SBZ in CLIDR
anyway, but it's still nice to fix it. This whole thing should really be
an AND for clarity anyway in my opinion.

Bug found in upstream NetBSD (who would've thought...).

BUG=None
TEST=Still boots.

Change-Id: Ic826e82d58fd1ce984971afea3dfa9296f746d9f
Signed-off-by: Julius Werner <jwerner@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/193300
Reviewed-by: David Hendricks <dhendrix@chromium.org>
Reviewed-by: Gabe Black <gabeblack@chromium.org>
(cherry picked from commit d270c0ec18b74b272451c456cbf07e99d95896cb)
Signed-off-by: Marc Jones <marc.jones@se-eng.com>
Reviewed-on: http://review.coreboot.org/7745
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2014-12-15 23:27:41 +01:00

117 lines
4.5 KiB
ArmAsm

/*
* Optimized assembly for low-level CPU operations on ARMv7 processors.
*
* Cache flushing code based off sys/arch/arm/arm/cpufunc_asm_armv7.S in NetBSD
*
* Copyright (c) 2010 Per Odlund <per.odlund@armagedon.se>
* Copyright (c) 2014 Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <arch/asm.h>
/*
* Dcache invalidations by set/way work by passing a [way:sbz:set:sbz:level:0]
* bitfield in a register to the appropriate MCR instruction. This algorithm
* works by initializing a bitfield with the highest-numbered set and way, and
* generating a "set decrement" and a "way decrement". The former just contains
* the LSB of the set field, but the latter contains the LSB of the way field
* minus the highest valid set field... such that when you subtract it from a
* [way:0:level] field you end up with a [way - 1:highest_set:level] field
* through the magic of double subtraction. It's quite ingenius, really.
* Takes care to only use r0-r3 and ip so it's pefectly ABI-compatible without
* needing to write to memory.
*/
.macro dcache_apply_all crm
dsb
mov r3, #-2 @ initialize level so that we start at 0
1: @next_level
add r3, r3, #2 @ increment level
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)
cmp r3, ip @ compare
bge 3f @done @ else fall through (r0 == CLIDR)
add r2, r3, r3, lsr #1 @ r2 = (level << 1) * 3 / 2
mov r1, r0, lsr r2 @ r1 = cache type
and r1, r1, #7
cmp r1, #2 @ is it data or i&d?
blt 1b @next_level @ nope, skip level
mcr p15, 2, r3, c0, c0, 0 @ select cache level
isb
mrc p15, 1, r0, c0, c0, 0 @ read CCSIDR
ubfx ip, r0, #0, #3 @ get linesize from CCSIDR
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
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
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
bfc r0, #0, #4 @ clear low 4 bits (level) to get numset - 1
sub r2, r2, r0 @ subtract from way decr
/* r3 = ways/sets/level, r2 = way decr, r1 = set decr, r0 and ip are free */
2: mcr p15, 0, r3, c7, \crm, 2 @ writeback and/or invalidate line
cmp r3, #15 @ are we done with this level (way/set == 0)
bls 1b @next_level @ yes, go to next level
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 2b
3: @done
mov r0, #0 @ default back to cache level 0
mcr p15, 2, r0, c0, c0, 0 @ select cache level
dsb
isb
bx lr
.endm
ENTRY(dcache_invalidate_all)
dcache_apply_all crm=c6
ENDPROC(dcache_invalidate_all)
ENTRY(dcache_clean_all)
dcache_apply_all crm=c10
ENDPROC(dcache_clean_all)
ENTRY(dcache_clean_invalidate_all)
dcache_apply_all crm=c14
ENDPROC(dcache_clean_invalidate_all)