xref: /openbmc/linux/arch/arm64/lib/copy_from_user.S (revision 338d4f49)
10aea86a2SCatalin Marinas/*
20aea86a2SCatalin Marinas * Copyright (C) 2012 ARM Ltd.
30aea86a2SCatalin Marinas *
40aea86a2SCatalin Marinas * This program is free software; you can redistribute it and/or modify
50aea86a2SCatalin Marinas * it under the terms of the GNU General Public License version 2 as
60aea86a2SCatalin Marinas * published by the Free Software Foundation.
70aea86a2SCatalin Marinas *
80aea86a2SCatalin Marinas * This program is distributed in the hope that it will be useful,
90aea86a2SCatalin Marinas * but WITHOUT ANY WARRANTY; without even the implied warranty of
100aea86a2SCatalin Marinas * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
110aea86a2SCatalin Marinas * GNU General Public License for more details.
120aea86a2SCatalin Marinas *
130aea86a2SCatalin Marinas * You should have received a copy of the GNU General Public License
140aea86a2SCatalin Marinas * along with this program.  If not, see <http://www.gnu.org/licenses/>.
150aea86a2SCatalin Marinas */
160aea86a2SCatalin Marinas
170aea86a2SCatalin Marinas#include <linux/linkage.h>
18338d4f49SJames Morse
19338d4f49SJames Morse#include <asm/alternative.h>
200aea86a2SCatalin Marinas#include <asm/assembler.h>
21338d4f49SJames Morse#include <asm/cpufeature.h>
22338d4f49SJames Morse#include <asm/sysreg.h>
230aea86a2SCatalin Marinas
240aea86a2SCatalin Marinas/*
250aea86a2SCatalin Marinas * Copy from user space to a kernel buffer (alignment handled by the hardware)
260aea86a2SCatalin Marinas *
270aea86a2SCatalin Marinas * Parameters:
280aea86a2SCatalin Marinas *	x0 - to
290aea86a2SCatalin Marinas *	x1 - from
300aea86a2SCatalin Marinas *	x2 - n
310aea86a2SCatalin Marinas * Returns:
320aea86a2SCatalin Marinas *	x0 - bytes not copied
330aea86a2SCatalin Marinas */
340aea86a2SCatalin MarinasENTRY(__copy_from_user)
35338d4f49SJames MorseALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_HAS_PAN, \
36338d4f49SJames Morse	    CONFIG_ARM64_PAN)
3723e94994SWill Deacon	add	x5, x1, x2			// upper user buffer boundary
3823e94994SWill Deacon	subs	x2, x2, #16
3923e94994SWill Deacon	b.mi	1f
4023e94994SWill Deacon0:
4123e94994SWill DeaconUSER(9f, ldp	x3, x4, [x1], #16)
4223e94994SWill Deacon	subs	x2, x2, #16
4323e94994SWill Deacon	stp	x3, x4, [x0], #16
4423e94994SWill Deacon	b.pl	0b
4523e94994SWill Deacon1:	adds	x2, x2, #8
460aea86a2SCatalin Marinas	b.mi	2f
470aea86a2SCatalin MarinasUSER(9f, ldr	x3, [x1], #8	)
4823e94994SWill Deacon	sub	x2, x2, #8
490aea86a2SCatalin Marinas	str	x3, [x0], #8
500aea86a2SCatalin Marinas2:	adds	x2, x2, #4
510aea86a2SCatalin Marinas	b.mi	3f
520aea86a2SCatalin MarinasUSER(9f, ldr	w3, [x1], #4	)
530aea86a2SCatalin Marinas	sub	x2, x2, #4
540aea86a2SCatalin Marinas	str	w3, [x0], #4
550aea86a2SCatalin Marinas3:	adds	x2, x2, #2
560aea86a2SCatalin Marinas	b.mi	4f
570aea86a2SCatalin MarinasUSER(9f, ldrh	w3, [x1], #2	)
580aea86a2SCatalin Marinas	sub	x2, x2, #2
590aea86a2SCatalin Marinas	strh	w3, [x0], #2
600aea86a2SCatalin Marinas4:	adds	x2, x2, #1
610aea86a2SCatalin Marinas	b.mi	5f
620aea86a2SCatalin MarinasUSER(9f, ldrb	w3, [x1]	)
630aea86a2SCatalin Marinas	strb	w3, [x0]
640aea86a2SCatalin Marinas5:	mov	x0, #0
65338d4f49SJames MorseALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_HAS_PAN, \
66338d4f49SJames Morse	    CONFIG_ARM64_PAN)
670aea86a2SCatalin Marinas	ret
680aea86a2SCatalin MarinasENDPROC(__copy_from_user)
690aea86a2SCatalin Marinas
700aea86a2SCatalin Marinas	.section .fixup,"ax"
710aea86a2SCatalin Marinas	.align	2
7223e94994SWill Deacon9:	sub	x2, x5, x1
730aea86a2SCatalin Marinas	mov	x3, x2
740aea86a2SCatalin Marinas10:	strb	wzr, [x0], #1			// zero remaining buffer space
750aea86a2SCatalin Marinas	subs	x3, x3, #1
760aea86a2SCatalin Marinas	b.ne	10b
770aea86a2SCatalin Marinas	mov	x0, x2				// bytes not copied
780aea86a2SCatalin Marinas	ret
790aea86a2SCatalin Marinas	.previous
80