[PATCH 13/27] asm-generic: make uaccess.h usable by mmu archs

Arnd Bergmann
2009-04-30T15:42:03Z

Make it possible to override some functions from uaccess.h
so that architectures with an mmu can provide assembly
versions of the functions with their own fixup logic.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
include/asm-generic/uaccess.h | 102 +++++++++++++++++++++++++---------------
1 files changed, 64 insertions(+), 38 deletions(-)

diff --git a/include/asm-generic/uaccess.h b/include/asm-generic/uaccess.h
index ebeacd9..e05f6a9 100644
--- a/include/asm-generic/uaccess.h
+++ b/include/asm-generic/uaccess.h
@@ -31,14 +31,14 @@ static inline void set_fs(mm_segment_t fs)
#define VERIFY_READ 0
#define VERIFY_WRITE 1

-#define access_ok(type, addr, size) _access_ok((unsigned long)(addr),(size))
+#define access_ok(type, addr, size) __access_ok((unsigned long)(addr),(size))

/*
* The architecture should really override this if possible, at least
* doing a check on the get_fs()
*/
-#ifndef _access_ok
-static inline int _access_ok(unsigned long addr, unsigned long size)
+#ifndef __access_ok
+static inline int __access_ok(unsigned long addr, unsigned long size)
{
return 1;
}
@@ -93,7 +93,7 @@ extern int __put_user_bad(void);
#endif

#define put_user(x, ptr) ( \
- access_ok(VERIFY_WRITE, ptr, sizeof (*ptr)) ? \
+ __access_ok(ptr, sizeof (*ptr)) ? \
__put_user(x, ptr) : \
-EFAULT)

@@ -120,45 +120,62 @@ extern int __get_user_bad(void);
#endif

#define get_user(x, ptr) ( \
- access_ok(VERIFY_READ, ptr, sizeof (*ptr)) ? \
+ __access_ok(ptr, sizeof (*ptr)) ? \
__get_user(x, ptr) : \
-EFAULT)

-#define __copy_from_user(to, from, n) (memcpy(to, from, n), 0)
-#define __copy_to_user(to, from, n) (memcpy(to, from, n), 0)
-#define __copy_to_user_inatomic __copy_to_user
-#define __copy_from_user_inatomic __copy_from_user
+#ifndef __copy_from_user
+static inline __must_check long __copy_from_user(void *to,
+ const void __user *from, unsigned long n)
+{
+ memcpy(to, (const void __force *)from, n);
+ return 0;
+}
+#endif

-#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; })
+#ifndef __copy_to_user
+static inline __must_check long __copy_to_user(void __user *to,
+ const void *from, unsigned long n)
+{
+ memcpy((void __force *)to, from, n);
+ return 0;
+}
+#endif
+
+#ifndef __copy_from_user_inatomic
+#define __copy_from_user_inatomic __copy_from_user
+#endif

-#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; })
+#ifndef __copy_to_user_inatomic
+#define __copy_to_user_inatomic __copy_to_user
+#endif

static inline long copy_from_user(void *to,
- const void __user * from, unsigned long n)
+ const void __user * from, unsigned long n)
{
- if (access_ok(VERIFY_READ, from, n))
- __copy_from_user(to, from, n);
+ might_sleep();
+ if (__access_ok(from, n))
+ return __copy_from_user(to, from, n);
else
return n;
- return 0;
}

-static inline long copy_to_user(void *to,
- const void __user * from, unsigned long n)
+static inline long copy_to_user(void __user *to,
+ const void *from, unsigned long n)
{
- if (access_ok(VERIFY_WRITE, to, n))
- __copy_to_user(to, from, n);
+ might_sleep();
+ if (__access_ok(to, n))
+ return __copy_to_user(to, from, n);
else
return n;
- return 0;
}

/*
* Copy a null terminated string from userspace.
*/
-
+#ifndef __strncpy_from_user
static inline long
-__do_strncpy_from_user(char *dst, const char __user *src, long count)
+__strncpy_from_user(char *dst, const char __user *src, long count)
{
char *tmp;
strncpy(dst, src, count);
@@ -166,19 +183,14 @@ __do_strncpy_from_user(char *dst, const char __user *src, long count)
;
return (tmp - dst);
}
+#endif

static inline long
strncpy_from_user(char *dst, const char __user *src, long count)
{
- if (!access_ok(VERIFY_READ, src, 1))
+ if (!__access_ok(src, 1))
return -EFAULT;
- return __do_strncpy_from_user(dst, src, count);
-}
-
-static inline long
-__strncpy_from_user(char *dst, const char __user *src, long count)
-{
- return __do_strncpy_from_user(dst, src, count);
+ return __strncpy_from_user(dst, src, count);
}

/*
@@ -186,24 +198,38 @@ __strncpy_from_user(char *dst, const char __user *src, long count)
*
* Return 0 on exception, a value greater than N if too long
*/
-static inline long strnlen_user(const char *src, long n)
+#ifndef strnlen_user
+static inline long strnlen_user(const char __user *src, long n)
{
- return strlen(src) + 1;
+ return strlen((void * __force)src) + 1;
}
+#endif

-#define strlen_user(str) strnlen_user(str, 32767)
+static inline long strlen_user(const char __user *src)
+{
+ return strnlen_user(src, 32767);
+}

/*
* Zero Userspace
*/
-
-static inline unsigned long
-__clear_user(void *to, unsigned long n)
+#ifndef __clear_user
+static inline __must_check unsigned long
+__clear_user(void __user *to, unsigned long n)
{
- memset(to, 0, n);
+ memset((void __force *)to, 0, n);
return 0;
}
+#endif

-#define clear_user(to, n) __clear_user(to, n)
+static inline __must_check unsigned long
+clear_user(void __user *to, unsigned long n)
+{
+ might_sleep();
+ if (!__access_ok(to, n))
+ return n;
+
+ return __clear_user(to, n);
+}

#endif /* __ASM_GENERIC_UACCESS_H */
--
1.5.6.3