xref: /openbmc/linux/arch/riscv/lib/uaccess.S (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
15d8544e2SPalmer Dabbelt#include <linux/linkage.h>
24d47ce15SLuc Van Oostenryck#include <asm-generic/export.h>
35d8544e2SPalmer Dabbelt#include <asm/asm.h>
46dd10d91SJisheng Zhang#include <asm/asm-extable.h>
55d8544e2SPalmer Dabbelt#include <asm/csr.h>
65d8544e2SPalmer Dabbelt
75d8544e2SPalmer Dabbelt	.macro fixup op reg addr lbl
8abc71bf0SPalmer Dabbelt100:
95d8544e2SPalmer Dabbelt	\op \reg, \addr
106dd10d91SJisheng Zhang	_asm_extable	100b, \lbl
115d8544e2SPalmer Dabbelt	.endm
125d8544e2SPalmer Dabbelt
1386406d51SLuc Van OostenryckENTRY(__asm_copy_to_user)
1486406d51SLuc Van OostenryckENTRY(__asm_copy_from_user)
155d8544e2SPalmer Dabbelt
165d8544e2SPalmer Dabbelt	/* Enable access to user memory */
175d8544e2SPalmer Dabbelt	li t6, SR_SUM
18a4c3733dSChristoph Hellwig	csrs CSR_STATUS, t6
195d8544e2SPalmer Dabbelt
20*4b05b993SAlexandre Ghiti	/*
21*4b05b993SAlexandre Ghiti	 * Save the terminal address which will be used to compute the number
22*4b05b993SAlexandre Ghiti	 * of bytes copied in case of a fixup exception.
23*4b05b993SAlexandre Ghiti	 */
24*4b05b993SAlexandre Ghiti	add	t5, a0, a2
255d8544e2SPalmer Dabbelt
265d8544e2SPalmer Dabbelt	/*
27ca6eaaa2SAkira Tsukamoto	 * Register allocation for code below:
28ca6eaaa2SAkira Tsukamoto	 * a0 - start of uncopied dst
29ca6eaaa2SAkira Tsukamoto	 * a1 - start of uncopied src
30ca6eaaa2SAkira Tsukamoto	 * a2 - size
31ca6eaaa2SAkira Tsukamoto	 * t0 - end of uncopied dst
325d8544e2SPalmer Dabbelt	 */
33ca6eaaa2SAkira Tsukamoto	add	t0, a0, a2
34ca6eaaa2SAkira Tsukamoto
35ca6eaaa2SAkira Tsukamoto	/*
36ca6eaaa2SAkira Tsukamoto	 * Use byte copy only if too small.
37ea196c54SAkira Tsukamoto	 * SZREG holds 4 for RV32 and 8 for RV64
38ca6eaaa2SAkira Tsukamoto	 */
396010d300SAkira Tsukamoto	li	a3, 9*SZREG /* size must be larger than size in word_copy */
40ca6eaaa2SAkira Tsukamoto	bltu	a2, a3, .Lbyte_copy_tail
41ca6eaaa2SAkira Tsukamoto
42ca6eaaa2SAkira Tsukamoto	/*
43ea196c54SAkira Tsukamoto	 * Copy first bytes until dst is aligned to word boundary.
44ca6eaaa2SAkira Tsukamoto	 * a0 - start of dst
45ca6eaaa2SAkira Tsukamoto	 * t1 - start of aligned dst
46ca6eaaa2SAkira Tsukamoto	 */
47ca6eaaa2SAkira Tsukamoto	addi	t1, a0, SZREG-1
48ca6eaaa2SAkira Tsukamoto	andi	t1, t1, ~(SZREG-1)
49ca6eaaa2SAkira Tsukamoto	/* dst is already aligned, skip */
50ea196c54SAkira Tsukamoto	beq	a0, t1, .Lskip_align_dst
515d8544e2SPalmer Dabbelt1:
52ca6eaaa2SAkira Tsukamoto	/* a5 - one byte for copying data */
53ca6eaaa2SAkira Tsukamoto	fixup lb      a5, 0(a1), 10f
54ca6eaaa2SAkira Tsukamoto	addi	a1, a1, 1	/* src */
55ca6eaaa2SAkira Tsukamoto	fixup sb      a5, 0(a0), 10f
56ca6eaaa2SAkira Tsukamoto	addi	a0, a0, 1	/* dst */
57ca6eaaa2SAkira Tsukamoto	bltu	a0, t1, 1b	/* t1 - start of aligned dst */
58ca6eaaa2SAkira Tsukamoto
59ea196c54SAkira Tsukamoto.Lskip_align_dst:
60ca6eaaa2SAkira Tsukamoto	/*
61ca6eaaa2SAkira Tsukamoto	 * Now dst is aligned.
62ca6eaaa2SAkira Tsukamoto	 * Use shift-copy if src is misaligned.
63ca6eaaa2SAkira Tsukamoto	 * Use word-copy if both src and dst are aligned because
64ca6eaaa2SAkira Tsukamoto	 * can not use shift-copy which do not require shifting
65ca6eaaa2SAkira Tsukamoto	 */
66ca6eaaa2SAkira Tsukamoto	/* a1 - start of src */
67ca6eaaa2SAkira Tsukamoto	andi	a3, a1, SZREG-1
68ca6eaaa2SAkira Tsukamoto	bnez	a3, .Lshift_copy
69ca6eaaa2SAkira Tsukamoto
70ca6eaaa2SAkira Tsukamoto.Lword_copy:
71ca6eaaa2SAkira Tsukamoto        /*
72ca6eaaa2SAkira Tsukamoto	 * Both src and dst are aligned, unrolled word copy
73ca6eaaa2SAkira Tsukamoto	 *
74ca6eaaa2SAkira Tsukamoto	 * a0 - start of aligned dst
75ca6eaaa2SAkira Tsukamoto	 * a1 - start of aligned src
76ca6eaaa2SAkira Tsukamoto	 * t0 - end of aligned dst
77ca6eaaa2SAkira Tsukamoto	 */
786010d300SAkira Tsukamoto	addi	t0, t0, -(8*SZREG) /* not to over run */
795d8544e2SPalmer Dabbelt2:
80ca6eaaa2SAkira Tsukamoto	fixup REG_L   a4,        0(a1), 10f
81ca6eaaa2SAkira Tsukamoto	fixup REG_L   a5,    SZREG(a1), 10f
82ca6eaaa2SAkira Tsukamoto	fixup REG_L   a6,  2*SZREG(a1), 10f
83ca6eaaa2SAkira Tsukamoto	fixup REG_L   a7,  3*SZREG(a1), 10f
84ca6eaaa2SAkira Tsukamoto	fixup REG_L   t1,  4*SZREG(a1), 10f
85ca6eaaa2SAkira Tsukamoto	fixup REG_L   t2,  5*SZREG(a1), 10f
86ca6eaaa2SAkira Tsukamoto	fixup REG_L   t3,  6*SZREG(a1), 10f
87ca6eaaa2SAkira Tsukamoto	fixup REG_L   t4,  7*SZREG(a1), 10f
88ca6eaaa2SAkira Tsukamoto	fixup REG_S   a4,        0(a0), 10f
89ca6eaaa2SAkira Tsukamoto	fixup REG_S   a5,    SZREG(a0), 10f
90ca6eaaa2SAkira Tsukamoto	fixup REG_S   a6,  2*SZREG(a0), 10f
91ca6eaaa2SAkira Tsukamoto	fixup REG_S   a7,  3*SZREG(a0), 10f
92ca6eaaa2SAkira Tsukamoto	fixup REG_S   t1,  4*SZREG(a0), 10f
93ca6eaaa2SAkira Tsukamoto	fixup REG_S   t2,  5*SZREG(a0), 10f
94ca6eaaa2SAkira Tsukamoto	fixup REG_S   t3,  6*SZREG(a0), 10f
95ca6eaaa2SAkira Tsukamoto	fixup REG_S   t4,  7*SZREG(a0), 10f
96ca6eaaa2SAkira Tsukamoto	addi	a0, a0, 8*SZREG
97ca6eaaa2SAkira Tsukamoto	addi	a1, a1, 8*SZREG
98ca6eaaa2SAkira Tsukamoto	bltu	a0, t0, 2b
99ca6eaaa2SAkira Tsukamoto
1006010d300SAkira Tsukamoto	addi	t0, t0, 8*SZREG /* revert to original value */
101ca6eaaa2SAkira Tsukamoto	j	.Lbyte_copy_tail
102ca6eaaa2SAkira Tsukamoto
103ca6eaaa2SAkira Tsukamoto.Lshift_copy:
104ca6eaaa2SAkira Tsukamoto
105ca6eaaa2SAkira Tsukamoto	/*
106ca6eaaa2SAkira Tsukamoto	 * Word copy with shifting.
107ca6eaaa2SAkira Tsukamoto	 * For misaligned copy we still perform aligned word copy, but
108ca6eaaa2SAkira Tsukamoto	 * we need to use the value fetched from the previous iteration and
109ca6eaaa2SAkira Tsukamoto	 * do some shifts.
110ea196c54SAkira Tsukamoto	 * This is safe because reading is less than a word size.
111ca6eaaa2SAkira Tsukamoto	 *
112ca6eaaa2SAkira Tsukamoto	 * a0 - start of aligned dst
113ca6eaaa2SAkira Tsukamoto	 * a1 - start of src
114ca6eaaa2SAkira Tsukamoto	 * a3 - a1 & mask:(SZREG-1)
115ca6eaaa2SAkira Tsukamoto	 * t0 - end of uncopied dst
116ca6eaaa2SAkira Tsukamoto	 * t1 - end of aligned dst
117ca6eaaa2SAkira Tsukamoto	 */
118ca6eaaa2SAkira Tsukamoto	/* calculating aligned word boundary for dst */
119ca6eaaa2SAkira Tsukamoto	andi	t1, t0, ~(SZREG-1)
120ea196c54SAkira Tsukamoto	/* Converting unaligned src to aligned src */
121ca6eaaa2SAkira Tsukamoto	andi	a1, a1, ~(SZREG-1)
122ca6eaaa2SAkira Tsukamoto
123ca6eaaa2SAkira Tsukamoto	/*
124ca6eaaa2SAkira Tsukamoto	 * Calculate shifts
125ca6eaaa2SAkira Tsukamoto	 * t3 - prev shift
126ca6eaaa2SAkira Tsukamoto	 * t4 - current shift
127ca6eaaa2SAkira Tsukamoto	 */
12822b5f16fSAkira Tsukamoto	slli	t3, a3, 3 /* converting bytes in a3 to bits */
129ca6eaaa2SAkira Tsukamoto	li	a5, SZREG*8
130ca6eaaa2SAkira Tsukamoto	sub	t4, a5, t3
131ca6eaaa2SAkira Tsukamoto
132ea196c54SAkira Tsukamoto	/* Load the first word to combine with second word */
133ca6eaaa2SAkira Tsukamoto	fixup REG_L   a5, 0(a1), 10f
1345d8544e2SPalmer Dabbelt
1355d8544e2SPalmer Dabbelt3:
136ca6eaaa2SAkira Tsukamoto	/* Main shifting copy
137ca6eaaa2SAkira Tsukamoto	 *
138ca6eaaa2SAkira Tsukamoto	 * a0 - start of aligned dst
139ca6eaaa2SAkira Tsukamoto	 * a1 - start of aligned src
140ca6eaaa2SAkira Tsukamoto	 * t1 - end of aligned dst
141ca6eaaa2SAkira Tsukamoto	 */
142ca6eaaa2SAkira Tsukamoto
143ca6eaaa2SAkira Tsukamoto	/* At least one iteration will be executed */
144ca6eaaa2SAkira Tsukamoto	srl	a4, a5, t3
145ca6eaaa2SAkira Tsukamoto	fixup REG_L   a5, SZREG(a1), 10f
146ca6eaaa2SAkira Tsukamoto	addi	a1, a1, SZREG
147ca6eaaa2SAkira Tsukamoto	sll	a2, a5, t4
148ca6eaaa2SAkira Tsukamoto	or	a2, a2, a4
149ca6eaaa2SAkira Tsukamoto	fixup REG_S   a2, 0(a0), 10f
150ca6eaaa2SAkira Tsukamoto	addi	a0, a0, SZREG
151ca6eaaa2SAkira Tsukamoto	bltu	a0, t1, 3b
152ca6eaaa2SAkira Tsukamoto
153ca6eaaa2SAkira Tsukamoto	/* Revert src to original unaligned value  */
154ca6eaaa2SAkira Tsukamoto	add	a1, a1, a3
155ca6eaaa2SAkira Tsukamoto
156ca6eaaa2SAkira Tsukamoto.Lbyte_copy_tail:
157ca6eaaa2SAkira Tsukamoto	/*
158ca6eaaa2SAkira Tsukamoto	 * Byte copy anything left.
159ca6eaaa2SAkira Tsukamoto	 *
160ca6eaaa2SAkira Tsukamoto	 * a0 - start of remaining dst
161ca6eaaa2SAkira Tsukamoto	 * a1 - start of remaining src
162ca6eaaa2SAkira Tsukamoto	 * t0 - end of remaining dst
163ca6eaaa2SAkira Tsukamoto	 */
164ea196c54SAkira Tsukamoto	bgeu	a0, t0, .Lout_copy_user  /* check if end of copy */
165ca6eaaa2SAkira Tsukamoto4:
166ca6eaaa2SAkira Tsukamoto	fixup lb      a5, 0(a1), 10f
167ca6eaaa2SAkira Tsukamoto	addi	a1, a1, 1	/* src */
168ca6eaaa2SAkira Tsukamoto	fixup sb      a5, 0(a0), 10f
169ca6eaaa2SAkira Tsukamoto	addi	a0, a0, 1	/* dst */
170ca6eaaa2SAkira Tsukamoto	bltu	a0, t0, 4b	/* t0 - end of dst */
171ca6eaaa2SAkira Tsukamoto
172ea196c54SAkira Tsukamoto.Lout_copy_user:
1735d8544e2SPalmer Dabbelt	/* Disable access to user memory */
174a4c3733dSChristoph Hellwig	csrc CSR_STATUS, t6
1755d8544e2SPalmer Dabbelt	li	a0, 0
1765d8544e2SPalmer Dabbelt	ret
1779d504f9aSJisheng Zhang
1789d504f9aSJisheng Zhang	/* Exception fixup code */
1799d504f9aSJisheng Zhang10:
1809d504f9aSJisheng Zhang	/* Disable access to user memory */
181c08b4848SChen Lifu	csrc CSR_STATUS, t6
182*4b05b993SAlexandre Ghiti	sub a0, t5, a0
1839d504f9aSJisheng Zhang	ret
18486406d51SLuc Van OostenryckENDPROC(__asm_copy_to_user)
18586406d51SLuc Van OostenryckENDPROC(__asm_copy_from_user)
1864d47ce15SLuc Van OostenryckEXPORT_SYMBOL(__asm_copy_to_user)
1874d47ce15SLuc Van OostenryckEXPORT_SYMBOL(__asm_copy_from_user)
1885d8544e2SPalmer Dabbelt
1895d8544e2SPalmer Dabbelt
1905d8544e2SPalmer DabbeltENTRY(__clear_user)
1915d8544e2SPalmer Dabbelt
1925d8544e2SPalmer Dabbelt	/* Enable access to user memory */
1935d8544e2SPalmer Dabbelt	li t6, SR_SUM
194a4c3733dSChristoph Hellwig	csrs CSR_STATUS, t6
1955d8544e2SPalmer Dabbelt
1965d8544e2SPalmer Dabbelt	add a3, a0, a1
1975d8544e2SPalmer Dabbelt	addi t0, a0, SZREG-1
1985d8544e2SPalmer Dabbelt	andi t1, a3, ~(SZREG-1)
1995d8544e2SPalmer Dabbelt	andi t0, t0, ~(SZREG-1)
2005d8544e2SPalmer Dabbelt	/*
2015d8544e2SPalmer Dabbelt	 * a3: terminal address of target region
2025d8544e2SPalmer Dabbelt	 * t0: lowest doubleword-aligned address in target region
2035d8544e2SPalmer Dabbelt	 * t1: highest doubleword-aligned address in target region
2045d8544e2SPalmer Dabbelt	 */
2055d8544e2SPalmer Dabbelt	bgeu t0, t1, 2f
2065d8544e2SPalmer Dabbelt	bltu a0, t0, 4f
2075d8544e2SPalmer Dabbelt1:
208ebcbd75eSAlan Kao	fixup REG_S, zero, (a0), 11f
2095d8544e2SPalmer Dabbelt	addi a0, a0, SZREG
2105d8544e2SPalmer Dabbelt	bltu a0, t1, 1b
2115d8544e2SPalmer Dabbelt2:
2125d8544e2SPalmer Dabbelt	bltu a0, a3, 5f
2135d8544e2SPalmer Dabbelt
2145d8544e2SPalmer Dabbelt3:
2155d8544e2SPalmer Dabbelt	/* Disable access to user memory */
216a4c3733dSChristoph Hellwig	csrc CSR_STATUS, t6
2175d8544e2SPalmer Dabbelt	li a0, 0
2185d8544e2SPalmer Dabbelt	ret
2195d8544e2SPalmer Dabbelt4: /* Edge case: unalignment */
220ebcbd75eSAlan Kao	fixup sb, zero, (a0), 11f
2215d8544e2SPalmer Dabbelt	addi a0, a0, 1
2225d8544e2SPalmer Dabbelt	bltu a0, t0, 4b
2235d8544e2SPalmer Dabbelt	j 1b
2245d8544e2SPalmer Dabbelt5: /* Edge case: remainder */
225ebcbd75eSAlan Kao	fixup sb, zero, (a0), 11f
2265d8544e2SPalmer Dabbelt	addi a0, a0, 1
2275d8544e2SPalmer Dabbelt	bltu a0, a3, 5b
2285d8544e2SPalmer Dabbelt	j 3b
2295d8544e2SPalmer Dabbelt
2309d504f9aSJisheng Zhang	/* Exception fixup code */
231ebcbd75eSAlan Kao11:
2329d504f9aSJisheng Zhang	/* Disable access to user memory */
233c08b4848SChen Lifu	csrc CSR_STATUS, t6
234*4b05b993SAlexandre Ghiti	sub a0, a3, a0
2355d8544e2SPalmer Dabbelt	ret
2369d504f9aSJisheng ZhangENDPROC(__clear_user)
2379d504f9aSJisheng ZhangEXPORT_SYMBOL(__clear_user)
238