blob: 884f46499d4e03b6957399dc99397ee698634bef [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* copy_in_user.S: Copy from userspace to userspace.
2 *
3 * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com)
4 */
5
6#include <asm/asi.h>
7
8#define XCC xcc
9
10#define EX(x,y) \
1198: x,y; \
David S. Miller4d000d52006-03-04 23:23:56 -080012 .section __ex_table,"a";\
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 .align 4; \
David S. Miller40bdac72009-02-08 22:00:55 -080014 .word 98b, __retl_one; \
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 .text; \
16 .align 4;
17
18 .register %g2,#scratch
19 .register %g3,#scratch
20
21 .text
22 .align 32
23
24 /* Don't try to get too fancy here, just nice and
25 * simple. This is predominantly used for well aligned
26 * small copies in the compat layer. It is also used
27 * to copy register windows around during thread cloning.
28 */
29
30 .globl ___copy_in_user
31 .type ___copy_in_user,#function
32___copy_in_user: /* %o0=dst, %o1=src, %o2=len */
33 /* Writing to %asi is _expensive_ so we hardcode it.
34 * Reading %asi to check for KERNEL_DS is comparatively
35 * cheap.
36 */
37 rd %asi, %g1
38 cmp %g1, ASI_AIUS
39 bne,pn %icc, memcpy_user_stub
40 nop
41
42 cmp %o2, 0
43 be,pn %XCC, 85f
44 or %o0, %o1, %o3
45 cmp %o2, 16
46 bleu,a,pn %XCC, 80f
47 or %o3, %o2, %o3
48
49 /* 16 < len <= 64 */
50 andcc %o3, 0x7, %g0
51 bne,pn %XCC, 90f
52 sub %o0, %o1, %o3
53
54 andn %o2, 0x7, %o4
55 and %o2, 0x7, %o2
561: subcc %o4, 0x8, %o4
57 EX(ldxa [%o1] %asi, %o5)
58 EX(stxa %o5, [%o1 + %o3] ASI_AIUS)
59 bgu,pt %XCC, 1b
60 add %o1, 0x8, %o1
61 andcc %o2, 0x4, %g0
62 be,pt %XCC, 1f
63 nop
64 sub %o2, 0x4, %o2
65 EX(lduwa [%o1] %asi, %o5)
66 EX(stwa %o5, [%o1 + %o3] ASI_AIUS)
67 add %o1, 0x4, %o1
681: cmp %o2, 0
69 be,pt %XCC, 85f
70 nop
71 ba,pt %xcc, 90f
72 nop
73
7480: /* 0 < len <= 16 */
75 andcc %o3, 0x3, %g0
76 bne,pn %XCC, 90f
77 sub %o0, %o1, %o3
78
7982:
80 subcc %o2, 4, %o2
81 EX(lduwa [%o1] %asi, %g1)
82 EX(stwa %g1, [%o1 + %o3] ASI_AIUS)
83 bgu,pt %XCC, 82b
84 add %o1, 4, %o1
85
8685: retl
87 clr %o0
88
89 .align 32
9090:
91 subcc %o2, 1, %o2
92 EX(lduba [%o1] %asi, %g1)
93 EX(stba %g1, [%o1 + %o3] ASI_AIUS)
94 bgu,pt %XCC, 90b
95 add %o1, 1, %o1
96 retl
97 clr %o0
98
99 .size ___copy_in_user, .-___copy_in_user
100
101 /* Act like copy_{to,in}_user(), ie. return zero instead
102 * of original destination pointer. This is invoked when
103 * copy_{to,in}_user() finds that %asi is kernel space.
104 */
105 .globl memcpy_user_stub
106 .type memcpy_user_stub,#function
107memcpy_user_stub:
108 save %sp, -192, %sp
109 mov %i0, %o0
110 mov %i1, %o1
111 call memcpy
112 mov %i2, %o2
113 ret
114 restore %g0, %g0, %o0
115 .size memcpy_user_stub, .-memcpy_user_stub