| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 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 |  | 
|  | 14 | unsigned 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 |  | 
|  | 22 | unsigned 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)		\ | 
|  | 34 | do {								\ | 
|  | 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");					\ | 
|  | 66 | } while (0) | 
|  | 67 |  | 
|  | 68 | long | 
|  | 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 |  | 
|  | 76 | long | 
|  | 77 | strncpy_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)		\ | 
|  | 90 | do {						\ | 
|  | 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");			\ | 
|  | 113 | } while (0) | 
|  | 114 |  | 
|  | 115 | unsigned long | 
|  | 116 | __clear_user(void *to, unsigned long n) | 
|  | 117 | { | 
|  | 118 | __do_clear_user(to, n); | 
|  | 119 | return n; | 
|  | 120 | } | 
|  | 121 |  | 
|  | 122 | unsigned long | 
|  | 123 | clear_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 | */ | 
|  | 135 | long 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"); | 
|  | 165 | return res; | 
|  | 166 | } |