1281494Sandrew/*-
2281494Sandrew * Copyright (c) 2015 The FreeBSD Foundation
3281494Sandrew * All rights reserved.
4281494Sandrew *
5281494Sandrew * This software was developed by Andrew Turner under
6281494Sandrew * sponsorship from the FreeBSD Foundation.
7281494Sandrew *
8281494Sandrew * Redistribution and use in source and binary forms, with or without
9281494Sandrew * modification, are permitted provided that the following conditions
10281494Sandrew * are met:
11281494Sandrew * 1. Redistributions of source code must retain the above copyright
12281494Sandrew *    notice, this list of conditions and the following disclaimer.
13281494Sandrew * 2. Redistributions in binary form must reproduce the above copyright
14281494Sandrew *    notice, this list of conditions and the following disclaimer in the
15281494Sandrew *    documentation and/or other materials provided with the distribution.
16281494Sandrew *
17281494Sandrew * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18281494Sandrew * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19281494Sandrew * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20281494Sandrew * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21281494Sandrew * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22281494Sandrew * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23281494Sandrew * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24281494Sandrew * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25281494Sandrew * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26281494Sandrew * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27281494Sandrew * SUCH DAMAGE.
28281494Sandrew *
29281494Sandrew */
30281494Sandrew
31281494Sandrew#include <machine/asm.h>
32281494Sandrew__FBSDID("$FreeBSD: stable/11/sys/arm64/arm64/copyinout.S 319202 2017-05-30 12:26:36Z andrew $");
33281494Sandrew
34281494Sandrew#include <sys/errno.h>
35281494Sandrew
36297615Sandrew#include <machine/vmparam.h>
37297615Sandrew
38281494Sandrew#include "assym.s"
39281494Sandrew
40281494Sandrew/*
41281494Sandrew * Fault handler for the copy{in,out} functions below.
42281494Sandrew */
43281494SandrewENTRY(copyio_fault)
44281494Sandrew	SET_FAULT_HANDLER(xzr, x1) /* Clear the handler */
45319202Sandrew	EXIT_USER_ACCESS_CHECK(w0, x1)
46289454Skibcopyio_fault_nopcb:
47281494Sandrew	mov	x0, #EFAULT
48281494Sandrew	ret
49281494SandrewEND(copyio_fault)
50281494Sandrew
51281494Sandrew/*
52281494Sandrew * Copies from a kernel to user address
53281494Sandrew *
54281494Sandrew * int copyout(const void *kaddr, void *udaddr, size_t len)
55281494Sandrew */
56281494SandrewENTRY(copyout)
57297209Swma	cbz	x2, 1f
58297235Swma	adds	x3, x1, x2
59297235Swma	b.cs 	copyio_fault_nopcb
60289454Skib	ldr	x4, =VM_MAXUSER_ADDRESS
61289454Skib	cmp	x3, x4
62289454Skib	b.hi	copyio_fault_nopcb
63281494Sandrew
64297209Swma	b	copycommon
65281494Sandrew
66297209Swma1:	mov	x0, xzr		/* return 0 */
67297209Swma	ret
68281494Sandrew
69281494SandrewEND(copyout)
70281494Sandrew
71281494Sandrew/*
72281494Sandrew * Copies from a user to kernel address
73281494Sandrew *
74281494Sandrew * int copyin(const void *uaddr, void *kdaddr, size_t len)
75281494Sandrew */
76281494SandrewENTRY(copyin)
77297209Swma	cbz	x2, 1f
78297235Swma	adds	x3, x0, x2
79297235Swma	b.cs    copyio_fault_nopcb
80289454Skib	ldr	x4, =VM_MAXUSER_ADDRESS
81289454Skib	cmp	x3, x4
82289454Skib	b.hi	copyio_fault_nopcb
83281494Sandrew
84297209Swma	b	copycommon
85281494Sandrew
86297209Swma1:	mov	x0, xzr		/* return 0 */
87297209Swma	ret
88281494Sandrew
89281494SandrewEND(copyin)
90281494Sandrew
91281494Sandrew/*
92281494Sandrew * Copies a string from a user to kernel address
93281494Sandrew *
94281494Sandrew * int copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
95281494Sandrew */
96281494SandrewENTRY(copyinstr)
97281494Sandrew	mov	x5, xzr		/* count = 0 */
98287596Sandrew	mov	w4, #1		/* If zero return faulure */
99281494Sandrew	cbz	x2, 3f		/* If len == 0 then skip loop */
100281494Sandrew
101281494Sandrew	adr	x6, copyio_fault /* Get the handler address */
102281494Sandrew	SET_FAULT_HANDLER(x6, x7) /* Set the handler */
103319202Sandrew	ENTER_USER_ACCESS(w6, x7)
104281494Sandrew
105297235Swma	ldr	x7, =VM_MAXUSER_ADDRESS
106289454Skib1:	cmp	x0, x7
107289454Skib	b.cs	copyio_fault
108319202Sandrew	ldtrb	w4, [x0]	/* Load from uaddr */
109319202Sandrew	add	x0, x0, #1	/* Next char */
110281494Sandrew	strb	w4, [x1], #1	/* Store in kaddr */
111287596Sandrew	add	x5, x5, #1	/* count++ */
112287596Sandrew	cbz	w4, 2f		/* Break when NUL-terminated */
113281494Sandrew	sub	x2, x2, #1	/* len-- */
114281494Sandrew	cbnz	x2, 1b
115281494Sandrew
116319202Sandrew2:	EXIT_USER_ACCESS(w6)
117319202Sandrew	SET_FAULT_HANDLER(xzr, x7) /* Clear the handler */
118281494Sandrew
119319202Sandrew
120281494Sandrew3:	cbz	x3, 4f		/* Check if done != NULL */
121281494Sandrew	str	x5, [x3]	/* done = count */
122281494Sandrew
123287596Sandrew4:	mov	w1, #ENAMETOOLONG /* Load ENAMETOOLONG to return if failed */
124287596Sandrew	cmp	w4, #0		/* Check if we saved the NUL-terminator */
125287596Sandrew	csel	w0, wzr, w1, eq	/* If so return success, else failure */
126281494Sandrew	ret
127281494SandrewEND(copyinstr)
128297209Swma
129297209Swma/*
130297209Swma * Local helper
131297209Swma *
132297209Swma * x0 - src pointer
133297209Swma * x1 - dst pointer
134297209Swma * x2 - size
135297209Swma * lr - the return address, so jump here instead of calling
136297209Swma *
137297209Swma * This function is optimized to minimize concurrent memory accesses. In
138297209Swma * present form it is suited for cores with a single memory prefetching
139297209Swma * unit.
140297209Swma * ARM64TODO:
141297209Swma *   Consider using separate functions for each ARM64 core. Adding memory
142297209Swma *   access interleaving might increase a total throughput on A57 or A72.
143297209Swma */
144297209Swma	.text
145297209Swma	.align	4
146297209Swma	.local	copycommon
147297209Swma	.type	copycommon,@function
148297209Swma
149297209Swmacopycommon:
150297209Swma	adr	x6, copyio_fault /* Get the handler address */
151297209Swma	SET_FAULT_HANDLER(x6, x7) /* Set the handler */
152319202Sandrew	ENTER_USER_ACCESS(w6, x7)
153297209Swma
154297209Swma	/* Check alignment */
155297209Swma	orr	x3, x0, x1
156297209Swma	ands	x3, x3, 0x07
157297209Swma	b.eq	aligned
158297209Swma
159297209Swma	/* Unaligned is byte by byte copy */
160297209Swmabyte_by_byte:
161297209Swma	ldrb	w3, [x0], #0x01
162297209Swma	strb	w3, [x1], #0x01
163297209Swma	subs	x2, x2, #0x01
164297209Swma	b.ne	byte_by_byte
165297209Swma	b	ending
166297209Swma
167297209Swmaaligned:
168297209Swma	cmp	x2, #0x10
169297209Swma	b.lt	lead_out
170297209Swma	cmp	x2, #0x40
171297209Swma	b.lt	by_dwords_start
172297209Swma
173297209Swma	/* Block copy */
174297209Swma	lsr	x15, x2, #0x06
175297209Swmaby_blocks:
176297209Swma	ldp	x3, x4, [x0], #0x10
177297209Swma	ldp	x5, x6, [x0], #0x10
178297209Swma	ldp	x7, x8, [x0], #0x10
179297209Swma	ldp	x9, x10, [x0], #0x10
180297209Swma	stp	x3, x4, [x1], #0x10
181297209Swma	stp	x5, x6, [x1], #0x10
182297209Swma	stp	x7, x8, [x1], #0x10
183297209Swma	stp	x9, x10, [x1], #0x10
184297209Swma
185297209Swma	subs	x15, x15, #0x01
186297209Swma	b.ne	by_blocks
187297209Swma
188297209Swma	and	x2, x2, #0x3f
189297209Swma
190297209Swmaby_dwords_start:
191297209Swma	lsr	x15, x2, #0x04
192297209Swma	cbz	x15, lead_out
193297209Swmaby_dwords:
194297209Swma	ldp	x3, x4, [x0], #0x10
195297209Swma	stp	x3, x4, [x1], #0x10
196297209Swma	subs	x15, x15, #0x01
197297209Swma	b.ne  	by_dwords
198297209Swma
199297209Swma	/* Less than 16 bytes to copy */
200297209Swmalead_out:
201297209Swma	tbz	x2, #0x03, last_word
202297209Swma	ldr	x3, [x0], #0x08
203297209Swma	str	x3, [x1], #0x08
204297209Swma
205297209Swmalast_word:
206297209Swma	tbz	x2, #0x02, last_hword
207297209Swma	ldr	w3, [x0], #0x04
208297209Swma	str	w3, [x1], #0x04
209297209Swma
210297209Swmalast_hword:
211297209Swma	tbz	x2, #0x01, last_byte
212297209Swma	ldrh	w3, [x0], #0x02
213297209Swma	strh	w3, [x1], #0x02
214297209Swma
215297209Swmalast_byte:
216297209Swma	tbz	x2, #0x00, ending
217297209Swma	ldrb	w3, [x0]
218297209Swma	strb	w3, [x1]
219297209Swma
220297209Swmaending:
221319202Sandrew	EXIT_USER_ACCESS_CHECK(w6, x7)
222297209Swma	SET_FAULT_HANDLER(xzr, x7) /* Clear the handler */
223297209Swma
224297209Swma	mov	x0, xzr		/* return 0 */
225297209Swma	ret
226297209Swma	.size	copycommon, . - copycommon
227