xref: /kernel/linux/linux-6.6/arch/s390/lib/mem.S (revision 62306a36)
162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * String handling functions.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright IBM Corp. 2012
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/export.h>
962306a36Sopenharmony_ci#include <linux/linkage.h>
1062306a36Sopenharmony_ci#include <asm/nospec-insn.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci	GEN_BR_THUNK %r14
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/*
1562306a36Sopenharmony_ci * void *memmove(void *dest, const void *src, size_t n)
1662306a36Sopenharmony_ci */
1762306a36Sopenharmony_ciSYM_FUNC_START(__memmove)
1862306a36Sopenharmony_ci	ltgr	%r4,%r4
1962306a36Sopenharmony_ci	lgr	%r1,%r2
2062306a36Sopenharmony_ci	jz	.Lmemmove_exit
2162306a36Sopenharmony_ci	aghi	%r4,-1
2262306a36Sopenharmony_ci	clgr	%r2,%r3
2362306a36Sopenharmony_ci	jnh	.Lmemmove_forward
2462306a36Sopenharmony_ci	la	%r5,1(%r4,%r3)
2562306a36Sopenharmony_ci	clgr	%r2,%r5
2662306a36Sopenharmony_ci	jl	.Lmemmove_reverse
2762306a36Sopenharmony_ci.Lmemmove_forward:
2862306a36Sopenharmony_ci	srlg	%r0,%r4,8
2962306a36Sopenharmony_ci	ltgr	%r0,%r0
3062306a36Sopenharmony_ci	jz	.Lmemmove_forward_remainder
3162306a36Sopenharmony_ci.Lmemmove_forward_loop:
3262306a36Sopenharmony_ci	mvc	0(256,%r1),0(%r3)
3362306a36Sopenharmony_ci	la	%r1,256(%r1)
3462306a36Sopenharmony_ci	la	%r3,256(%r3)
3562306a36Sopenharmony_ci	brctg	%r0,.Lmemmove_forward_loop
3662306a36Sopenharmony_ci.Lmemmove_forward_remainder:
3762306a36Sopenharmony_ci	larl	%r5,.Lmemmove_mvc
3862306a36Sopenharmony_ci	ex	%r4,0(%r5)
3962306a36Sopenharmony_ci.Lmemmove_exit:
4062306a36Sopenharmony_ci	BR_EX	%r14
4162306a36Sopenharmony_ci.Lmemmove_reverse:
4262306a36Sopenharmony_ci	ic	%r0,0(%r4,%r3)
4362306a36Sopenharmony_ci	stc	%r0,0(%r4,%r1)
4462306a36Sopenharmony_ci	brctg	%r4,.Lmemmove_reverse
4562306a36Sopenharmony_ci	ic	%r0,0(%r4,%r3)
4662306a36Sopenharmony_ci	stc	%r0,0(%r4,%r1)
4762306a36Sopenharmony_ci	BR_EX	%r14
4862306a36Sopenharmony_ci.Lmemmove_mvc:
4962306a36Sopenharmony_ci	mvc	0(1,%r1),0(%r3)
5062306a36Sopenharmony_ciSYM_FUNC_END(__memmove)
5162306a36Sopenharmony_ciEXPORT_SYMBOL(__memmove)
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ciSYM_FUNC_ALIAS(memmove, __memmove)
5462306a36Sopenharmony_ciEXPORT_SYMBOL(memmove)
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci/*
5762306a36Sopenharmony_ci * memset implementation
5862306a36Sopenharmony_ci *
5962306a36Sopenharmony_ci * This code corresponds to the C construct below. We do distinguish
6062306a36Sopenharmony_ci * between clearing (c == 0) and setting a memory array (c != 0) simply
6162306a36Sopenharmony_ci * because nearly all memset invocations in the kernel clear memory and
6262306a36Sopenharmony_ci * the xc instruction is preferred in such cases.
6362306a36Sopenharmony_ci *
6462306a36Sopenharmony_ci * void *memset(void *s, int c, size_t n)
6562306a36Sopenharmony_ci * {
6662306a36Sopenharmony_ci *	if (likely(c == 0))
6762306a36Sopenharmony_ci *		return __builtin_memset(s, 0, n);
6862306a36Sopenharmony_ci *	return __builtin_memset(s, c, n);
6962306a36Sopenharmony_ci * }
7062306a36Sopenharmony_ci */
7162306a36Sopenharmony_ciSYM_FUNC_START(__memset)
7262306a36Sopenharmony_ci	ltgr	%r4,%r4
7362306a36Sopenharmony_ci	jz	.Lmemset_exit
7462306a36Sopenharmony_ci	ltgr	%r3,%r3
7562306a36Sopenharmony_ci	jnz	.Lmemset_fill
7662306a36Sopenharmony_ci	aghi	%r4,-1
7762306a36Sopenharmony_ci	srlg	%r3,%r4,8
7862306a36Sopenharmony_ci	ltgr	%r3,%r3
7962306a36Sopenharmony_ci	lgr	%r1,%r2
8062306a36Sopenharmony_ci	jz	.Lmemset_clear_remainder
8162306a36Sopenharmony_ci.Lmemset_clear_loop:
8262306a36Sopenharmony_ci	xc	0(256,%r1),0(%r1)
8362306a36Sopenharmony_ci	la	%r1,256(%r1)
8462306a36Sopenharmony_ci	brctg	%r3,.Lmemset_clear_loop
8562306a36Sopenharmony_ci.Lmemset_clear_remainder:
8662306a36Sopenharmony_ci	larl	%r3,.Lmemset_xc
8762306a36Sopenharmony_ci	ex	%r4,0(%r3)
8862306a36Sopenharmony_ci.Lmemset_exit:
8962306a36Sopenharmony_ci	BR_EX	%r14
9062306a36Sopenharmony_ci.Lmemset_fill:
9162306a36Sopenharmony_ci	cghi	%r4,1
9262306a36Sopenharmony_ci	lgr	%r1,%r2
9362306a36Sopenharmony_ci	je	.Lmemset_fill_exit
9462306a36Sopenharmony_ci	aghi	%r4,-2
9562306a36Sopenharmony_ci	srlg	%r5,%r4,8
9662306a36Sopenharmony_ci	ltgr	%r5,%r5
9762306a36Sopenharmony_ci	jz	.Lmemset_fill_remainder
9862306a36Sopenharmony_ci.Lmemset_fill_loop:
9962306a36Sopenharmony_ci	stc	%r3,0(%r1)
10062306a36Sopenharmony_ci	mvc	1(255,%r1),0(%r1)
10162306a36Sopenharmony_ci	la	%r1,256(%r1)
10262306a36Sopenharmony_ci	brctg	%r5,.Lmemset_fill_loop
10362306a36Sopenharmony_ci.Lmemset_fill_remainder:
10462306a36Sopenharmony_ci	stc	%r3,0(%r1)
10562306a36Sopenharmony_ci	larl	%r5,.Lmemset_mvc
10662306a36Sopenharmony_ci	ex	%r4,0(%r5)
10762306a36Sopenharmony_ci	BR_EX	%r14
10862306a36Sopenharmony_ci.Lmemset_fill_exit:
10962306a36Sopenharmony_ci	stc	%r3,0(%r1)
11062306a36Sopenharmony_ci	BR_EX	%r14
11162306a36Sopenharmony_ci.Lmemset_xc:
11262306a36Sopenharmony_ci	xc	0(1,%r1),0(%r1)
11362306a36Sopenharmony_ci.Lmemset_mvc:
11462306a36Sopenharmony_ci	mvc	1(1,%r1),0(%r1)
11562306a36Sopenharmony_ciSYM_FUNC_END(__memset)
11662306a36Sopenharmony_ciEXPORT_SYMBOL(__memset)
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ciSYM_FUNC_ALIAS(memset, __memset)
11962306a36Sopenharmony_ciEXPORT_SYMBOL(memset)
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci/*
12262306a36Sopenharmony_ci * memcpy implementation
12362306a36Sopenharmony_ci *
12462306a36Sopenharmony_ci * void *memcpy(void *dest, const void *src, size_t n)
12562306a36Sopenharmony_ci */
12662306a36Sopenharmony_ciSYM_FUNC_START(__memcpy)
12762306a36Sopenharmony_ci	ltgr	%r4,%r4
12862306a36Sopenharmony_ci	jz	.Lmemcpy_exit
12962306a36Sopenharmony_ci	aghi	%r4,-1
13062306a36Sopenharmony_ci	srlg	%r5,%r4,8
13162306a36Sopenharmony_ci	ltgr	%r5,%r5
13262306a36Sopenharmony_ci	lgr	%r1,%r2
13362306a36Sopenharmony_ci	jnz	.Lmemcpy_loop
13462306a36Sopenharmony_ci.Lmemcpy_remainder:
13562306a36Sopenharmony_ci	larl	%r5,.Lmemcpy_mvc
13662306a36Sopenharmony_ci	ex	%r4,0(%r5)
13762306a36Sopenharmony_ci.Lmemcpy_exit:
13862306a36Sopenharmony_ci	BR_EX	%r14
13962306a36Sopenharmony_ci.Lmemcpy_loop:
14062306a36Sopenharmony_ci	mvc	0(256,%r1),0(%r3)
14162306a36Sopenharmony_ci	la	%r1,256(%r1)
14262306a36Sopenharmony_ci	la	%r3,256(%r3)
14362306a36Sopenharmony_ci	brctg	%r5,.Lmemcpy_loop
14462306a36Sopenharmony_ci	j	.Lmemcpy_remainder
14562306a36Sopenharmony_ci.Lmemcpy_mvc:
14662306a36Sopenharmony_ci	mvc	0(1,%r1),0(%r3)
14762306a36Sopenharmony_ciSYM_FUNC_END(__memcpy)
14862306a36Sopenharmony_ciEXPORT_SYMBOL(__memcpy)
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ciSYM_FUNC_ALIAS(memcpy, __memcpy)
15162306a36Sopenharmony_ciEXPORT_SYMBOL(memcpy)
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci/*
15462306a36Sopenharmony_ci * __memset16/32/64
15562306a36Sopenharmony_ci *
15662306a36Sopenharmony_ci * void *__memset16(uint16_t *s, uint16_t v, size_t count)
15762306a36Sopenharmony_ci * void *__memset32(uint32_t *s, uint32_t v, size_t count)
15862306a36Sopenharmony_ci * void *__memset64(uint64_t *s, uint64_t v, size_t count)
15962306a36Sopenharmony_ci */
16062306a36Sopenharmony_ci.macro __MEMSET bits,bytes,insn
16162306a36Sopenharmony_ciSYM_FUNC_START(__memset\bits)
16262306a36Sopenharmony_ci	ltgr	%r4,%r4
16362306a36Sopenharmony_ci	jz	.L__memset_exit\bits
16462306a36Sopenharmony_ci	cghi	%r4,\bytes
16562306a36Sopenharmony_ci	je	.L__memset_store\bits
16662306a36Sopenharmony_ci	aghi	%r4,-(\bytes+1)
16762306a36Sopenharmony_ci	srlg	%r5,%r4,8
16862306a36Sopenharmony_ci	ltgr	%r5,%r5
16962306a36Sopenharmony_ci	lgr	%r1,%r2
17062306a36Sopenharmony_ci	jz	.L__memset_remainder\bits
17162306a36Sopenharmony_ci.L__memset_loop\bits:
17262306a36Sopenharmony_ci	\insn	%r3,0(%r1)
17362306a36Sopenharmony_ci	mvc	\bytes(256-\bytes,%r1),0(%r1)
17462306a36Sopenharmony_ci	la	%r1,256(%r1)
17562306a36Sopenharmony_ci	brctg	%r5,.L__memset_loop\bits
17662306a36Sopenharmony_ci.L__memset_remainder\bits:
17762306a36Sopenharmony_ci	\insn	%r3,0(%r1)
17862306a36Sopenharmony_ci	larl	%r5,.L__memset_mvc\bits
17962306a36Sopenharmony_ci	ex	%r4,0(%r5)
18062306a36Sopenharmony_ci	BR_EX	%r14
18162306a36Sopenharmony_ci.L__memset_store\bits:
18262306a36Sopenharmony_ci	\insn	%r3,0(%r2)
18362306a36Sopenharmony_ci.L__memset_exit\bits:
18462306a36Sopenharmony_ci	BR_EX	%r14
18562306a36Sopenharmony_ci.L__memset_mvc\bits:
18662306a36Sopenharmony_ci	mvc	\bytes(1,%r1),0(%r1)
18762306a36Sopenharmony_ciSYM_FUNC_END(__memset\bits)
18862306a36Sopenharmony_ci.endm
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci__MEMSET 16,2,sth
19162306a36Sopenharmony_ciEXPORT_SYMBOL(__memset16)
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci__MEMSET 32,4,st
19462306a36Sopenharmony_ciEXPORT_SYMBOL(__memset32)
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci__MEMSET 64,8,stg
19762306a36Sopenharmony_ciEXPORT_SYMBOL(__memset64)
198