162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Memory copy functions for 32-bit PowerPC. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1996-2005 Paul Mackerras. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include <linux/export.h> 862306a36Sopenharmony_ci#include <asm/processor.h> 962306a36Sopenharmony_ci#include <asm/cache.h> 1062306a36Sopenharmony_ci#include <asm/errno.h> 1162306a36Sopenharmony_ci#include <asm/ppc_asm.h> 1262306a36Sopenharmony_ci#include <asm/code-patching-asm.h> 1362306a36Sopenharmony_ci#include <asm/kasan.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define COPY_16_BYTES \ 1662306a36Sopenharmony_ci lwz r7,4(r4); \ 1762306a36Sopenharmony_ci lwz r8,8(r4); \ 1862306a36Sopenharmony_ci lwz r9,12(r4); \ 1962306a36Sopenharmony_ci lwzu r10,16(r4); \ 2062306a36Sopenharmony_ci stw r7,4(r6); \ 2162306a36Sopenharmony_ci stw r8,8(r6); \ 2262306a36Sopenharmony_ci stw r9,12(r6); \ 2362306a36Sopenharmony_ci stwu r10,16(r6) 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define COPY_16_BYTES_WITHEX(n) \ 2662306a36Sopenharmony_ci8 ## n ## 0: \ 2762306a36Sopenharmony_ci lwz r7,4(r4); \ 2862306a36Sopenharmony_ci8 ## n ## 1: \ 2962306a36Sopenharmony_ci lwz r8,8(r4); \ 3062306a36Sopenharmony_ci8 ## n ## 2: \ 3162306a36Sopenharmony_ci lwz r9,12(r4); \ 3262306a36Sopenharmony_ci8 ## n ## 3: \ 3362306a36Sopenharmony_ci lwzu r10,16(r4); \ 3462306a36Sopenharmony_ci8 ## n ## 4: \ 3562306a36Sopenharmony_ci stw r7,4(r6); \ 3662306a36Sopenharmony_ci8 ## n ## 5: \ 3762306a36Sopenharmony_ci stw r8,8(r6); \ 3862306a36Sopenharmony_ci8 ## n ## 6: \ 3962306a36Sopenharmony_ci stw r9,12(r6); \ 4062306a36Sopenharmony_ci8 ## n ## 7: \ 4162306a36Sopenharmony_ci stwu r10,16(r6) 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define COPY_16_BYTES_EXCODE(n) \ 4462306a36Sopenharmony_ci9 ## n ## 0: \ 4562306a36Sopenharmony_ci addi r5,r5,-(16 * n); \ 4662306a36Sopenharmony_ci b 104f; \ 4762306a36Sopenharmony_ci9 ## n ## 1: \ 4862306a36Sopenharmony_ci addi r5,r5,-(16 * n); \ 4962306a36Sopenharmony_ci b 105f; \ 5062306a36Sopenharmony_ci EX_TABLE(8 ## n ## 0b,9 ## n ## 0b); \ 5162306a36Sopenharmony_ci EX_TABLE(8 ## n ## 1b,9 ## n ## 0b); \ 5262306a36Sopenharmony_ci EX_TABLE(8 ## n ## 2b,9 ## n ## 0b); \ 5362306a36Sopenharmony_ci EX_TABLE(8 ## n ## 3b,9 ## n ## 0b); \ 5462306a36Sopenharmony_ci EX_TABLE(8 ## n ## 4b,9 ## n ## 1b); \ 5562306a36Sopenharmony_ci EX_TABLE(8 ## n ## 5b,9 ## n ## 1b); \ 5662306a36Sopenharmony_ci EX_TABLE(8 ## n ## 6b,9 ## n ## 1b); \ 5762306a36Sopenharmony_ci EX_TABLE(8 ## n ## 7b,9 ## n ## 1b) 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci .text 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ciCACHELINE_BYTES = L1_CACHE_BYTES 6262306a36Sopenharmony_ciLG_CACHELINE_BYTES = L1_CACHE_SHIFT 6362306a36Sopenharmony_ciCACHELINE_MASK = (L1_CACHE_BYTES-1) 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#ifndef CONFIG_KASAN 6662306a36Sopenharmony_ci_GLOBAL(memset16) 6762306a36Sopenharmony_ci rlwinm. r0 ,r5, 31, 1, 31 6862306a36Sopenharmony_ci addi r6, r3, -4 6962306a36Sopenharmony_ci beq- 2f 7062306a36Sopenharmony_ci rlwimi r4 ,r4 ,16 ,0 ,15 7162306a36Sopenharmony_ci mtctr r0 7262306a36Sopenharmony_ci1: stwu r4, 4(r6) 7362306a36Sopenharmony_ci bdnz 1b 7462306a36Sopenharmony_ci2: andi. r0, r5, 1 7562306a36Sopenharmony_ci beqlr 7662306a36Sopenharmony_ci sth r4, 4(r6) 7762306a36Sopenharmony_ci blr 7862306a36Sopenharmony_ciEXPORT_SYMBOL(memset16) 7962306a36Sopenharmony_ci#endif 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* 8262306a36Sopenharmony_ci * Use dcbz on the complete cache lines in the destination 8362306a36Sopenharmony_ci * to set them to zero. This requires that the destination 8462306a36Sopenharmony_ci * area is cacheable. -- paulus 8562306a36Sopenharmony_ci * 8662306a36Sopenharmony_ci * During early init, cache might not be active yet, so dcbz cannot be used. 8762306a36Sopenharmony_ci * We therefore skip the optimised bloc that uses dcbz. This jump is 8862306a36Sopenharmony_ci * replaced by a nop once cache is active. This is done in machine_init() 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci_GLOBAL_KASAN(memset) 9162306a36Sopenharmony_ci cmplwi 0,r5,4 9262306a36Sopenharmony_ci blt 7f 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci rlwimi r4,r4,8,16,23 9562306a36Sopenharmony_ci rlwimi r4,r4,16,0,15 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci stw r4,0(r3) 9862306a36Sopenharmony_ci beqlr 9962306a36Sopenharmony_ci andi. r0,r3,3 10062306a36Sopenharmony_ci add r5,r0,r5 10162306a36Sopenharmony_ci subf r6,r0,r3 10262306a36Sopenharmony_ci cmplwi 0,r4,0 10362306a36Sopenharmony_ci /* 10462306a36Sopenharmony_ci * Skip optimised bloc until cache is enabled. Will be replaced 10562306a36Sopenharmony_ci * by 'bne' during boot to use normal procedure if r4 is not zero 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_ci5: b 2f 10862306a36Sopenharmony_ci patch_site 5b, patch__memset_nocache 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci clrlwi r7,r6,32-LG_CACHELINE_BYTES 11162306a36Sopenharmony_ci add r8,r7,r5 11262306a36Sopenharmony_ci srwi r9,r8,LG_CACHELINE_BYTES 11362306a36Sopenharmony_ci addic. r9,r9,-1 /* total number of complete cachelines */ 11462306a36Sopenharmony_ci ble 2f 11562306a36Sopenharmony_ci xori r0,r7,CACHELINE_MASK & ~3 11662306a36Sopenharmony_ci srwi. r0,r0,2 11762306a36Sopenharmony_ci beq 3f 11862306a36Sopenharmony_ci mtctr r0 11962306a36Sopenharmony_ci4: stwu r4,4(r6) 12062306a36Sopenharmony_ci bdnz 4b 12162306a36Sopenharmony_ci3: mtctr r9 12262306a36Sopenharmony_ci li r7,4 12362306a36Sopenharmony_ci10: dcbz r7,r6 12462306a36Sopenharmony_ci addi r6,r6,CACHELINE_BYTES 12562306a36Sopenharmony_ci bdnz 10b 12662306a36Sopenharmony_ci clrlwi r5,r8,32-LG_CACHELINE_BYTES 12762306a36Sopenharmony_ci addi r5,r5,4 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci2: srwi r0,r5,2 13062306a36Sopenharmony_ci mtctr r0 13162306a36Sopenharmony_ci bdz 6f 13262306a36Sopenharmony_ci1: stwu r4,4(r6) 13362306a36Sopenharmony_ci bdnz 1b 13462306a36Sopenharmony_ci6: andi. r5,r5,3 13562306a36Sopenharmony_ci beqlr 13662306a36Sopenharmony_ci mtctr r5 13762306a36Sopenharmony_ci addi r6,r6,3 13862306a36Sopenharmony_ci8: stbu r4,1(r6) 13962306a36Sopenharmony_ci bdnz 8b 14062306a36Sopenharmony_ci blr 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci7: cmpwi 0,r5,0 14362306a36Sopenharmony_ci beqlr 14462306a36Sopenharmony_ci mtctr r5 14562306a36Sopenharmony_ci addi r6,r3,-1 14662306a36Sopenharmony_ci9: stbu r4,1(r6) 14762306a36Sopenharmony_ci bdnz 9b 14862306a36Sopenharmony_ci blr 14962306a36Sopenharmony_ciEXPORT_SYMBOL(memset) 15062306a36Sopenharmony_ciEXPORT_SYMBOL_KASAN(memset) 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/* 15362306a36Sopenharmony_ci * This version uses dcbz on the complete cache lines in the 15462306a36Sopenharmony_ci * destination area to reduce memory traffic. This requires that 15562306a36Sopenharmony_ci * the destination area is cacheable. 15662306a36Sopenharmony_ci * We only use this version if the source and dest don't overlap. 15762306a36Sopenharmony_ci * -- paulus. 15862306a36Sopenharmony_ci * 15962306a36Sopenharmony_ci * During early init, cache might not be active yet, so dcbz cannot be used. 16062306a36Sopenharmony_ci * We therefore jump to generic_memcpy which doesn't use dcbz. This jump is 16162306a36Sopenharmony_ci * replaced by a nop once cache is active. This is done in machine_init() 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_ci_GLOBAL_KASAN(memmove) 16462306a36Sopenharmony_ci cmplw 0,r3,r4 16562306a36Sopenharmony_ci bgt backwards_memcpy 16662306a36Sopenharmony_ci /* fall through */ 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci_GLOBAL_KASAN(memcpy) 16962306a36Sopenharmony_ci1: b generic_memcpy 17062306a36Sopenharmony_ci patch_site 1b, patch__memcpy_nocache 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci add r7,r3,r5 /* test if the src & dst overlap */ 17362306a36Sopenharmony_ci add r8,r4,r5 17462306a36Sopenharmony_ci cmplw 0,r4,r7 17562306a36Sopenharmony_ci cmplw 1,r3,r8 17662306a36Sopenharmony_ci crand 0,0,4 /* cr0.lt &= cr1.lt */ 17762306a36Sopenharmony_ci blt generic_memcpy /* if regions overlap */ 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci addi r4,r4,-4 18062306a36Sopenharmony_ci addi r6,r3,-4 18162306a36Sopenharmony_ci neg r0,r3 18262306a36Sopenharmony_ci andi. r0,r0,CACHELINE_MASK /* # bytes to start of cache line */ 18362306a36Sopenharmony_ci beq 58f 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci cmplw 0,r5,r0 /* is this more than total to do? */ 18662306a36Sopenharmony_ci blt 63f /* if not much to do */ 18762306a36Sopenharmony_ci andi. r8,r0,3 /* get it word-aligned first */ 18862306a36Sopenharmony_ci subf r5,r0,r5 18962306a36Sopenharmony_ci mtctr r8 19062306a36Sopenharmony_ci beq+ 61f 19162306a36Sopenharmony_ci70: lbz r9,4(r4) /* do some bytes */ 19262306a36Sopenharmony_ci addi r4,r4,1 19362306a36Sopenharmony_ci addi r6,r6,1 19462306a36Sopenharmony_ci stb r9,3(r6) 19562306a36Sopenharmony_ci bdnz 70b 19662306a36Sopenharmony_ci61: srwi. r0,r0,2 19762306a36Sopenharmony_ci mtctr r0 19862306a36Sopenharmony_ci beq 58f 19962306a36Sopenharmony_ci72: lwzu r9,4(r4) /* do some words */ 20062306a36Sopenharmony_ci stwu r9,4(r6) 20162306a36Sopenharmony_ci bdnz 72b 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci58: srwi. r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */ 20462306a36Sopenharmony_ci clrlwi r5,r5,32-LG_CACHELINE_BYTES 20562306a36Sopenharmony_ci li r11,4 20662306a36Sopenharmony_ci mtctr r0 20762306a36Sopenharmony_ci beq 63f 20862306a36Sopenharmony_ci53: 20962306a36Sopenharmony_ci dcbz r11,r6 21062306a36Sopenharmony_ci COPY_16_BYTES 21162306a36Sopenharmony_ci#if L1_CACHE_BYTES >= 32 21262306a36Sopenharmony_ci COPY_16_BYTES 21362306a36Sopenharmony_ci#if L1_CACHE_BYTES >= 64 21462306a36Sopenharmony_ci COPY_16_BYTES 21562306a36Sopenharmony_ci COPY_16_BYTES 21662306a36Sopenharmony_ci#if L1_CACHE_BYTES >= 128 21762306a36Sopenharmony_ci COPY_16_BYTES 21862306a36Sopenharmony_ci COPY_16_BYTES 21962306a36Sopenharmony_ci COPY_16_BYTES 22062306a36Sopenharmony_ci COPY_16_BYTES 22162306a36Sopenharmony_ci#endif 22262306a36Sopenharmony_ci#endif 22362306a36Sopenharmony_ci#endif 22462306a36Sopenharmony_ci bdnz 53b 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci63: srwi. r0,r5,2 22762306a36Sopenharmony_ci mtctr r0 22862306a36Sopenharmony_ci beq 64f 22962306a36Sopenharmony_ci30: lwzu r0,4(r4) 23062306a36Sopenharmony_ci stwu r0,4(r6) 23162306a36Sopenharmony_ci bdnz 30b 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci64: andi. r0,r5,3 23462306a36Sopenharmony_ci mtctr r0 23562306a36Sopenharmony_ci beq+ 65f 23662306a36Sopenharmony_ci addi r4,r4,3 23762306a36Sopenharmony_ci addi r6,r6,3 23862306a36Sopenharmony_ci40: lbzu r0,1(r4) 23962306a36Sopenharmony_ci stbu r0,1(r6) 24062306a36Sopenharmony_ci bdnz 40b 24162306a36Sopenharmony_ci65: blr 24262306a36Sopenharmony_ciEXPORT_SYMBOL(memcpy) 24362306a36Sopenharmony_ciEXPORT_SYMBOL(memmove) 24462306a36Sopenharmony_ciEXPORT_SYMBOL_KASAN(memcpy) 24562306a36Sopenharmony_ciEXPORT_SYMBOL_KASAN(memmove) 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cigeneric_memcpy: 24862306a36Sopenharmony_ci srwi. r7,r5,3 24962306a36Sopenharmony_ci addi r6,r3,-4 25062306a36Sopenharmony_ci addi r4,r4,-4 25162306a36Sopenharmony_ci beq 2f /* if less than 8 bytes to do */ 25262306a36Sopenharmony_ci andi. r0,r6,3 /* get dest word aligned */ 25362306a36Sopenharmony_ci mtctr r7 25462306a36Sopenharmony_ci bne 5f 25562306a36Sopenharmony_ci1: lwz r7,4(r4) 25662306a36Sopenharmony_ci lwzu r8,8(r4) 25762306a36Sopenharmony_ci stw r7,4(r6) 25862306a36Sopenharmony_ci stwu r8,8(r6) 25962306a36Sopenharmony_ci bdnz 1b 26062306a36Sopenharmony_ci andi. r5,r5,7 26162306a36Sopenharmony_ci2: cmplwi 0,r5,4 26262306a36Sopenharmony_ci blt 3f 26362306a36Sopenharmony_ci lwzu r0,4(r4) 26462306a36Sopenharmony_ci addi r5,r5,-4 26562306a36Sopenharmony_ci stwu r0,4(r6) 26662306a36Sopenharmony_ci3: cmpwi 0,r5,0 26762306a36Sopenharmony_ci beqlr 26862306a36Sopenharmony_ci mtctr r5 26962306a36Sopenharmony_ci addi r4,r4,3 27062306a36Sopenharmony_ci addi r6,r6,3 27162306a36Sopenharmony_ci4: lbzu r0,1(r4) 27262306a36Sopenharmony_ci stbu r0,1(r6) 27362306a36Sopenharmony_ci bdnz 4b 27462306a36Sopenharmony_ci blr 27562306a36Sopenharmony_ci5: subfic r0,r0,4 27662306a36Sopenharmony_ci mtctr r0 27762306a36Sopenharmony_ci6: lbz r7,4(r4) 27862306a36Sopenharmony_ci addi r4,r4,1 27962306a36Sopenharmony_ci stb r7,4(r6) 28062306a36Sopenharmony_ci addi r6,r6,1 28162306a36Sopenharmony_ci bdnz 6b 28262306a36Sopenharmony_ci subf r5,r0,r5 28362306a36Sopenharmony_ci rlwinm. r7,r5,32-3,3,31 28462306a36Sopenharmony_ci beq 2b 28562306a36Sopenharmony_ci mtctr r7 28662306a36Sopenharmony_ci b 1b 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci_GLOBAL(backwards_memcpy) 28962306a36Sopenharmony_ci rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ 29062306a36Sopenharmony_ci add r6,r3,r5 29162306a36Sopenharmony_ci add r4,r4,r5 29262306a36Sopenharmony_ci beq 2f 29362306a36Sopenharmony_ci andi. r0,r6,3 29462306a36Sopenharmony_ci mtctr r7 29562306a36Sopenharmony_ci bne 5f 29662306a36Sopenharmony_ci1: lwz r7,-4(r4) 29762306a36Sopenharmony_ci lwzu r8,-8(r4) 29862306a36Sopenharmony_ci stw r7,-4(r6) 29962306a36Sopenharmony_ci stwu r8,-8(r6) 30062306a36Sopenharmony_ci bdnz 1b 30162306a36Sopenharmony_ci andi. r5,r5,7 30262306a36Sopenharmony_ci2: cmplwi 0,r5,4 30362306a36Sopenharmony_ci blt 3f 30462306a36Sopenharmony_ci lwzu r0,-4(r4) 30562306a36Sopenharmony_ci subi r5,r5,4 30662306a36Sopenharmony_ci stwu r0,-4(r6) 30762306a36Sopenharmony_ci3: cmpwi 0,r5,0 30862306a36Sopenharmony_ci beqlr 30962306a36Sopenharmony_ci mtctr r5 31062306a36Sopenharmony_ci4: lbzu r0,-1(r4) 31162306a36Sopenharmony_ci stbu r0,-1(r6) 31262306a36Sopenharmony_ci bdnz 4b 31362306a36Sopenharmony_ci blr 31462306a36Sopenharmony_ci5: mtctr r0 31562306a36Sopenharmony_ci6: lbzu r7,-1(r4) 31662306a36Sopenharmony_ci stbu r7,-1(r6) 31762306a36Sopenharmony_ci bdnz 6b 31862306a36Sopenharmony_ci subf r5,r0,r5 31962306a36Sopenharmony_ci rlwinm. r7,r5,32-3,3,31 32062306a36Sopenharmony_ci beq 2b 32162306a36Sopenharmony_ci mtctr r7 32262306a36Sopenharmony_ci b 1b 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci_GLOBAL(__copy_tofrom_user) 32562306a36Sopenharmony_ci addi r4,r4,-4 32662306a36Sopenharmony_ci addi r6,r3,-4 32762306a36Sopenharmony_ci neg r0,r3 32862306a36Sopenharmony_ci andi. r0,r0,CACHELINE_MASK /* # bytes to start of cache line */ 32962306a36Sopenharmony_ci beq 58f 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci cmplw 0,r5,r0 /* is this more than total to do? */ 33262306a36Sopenharmony_ci blt 63f /* if not much to do */ 33362306a36Sopenharmony_ci andi. r8,r0,3 /* get it word-aligned first */ 33462306a36Sopenharmony_ci mtctr r8 33562306a36Sopenharmony_ci beq+ 61f 33662306a36Sopenharmony_ci70: lbz r9,4(r4) /* do some bytes */ 33762306a36Sopenharmony_ci71: stb r9,4(r6) 33862306a36Sopenharmony_ci addi r4,r4,1 33962306a36Sopenharmony_ci addi r6,r6,1 34062306a36Sopenharmony_ci bdnz 70b 34162306a36Sopenharmony_ci61: subf r5,r0,r5 34262306a36Sopenharmony_ci srwi. r0,r0,2 34362306a36Sopenharmony_ci mtctr r0 34462306a36Sopenharmony_ci beq 58f 34562306a36Sopenharmony_ci72: lwzu r9,4(r4) /* do some words */ 34662306a36Sopenharmony_ci73: stwu r9,4(r6) 34762306a36Sopenharmony_ci bdnz 72b 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci EX_TABLE(70b,100f) 35062306a36Sopenharmony_ci EX_TABLE(71b,101f) 35162306a36Sopenharmony_ci EX_TABLE(72b,102f) 35262306a36Sopenharmony_ci EX_TABLE(73b,103f) 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci58: srwi. r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */ 35562306a36Sopenharmony_ci clrlwi r5,r5,32-LG_CACHELINE_BYTES 35662306a36Sopenharmony_ci li r11,4 35762306a36Sopenharmony_ci beq 63f 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci /* Here we decide how far ahead to prefetch the source */ 36062306a36Sopenharmony_ci li r3,4 36162306a36Sopenharmony_ci cmpwi r0,1 36262306a36Sopenharmony_ci li r7,0 36362306a36Sopenharmony_ci ble 114f 36462306a36Sopenharmony_ci li r7,1 36562306a36Sopenharmony_ci#if MAX_COPY_PREFETCH > 1 36662306a36Sopenharmony_ci /* Heuristically, for large transfers we prefetch 36762306a36Sopenharmony_ci MAX_COPY_PREFETCH cachelines ahead. For small transfers 36862306a36Sopenharmony_ci we prefetch 1 cacheline ahead. */ 36962306a36Sopenharmony_ci cmpwi r0,MAX_COPY_PREFETCH 37062306a36Sopenharmony_ci ble 112f 37162306a36Sopenharmony_ci li r7,MAX_COPY_PREFETCH 37262306a36Sopenharmony_ci112: mtctr r7 37362306a36Sopenharmony_ci111: dcbt r3,r4 37462306a36Sopenharmony_ci addi r3,r3,CACHELINE_BYTES 37562306a36Sopenharmony_ci bdnz 111b 37662306a36Sopenharmony_ci#else 37762306a36Sopenharmony_ci dcbt r3,r4 37862306a36Sopenharmony_ci addi r3,r3,CACHELINE_BYTES 37962306a36Sopenharmony_ci#endif /* MAX_COPY_PREFETCH > 1 */ 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci114: subf r8,r7,r0 38262306a36Sopenharmony_ci mr r0,r7 38362306a36Sopenharmony_ci mtctr r8 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci53: dcbt r3,r4 38662306a36Sopenharmony_ci54: dcbz r11,r6 38762306a36Sopenharmony_ci EX_TABLE(54b,105f) 38862306a36Sopenharmony_ci/* the main body of the cacheline loop */ 38962306a36Sopenharmony_ci COPY_16_BYTES_WITHEX(0) 39062306a36Sopenharmony_ci#if L1_CACHE_BYTES >= 32 39162306a36Sopenharmony_ci COPY_16_BYTES_WITHEX(1) 39262306a36Sopenharmony_ci#if L1_CACHE_BYTES >= 64 39362306a36Sopenharmony_ci COPY_16_BYTES_WITHEX(2) 39462306a36Sopenharmony_ci COPY_16_BYTES_WITHEX(3) 39562306a36Sopenharmony_ci#if L1_CACHE_BYTES >= 128 39662306a36Sopenharmony_ci COPY_16_BYTES_WITHEX(4) 39762306a36Sopenharmony_ci COPY_16_BYTES_WITHEX(5) 39862306a36Sopenharmony_ci COPY_16_BYTES_WITHEX(6) 39962306a36Sopenharmony_ci COPY_16_BYTES_WITHEX(7) 40062306a36Sopenharmony_ci#endif 40162306a36Sopenharmony_ci#endif 40262306a36Sopenharmony_ci#endif 40362306a36Sopenharmony_ci bdnz 53b 40462306a36Sopenharmony_ci cmpwi r0,0 40562306a36Sopenharmony_ci li r3,4 40662306a36Sopenharmony_ci li r7,0 40762306a36Sopenharmony_ci bne 114b 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci63: srwi. r0,r5,2 41062306a36Sopenharmony_ci mtctr r0 41162306a36Sopenharmony_ci beq 64f 41262306a36Sopenharmony_ci30: lwzu r0,4(r4) 41362306a36Sopenharmony_ci31: stwu r0,4(r6) 41462306a36Sopenharmony_ci bdnz 30b 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci64: andi. r0,r5,3 41762306a36Sopenharmony_ci mtctr r0 41862306a36Sopenharmony_ci beq+ 65f 41962306a36Sopenharmony_ci40: lbz r0,4(r4) 42062306a36Sopenharmony_ci41: stb r0,4(r6) 42162306a36Sopenharmony_ci addi r4,r4,1 42262306a36Sopenharmony_ci addi r6,r6,1 42362306a36Sopenharmony_ci bdnz 40b 42462306a36Sopenharmony_ci65: li r3,0 42562306a36Sopenharmony_ci blr 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci/* read fault, initial single-byte copy */ 42862306a36Sopenharmony_ci100: li r9,0 42962306a36Sopenharmony_ci b 90f 43062306a36Sopenharmony_ci/* write fault, initial single-byte copy */ 43162306a36Sopenharmony_ci101: li r9,1 43262306a36Sopenharmony_ci90: subf r5,r8,r5 43362306a36Sopenharmony_ci li r3,0 43462306a36Sopenharmony_ci b 99f 43562306a36Sopenharmony_ci/* read fault, initial word copy */ 43662306a36Sopenharmony_ci102: li r9,0 43762306a36Sopenharmony_ci b 91f 43862306a36Sopenharmony_ci/* write fault, initial word copy */ 43962306a36Sopenharmony_ci103: li r9,1 44062306a36Sopenharmony_ci91: li r3,2 44162306a36Sopenharmony_ci b 99f 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci/* 44462306a36Sopenharmony_ci * this stuff handles faults in the cacheline loop and branches to either 44562306a36Sopenharmony_ci * 104f (if in read part) or 105f (if in write part), after updating r5 44662306a36Sopenharmony_ci */ 44762306a36Sopenharmony_ci COPY_16_BYTES_EXCODE(0) 44862306a36Sopenharmony_ci#if L1_CACHE_BYTES >= 32 44962306a36Sopenharmony_ci COPY_16_BYTES_EXCODE(1) 45062306a36Sopenharmony_ci#if L1_CACHE_BYTES >= 64 45162306a36Sopenharmony_ci COPY_16_BYTES_EXCODE(2) 45262306a36Sopenharmony_ci COPY_16_BYTES_EXCODE(3) 45362306a36Sopenharmony_ci#if L1_CACHE_BYTES >= 128 45462306a36Sopenharmony_ci COPY_16_BYTES_EXCODE(4) 45562306a36Sopenharmony_ci COPY_16_BYTES_EXCODE(5) 45662306a36Sopenharmony_ci COPY_16_BYTES_EXCODE(6) 45762306a36Sopenharmony_ci COPY_16_BYTES_EXCODE(7) 45862306a36Sopenharmony_ci#endif 45962306a36Sopenharmony_ci#endif 46062306a36Sopenharmony_ci#endif 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci/* read fault in cacheline loop */ 46362306a36Sopenharmony_ci104: li r9,0 46462306a36Sopenharmony_ci b 92f 46562306a36Sopenharmony_ci/* fault on dcbz (effectively a write fault) */ 46662306a36Sopenharmony_ci/* or write fault in cacheline loop */ 46762306a36Sopenharmony_ci105: li r9,1 46862306a36Sopenharmony_ci92: li r3,LG_CACHELINE_BYTES 46962306a36Sopenharmony_ci mfctr r8 47062306a36Sopenharmony_ci add r0,r0,r8 47162306a36Sopenharmony_ci b 106f 47262306a36Sopenharmony_ci/* read fault in final word loop */ 47362306a36Sopenharmony_ci108: li r9,0 47462306a36Sopenharmony_ci b 93f 47562306a36Sopenharmony_ci/* write fault in final word loop */ 47662306a36Sopenharmony_ci109: li r9,1 47762306a36Sopenharmony_ci93: andi. r5,r5,3 47862306a36Sopenharmony_ci li r3,2 47962306a36Sopenharmony_ci b 99f 48062306a36Sopenharmony_ci/* read fault in final byte loop */ 48162306a36Sopenharmony_ci110: li r9,0 48262306a36Sopenharmony_ci b 94f 48362306a36Sopenharmony_ci/* write fault in final byte loop */ 48462306a36Sopenharmony_ci111: li r9,1 48562306a36Sopenharmony_ci94: li r5,0 48662306a36Sopenharmony_ci li r3,0 48762306a36Sopenharmony_ci/* 48862306a36Sopenharmony_ci * At this stage the number of bytes not copied is 48962306a36Sopenharmony_ci * r5 + (ctr << r3), and r9 is 0 for read or 1 for write. 49062306a36Sopenharmony_ci */ 49162306a36Sopenharmony_ci99: mfctr r0 49262306a36Sopenharmony_ci106: slw r3,r0,r3 49362306a36Sopenharmony_ci add. r3,r3,r5 49462306a36Sopenharmony_ci beq 120f /* shouldn't happen */ 49562306a36Sopenharmony_ci cmpwi 0,r9,0 49662306a36Sopenharmony_ci bne 120f 49762306a36Sopenharmony_ci/* for a read fault, first try to continue the copy one byte at a time */ 49862306a36Sopenharmony_ci mtctr r3 49962306a36Sopenharmony_ci130: lbz r0,4(r4) 50062306a36Sopenharmony_ci131: stb r0,4(r6) 50162306a36Sopenharmony_ci addi r4,r4,1 50262306a36Sopenharmony_ci addi r6,r6,1 50362306a36Sopenharmony_ci bdnz 130b 50462306a36Sopenharmony_ci/* then clear out the destination: r3 bytes starting at 4(r6) */ 50562306a36Sopenharmony_ci132: mfctr r3 50662306a36Sopenharmony_ci120: blr 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci EX_TABLE(30b,108b) 50962306a36Sopenharmony_ci EX_TABLE(31b,109b) 51062306a36Sopenharmony_ci EX_TABLE(40b,110b) 51162306a36Sopenharmony_ci EX_TABLE(41b,111b) 51262306a36Sopenharmony_ci EX_TABLE(130b,132b) 51362306a36Sopenharmony_ci EX_TABLE(131b,120b) 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ciEXPORT_SYMBOL(__copy_tofrom_user) 516