1/* MN10300 Userspace accessor functions 2 * 3 * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd. 4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 5 * Written by David Howells (dhowells@redhat.com) 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public Licence 9 * as published by the Free Software Foundation; either version 10 * 2 of the Licence, or (at your option) any later version. 11 */ 12#include <asm/uaccess.h> 13 14unsigned long 15__generic_copy_to_user(void *to, const void *from, unsigned long n) 16{ 17 if (access_ok(VERIFY_WRITE, to, n)) 18 __copy_user(to, from, n); 19 return n; 20} 21 22unsigned long 23__generic_copy_from_user(void *to, const void *from, unsigned long n) 24{ 25 if (access_ok(VERIFY_READ, from, n)) 26 __copy_user_zeroing(to, from, n); 27 return n; 28} 29 30/* 31 * Copy a null terminated string from userspace. 32 */ 33#define __do_strncpy_from_user(dst, src, count, res) \ 34do { \ 35 int w; \ 36 asm volatile( \ 37 " mov %1,%0\n" \ 38 " cmp 0,%1\n" \ 39 " beq 2f\n" \ 40 "0:\n" \ 41 " movbu (%5),%2\n" \ 42 "1:\n" \ 43 " movbu %2,(%6)\n" \ 44 " inc %5\n" \ 45 " inc %6\n" \ 46 " cmp 0,%2\n" \ 47 " beq 2f\n" \ 48 " add -1,%1\n" \ 49 " bne 0b\n" \ 50 "2:\n" \ 51 " sub %1,%0\n" \ 52 "3:\n" \ 53 " .section .fixup,\"ax\"\n" \ 54 "4:\n" \ 55 " mov %3,%0\n" \ 56 " jmp 3b\n" \ 57 " .previous\n" \ 58 " .section __ex_table,\"a\"\n" \ 59 " .balign 4\n" \ 60 " .long 0b,4b\n" \ 61 " .long 1b,4b\n" \ 62 " .previous" \ 63 :"=&r"(res), "=r"(count), "=&r"(w) \ 64 :"i"(-EFAULT), "1"(count), "a"(src), "a"(dst) \ 65 : "memory", "cc"); \ 66} while (0) 67 68long 69__strncpy_from_user(char *dst, const char *src, long count) 70{ 71 long res; 72 __do_strncpy_from_user(dst, src, count, res); 73 return res; 74} 75 76long 77strncpy_from_user(char *dst, const char *src, long count) 78{ 79 long res = -EFAULT; 80 if (access_ok(VERIFY_READ, src, 1)) 81 __do_strncpy_from_user(dst, src, count, res); 82 return res; 83} 84 85 86/* 87 * Clear a userspace memory 88 */ 89#define __do_clear_user(addr, size) \ 90do { \ 91 int w; \ 92 asm volatile( \ 93 " cmp 0,%0\n" \ 94 " beq 1f\n" \ 95 " clr %1\n" \ 96 "0: movbu %1,(%3,%2)\n" \ 97 " inc %3\n" \ 98 " cmp %0,%3\n" \ 99 " bne 0b\n" \ 100 "1:\n" \ 101 " sub %3,%0\n" \ 102 "2:\n" \ 103 ".section .fixup,\"ax\"\n" \ 104 "3: jmp 2b\n" \ 105 ".previous\n" \ 106 ".section __ex_table,\"a\"\n" \ 107 " .balign 4\n" \ 108 " .long 0b,3b\n" \ 109 ".previous\n" \ 110 : "+r"(size), "=&r"(w) \ 111 : "a"(addr), "d"(0) \ 112 : "memory", "cc"); \ 113} while (0) 114 115unsigned long 116__clear_user(void *to, unsigned long n) 117{ 118 __do_clear_user(to, n); 119 return n; 120} 121 122unsigned long 123clear_user(void *to, unsigned long n) 124{ 125 if (access_ok(VERIFY_WRITE, to, n)) 126 __do_clear_user(to, n); 127 return n; 128} 129 130/* 131 * Return the size of a string (including the ending 0) 132 * 133 * Return 0 on exception, a value greater than N if too long 134 */ 135long strnlen_user(const char *s, long n) 136{ 137 unsigned long res, w; 138 139 if (!__addr_ok(s)) 140 return 0; 141 142 if (n < 0 || n + (u_long) s > current_thread_info()->addr_limit.seg) 143 n = current_thread_info()->addr_limit.seg - (u_long)s; 144 145 asm volatile( 146 "0: cmp %4,%0\n" 147 " beq 2f\n" 148 "1: movbu (%0,%3),%1\n" 149 " inc %0\n" 150 " cmp 0,%1\n" 151 " beq 3f\n" 152 " bra 0b\n" 153 "2: clr %0\n" 154 "3:\n" 155 ".section .fixup,\"ax\"\n" 156 "4: jmp 2b\n" 157 ".previous\n" 158 ".section __ex_table,\"a\"\n" 159 " .balign 4\n" 160 " .long 1b,4b\n" 161 ".previous\n" 162 :"=d"(res), "=&r"(w) 163 :"0"(0), "a"(s), "r"(n) 164 : "memory", "cc"); 165 return res; 166} 167