diff options
author | Paul Mundt <lethal@linux-sh.org> | 2008-06-03 20:05:39 +0900 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2008-07-28 18:10:29 +0900 |
commit | 42fd3b142d8867f5b58d6fb75592cd20fd654c1b (patch) | |
tree | b05b9543e34e008f8d466bb3a464e1f9e3081817 /include/asm-sh/uaccess_32.h | |
parent | 31f6a11fe764dc580b645d7aa878854fa9e85a06 (diff) |
sh: Initial consolidation of the _32/_64 uaccess split.
This consolidates everything but the bare assembly routines, which we
will sync up in a follow-up patch.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'include/asm-sh/uaccess_32.h')
-rw-r--r-- | include/asm-sh/uaccess_32.h | 277 |
1 files changed, 48 insertions, 229 deletions
diff --git a/include/asm-sh/uaccess_32.h b/include/asm-sh/uaccess_32.h index 44abd1682329..ae0d24f6653f 100644 --- a/include/asm-sh/uaccess_32.h +++ b/include/asm-sh/uaccess_32.h @@ -12,56 +12,6 @@ #ifndef __ASM_SH_UACCESS_32_H #define __ASM_SH_UACCESS_32_H -#include <linux/errno.h> -#include <linux/sched.h> -#include <asm/segment.h> - -#define VERIFY_READ 0 -#define VERIFY_WRITE 1 - -#define __addr_ok(addr) \ - ((unsigned long __force)(addr) < current_thread_info()->addr_limit.seg) - -/* - * __access_ok: Check if address with size is OK or not. - * - * Uhhuh, this needs 33-bit arithmetic. We have a carry.. - * - * sum := addr + size; carry? --> flag = true; - * if (sum >= addr_limit) flag = true; - */ -#define __access_ok(addr, size) \ - (__addr_ok((addr) + (size))) -#define access_ok(type, addr, size) \ - (__chk_user_ptr(addr), \ - __access_ok((unsigned long __force)(addr), (size))) - -/* - * Uh, these should become the main single-value transfer routines ... - * They automatically use the right size if we just have the right - * pointer type ... - * - * As SuperH uses the same address space for kernel and user data, we - * can just do these as direct assignments. - * - * Careful to not - * (a) re-use the arguments for side effects (sizeof is ok) - * (b) require any knowledge of processes at this stage - */ -#define put_user(x,ptr) __put_user_check((x), (ptr), sizeof(*(ptr))) -#define get_user(x,ptr) __get_user_check((x), (ptr), sizeof(*(ptr))) - -/* - * The "__xxx" versions do not do address space checking, useful when - * doing multiple accesses to the same area (the user has to do the - * checks by hand with "access_ok()") - */ -#define __put_user(x,ptr) __put_user_nocheck((x), (ptr), sizeof(*(ptr))) -#define __get_user(x,ptr) __get_user_nocheck((x), (ptr), sizeof(*(ptr))) - -struct __large_struct { unsigned long buf[100]; }; -#define __m(x) (*(struct __large_struct __user *)(x)) - #define __get_user_size(x,ptr,size,retval) \ do { \ retval = 0; \ @@ -81,28 +31,7 @@ do { \ } \ } while (0) -#define __get_user_nocheck(x,ptr,size) \ -({ \ - long __gu_err; \ - unsigned long __gu_val; \ - const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ - __chk_user_ptr(ptr); \ - __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ - (x) = (__typeof__(*(ptr)))__gu_val; \ - __gu_err; \ -}) - -#define __get_user_check(x,ptr,size) \ -({ \ - long __gu_err = -EFAULT; \ - unsigned long __gu_val = 0; \ - const __typeof__(*(ptr)) *__gu_addr = (ptr); \ - if (likely(access_ok(VERIFY_READ, __gu_addr, (size)))) \ - __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ - (x) = (__typeof__(*(ptr)))__gu_val; \ - __gu_err; \ -}) - +#ifdef CONFIG_MMU #define __get_user_asm(x, addr, err, insn) \ ({ \ __asm__ __volatile__( \ @@ -123,6 +52,16 @@ __asm__ __volatile__( \ ".previous" \ :"=&r" (err), "=&r" (x) \ :"m" (__m(addr)), "i" (-EFAULT), "0" (err)); }) +#else +#define __get_user_asm(x, addr, err, insn) \ +do { \ + __asm__ __volatile__ ( \ + "mov." insn " %1, %0\n\t" \ + : "=&r" (x) \ + : "m" (__m(addr)) \ + ); \ +} while (0) +#endif /* CONFIG_MMU */ extern void __get_user_unknown(void); @@ -147,45 +86,41 @@ do { \ } \ } while (0) -#define __put_user_nocheck(x,ptr,size) \ -({ \ - long __pu_err; \ - __typeof__(*(ptr)) __user *__pu_addr = (ptr); \ - __chk_user_ptr(ptr); \ - __put_user_size((x), __pu_addr, (size), __pu_err); \ - __pu_err; \ -}) - -#define __put_user_check(x,ptr,size) \ -({ \ - long __pu_err = -EFAULT; \ - __typeof__(*(ptr)) __user *__pu_addr = (ptr); \ - if (likely(access_ok(VERIFY_WRITE, __pu_addr, size))) \ - __put_user_size((x), __pu_addr, (size), \ - __pu_err); \ - __pu_err; \ -}) - -#define __put_user_asm(x, addr, err, insn) \ -({ \ -__asm__ __volatile__( \ - "1:\n\t" \ - "mov." insn " %1, %2\n\t" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3:\n\t" \ - "mov.l 4f, %0\n\t" \ - "jmp @%0\n\t" \ - " mov %3, %0\n\t" \ - ".balign 4\n" \ - "4: .long 2b\n\t" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n\t" \ - ".long 1b, 3b\n\t" \ - ".previous" \ - :"=&r" (err) \ - :"r" (x), "m" (__m(addr)), "i" (-EFAULT), "0" (err) \ - :"memory"); }) +#ifdef CONFIG_MMU +#define __put_user_asm(x, addr, err, insn) \ +do { \ + __asm__ __volatile__ ( \ + "1:\n\t" \ + "mov." insn " %1, %2\n\t" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3:\n\t" \ + "mov.l 4f, %0\n\t" \ + "jmp @%0\n\t" \ + " mov %3, %0\n\t" \ + ".balign 4\n" \ + "4: .long 2b\n\t" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n\t" \ + ".long 1b, 3b\n\t" \ + ".previous" \ + : "=&r" (err) \ + : "r" (x), "m" (__m(addr)), "i" (-EFAULT), \ + "0" (err) \ + : "memory" \ + ); \ +} while (0) +#else +#define __put_user_asm(x, addr, err, insn) \ +do { \ + __asm__ __volatile__ ( \ + "mov." insn " %0, %1\n\t" \ + : /* no outputs */ \ + : "r" (x), "m" (__m(addr)) \ + : "memory" \ + ); \ +} while (0) +#endif /* CONFIG_MMU */ #if defined(CONFIG_CPU_LITTLE_ENDIAN) #define __put_user_u64(val,addr,retval) \ @@ -235,40 +170,7 @@ __asm__ __volatile__( \ extern void __put_user_unknown(void); -/* Generic arbitrary sized copy. */ -/* Return the number of bytes NOT copied */ -__kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n); - - -static __always_inline unsigned long -__copy_from_user(void *to, const void __user *from, unsigned long n) -{ - return __copy_user(to, (__force void *)from, n); -} - -static __always_inline unsigned long __must_check -__copy_to_user(void __user *to, const void *from, unsigned long n) -{ - return __copy_user((__force void *)to, from, n); -} - -#define __copy_to_user_inatomic __copy_to_user -#define __copy_from_user_inatomic __copy_from_user - -/* - * Clear the area and return remaining number of bytes - * (on failure. Usually it's 0.) - */ -extern __kernel_size_t __clear_user(void *addr, __kernel_size_t size); - -#define clear_user(addr,n) ({ \ -void * __cl_addr = (addr); \ -unsigned long __cl_size = (n); \ -if (__cl_size && __access_ok(((unsigned long)(__cl_addr)), __cl_size)) \ -__cl_size = __clear_user(__cl_addr, __cl_size); \ -__cl_size; }) - -static __inline__ int +static inline int __strncpy_from_user(unsigned long __dest, unsigned long __user __src, int __count) { __kernel_size_t res; @@ -307,37 +209,11 @@ __strncpy_from_user(unsigned long __dest, unsigned long __user __src, int __coun return res; } -/** - * strncpy_from_user: - Copy a NUL terminated string from userspace. - * @dst: Destination address, in kernel space. This buffer must be at - * least @count bytes long. - * @src: Source address, in user space. - * @count: Maximum number of bytes to copy, including the trailing NUL. - * - * Copies a NUL-terminated string from userspace to kernel space. - * - * On success, returns the length of the string (not including the trailing - * NUL). - * - * If access to userspace fails, returns -EFAULT (some data may have been - * copied). - * - * If @count is smaller than the length of the string, copies @count bytes - * and returns @count. - */ -#define strncpy_from_user(dest,src,count) ({ \ -unsigned long __sfu_src = (unsigned long) (src); \ -int __sfu_count = (int) (count); \ -long __sfu_res = -EFAULT; \ -if(__access_ok(__sfu_src, __sfu_count)) { \ -__sfu_res = __strncpy_from_user((unsigned long) (dest), __sfu_src, __sfu_count); \ -} __sfu_res; }) - /* * Return the size of a string (including the ending 0 even when we have * exceeded the maximum string length). */ -static __inline__ long __strnlen_user(const char __user *__s, long __n) +static inline long __strnlen_user(const char __user *__s, long __n) { unsigned long res; unsigned long __dummy; @@ -369,61 +245,4 @@ static __inline__ long __strnlen_user(const char __user *__s, long __n) return res; } -/** - * strnlen_user: - Get the size of a string in user space. - * @s: The string to measure. - * @n: The maximum valid length - * - * Context: User context only. This function may sleep. - * - * Get the size of a NUL-terminated string in user space. - * - * Returns the size of the string INCLUDING the terminating NUL. - * On exception, returns 0. - * If the string is too long, returns a value greater than @n. - */ -static __inline__ long strnlen_user(const char __user *s, long n) -{ - if (!__addr_ok(s)) - return 0; - else - return __strnlen_user(s, n); -} - -/** - * strlen_user: - Get the size of a string in user space. - * @str: The string to measure. - * - * Context: User context only. This function may sleep. - * - * Get the size of a NUL-terminated string in user space. - * - * Returns the size of the string INCLUDING the terminating NUL. - * On exception, returns 0. - * - * If there is a limit on the length of a valid string, you may wish to - * consider using strnlen_user() instead. - */ -#define strlen_user(str) strnlen_user(str, ~0UL >> 1) - -/* - * The exception table consists of pairs of addresses: the first is the - * address of an instruction that is allowed to fault, and the second is - * the address at which the program should continue. No registers are - * modified, so it is entirely up to the continuation code to figure out - * what to do. - * - * All the routines below use bits of fixup code that are out of line - * with the main instruction path. This means when everything is well, - * we don't even have to jump over them. Further, they do not intrude - * on our cache or tlb entries. - */ - -struct exception_table_entry -{ - unsigned long insn, fixup; -}; - -extern int fixup_exception(struct pt_regs *regs); - #endif /* __ASM_SH_UACCESS_32_H */ |