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