162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2002 Paul Mackerras, IBM Corp. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci#include <linux/export.h> 662306a36Sopenharmony_ci#include <asm/processor.h> 762306a36Sopenharmony_ci#include <asm/ppc_asm.h> 862306a36Sopenharmony_ci#include <asm/asm-compat.h> 962306a36Sopenharmony_ci#include <asm/feature-fixups.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#ifndef SELFTEST_CASE 1262306a36Sopenharmony_ci/* 0 == most CPUs, 1 == POWER6, 2 == Cell */ 1362306a36Sopenharmony_ci#define SELFTEST_CASE 0 1462306a36Sopenharmony_ci#endif 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#ifdef __BIG_ENDIAN__ 1762306a36Sopenharmony_ci#define sLd sld /* Shift towards low-numbered address. */ 1862306a36Sopenharmony_ci#define sHd srd /* Shift towards high-numbered address. */ 1962306a36Sopenharmony_ci#else 2062306a36Sopenharmony_ci#define sLd srd /* Shift towards low-numbered address. */ 2162306a36Sopenharmony_ci#define sHd sld /* Shift towards high-numbered address. */ 2262306a36Sopenharmony_ci#endif 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* 2562306a36Sopenharmony_ci * These macros are used to generate exception table entries. 2662306a36Sopenharmony_ci * The exception handlers below use the original arguments 2762306a36Sopenharmony_ci * (stored on the stack) and the point where we're up to in 2862306a36Sopenharmony_ci * the destination buffer, i.e. the address of the first 2962306a36Sopenharmony_ci * unmodified byte. Generally r3 points into the destination 3062306a36Sopenharmony_ci * buffer, but the first unmodified byte is at a variable 3162306a36Sopenharmony_ci * offset from r3. In the code below, the symbol r3_offset 3262306a36Sopenharmony_ci * is set to indicate the current offset at each point in 3362306a36Sopenharmony_ci * the code. This offset is then used as a negative offset 3462306a36Sopenharmony_ci * from the exception handler code, and those instructions 3562306a36Sopenharmony_ci * before the exception handlers are addi instructions that 3662306a36Sopenharmony_ci * adjust r3 to point to the correct place. 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ci .macro lex /* exception handler for load */ 3962306a36Sopenharmony_ci100: EX_TABLE(100b, .Lld_exc - r3_offset) 4062306a36Sopenharmony_ci .endm 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci .macro stex /* exception handler for store */ 4362306a36Sopenharmony_ci100: EX_TABLE(100b, .Lst_exc - r3_offset) 4462306a36Sopenharmony_ci .endm 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci .align 7 4762306a36Sopenharmony_ci_GLOBAL_TOC(__copy_tofrom_user) 4862306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64 4962306a36Sopenharmony_ciBEGIN_FTR_SECTION 5062306a36Sopenharmony_ci nop 5162306a36Sopenharmony_ciFTR_SECTION_ELSE 5262306a36Sopenharmony_ci b __copy_tofrom_user_power7 5362306a36Sopenharmony_ciALT_FTR_SECTION_END_IFCLR(CPU_FTR_VMX_COPY) 5462306a36Sopenharmony_ci#endif 5562306a36Sopenharmony_ci_GLOBAL(__copy_tofrom_user_base) 5662306a36Sopenharmony_ci /* first check for a 4kB copy on a 4kB boundary */ 5762306a36Sopenharmony_ci cmpldi cr1,r5,16 5862306a36Sopenharmony_ci cmpdi cr6,r5,4096 5962306a36Sopenharmony_ci or r0,r3,r4 6062306a36Sopenharmony_ci neg r6,r3 /* LS 3 bits = # bytes to 8-byte dest bdry */ 6162306a36Sopenharmony_ci andi. r0,r0,4095 6262306a36Sopenharmony_ci std r3,-24(r1) 6362306a36Sopenharmony_ci crand cr0*4+2,cr0*4+2,cr6*4+2 6462306a36Sopenharmony_ci std r4,-16(r1) 6562306a36Sopenharmony_ci std r5,-8(r1) 6662306a36Sopenharmony_ci dcbt 0,r4 6762306a36Sopenharmony_ci beq .Lcopy_page_4K 6862306a36Sopenharmony_ci andi. r6,r6,7 6962306a36Sopenharmony_ci PPC_MTOCRF(0x01,r5) 7062306a36Sopenharmony_ci blt cr1,.Lshort_copy 7162306a36Sopenharmony_ci/* Below we want to nop out the bne if we're on a CPU that has the 7262306a36Sopenharmony_ci * CPU_FTR_UNALIGNED_LD_STD bit set and the CPU_FTR_CP_USE_DCBTZ bit 7362306a36Sopenharmony_ci * cleared. 7462306a36Sopenharmony_ci * At the time of writing the only CPU that has this combination of bits 7562306a36Sopenharmony_ci * set is Power6. 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_citest_feature = (SELFTEST_CASE == 1) 7862306a36Sopenharmony_ciBEGIN_FTR_SECTION 7962306a36Sopenharmony_ci nop 8062306a36Sopenharmony_ciFTR_SECTION_ELSE 8162306a36Sopenharmony_ci bne .Ldst_unaligned 8262306a36Sopenharmony_ciALT_FTR_SECTION_END(CPU_FTR_UNALIGNED_LD_STD | CPU_FTR_CP_USE_DCBTZ, \ 8362306a36Sopenharmony_ci CPU_FTR_UNALIGNED_LD_STD) 8462306a36Sopenharmony_ci.Ldst_aligned: 8562306a36Sopenharmony_ci addi r3,r3,-16 8662306a36Sopenharmony_cir3_offset = 16 8762306a36Sopenharmony_citest_feature = (SELFTEST_CASE == 0) 8862306a36Sopenharmony_ciBEGIN_FTR_SECTION 8962306a36Sopenharmony_ci andi. r0,r4,7 9062306a36Sopenharmony_ci bne .Lsrc_unaligned 9162306a36Sopenharmony_ciEND_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD) 9262306a36Sopenharmony_ci blt cr1,.Ldo_tail /* if < 16 bytes to copy */ 9362306a36Sopenharmony_ci srdi r0,r5,5 9462306a36Sopenharmony_ci cmpdi cr1,r0,0 9562306a36Sopenharmony_cilex; ld r7,0(r4) 9662306a36Sopenharmony_cilex; ld r6,8(r4) 9762306a36Sopenharmony_ci addi r4,r4,16 9862306a36Sopenharmony_ci mtctr r0 9962306a36Sopenharmony_ci andi. r0,r5,0x10 10062306a36Sopenharmony_ci beq 22f 10162306a36Sopenharmony_ci addi r3,r3,16 10262306a36Sopenharmony_cir3_offset = 0 10362306a36Sopenharmony_ci addi r4,r4,-16 10462306a36Sopenharmony_ci mr r9,r7 10562306a36Sopenharmony_ci mr r8,r6 10662306a36Sopenharmony_ci beq cr1,72f 10762306a36Sopenharmony_ci21: 10862306a36Sopenharmony_cilex; ld r7,16(r4) 10962306a36Sopenharmony_cilex; ld r6,24(r4) 11062306a36Sopenharmony_ci addi r4,r4,32 11162306a36Sopenharmony_cistex; std r9,0(r3) 11262306a36Sopenharmony_cir3_offset = 8 11362306a36Sopenharmony_cistex; std r8,8(r3) 11462306a36Sopenharmony_cir3_offset = 16 11562306a36Sopenharmony_ci22: 11662306a36Sopenharmony_cilex; ld r9,0(r4) 11762306a36Sopenharmony_cilex; ld r8,8(r4) 11862306a36Sopenharmony_cistex; std r7,16(r3) 11962306a36Sopenharmony_cir3_offset = 24 12062306a36Sopenharmony_cistex; std r6,24(r3) 12162306a36Sopenharmony_ci addi r3,r3,32 12262306a36Sopenharmony_cir3_offset = 0 12362306a36Sopenharmony_ci bdnz 21b 12462306a36Sopenharmony_ci72: 12562306a36Sopenharmony_cistex; std r9,0(r3) 12662306a36Sopenharmony_cir3_offset = 8 12762306a36Sopenharmony_cistex; std r8,8(r3) 12862306a36Sopenharmony_cir3_offset = 16 12962306a36Sopenharmony_ci andi. r5,r5,0xf 13062306a36Sopenharmony_ci beq+ 3f 13162306a36Sopenharmony_ci addi r4,r4,16 13262306a36Sopenharmony_ci.Ldo_tail: 13362306a36Sopenharmony_ci addi r3,r3,16 13462306a36Sopenharmony_cir3_offset = 0 13562306a36Sopenharmony_ci bf cr7*4+0,246f 13662306a36Sopenharmony_cilex; ld r9,0(r4) 13762306a36Sopenharmony_ci addi r4,r4,8 13862306a36Sopenharmony_cistex; std r9,0(r3) 13962306a36Sopenharmony_ci addi r3,r3,8 14062306a36Sopenharmony_ci246: bf cr7*4+1,1f 14162306a36Sopenharmony_cilex; lwz r9,0(r4) 14262306a36Sopenharmony_ci addi r4,r4,4 14362306a36Sopenharmony_cistex; stw r9,0(r3) 14462306a36Sopenharmony_ci addi r3,r3,4 14562306a36Sopenharmony_ci1: bf cr7*4+2,2f 14662306a36Sopenharmony_cilex; lhz r9,0(r4) 14762306a36Sopenharmony_ci addi r4,r4,2 14862306a36Sopenharmony_cistex; sth r9,0(r3) 14962306a36Sopenharmony_ci addi r3,r3,2 15062306a36Sopenharmony_ci2: bf cr7*4+3,3f 15162306a36Sopenharmony_cilex; lbz r9,0(r4) 15262306a36Sopenharmony_cistex; stb r9,0(r3) 15362306a36Sopenharmony_ci3: li r3,0 15462306a36Sopenharmony_ci blr 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci.Lsrc_unaligned: 15762306a36Sopenharmony_cir3_offset = 16 15862306a36Sopenharmony_ci srdi r6,r5,3 15962306a36Sopenharmony_ci addi r5,r5,-16 16062306a36Sopenharmony_ci subf r4,r0,r4 16162306a36Sopenharmony_ci srdi r7,r5,4 16262306a36Sopenharmony_ci sldi r10,r0,3 16362306a36Sopenharmony_ci cmpldi cr6,r6,3 16462306a36Sopenharmony_ci andi. r5,r5,7 16562306a36Sopenharmony_ci mtctr r7 16662306a36Sopenharmony_ci subfic r11,r10,64 16762306a36Sopenharmony_ci add r5,r5,r0 16862306a36Sopenharmony_ci bt cr7*4+0,28f 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cilex; ld r9,0(r4) /* 3+2n loads, 2+2n stores */ 17162306a36Sopenharmony_cilex; ld r0,8(r4) 17262306a36Sopenharmony_ci sLd r6,r9,r10 17362306a36Sopenharmony_cilex; ldu r9,16(r4) 17462306a36Sopenharmony_ci sHd r7,r0,r11 17562306a36Sopenharmony_ci sLd r8,r0,r10 17662306a36Sopenharmony_ci or r7,r7,r6 17762306a36Sopenharmony_ci blt cr6,79f 17862306a36Sopenharmony_cilex; ld r0,8(r4) 17962306a36Sopenharmony_ci b 2f 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci28: 18262306a36Sopenharmony_cilex; ld r0,0(r4) /* 4+2n loads, 3+2n stores */ 18362306a36Sopenharmony_cilex; ldu r9,8(r4) 18462306a36Sopenharmony_ci sLd r8,r0,r10 18562306a36Sopenharmony_ci addi r3,r3,-8 18662306a36Sopenharmony_cir3_offset = 24 18762306a36Sopenharmony_ci blt cr6,5f 18862306a36Sopenharmony_cilex; ld r0,8(r4) 18962306a36Sopenharmony_ci sHd r12,r9,r11 19062306a36Sopenharmony_ci sLd r6,r9,r10 19162306a36Sopenharmony_cilex; ldu r9,16(r4) 19262306a36Sopenharmony_ci or r12,r8,r12 19362306a36Sopenharmony_ci sHd r7,r0,r11 19462306a36Sopenharmony_ci sLd r8,r0,r10 19562306a36Sopenharmony_ci addi r3,r3,16 19662306a36Sopenharmony_cir3_offset = 8 19762306a36Sopenharmony_ci beq cr6,78f 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci1: or r7,r7,r6 20062306a36Sopenharmony_cilex; ld r0,8(r4) 20162306a36Sopenharmony_cistex; std r12,8(r3) 20262306a36Sopenharmony_cir3_offset = 16 20362306a36Sopenharmony_ci2: sHd r12,r9,r11 20462306a36Sopenharmony_ci sLd r6,r9,r10 20562306a36Sopenharmony_cilex; ldu r9,16(r4) 20662306a36Sopenharmony_ci or r12,r8,r12 20762306a36Sopenharmony_cistex; stdu r7,16(r3) 20862306a36Sopenharmony_cir3_offset = 8 20962306a36Sopenharmony_ci sHd r7,r0,r11 21062306a36Sopenharmony_ci sLd r8,r0,r10 21162306a36Sopenharmony_ci bdnz 1b 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci78: 21462306a36Sopenharmony_cistex; std r12,8(r3) 21562306a36Sopenharmony_cir3_offset = 16 21662306a36Sopenharmony_ci or r7,r7,r6 21762306a36Sopenharmony_ci79: 21862306a36Sopenharmony_cistex; std r7,16(r3) 21962306a36Sopenharmony_cir3_offset = 24 22062306a36Sopenharmony_ci5: sHd r12,r9,r11 22162306a36Sopenharmony_ci or r12,r8,r12 22262306a36Sopenharmony_cistex; std r12,24(r3) 22362306a36Sopenharmony_cir3_offset = 32 22462306a36Sopenharmony_ci bne 6f 22562306a36Sopenharmony_ci li r3,0 22662306a36Sopenharmony_ci blr 22762306a36Sopenharmony_ci6: cmpwi cr1,r5,8 22862306a36Sopenharmony_ci addi r3,r3,32 22962306a36Sopenharmony_cir3_offset = 0 23062306a36Sopenharmony_ci sLd r9,r9,r10 23162306a36Sopenharmony_ci ble cr1,7f 23262306a36Sopenharmony_cilex; ld r0,8(r4) 23362306a36Sopenharmony_ci sHd r7,r0,r11 23462306a36Sopenharmony_ci or r9,r7,r9 23562306a36Sopenharmony_ci7: 23662306a36Sopenharmony_ci bf cr7*4+1,1f 23762306a36Sopenharmony_ci#ifdef __BIG_ENDIAN__ 23862306a36Sopenharmony_ci rotldi r9,r9,32 23962306a36Sopenharmony_ci#endif 24062306a36Sopenharmony_cistex; stw r9,0(r3) 24162306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN__ 24262306a36Sopenharmony_ci rotrdi r9,r9,32 24362306a36Sopenharmony_ci#endif 24462306a36Sopenharmony_ci addi r3,r3,4 24562306a36Sopenharmony_ci1: bf cr7*4+2,2f 24662306a36Sopenharmony_ci#ifdef __BIG_ENDIAN__ 24762306a36Sopenharmony_ci rotldi r9,r9,16 24862306a36Sopenharmony_ci#endif 24962306a36Sopenharmony_cistex; sth r9,0(r3) 25062306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN__ 25162306a36Sopenharmony_ci rotrdi r9,r9,16 25262306a36Sopenharmony_ci#endif 25362306a36Sopenharmony_ci addi r3,r3,2 25462306a36Sopenharmony_ci2: bf cr7*4+3,3f 25562306a36Sopenharmony_ci#ifdef __BIG_ENDIAN__ 25662306a36Sopenharmony_ci rotldi r9,r9,8 25762306a36Sopenharmony_ci#endif 25862306a36Sopenharmony_cistex; stb r9,0(r3) 25962306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN__ 26062306a36Sopenharmony_ci rotrdi r9,r9,8 26162306a36Sopenharmony_ci#endif 26262306a36Sopenharmony_ci3: li r3,0 26362306a36Sopenharmony_ci blr 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci.Ldst_unaligned: 26662306a36Sopenharmony_cir3_offset = 0 26762306a36Sopenharmony_ci PPC_MTOCRF(0x01,r6) /* put #bytes to 8B bdry into cr7 */ 26862306a36Sopenharmony_ci subf r5,r6,r5 26962306a36Sopenharmony_ci li r7,0 27062306a36Sopenharmony_ci cmpldi cr1,r5,16 27162306a36Sopenharmony_ci bf cr7*4+3,1f 27262306a36Sopenharmony_ci100: EX_TABLE(100b, .Lld_exc_r7) 27362306a36Sopenharmony_ci lbz r0,0(r4) 27462306a36Sopenharmony_ci100: EX_TABLE(100b, .Lst_exc_r7) 27562306a36Sopenharmony_ci stb r0,0(r3) 27662306a36Sopenharmony_ci addi r7,r7,1 27762306a36Sopenharmony_ci1: bf cr7*4+2,2f 27862306a36Sopenharmony_ci100: EX_TABLE(100b, .Lld_exc_r7) 27962306a36Sopenharmony_ci lhzx r0,r7,r4 28062306a36Sopenharmony_ci100: EX_TABLE(100b, .Lst_exc_r7) 28162306a36Sopenharmony_ci sthx r0,r7,r3 28262306a36Sopenharmony_ci addi r7,r7,2 28362306a36Sopenharmony_ci2: bf cr7*4+1,3f 28462306a36Sopenharmony_ci100: EX_TABLE(100b, .Lld_exc_r7) 28562306a36Sopenharmony_ci lwzx r0,r7,r4 28662306a36Sopenharmony_ci100: EX_TABLE(100b, .Lst_exc_r7) 28762306a36Sopenharmony_ci stwx r0,r7,r3 28862306a36Sopenharmony_ci3: PPC_MTOCRF(0x01,r5) 28962306a36Sopenharmony_ci add r4,r6,r4 29062306a36Sopenharmony_ci add r3,r6,r3 29162306a36Sopenharmony_ci b .Ldst_aligned 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci.Lshort_copy: 29462306a36Sopenharmony_cir3_offset = 0 29562306a36Sopenharmony_ci bf cr7*4+0,1f 29662306a36Sopenharmony_cilex; lwz r0,0(r4) 29762306a36Sopenharmony_cilex; lwz r9,4(r4) 29862306a36Sopenharmony_ci addi r4,r4,8 29962306a36Sopenharmony_cistex; stw r0,0(r3) 30062306a36Sopenharmony_cistex; stw r9,4(r3) 30162306a36Sopenharmony_ci addi r3,r3,8 30262306a36Sopenharmony_ci1: bf cr7*4+1,2f 30362306a36Sopenharmony_cilex; lwz r0,0(r4) 30462306a36Sopenharmony_ci addi r4,r4,4 30562306a36Sopenharmony_cistex; stw r0,0(r3) 30662306a36Sopenharmony_ci addi r3,r3,4 30762306a36Sopenharmony_ci2: bf cr7*4+2,3f 30862306a36Sopenharmony_cilex; lhz r0,0(r4) 30962306a36Sopenharmony_ci addi r4,r4,2 31062306a36Sopenharmony_cistex; sth r0,0(r3) 31162306a36Sopenharmony_ci addi r3,r3,2 31262306a36Sopenharmony_ci3: bf cr7*4+3,4f 31362306a36Sopenharmony_cilex; lbz r0,0(r4) 31462306a36Sopenharmony_cistex; stb r0,0(r3) 31562306a36Sopenharmony_ci4: li r3,0 31662306a36Sopenharmony_ci blr 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci/* 31962306a36Sopenharmony_ci * exception handlers follow 32062306a36Sopenharmony_ci * we have to return the number of bytes not copied 32162306a36Sopenharmony_ci * for an exception on a load, we set the rest of the destination to 0 32262306a36Sopenharmony_ci * Note that the number of bytes of instructions for adjusting r3 needs 32362306a36Sopenharmony_ci * to equal the amount of the adjustment, due to the trick of using 32462306a36Sopenharmony_ci * .Lld_exc - r3_offset as the handler address. 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci.Lld_exc_r7: 32862306a36Sopenharmony_ci add r3,r3,r7 32962306a36Sopenharmony_ci b .Lld_exc 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* adjust by 24 */ 33262306a36Sopenharmony_ci addi r3,r3,8 33362306a36Sopenharmony_ci nop 33462306a36Sopenharmony_ci /* adjust by 16 */ 33562306a36Sopenharmony_ci addi r3,r3,8 33662306a36Sopenharmony_ci nop 33762306a36Sopenharmony_ci /* adjust by 8 */ 33862306a36Sopenharmony_ci addi r3,r3,8 33962306a36Sopenharmony_ci nop 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci/* 34262306a36Sopenharmony_ci * Here we have had a fault on a load and r3 points to the first 34362306a36Sopenharmony_ci * unmodified byte of the destination. We use the original arguments 34462306a36Sopenharmony_ci * and r3 to work out how much wasn't copied. Since we load some 34562306a36Sopenharmony_ci * distance ahead of the stores, we continue copying byte-by-byte until 34662306a36Sopenharmony_ci * we hit the load fault again in order to copy as much as possible. 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_ci.Lld_exc: 34962306a36Sopenharmony_ci ld r6,-24(r1) 35062306a36Sopenharmony_ci ld r4,-16(r1) 35162306a36Sopenharmony_ci ld r5,-8(r1) 35262306a36Sopenharmony_ci subf r6,r6,r3 35362306a36Sopenharmony_ci add r4,r4,r6 35462306a36Sopenharmony_ci subf r5,r6,r5 /* #bytes left to go */ 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci/* 35762306a36Sopenharmony_ci * first see if we can copy any more bytes before hitting another exception 35862306a36Sopenharmony_ci */ 35962306a36Sopenharmony_ci mtctr r5 36062306a36Sopenharmony_cir3_offset = 0 36162306a36Sopenharmony_ci100: EX_TABLE(100b, .Ldone) 36262306a36Sopenharmony_ci43: lbz r0,0(r4) 36362306a36Sopenharmony_ci addi r4,r4,1 36462306a36Sopenharmony_cistex; stb r0,0(r3) 36562306a36Sopenharmony_ci addi r3,r3,1 36662306a36Sopenharmony_ci bdnz 43b 36762306a36Sopenharmony_ci li r3,0 /* huh? all copied successfully this time? */ 36862306a36Sopenharmony_ci blr 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci/* 37162306a36Sopenharmony_ci * here we have trapped again, amount remaining is in ctr. 37262306a36Sopenharmony_ci */ 37362306a36Sopenharmony_ci.Ldone: 37462306a36Sopenharmony_ci mfctr r3 37562306a36Sopenharmony_ci blr 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci/* 37862306a36Sopenharmony_ci * exception handlers for stores: we need to work out how many bytes 37962306a36Sopenharmony_ci * weren't copied, and we may need to copy some more. 38062306a36Sopenharmony_ci * Note that the number of bytes of instructions for adjusting r3 needs 38162306a36Sopenharmony_ci * to equal the amount of the adjustment, due to the trick of using 38262306a36Sopenharmony_ci * .Lst_exc - r3_offset as the handler address. 38362306a36Sopenharmony_ci */ 38462306a36Sopenharmony_ci.Lst_exc_r7: 38562306a36Sopenharmony_ci add r3,r3,r7 38662306a36Sopenharmony_ci b .Lst_exc 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci /* adjust by 24 */ 38962306a36Sopenharmony_ci addi r3,r3,8 39062306a36Sopenharmony_ci nop 39162306a36Sopenharmony_ci /* adjust by 16 */ 39262306a36Sopenharmony_ci addi r3,r3,8 39362306a36Sopenharmony_ci nop 39462306a36Sopenharmony_ci /* adjust by 8 */ 39562306a36Sopenharmony_ci addi r3,r3,4 39662306a36Sopenharmony_ci /* adjust by 4 */ 39762306a36Sopenharmony_ci addi r3,r3,4 39862306a36Sopenharmony_ci.Lst_exc: 39962306a36Sopenharmony_ci ld r6,-24(r1) /* original destination pointer */ 40062306a36Sopenharmony_ci ld r4,-16(r1) /* original source pointer */ 40162306a36Sopenharmony_ci ld r5,-8(r1) /* original number of bytes */ 40262306a36Sopenharmony_ci add r7,r6,r5 40362306a36Sopenharmony_ci /* 40462306a36Sopenharmony_ci * If the destination pointer isn't 8-byte aligned, 40562306a36Sopenharmony_ci * we may have got the exception as a result of a 40662306a36Sopenharmony_ci * store that overlapped a page boundary, so we may be 40762306a36Sopenharmony_ci * able to copy a few more bytes. 40862306a36Sopenharmony_ci */ 40962306a36Sopenharmony_ci17: andi. r0,r3,7 41062306a36Sopenharmony_ci beq 19f 41162306a36Sopenharmony_ci subf r8,r6,r3 /* #bytes copied */ 41262306a36Sopenharmony_ci100: EX_TABLE(100b,19f) 41362306a36Sopenharmony_ci lbzx r0,r8,r4 41462306a36Sopenharmony_ci100: EX_TABLE(100b,19f) 41562306a36Sopenharmony_ci stb r0,0(r3) 41662306a36Sopenharmony_ci addi r3,r3,1 41762306a36Sopenharmony_ci cmpld r3,r7 41862306a36Sopenharmony_ci blt 17b 41962306a36Sopenharmony_ci19: subf r3,r3,r7 /* #bytes not copied in r3 */ 42062306a36Sopenharmony_ci blr 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci/* 42362306a36Sopenharmony_ci * Routine to copy a whole page of data, optimized for POWER4. 42462306a36Sopenharmony_ci * On POWER4 it is more than 50% faster than the simple loop 42562306a36Sopenharmony_ci * above (following the .Ldst_aligned label). 42662306a36Sopenharmony_ci */ 42762306a36Sopenharmony_ci .macro exc 42862306a36Sopenharmony_ci100: EX_TABLE(100b, .Labort) 42962306a36Sopenharmony_ci .endm 43062306a36Sopenharmony_ci.Lcopy_page_4K: 43162306a36Sopenharmony_ci std r31,-32(1) 43262306a36Sopenharmony_ci std r30,-40(1) 43362306a36Sopenharmony_ci std r29,-48(1) 43462306a36Sopenharmony_ci std r28,-56(1) 43562306a36Sopenharmony_ci std r27,-64(1) 43662306a36Sopenharmony_ci std r26,-72(1) 43762306a36Sopenharmony_ci std r25,-80(1) 43862306a36Sopenharmony_ci std r24,-88(1) 43962306a36Sopenharmony_ci std r23,-96(1) 44062306a36Sopenharmony_ci std r22,-104(1) 44162306a36Sopenharmony_ci std r21,-112(1) 44262306a36Sopenharmony_ci std r20,-120(1) 44362306a36Sopenharmony_ci li r5,4096/32 - 1 44462306a36Sopenharmony_ci addi r3,r3,-8 44562306a36Sopenharmony_ci li r0,5 44662306a36Sopenharmony_ci0: addi r5,r5,-24 44762306a36Sopenharmony_ci mtctr r0 44862306a36Sopenharmony_ciexc; ld r22,640(4) 44962306a36Sopenharmony_ciexc; ld r21,512(4) 45062306a36Sopenharmony_ciexc; ld r20,384(4) 45162306a36Sopenharmony_ciexc; ld r11,256(4) 45262306a36Sopenharmony_ciexc; ld r9,128(4) 45362306a36Sopenharmony_ciexc; ld r7,0(4) 45462306a36Sopenharmony_ciexc; ld r25,648(4) 45562306a36Sopenharmony_ciexc; ld r24,520(4) 45662306a36Sopenharmony_ciexc; ld r23,392(4) 45762306a36Sopenharmony_ciexc; ld r10,264(4) 45862306a36Sopenharmony_ciexc; ld r8,136(4) 45962306a36Sopenharmony_ciexc; ldu r6,8(4) 46062306a36Sopenharmony_ci cmpwi r5,24 46162306a36Sopenharmony_ci1: 46262306a36Sopenharmony_ciexc; std r22,648(3) 46362306a36Sopenharmony_ciexc; std r21,520(3) 46462306a36Sopenharmony_ciexc; std r20,392(3) 46562306a36Sopenharmony_ciexc; std r11,264(3) 46662306a36Sopenharmony_ciexc; std r9,136(3) 46762306a36Sopenharmony_ciexc; std r7,8(3) 46862306a36Sopenharmony_ciexc; ld r28,648(4) 46962306a36Sopenharmony_ciexc; ld r27,520(4) 47062306a36Sopenharmony_ciexc; ld r26,392(4) 47162306a36Sopenharmony_ciexc; ld r31,264(4) 47262306a36Sopenharmony_ciexc; ld r30,136(4) 47362306a36Sopenharmony_ciexc; ld r29,8(4) 47462306a36Sopenharmony_ciexc; std r25,656(3) 47562306a36Sopenharmony_ciexc; std r24,528(3) 47662306a36Sopenharmony_ciexc; std r23,400(3) 47762306a36Sopenharmony_ciexc; std r10,272(3) 47862306a36Sopenharmony_ciexc; std r8,144(3) 47962306a36Sopenharmony_ciexc; std r6,16(3) 48062306a36Sopenharmony_ciexc; ld r22,656(4) 48162306a36Sopenharmony_ciexc; ld r21,528(4) 48262306a36Sopenharmony_ciexc; ld r20,400(4) 48362306a36Sopenharmony_ciexc; ld r11,272(4) 48462306a36Sopenharmony_ciexc; ld r9,144(4) 48562306a36Sopenharmony_ciexc; ld r7,16(4) 48662306a36Sopenharmony_ciexc; std r28,664(3) 48762306a36Sopenharmony_ciexc; std r27,536(3) 48862306a36Sopenharmony_ciexc; std r26,408(3) 48962306a36Sopenharmony_ciexc; std r31,280(3) 49062306a36Sopenharmony_ciexc; std r30,152(3) 49162306a36Sopenharmony_ciexc; stdu r29,24(3) 49262306a36Sopenharmony_ciexc; ld r25,664(4) 49362306a36Sopenharmony_ciexc; ld r24,536(4) 49462306a36Sopenharmony_ciexc; ld r23,408(4) 49562306a36Sopenharmony_ciexc; ld r10,280(4) 49662306a36Sopenharmony_ciexc; ld r8,152(4) 49762306a36Sopenharmony_ciexc; ldu r6,24(4) 49862306a36Sopenharmony_ci bdnz 1b 49962306a36Sopenharmony_ciexc; std r22,648(3) 50062306a36Sopenharmony_ciexc; std r21,520(3) 50162306a36Sopenharmony_ciexc; std r20,392(3) 50262306a36Sopenharmony_ciexc; std r11,264(3) 50362306a36Sopenharmony_ciexc; std r9,136(3) 50462306a36Sopenharmony_ciexc; std r7,8(3) 50562306a36Sopenharmony_ci addi r4,r4,640 50662306a36Sopenharmony_ci addi r3,r3,648 50762306a36Sopenharmony_ci bge 0b 50862306a36Sopenharmony_ci mtctr r5 50962306a36Sopenharmony_ciexc; ld r7,0(4) 51062306a36Sopenharmony_ciexc; ld r8,8(4) 51162306a36Sopenharmony_ciexc; ldu r9,16(4) 51262306a36Sopenharmony_ci3: 51362306a36Sopenharmony_ciexc; ld r10,8(4) 51462306a36Sopenharmony_ciexc; std r7,8(3) 51562306a36Sopenharmony_ciexc; ld r7,16(4) 51662306a36Sopenharmony_ciexc; std r8,16(3) 51762306a36Sopenharmony_ciexc; ld r8,24(4) 51862306a36Sopenharmony_ciexc; std r9,24(3) 51962306a36Sopenharmony_ciexc; ldu r9,32(4) 52062306a36Sopenharmony_ciexc; stdu r10,32(3) 52162306a36Sopenharmony_ci bdnz 3b 52262306a36Sopenharmony_ci4: 52362306a36Sopenharmony_ciexc; ld r10,8(4) 52462306a36Sopenharmony_ciexc; std r7,8(3) 52562306a36Sopenharmony_ciexc; std r8,16(3) 52662306a36Sopenharmony_ciexc; std r9,24(3) 52762306a36Sopenharmony_ciexc; std r10,32(3) 52862306a36Sopenharmony_ci9: ld r20,-120(1) 52962306a36Sopenharmony_ci ld r21,-112(1) 53062306a36Sopenharmony_ci ld r22,-104(1) 53162306a36Sopenharmony_ci ld r23,-96(1) 53262306a36Sopenharmony_ci ld r24,-88(1) 53362306a36Sopenharmony_ci ld r25,-80(1) 53462306a36Sopenharmony_ci ld r26,-72(1) 53562306a36Sopenharmony_ci ld r27,-64(1) 53662306a36Sopenharmony_ci ld r28,-56(1) 53762306a36Sopenharmony_ci ld r29,-48(1) 53862306a36Sopenharmony_ci ld r30,-40(1) 53962306a36Sopenharmony_ci ld r31,-32(1) 54062306a36Sopenharmony_ci li r3,0 54162306a36Sopenharmony_ci blr 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci/* 54462306a36Sopenharmony_ci * on an exception, reset to the beginning and jump back into the 54562306a36Sopenharmony_ci * standard __copy_tofrom_user 54662306a36Sopenharmony_ci */ 54762306a36Sopenharmony_ci.Labort: 54862306a36Sopenharmony_ci ld r20,-120(1) 54962306a36Sopenharmony_ci ld r21,-112(1) 55062306a36Sopenharmony_ci ld r22,-104(1) 55162306a36Sopenharmony_ci ld r23,-96(1) 55262306a36Sopenharmony_ci ld r24,-88(1) 55362306a36Sopenharmony_ci ld r25,-80(1) 55462306a36Sopenharmony_ci ld r26,-72(1) 55562306a36Sopenharmony_ci ld r27,-64(1) 55662306a36Sopenharmony_ci ld r28,-56(1) 55762306a36Sopenharmony_ci ld r29,-48(1) 55862306a36Sopenharmony_ci ld r30,-40(1) 55962306a36Sopenharmony_ci ld r31,-32(1) 56062306a36Sopenharmony_ci ld r3,-24(r1) 56162306a36Sopenharmony_ci ld r4,-16(r1) 56262306a36Sopenharmony_ci li r5,4096 56362306a36Sopenharmony_ci b .Ldst_aligned 56462306a36Sopenharmony_ciEXPORT_SYMBOL(__copy_tofrom_user) 565