uaccess.h (4930B)
1/* 2 * User space memory access functions for Nios II 3 * 4 * Copyright (C) 2010-2011, Tobias Klauser <tklauser@distanz.ch> 5 * Copyright (C) 2009, Wind River Systems Inc 6 * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com 7 * 8 * This file is subject to the terms and conditions of the GNU General Public 9 * License. See the file "COPYING" in the main directory of this archive 10 * for more details. 11 */ 12 13#ifndef _ASM_NIOS2_UACCESS_H 14#define _ASM_NIOS2_UACCESS_H 15 16#include <linux/string.h> 17 18#include <asm/page.h> 19 20#include <asm/extable.h> 21#include <asm-generic/access_ok.h> 22 23# define __EX_TABLE_SECTION ".section __ex_table,\"a\"\n" 24 25/* 26 * Zero Userspace 27 */ 28 29static inline unsigned long __must_check __clear_user(void __user *to, 30 unsigned long n) 31{ 32 __asm__ __volatile__ ( 33 "1: stb zero, 0(%1)\n" 34 " addi %0, %0, -1\n" 35 " addi %1, %1, 1\n" 36 " bne %0, zero, 1b\n" 37 "2:\n" 38 __EX_TABLE_SECTION 39 ".word 1b, 2b\n" 40 ".previous\n" 41 : "=r" (n), "=r" (to) 42 : "0" (n), "1" (to) 43 ); 44 45 return n; 46} 47 48static inline unsigned long __must_check clear_user(void __user *to, 49 unsigned long n) 50{ 51 if (!access_ok(to, n)) 52 return n; 53 return __clear_user(to, n); 54} 55 56extern unsigned long 57raw_copy_from_user(void *to, const void __user *from, unsigned long n); 58extern unsigned long 59raw_copy_to_user(void __user *to, const void *from, unsigned long n); 60#define INLINE_COPY_FROM_USER 61#define INLINE_COPY_TO_USER 62 63extern long strncpy_from_user(char *__to, const char __user *__from, 64 long __len); 65extern __must_check long strnlen_user(const char __user *s, long n); 66 67/* Optimized macros */ 68#define __get_user_asm(val, insn, addr, err) \ 69{ \ 70 unsigned long __gu_val; \ 71 __asm__ __volatile__( \ 72 " movi %0, %3\n" \ 73 "1: " insn " %1, 0(%2)\n" \ 74 " movi %0, 0\n" \ 75 "2:\n" \ 76 " .section __ex_table,\"a\"\n" \ 77 " .word 1b, 2b\n" \ 78 " .previous" \ 79 : "=&r" (err), "=r" (__gu_val) \ 80 : "r" (addr), "i" (-EFAULT)); \ 81 val = (__force __typeof__(*(addr)))__gu_val; \ 82} 83 84extern void __get_user_unknown(void); 85 86#define __get_user_8(val, ptr, err) do { \ 87 u64 __val = 0; \ 88 err = 0; \ 89 if (raw_copy_from_user(&(__val), ptr, sizeof(val))) { \ 90 err = -EFAULT; \ 91 } else { \ 92 val = (typeof(val))(typeof((val) - (val)))__val; \ 93 } \ 94 } while (0) 95 96#define __get_user_common(val, size, ptr, err) \ 97do { \ 98 switch (size) { \ 99 case 1: \ 100 __get_user_asm(val, "ldbu", ptr, err); \ 101 break; \ 102 case 2: \ 103 __get_user_asm(val, "ldhu", ptr, err); \ 104 break; \ 105 case 4: \ 106 __get_user_asm(val, "ldw", ptr, err); \ 107 break; \ 108 case 8: \ 109 __get_user_8(val, ptr, err); \ 110 break; \ 111 default: \ 112 __get_user_unknown(); \ 113 break; \ 114 } \ 115} while (0) 116 117#define __get_user(x, ptr) \ 118 ({ \ 119 long __gu_err = -EFAULT; \ 120 const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ 121 __get_user_common(x, sizeof(*(ptr)), __gu_ptr, __gu_err); \ 122 __gu_err; \ 123 }) 124 125#define get_user(x, ptr) \ 126({ \ 127 long __gu_err = -EFAULT; \ 128 const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ 129 if (access_ok( __gu_ptr, sizeof(*__gu_ptr))) \ 130 __get_user_common(x, sizeof(*__gu_ptr), \ 131 __gu_ptr, __gu_err); \ 132 __gu_err; \ 133}) 134 135#define __put_user_asm(val, insn, ptr, err) \ 136{ \ 137 __asm__ __volatile__( \ 138 " movi %0, %3\n" \ 139 "1: " insn " %1, 0(%2)\n" \ 140 " movi %0, 0\n" \ 141 "2:\n" \ 142 " .section __ex_table,\"a\"\n" \ 143 " .word 1b, 2b\n" \ 144 " .previous\n" \ 145 : "=&r" (err) \ 146 : "r" (val), "r" (ptr), "i" (-EFAULT)); \ 147} 148 149#define __put_user_common(__pu_val, __pu_ptr) \ 150({ \ 151 long __pu_err = -EFAULT; \ 152 switch (sizeof(*__pu_ptr)) { \ 153 case 1: \ 154 __put_user_asm(__pu_val, "stb", __pu_ptr, __pu_err); \ 155 break; \ 156 case 2: \ 157 __put_user_asm(__pu_val, "sth", __pu_ptr, __pu_err); \ 158 break; \ 159 case 4: \ 160 __put_user_asm(__pu_val, "stw", __pu_ptr, __pu_err); \ 161 break; \ 162 default: \ 163 /* XXX: This looks wrong... */ \ 164 __pu_err = 0; \ 165 if (__copy_to_user(__pu_ptr, &(__pu_val), \ 166 sizeof(*__pu_ptr))) \ 167 __pu_err = -EFAULT; \ 168 break; \ 169 } \ 170 __pu_err; \ 171}) 172 173#define __put_user(x, ptr) \ 174({ \ 175 __auto_type __pu_ptr = (ptr); \ 176 typeof(*__pu_ptr) __pu_val = (typeof(*__pu_ptr))(x); \ 177 __put_user_common(__pu_val, __pu_ptr); \ 178}) 179 180#define put_user(x, ptr) \ 181({ \ 182 __auto_type __pu_ptr = (ptr); \ 183 typeof(*__pu_ptr) __pu_val = (typeof(*__pu_ptr))(x); \ 184 access_ok(__pu_ptr, sizeof(*__pu_ptr)) ? \ 185 __put_user_common(__pu_val, __pu_ptr) : \ 186 -EFAULT; \ 187}) 188 189#endif /* _ASM_NIOS2_UACCESS_H */