xref: /freebsd/sys/arm64/arm64/copyinout.S (revision 325151a3)
1/*-
2 * Copyright (c) 2015 The FreeBSD Foundation
3 * All rights reserved.
4 *
5 * This software was developed by Andrew Turner under
6 * sponsorship from the FreeBSD Foundation.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 */
30
31#include <machine/asm.h>
32__FBSDID("$FreeBSD$");
33
34#include <sys/errno.h>
35
36#include "assym.s"
37
38/*
39 * Fault handler for the copy{in,out} functions below.
40 */
41ENTRY(copyio_fault)
42	SET_FAULT_HANDLER(xzr, x1) /* Clear the handler */
43copyio_fault_nopcb:
44	mov	x0, #EFAULT
45	ret
46END(copyio_fault)
47
48/*
49 * Copies from a kernel to user address
50 *
51 * int copyout(const void *kaddr, void *udaddr, size_t len)
52 */
53ENTRY(copyout)
54	cbz	x2, 2f		/* If len == 0 then skip loop */
55	add	x3, x1, x2
56	ldr	x4, =VM_MAXUSER_ADDRESS
57	cmp	x3, x4
58	b.hi	copyio_fault_nopcb
59
60	adr	x6, copyio_fault /* Get the handler address */
61	SET_FAULT_HANDLER(x6, x7) /* Set the handler */
62
631:	ldrb	w4, [x0], #1	/* Load from kaddr */
64	strb	w4, [x1], #1	/* Store in uaddr */
65	sub	x2, x2, #1	/* len-- */
66	cbnz	x2, 1b
67
68	SET_FAULT_HANDLER(xzr, x7) /* Clear the handler */
69
702:	mov	x0, xzr		/* return 0 */
71	ret
72END(copyout)
73
74/*
75 * Copies from a user to kernel address
76 *
77 * int copyin(const void *uaddr, void *kdaddr, size_t len)
78 */
79ENTRY(copyin)
80	cbz	x2, 2f		/* If len == 0 then skip loop */
81	add	x3, x0, x2
82	ldr	x4, =VM_MAXUSER_ADDRESS
83	cmp	x3, x4
84	b.hi	copyio_fault_nopcb
85
86	adr	x6, copyio_fault /* Get the handler address */
87	SET_FAULT_HANDLER(x6, x7) /* Set the handler */
88
891:	ldrb	w4, [x0], #1	/* Load from uaddr */
90	strb	w4, [x1], #1	/* Store in kaddr */
91	sub	x2, x2, #1	/* len-- */
92	cbnz	x2, 1b
93
94	SET_FAULT_HANDLER(xzr, x7) /* Clear the handler */
95
962:	mov	x0, xzr		/* return 0 */
97	ret
98END(copyin)
99
100/*
101 * Copies a string from a user to kernel address
102 *
103 * int copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
104 */
105ENTRY(copyinstr)
106	mov	x5, xzr		/* count = 0 */
107	mov	w4, #1		/* If zero return faulure */
108	cbz	x2, 3f		/* If len == 0 then skip loop */
109	ldr	x7, =VM_MAXUSER_ADDRESS
110
111	adr	x6, copyio_fault /* Get the handler address */
112	SET_FAULT_HANDLER(x6, x7) /* Set the handler */
113
1141:	cmp	x0, x7
115	b.cs	copyio_fault
116	ldrb	w4, [x0], #1	/* Load from uaddr */
117	strb	w4, [x1], #1	/* Store in kaddr */
118	add	x5, x5, #1	/* count++ */
119	cbz	w4, 2f		/* Break when NUL-terminated */
120	sub	x2, x2, #1	/* len-- */
121	cbnz	x2, 1b
122
1232:	SET_FAULT_HANDLER(xzr, x7) /* Clear the handler */
124
1253:	cbz	x3, 4f		/* Check if done != NULL */
126	str	x5, [x3]	/* done = count */
127
1284:	mov	w1, #ENAMETOOLONG /* Load ENAMETOOLONG to return if failed */
129	cmp	w4, #0		/* Check if we saved the NUL-terminator */
130	csel	w0, wzr, w1, eq	/* If so return success, else failure */
131	ret
132END(copyinstr)
133