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