Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dfbf8c98 authored by Will Deacon's avatar Will Deacon Committed by Greg Kroah-Hartman
Browse files

arm64: Fix minor issues with the dcache_by_line_op macro



[ Upstream commit 33309ecda0070506c49182530abe7728850ebe78 ]

The dcache_by_line_op macro suffers from a couple of small problems:

First, the GAS directives that are currently being used rely on
assembler behavior that is not documented, and probably not guaranteed
to produce the correct behavior going forward. As a result, we end up
with some undefined symbols in cache.o:

$ nm arch/arm64/mm/cache.o
         ...
         U civac
         ...
         U cvac
         U cvap
         U cvau

This is due to the fact that the comparisons used to select the
operation type in the dcache_by_line_op macro are comparing symbols
not strings, and even though it seems that GAS is doing the right
thing here (undefined symbols by the same name are equal to each
other), it seems unwise to rely on this.

Second, when patching in a DC CVAP instruction on CPUs that support it,
the fallback path consists of a DC CVAU instruction which may be
affected by CPU errata that require ARM64_WORKAROUND_CLEAN_CACHE.

Solve these issues by unrolling the various maintenance routines and
using the conditional directives that are documented as operating on
strings. To avoid the complexity of nested alternatives, we move the
DC CVAP patching to __clean_dcache_area_pop, falling back to a branch
to __clean_dcache_area_poc if DCPOP is not supported by the CPU.

Reported-by: default avatarArd Biesheuvel <ard.biesheuvel@linaro.org>
Suggested-by: default avatarRobin Murphy <robin.murphy@arm.com>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 73f0b2e3
Loading
Loading
Loading
Loading
+18 −12
Original line number Original line Diff line number Diff line
@@ -378,27 +378,33 @@ alternative_endif
 * 	size:		size of the region
 * 	size:		size of the region
 * 	Corrupts:	kaddr, size, tmp1, tmp2
 * 	Corrupts:	kaddr, size, tmp1, tmp2
 */
 */
	.macro __dcache_op_workaround_clean_cache, op, kaddr
alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
	dc	\op, \kaddr
alternative_else
	dc	civac, \kaddr
alternative_endif
	.endm

	.macro dcache_by_line_op op, domain, kaddr, size, tmp1, tmp2
	.macro dcache_by_line_op op, domain, kaddr, size, tmp1, tmp2
	dcache_line_size \tmp1, \tmp2
	dcache_line_size \tmp1, \tmp2
	add	\size, \kaddr, \size
	add	\size, \kaddr, \size
	sub	\tmp2, \tmp1, #1
	sub	\tmp2, \tmp1, #1
	bic	\kaddr, \kaddr, \tmp2
	bic	\kaddr, \kaddr, \tmp2
9998:
9998:
	.if	(\op == cvau || \op == cvac)
	.ifc	\op, cvau
alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
	__dcache_op_workaround_clean_cache \op, \kaddr
	dc	\op, \kaddr
	.else
alternative_else
	.ifc	\op, cvac
	dc	civac, \kaddr
	__dcache_op_workaround_clean_cache \op, \kaddr
alternative_endif
	.else
	.elseif	(\op == cvap)
	.ifc	\op, cvap
alternative_if ARM64_HAS_DCPOP
	sys	3, c7, c12, 1, \kaddr	// dc cvap
	sys	3, c7, c12, 1, \kaddr	// dc cvap
alternative_else
	dc	cvac, \kaddr
alternative_endif
	.else
	.else
	dc	\op, \kaddr
	dc	\op, \kaddr
	.endif
	.endif
	.endif
	.endif
	add	\kaddr, \kaddr, \tmp1
	add	\kaddr, \kaddr, \tmp1
	cmp	\kaddr, \size
	cmp	\kaddr, \size
	b.lo	9998b
	b.lo	9998b
+3 −0
Original line number Original line Diff line number Diff line
@@ -212,6 +212,9 @@ ENDPROC(__dma_clean_area)
 *	- size    - size in question
 *	- size    - size in question
 */
 */
ENTRY(__clean_dcache_area_pop)
ENTRY(__clean_dcache_area_pop)
	alternative_if_not ARM64_HAS_DCPOP
	b	__clean_dcache_area_poc
	alternative_else_nop_endif
	dcache_by_line_op cvap, sy, x0, x1, x2, x3
	dcache_by_line_op cvap, sy, x0, x1, x2, x3
	ret
	ret
ENDPIPROC(__clean_dcache_area_pop)
ENDPIPROC(__clean_dcache_area_pop)