aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2006-06-21 15:38:17 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2006-06-28 12:59:46 -0400
commit9641c7cc5a7f6d5c9dc9b43eea4e5f8c3c08c94e (patch)
tree5ff57feabe0538d58404ec4918b0d94d75f69846
parent002547b4f86c27bfac5bae344b723d250857be6b (diff)
[ARM] nommu: uaccess tweaks
MMUless systems have only one address space for all threads, so both the usual access_ok() checks, and the exception handling do not make much sense. Hence, discard the fixup and exception tables at link time, use memcpy/memset for the user copy/clearing functions, and define the permission check macros to be constants. Some of this patch was derived from the equivalent patch by Hyok S. Choi. Signed-off-by: Hyok S. Choi <hyok.choi@samsung.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/kernel/armksyms.c7
-rw-r--r--arch/arm/kernel/vmlinux.lds.S8
-rw-r--r--arch/arm/lib/Makefile13
-rw-r--r--include/asm-arm/uaccess.h139
4 files changed, 108 insertions, 59 deletions
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index f8bb7abd3e9b..da69e660574b 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -109,11 +109,13 @@ EXPORT_SYMBOL(memchr);
109EXPORT_SYMBOL(__memzero); 109EXPORT_SYMBOL(__memzero);
110 110
111 /* user mem (segment) */ 111 /* user mem (segment) */
112EXPORT_SYMBOL(__strnlen_user);
113EXPORT_SYMBOL(__strncpy_from_user);
114
115#ifdef CONFIG_MMU
112EXPORT_SYMBOL(__copy_from_user); 116EXPORT_SYMBOL(__copy_from_user);
113EXPORT_SYMBOL(__copy_to_user); 117EXPORT_SYMBOL(__copy_to_user);
114EXPORT_SYMBOL(__clear_user); 118EXPORT_SYMBOL(__clear_user);
115EXPORT_SYMBOL(__strnlen_user);
116EXPORT_SYMBOL(__strncpy_from_user);
117 119
118EXPORT_SYMBOL(__get_user_1); 120EXPORT_SYMBOL(__get_user_1);
119EXPORT_SYMBOL(__get_user_2); 121EXPORT_SYMBOL(__get_user_2);
@@ -123,6 +125,7 @@ EXPORT_SYMBOL(__put_user_1);
123EXPORT_SYMBOL(__put_user_2); 125EXPORT_SYMBOL(__put_user_2);
124EXPORT_SYMBOL(__put_user_4); 126EXPORT_SYMBOL(__put_user_4);
125EXPORT_SYMBOL(__put_user_8); 127EXPORT_SYMBOL(__put_user_8);
128#endif
126 129
127 /* crypto hash */ 130 /* crypto hash */
128EXPORT_SYMBOL(sha_transform); 131EXPORT_SYMBOL(sha_transform);
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index 2b254e88595c..2df9688a7028 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -80,6 +80,10 @@ SECTIONS
80 *(.exit.text) 80 *(.exit.text)
81 *(.exit.data) 81 *(.exit.data)
82 *(.exitcall.exit) 82 *(.exitcall.exit)
83#ifndef CONFIG_MMU
84 *(.fixup)
85 *(__ex_table)
86#endif
83 } 87 }
84 88
85 .text : { /* Real text segment */ 89 .text : { /* Real text segment */
@@ -87,7 +91,9 @@ SECTIONS
87 *(.text) 91 *(.text)
88 SCHED_TEXT 92 SCHED_TEXT
89 LOCK_TEXT 93 LOCK_TEXT
94#ifdef CONFIG_MMU
90 *(.fixup) 95 *(.fixup)
96#endif
91 *(.gnu.warning) 97 *(.gnu.warning)
92 *(.rodata) 98 *(.rodata)
93 *(.rodata.*) 99 *(.rodata.*)
@@ -142,7 +148,9 @@ SECTIONS
142 */ 148 */
143 . = ALIGN(32); 149 . = ALIGN(32);
144 __start___ex_table = .; 150 __start___ex_table = .;
151#ifdef CONFIG_MMU
145 *(__ex_table) 152 *(__ex_table)
153#endif
146 __stop___ex_table = .; 154 __stop___ex_table = .;
147 155
148 /* 156 /*
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index 7b726b627ea5..30351cd4560d 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -6,28 +6,31 @@
6 6
7lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ 7lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \
8 csumpartialcopy.o csumpartialcopyuser.o clearbit.o \ 8 csumpartialcopy.o csumpartialcopyuser.o clearbit.o \
9 copy_page.o delay.o findbit.o memchr.o memcpy.o \ 9 delay.o findbit.o memchr.o memcpy.o \
10 memmove.o memset.o memzero.o setbit.o \ 10 memmove.o memset.o memzero.o setbit.o \
11 strncpy_from_user.o strnlen_user.o \ 11 strncpy_from_user.o strnlen_user.o \
12 strchr.o strrchr.o \ 12 strchr.o strrchr.o \
13 testchangebit.o testclearbit.o testsetbit.o \ 13 testchangebit.o testclearbit.o testsetbit.o \
14 getuser.o putuser.o clear_user.o \
15 ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ 14 ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
16 ucmpdi2.o lib1funcs.o div64.o sha1.o \ 15 ucmpdi2.o lib1funcs.o div64.o sha1.o \
17 io-readsb.o io-writesb.o io-readsl.o io-writesl.o 16 io-readsb.o io-writesb.o io-readsl.o io-writesl.o
18 17
18mmu-y := clear_user.o copy_page.o getuser.o putuser.o
19
19# the code in uaccess.S is not preemption safe and 20# the code in uaccess.S is not preemption safe and
20# probably faster on ARMv3 only 21# probably faster on ARMv3 only
21ifeq ($(CONFIG_PREEMPT),y) 22ifeq ($(CONFIG_PREEMPT),y)
22 lib-y += copy_from_user.o copy_to_user.o 23 mmu-y += copy_from_user.o copy_to_user.o
23else 24else
24ifneq ($(CONFIG_CPU_32v3),y) 25ifneq ($(CONFIG_CPU_32v3),y)
25 lib-y += copy_from_user.o copy_to_user.o 26 mmu-y += copy_from_user.o copy_to_user.o
26else 27else
27 lib-y += uaccess.o 28 mmu-y += uaccess.o
28endif 29endif
29endif 30endif
30 31
32lib-$(CONFIG_MMU) += $(mmu-y)
33
31ifeq ($(CONFIG_CPU_32v3),y) 34ifeq ($(CONFIG_CPU_32v3),y)
32 lib-y += io-readsw-armv3.o io-writesw-armv3.o 35 lib-y += io-readsw-armv3.o io-writesw-armv3.o
33else 36else
diff --git a/include/asm-arm/uaccess.h b/include/asm-arm/uaccess.h
index f909dc75301a..87aba57a66c4 100644
--- a/include/asm-arm/uaccess.h
+++ b/include/asm-arm/uaccess.h
@@ -41,15 +41,24 @@ struct exception_table_entry
41extern int fixup_exception(struct pt_regs *regs); 41extern int fixup_exception(struct pt_regs *regs);
42 42
43/* 43/*
44 * These two are intentionally not defined anywhere - if the kernel
45 * code generates any references to them, that's a bug.
46 */
47extern int __get_user_bad(void);
48extern int __put_user_bad(void);
49
50/*
44 * Note that this is actually 0x1,0000,0000 51 * Note that this is actually 0x1,0000,0000
45 */ 52 */
46#define KERNEL_DS 0x00000000 53#define KERNEL_DS 0x00000000
47#define USER_DS TASK_SIZE
48
49#define get_ds() (KERNEL_DS) 54#define get_ds() (KERNEL_DS)
55
56#ifdef CONFIG_MMU
57
58#define USER_DS TASK_SIZE
50#define get_fs() (current_thread_info()->addr_limit) 59#define get_fs() (current_thread_info()->addr_limit)
51 60
52static inline void set_fs (mm_segment_t fs) 61static inline void set_fs(mm_segment_t fs)
53{ 62{
54 current_thread_info()->addr_limit = fs; 63 current_thread_info()->addr_limit = fs;
55 modify_domain(DOMAIN_KERNEL, fs ? DOMAIN_CLIENT : DOMAIN_MANAGER); 64 modify_domain(DOMAIN_KERNEL, fs ? DOMAIN_CLIENT : DOMAIN_MANAGER);
@@ -75,8 +84,6 @@ static inline void set_fs (mm_segment_t fs)
75 : "cc"); \ 84 : "cc"); \
76 flag; }) 85 flag; })
77 86
78#define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
79
80/* 87/*
81 * Single-value transfer routines. They automatically use the right 88 * Single-value transfer routines. They automatically use the right
82 * size if we just have the right pointer type. Note that the functions 89 * size if we just have the right pointer type. Note that the functions
@@ -87,20 +94,10 @@ static inline void set_fs (mm_segment_t fs)
87 * fixup code, but there are a few places where it intrudes on the 94 * fixup code, but there are a few places where it intrudes on the
88 * main code path. When we only write to user space, there is no 95 * main code path. When we only write to user space, there is no
89 * problem. 96 * problem.
90 *
91 * The "__xxx" versions of the user access functions do not verify the
92 * address space - it must have been done previously with a separate
93 * "access_ok()" call.
94 *
95 * The "xxx_error" versions set the third argument to EFAULT if an
96 * error occurs, and leave it unchanged on success. Note that these
97 * versions are void (ie, don't return a value as such).
98 */ 97 */
99
100extern int __get_user_1(void *); 98extern int __get_user_1(void *);
101extern int __get_user_2(void *); 99extern int __get_user_2(void *);
102extern int __get_user_4(void *); 100extern int __get_user_4(void *);
103extern int __get_user_bad(void);
104 101
105#define __get_user_x(__r2,__p,__e,__s,__i...) \ 102#define __get_user_x(__r2,__p,__e,__s,__i...) \
106 __asm__ __volatile__ ( \ 103 __asm__ __volatile__ ( \
@@ -131,6 +128,74 @@ extern int __get_user_bad(void);
131 __e; \ 128 __e; \
132 }) 129 })
133 130
131extern int __put_user_1(void *, unsigned int);
132extern int __put_user_2(void *, unsigned int);
133extern int __put_user_4(void *, unsigned int);
134extern int __put_user_8(void *, unsigned long long);
135
136#define __put_user_x(__r2,__p,__e,__s) \
137 __asm__ __volatile__ ( \
138 __asmeq("%0", "r0") __asmeq("%2", "r2") \
139 "bl __put_user_" #__s \
140 : "=&r" (__e) \
141 : "0" (__p), "r" (__r2) \
142 : "ip", "lr", "cc")
143
144#define put_user(x,p) \
145 ({ \
146 const register typeof(*(p)) __r2 asm("r2") = (x); \
147 const register typeof(*(p)) __user *__p asm("r0") = (p);\
148 register int __e asm("r0"); \
149 switch (sizeof(*(__p))) { \
150 case 1: \
151 __put_user_x(__r2, __p, __e, 1); \
152 break; \
153 case 2: \
154 __put_user_x(__r2, __p, __e, 2); \
155 break; \
156 case 4: \
157 __put_user_x(__r2, __p, __e, 4); \
158 break; \
159 case 8: \
160 __put_user_x(__r2, __p, __e, 8); \
161 break; \
162 default: __e = __put_user_bad(); break; \
163 } \
164 __e; \
165 })
166
167#else /* CONFIG_MMU */
168
169/*
170 * uClinux has only one addr space, so has simplified address limits.
171 */
172#define USER_DS KERNEL_DS
173
174#define segment_eq(a,b) (1)
175#define __addr_ok(addr) (1)
176#define __range_ok(addr,size) (0)
177#define get_fs() (KERNEL_DS)
178
179static inline void set_fs(mm_segment_t fs)
180{
181}
182
183#define get_user(x,p) __get_user(x,p)
184#define put_user(x,p) __put_user(x,p)
185
186#endif /* CONFIG_MMU */
187
188#define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
189
190/*
191 * The "__xxx" versions of the user access functions do not verify the
192 * address space - it must have been done previously with a separate
193 * "access_ok()" call.
194 *
195 * The "xxx_error" versions set the third argument to EFAULT if an
196 * error occurs, and leave it unchanged on success. Note that these
197 * versions are void (ie, don't return a value as such).
198 */
134#define __get_user(x,ptr) \ 199#define __get_user(x,ptr) \
135({ \ 200({ \
136 long __gu_err = 0; \ 201 long __gu_err = 0; \
@@ -212,43 +277,6 @@ do { \
212 : "r" (addr), "i" (-EFAULT) \ 277 : "r" (addr), "i" (-EFAULT) \
213 : "cc") 278 : "cc")
214 279
215extern int __put_user_1(void *, unsigned int);
216extern int __put_user_2(void *, unsigned int);
217extern int __put_user_4(void *, unsigned int);
218extern int __put_user_8(void *, unsigned long long);
219extern int __put_user_bad(void);
220
221#define __put_user_x(__r2,__p,__e,__s) \
222 __asm__ __volatile__ ( \
223 __asmeq("%0", "r0") __asmeq("%2", "r2") \
224 "bl __put_user_" #__s \
225 : "=&r" (__e) \
226 : "0" (__p), "r" (__r2) \
227 : "ip", "lr", "cc")
228
229#define put_user(x,p) \
230 ({ \
231 const register typeof(*(p)) __r2 asm("r2") = (x); \
232 const register typeof(*(p)) __user *__p asm("r0") = (p);\
233 register int __e asm("r0"); \
234 switch (sizeof(*(__p))) { \
235 case 1: \
236 __put_user_x(__r2, __p, __e, 1); \
237 break; \
238 case 2: \
239 __put_user_x(__r2, __p, __e, 2); \
240 break; \
241 case 4: \
242 __put_user_x(__r2, __p, __e, 4); \
243 break; \
244 case 8: \
245 __put_user_x(__r2, __p, __e, 8); \
246 break; \
247 default: __e = __put_user_bad(); break; \
248 } \
249 __e; \
250 })
251
252#define __put_user(x,ptr) \ 280#define __put_user(x,ptr) \
253({ \ 281({ \
254 long __pu_err = 0; \ 282 long __pu_err = 0; \
@@ -354,9 +382,16 @@ do { \
354 : "cc") 382 : "cc")
355 383
356 384
385#ifdef CONFIG_MMU
357extern unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n); 386extern unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n);
358extern unsigned long __copy_to_user(void __user *to, const void *from, unsigned long n); 387extern unsigned long __copy_to_user(void __user *to, const void *from, unsigned long n);
359extern unsigned long __clear_user(void __user *addr, unsigned long n); 388extern unsigned long __clear_user(void __user *addr, unsigned long n);
389#else
390#define __copy_from_user(to,from,n) (memcpy(to, (void __force *)from, n), 0)
391#define __copy_to_user(to,from,n) (memcpy((void __force *)to, from, n), 0)
392#define __clear_user(addr,n) (memset((void __force *)addr, 0, n), 0)
393#endif
394
360extern unsigned long __strncpy_from_user(char *to, const char __user *from, unsigned long count); 395extern unsigned long __strncpy_from_user(char *to, const char __user *from, unsigned long count);
361extern unsigned long __strnlen_user(const char __user *s, long n); 396extern unsigned long __strnlen_user(const char __user *s, long n);
362 397