xref: /linux/arch/arm64/lib/copy_from_user.S (revision 0aea86a2176c22647a5b683768f858d880d5e05b)
1*0aea86a2SCatalin Marinas/*
2*0aea86a2SCatalin Marinas * Copyright (C) 2012 ARM Ltd.
3*0aea86a2SCatalin Marinas *
4*0aea86a2SCatalin Marinas * This program is free software; you can redistribute it and/or modify
5*0aea86a2SCatalin Marinas * it under the terms of the GNU General Public License version 2 as
6*0aea86a2SCatalin Marinas * published by the Free Software Foundation.
7*0aea86a2SCatalin Marinas *
8*0aea86a2SCatalin Marinas * This program is distributed in the hope that it will be useful,
9*0aea86a2SCatalin Marinas * but WITHOUT ANY WARRANTY; without even the implied warranty of
10*0aea86a2SCatalin Marinas * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11*0aea86a2SCatalin Marinas * GNU General Public License for more details.
12*0aea86a2SCatalin Marinas *
13*0aea86a2SCatalin Marinas * You should have received a copy of the GNU General Public License
14*0aea86a2SCatalin Marinas * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15*0aea86a2SCatalin Marinas */
16*0aea86a2SCatalin Marinas
17*0aea86a2SCatalin Marinas#include <linux/linkage.h>
18*0aea86a2SCatalin Marinas#include <asm/assembler.h>
19*0aea86a2SCatalin Marinas
20*0aea86a2SCatalin Marinas/*
21*0aea86a2SCatalin Marinas * Copy from user space to a kernel buffer (alignment handled by the hardware)
22*0aea86a2SCatalin Marinas *
23*0aea86a2SCatalin Marinas * Parameters:
24*0aea86a2SCatalin Marinas *	x0 - to
25*0aea86a2SCatalin Marinas *	x1 - from
26*0aea86a2SCatalin Marinas *	x2 - n
27*0aea86a2SCatalin Marinas * Returns:
28*0aea86a2SCatalin Marinas *	x0 - bytes not copied
29*0aea86a2SCatalin Marinas */
30*0aea86a2SCatalin MarinasENTRY(__copy_from_user)
31*0aea86a2SCatalin Marinas	add	x4, x1, x2			// upper user buffer boundary
32*0aea86a2SCatalin Marinas	subs	x2, x2, #8
33*0aea86a2SCatalin Marinas	b.mi	2f
34*0aea86a2SCatalin Marinas1:
35*0aea86a2SCatalin MarinasUSER(9f, ldr	x3, [x1], #8	)
36*0aea86a2SCatalin Marinas	subs	x2, x2, #8
37*0aea86a2SCatalin Marinas	str	x3, [x0], #8
38*0aea86a2SCatalin Marinas	b.pl	1b
39*0aea86a2SCatalin Marinas2:	adds	x2, x2, #4
40*0aea86a2SCatalin Marinas	b.mi	3f
41*0aea86a2SCatalin MarinasUSER(9f, ldr	w3, [x1], #4	)
42*0aea86a2SCatalin Marinas	sub	x2, x2, #4
43*0aea86a2SCatalin Marinas	str	w3, [x0], #4
44*0aea86a2SCatalin Marinas3:	adds	x2, x2, #2
45*0aea86a2SCatalin Marinas	b.mi	4f
46*0aea86a2SCatalin MarinasUSER(9f, ldrh	w3, [x1], #2	)
47*0aea86a2SCatalin Marinas	sub	x2, x2, #2
48*0aea86a2SCatalin Marinas	strh	w3, [x0], #2
49*0aea86a2SCatalin Marinas4:	adds	x2, x2, #1
50*0aea86a2SCatalin Marinas	b.mi	5f
51*0aea86a2SCatalin MarinasUSER(9f, ldrb	w3, [x1]	)
52*0aea86a2SCatalin Marinas	strb	w3, [x0]
53*0aea86a2SCatalin Marinas5:	mov	x0, #0
54*0aea86a2SCatalin Marinas	ret
55*0aea86a2SCatalin MarinasENDPROC(__copy_from_user)
56*0aea86a2SCatalin Marinas
57*0aea86a2SCatalin Marinas	.section .fixup,"ax"
58*0aea86a2SCatalin Marinas	.align	2
59*0aea86a2SCatalin Marinas9:	sub	x2, x4, x1
60*0aea86a2SCatalin Marinas	mov	x3, x2
61*0aea86a2SCatalin Marinas10:	strb	wzr, [x0], #1			// zero remaining buffer space
62*0aea86a2SCatalin Marinas	subs	x3, x3, #1
63*0aea86a2SCatalin Marinas	b.ne	10b
64*0aea86a2SCatalin Marinas	mov	x0, x2				// bytes not copied
65*0aea86a2SCatalin Marinas	ret
66*0aea86a2SCatalin Marinas	.previous
67