aboutsummaryrefslogtreecommitdiff
path: root/sys/riscv/riscv/copyinout.S
blob: 5a171f5a5e17f6b44cb3ba1c1813f9f3e48d904f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*-
 * Copyright (c) 2015-2018 Ruslan Bukin <br@bsdpad.com>
 * Copyright (c) 2019 Mitchell Horne
 * All rights reserved.
 *
 * Portions of this software were developed by SRI International and the
 * University of Cambridge Computer Laboratory under DARPA/AFRL contract
 * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
 *
 * Portions of this software were developed by the University of Cambridge
 * Computer Laboratory as part of the CTSRD Project, with support from the
 * UK Higher Education Innovation Fund (HEIF).
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <machine/asm.h>
__FBSDID("$FreeBSD$");

#include <machine/riscvreg.h>
#include <sys/errno.h>

#include "assym.inc"

/*
 * Fault handler for the copy{in,out} functions below.
 */
ENTRY(copyio_fault)
	SET_FAULT_HANDLER(x0, a1) /* Clear the handler */
	EXIT_USER_ACCESS(a1)
copyio_fault_nopcb:
	li	a0, EFAULT
	ret
END(copyio_fault)

/*
 * copycommon - common copy routine
 *
 * a0 - Source address
 * a1 - Destination address
 * a2 - Size of copy
 */
	.macro copycommon
	la	a6, copyio_fault	/* Get the handler address */
	SET_FAULT_HANDLER(a6, a7)	/* Set the handler */
	ENTER_USER_ACCESS(a7)

	li	t2, XLEN_BYTES
	blt	a2, t2, 4f		/* Byte-copy if len < XLEN_BYTES */

	/*
	 * Compare lower bits of src and dest.
	 * If they are aligned with each other, we can do word copy.
	 */
	andi	t0, a0, (XLEN_BYTES-1)	/* Low bits of src */
	andi	t1, a1, (XLEN_BYTES-1)	/* Low bits of dest */
	bne	t0, t1, 4f		/* Misaligned. Go to byte copy */
	beqz	t0, 2f			/* Already word-aligned, skip ahead */

	/* Byte copy until the first word-aligned address */
1:	lb	a4, 0(a0)		/* Load byte from src */
	addi	a0, a0, 1
	sb	a4, 0(a1)		/* Store byte in dest */
	addi	a1, a1, 1
	addi	a2, a2, -1		/* len-- */
	andi	t0, a0, (XLEN_BYTES-1)
	bnez	t0, 1b
	j	3f

	/* Copy words */
2:	ld	a4, 0(a0)		/* Load word from src */
	addi	a0, a0, XLEN_BYTES
	sd	a4, 0(a1)		/* Store word in dest */
	addi	a1, a1, XLEN_BYTES
	addi	a2, a2, -XLEN_BYTES	/* len -= XLEN_BYTES */
3:	bgeu	a2, t2, 2b		/* Again if len >= XLEN_BYTES */

	/* Check if we're finished */
	beqz	a2, 5f

	/* Copy any remaining bytes */
4:	lb	a4, 0(a0)		/* Load byte from src */
	addi	a0, a0, 1
	sb	a4, 0(a1)		/* Store byte in dest */
	addi	a1, a1, 1
	addi	a2, a2, -1		/* len-- */
	bnez	a2, 4b

5:	EXIT_USER_ACCESS(a7)
	SET_FAULT_HANDLER(x0, a7)	/* Clear the handler */
	.endm

/*
 * Copies from a kernel to user address
 *
 * int copyout(const void *kaddr, void *udaddr, size_t len)
 */
ENTRY(copyout)
	beqz	a2, copyout_end	/* If len == 0 then skip loop */
	add	a3, a1, a2
	li	a4, VM_MAXUSER_ADDRESS
	bgeu	a3, a4, copyio_fault_nopcb

	copycommon

copyout_end:
	li	a0, 0		/* return 0 */
	ret
END(copyout)

/*
 * Copies from a user to kernel address
 *
 * int copyin(const void *uaddr, void *kaddr, size_t len)
 */
ENTRY(copyin)
	beqz	a2, copyin_end	/* If len == 0 then skip loop */
	add	a3, a0, a2
	li	a4, VM_MAXUSER_ADDRESS
	bgeu	a3, a4, copyio_fault_nopcb

	copycommon

copyin_end:
	li	a0, 0		/* return 0 */
	ret
END(copyin)

/*
 * Copies a string from a user to kernel address
 *
 * int copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
 */
ENTRY(copyinstr)
	mv	a5, x0		/* count = 0 */
	beqz	a2, 3f		/* If len == 0 then skip loop */

	la	a6, copyio_fault /* Get the handler address */
	SET_FAULT_HANDLER(a6, a7) /* Set the handler */
	ENTER_USER_ACCESS(a7)

	li	a7, VM_MAXUSER_ADDRESS
1:	bgeu	a0, a7, copyio_fault
	lb	a4, 0(a0)	/* Load from uaddr */
	addi	a0, a0, 1
	sb	a4, 0(a1)	/* Store in kaddr */
	addi	a1, a1, 1
	beqz	a4, 2f
	addi	a2, a2, -1	/* len-- */
	addi	a5, a5, 1	/* count++ */
	bnez	a2, 1b

2:	EXIT_USER_ACCESS(a7)
	SET_FAULT_HANDLER(x0, a7) /* Clear the handler */

3:	beqz	a3, 4f		/* Check if done != NULL */
	addi	a5, a5, 1	/* count++ */
	sd	a5, 0(a3)	/* done = count */

4:	mv	a0, x0		/* return 0 */
	beqz	a4, 5f
	li	a0, ENAMETOOLONG
5:
	ret
END(copyinstr)