/* * User space memory access functions * * Copyright (C) 1999, 2002 Niibe Yutaka * Copyright (C) 2003 - 2008 Paul Mundt * * Based on: * MIPS implementation version 1.15 by * Copyright (C) 1996, 1997, 1998 by Ralf Baechle * and i386 version. */ #ifndef __ASM_SH_UACCESS_32_H #define __ASM_SH_UACCESS_32_H #define __get_user_size(x,ptr,size,retval) \ do { \ retval = 0; \ switch (size) { \ case 1: \ __get_user_asm(x, ptr, retval, "b"); \ break; \ case 2: \ __get_user_asm(x, ptr, retval, "w"); \ break; \ case 4: \ __get_user_asm(x, ptr, retval, "l"); \ break; \ default: \ __get_user_unknown(); \ break; \ } \ } while (0) #ifdef CONFIG_MMU #define __get_user_asm(x, addr, err, insn) \ ({ \ __asm__ __volatile__( \ "1:\n\t" \ "mov." insn " %2, %1\n\t" \ "2:\n" \ ".section .fixup,\"ax\"\n" \ "3:\n\t" \ "mov #0, %1\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)); }) #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); #define __put_user_size(x,ptr,size,retval) \ do { \ retval = 0; \ switch (size) { \ case 1: \ __put_user_asm(x, ptr, retval, "b"); \ break; \ case 2: \ __put_user_asm(x, ptr, retval, "w"); \ break; \ case 4: \ __put_user_asm(x, ptr, retval, "l"); \ break; \ case 8: \ __put_user_u64(x, ptr, retval); \ break; \ default: \ __put_user_unknown(); \ } \ } while (0) #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) \ ({ \ __asm__ __volatile__( \ "1:\n\t" \ "mov.l %R1,%2\n\t" \ "mov.l %S1,%T2\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" (retval) \ : "r" (val), "m" (__m(addr)), "i" (-EFAULT), "0" (retval) \ : "memory"); }) #else #define __put_user_u64(val,addr,retval) \ ({ \ __asm__ __volatile__( \ "1:\n\t" \ "mov.l %S1,%2\n\t" \ "mov.l %R1,%T2\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" (retval) \ : "r" (val), "m" (__m(addr)), "i" (-EFAULT), "0" (retval) \ : "memory"); }) #endif extern void __put_user_unknown(void); static inline int __strncpy_from_user(unsigned long __dest, unsigned long __user __src, int __count) { __kernel_size_t res; unsigned long __dummy, _d, _s, _c; __asm__ __volatile__( "9:\n" "mov.b @%2+, %1\n\t" "cmp/eq #0, %1\n\t" "bt/s 2f\n" "1:\n" "mov.b %1, @%3\n\t" "dt %4\n\t" "bf/s 9b\n\t" " add #1, %3\n\t" "2:\n\t" "sub %4, %0\n" "3:\n" ".section .fixup,\"ax\"\n" "4:\n\t" "mov.l 5f, %1\n\t" "jmp @%1\n\t" " mov %9, %0\n\t" ".balign 4\n" "5: .long 3b\n" ".previous\n" ".section __ex_table,\"a\"\n" " .balign 4\n" " .long 9b,4b\n" ".previous" : "=r" (res), "=&z" (__dummy), "=r" (_s), "=r" (_d), "=r"(_c) : "0" (__count), "2" (__src), "3" (__dest), "4" (__count), "i" (-EFAULT) : "memory", "t"); return 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) { unsigned long res; unsigned long __dummy; __asm__ __volatile__( "1:\t" "mov.b @(%0,%3), %1\n\t" "cmp/eq %4, %0\n\t" "bt/s 2f\n\t" " add #1, %0\n\t" "tst %1, %1\n\t" "bf 1b\n\t" "2:\n" ".section .fixup,\"ax\"\n" "3:\n\t" "mov.l 4f, %1\n\t" "jmp @%1\n\t" " mov #0, %0\n" ".balign 4\n" "4: .long 2b\n" ".previous\n" ".section __ex_table,\"a\"\n" " .balign 4\n" " .long 1b,3b\n" ".previous" : "=z" (res), "=&r" (__dummy) : "0" (0), "r" (__s), "r" (__n) : "t"); return res; } #endif /* __ASM_SH_UACCESS_32_H */