162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  linux/arch/arm/lib/copy_to_user.S
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Author:	Nicolas Pitre
662306a36Sopenharmony_ci *  Created:	Sep 29, 2005
762306a36Sopenharmony_ci *  Copyright:	MontaVista Software, Inc.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/linkage.h>
1162306a36Sopenharmony_ci#include <asm/assembler.h>
1262306a36Sopenharmony_ci#include <asm/unwind.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/*
1562306a36Sopenharmony_ci * Prototype:
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci *	size_t arm_copy_to_user(void *to, const void *from, size_t n)
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * Purpose:
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci *	copy a block to user memory from kernel memory
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * Params:
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci *	to = user memory
2662306a36Sopenharmony_ci *	from = kernel memory
2762306a36Sopenharmony_ci *	n = number of bytes to copy
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci * Return value:
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci *	Number of bytes NOT copied.
3262306a36Sopenharmony_ci */
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define LDR1W_SHIFT	0
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	.macro ldr1w ptr reg abort
3762306a36Sopenharmony_ci	W(ldr) \reg, [\ptr], #4
3862306a36Sopenharmony_ci	.endm
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	.macro ldr4w ptr reg1 reg2 reg3 reg4 abort
4162306a36Sopenharmony_ci	ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4}
4262306a36Sopenharmony_ci	.endm
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	.macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
4562306a36Sopenharmony_ci	ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
4662306a36Sopenharmony_ci	.endm
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	.macro ldr1b ptr reg cond=al abort
4962306a36Sopenharmony_ci	ldrb\cond \reg, [\ptr], #1
5062306a36Sopenharmony_ci	.endm
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#ifdef CONFIG_CPU_USE_DOMAINS
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#ifndef CONFIG_THUMB2_KERNEL
5562306a36Sopenharmony_ci#define STR1W_SHIFT	0
5662306a36Sopenharmony_ci#else
5762306a36Sopenharmony_ci#define STR1W_SHIFT	1
5862306a36Sopenharmony_ci#endif
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	.macro str1w ptr reg abort
6162306a36Sopenharmony_ci	strusr	\reg, \ptr, 4, abort=\abort
6262306a36Sopenharmony_ci	.endm
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
6562306a36Sopenharmony_ci	str1w \ptr, \reg1, \abort
6662306a36Sopenharmony_ci	str1w \ptr, \reg2, \abort
6762306a36Sopenharmony_ci	str1w \ptr, \reg3, \abort
6862306a36Sopenharmony_ci	str1w \ptr, \reg4, \abort
6962306a36Sopenharmony_ci	str1w \ptr, \reg5, \abort
7062306a36Sopenharmony_ci	str1w \ptr, \reg6, \abort
7162306a36Sopenharmony_ci	str1w \ptr, \reg7, \abort
7262306a36Sopenharmony_ci	str1w \ptr, \reg8, \abort
7362306a36Sopenharmony_ci	.endm
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci#else
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci#define STR1W_SHIFT	0
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	.macro str1w ptr reg abort
8062306a36Sopenharmony_ci	USERL(\abort, W(str) \reg, [\ptr], #4)
8162306a36Sopenharmony_ci	.endm
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
8462306a36Sopenharmony_ci	USERL(\abort, stmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8})
8562306a36Sopenharmony_ci	.endm
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci#endif /* CONFIG_CPU_USE_DOMAINS */
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	.macro str1b ptr reg cond=al abort
9062306a36Sopenharmony_ci	strusr	\reg, \ptr, 1, \cond, abort=\abort
9162306a36Sopenharmony_ci	.endm
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	.macro enter regs:vararg
9462306a36Sopenharmony_ci	mov	r3, #0
9562306a36Sopenharmony_ciUNWIND( .save	{r0, r2, r3, \regs}		)
9662306a36Sopenharmony_ci	stmdb	sp!, {r0, r2, r3, \regs}
9762306a36Sopenharmony_ci	.endm
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	.macro exit regs:vararg
10062306a36Sopenharmony_ci	add	sp, sp, #8
10162306a36Sopenharmony_ci	ldmfd	sp!, {r0, \regs}
10262306a36Sopenharmony_ci	.endm
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	.text
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ciENTRY(__copy_to_user_std)
10762306a36Sopenharmony_ciWEAK(arm_copy_to_user)
10862306a36Sopenharmony_ci#ifdef CONFIG_CPU_SPECTRE
10962306a36Sopenharmony_ci	ldr	r3, =TASK_SIZE
11062306a36Sopenharmony_ci	uaccess_mask_range_ptr r0, r2, r3, ip
11162306a36Sopenharmony_ci#endif
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci#include "copy_template.S"
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ciENDPROC(arm_copy_to_user)
11662306a36Sopenharmony_ciENDPROC(__copy_to_user_std)
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	.pushsection .text.fixup,"ax"
11962306a36Sopenharmony_ci	.align 0
12062306a36Sopenharmony_ci	copy_abort_preamble
12162306a36Sopenharmony_ci	ldmfd	sp!, {r1, r2, r3}
12262306a36Sopenharmony_ci	sub	r0, r0, r1
12362306a36Sopenharmony_ci	rsb	r0, r0, r2
12462306a36Sopenharmony_ci	copy_abort_end
12562306a36Sopenharmony_ci	.popsection
126