18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * User space memory access functions for Nios II 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2010-2011, Tobias Klauser <tklauser@distanz.ch> 58c2ecf20Sopenharmony_ci * Copyright (C) 2009, Wind River Systems Inc 68c2ecf20Sopenharmony_ci * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 98c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 108c2ecf20Sopenharmony_ci * for more details. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#ifndef _ASM_NIOS2_UACCESS_H 148c2ecf20Sopenharmony_ci#define _ASM_NIOS2_UACCESS_H 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/string.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <asm/page.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <asm/extable.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* 238c2ecf20Sopenharmony_ci * Segment stuff 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_ci#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) 268c2ecf20Sopenharmony_ci#define USER_DS MAKE_MM_SEG(0x80000000UL) 278c2ecf20Sopenharmony_ci#define KERNEL_DS MAKE_MM_SEG(0) 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define get_fs() (current_thread_info()->addr_limit) 318c2ecf20Sopenharmony_ci#define set_fs(seg) (current_thread_info()->addr_limit = (seg)) 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define uaccess_kernel() (get_fs().seg == KERNEL_DS.seg) 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define __access_ok(addr, len) \ 368c2ecf20Sopenharmony_ci (((signed long)(((long)get_fs().seg) & \ 378c2ecf20Sopenharmony_ci ((long)(addr) | (((long)(addr)) + (len)) | (len)))) == 0) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define access_ok(addr, len) \ 408c2ecf20Sopenharmony_ci likely(__access_ok((unsigned long)(addr), (unsigned long)(len))) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci# define __EX_TABLE_SECTION ".section __ex_table,\"a\"\n" 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define user_addr_max() (uaccess_kernel() ? ~0UL : TASK_SIZE) 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* 478c2ecf20Sopenharmony_ci * Zero Userspace 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic inline unsigned long __must_check __clear_user(void __user *to, 518c2ecf20Sopenharmony_ci unsigned long n) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci __asm__ __volatile__ ( 548c2ecf20Sopenharmony_ci "1: stb zero, 0(%1)\n" 558c2ecf20Sopenharmony_ci " addi %0, %0, -1\n" 568c2ecf20Sopenharmony_ci " addi %1, %1, 1\n" 578c2ecf20Sopenharmony_ci " bne %0, zero, 1b\n" 588c2ecf20Sopenharmony_ci "2:\n" 598c2ecf20Sopenharmony_ci __EX_TABLE_SECTION 608c2ecf20Sopenharmony_ci ".word 1b, 2b\n" 618c2ecf20Sopenharmony_ci ".previous\n" 628c2ecf20Sopenharmony_ci : "=r" (n), "=r" (to) 638c2ecf20Sopenharmony_ci : "0" (n), "1" (to) 648c2ecf20Sopenharmony_ci ); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci return n; 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic inline unsigned long __must_check clear_user(void __user *to, 708c2ecf20Sopenharmony_ci unsigned long n) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci if (!access_ok(to, n)) 738c2ecf20Sopenharmony_ci return n; 748c2ecf20Sopenharmony_ci return __clear_user(to, n); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ciextern unsigned long 788c2ecf20Sopenharmony_ciraw_copy_from_user(void *to, const void __user *from, unsigned long n); 798c2ecf20Sopenharmony_ciextern unsigned long 808c2ecf20Sopenharmony_ciraw_copy_to_user(void __user *to, const void *from, unsigned long n); 818c2ecf20Sopenharmony_ci#define INLINE_COPY_FROM_USER 828c2ecf20Sopenharmony_ci#define INLINE_COPY_TO_USER 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ciextern long strncpy_from_user(char *__to, const char __user *__from, 858c2ecf20Sopenharmony_ci long __len); 868c2ecf20Sopenharmony_ciextern __must_check long strlen_user(const char __user *str); 878c2ecf20Sopenharmony_ciextern __must_check long strnlen_user(const char __user *s, long n); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* Optimized macros */ 908c2ecf20Sopenharmony_ci#define __get_user_asm(val, insn, addr, err) \ 918c2ecf20Sopenharmony_ci{ \ 928c2ecf20Sopenharmony_ci unsigned long __gu_val; \ 938c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 948c2ecf20Sopenharmony_ci " movi %0, %3\n" \ 958c2ecf20Sopenharmony_ci "1: " insn " %1, 0(%2)\n" \ 968c2ecf20Sopenharmony_ci " movi %0, 0\n" \ 978c2ecf20Sopenharmony_ci "2:\n" \ 988c2ecf20Sopenharmony_ci " .section __ex_table,\"a\"\n" \ 998c2ecf20Sopenharmony_ci " .word 1b, 2b\n" \ 1008c2ecf20Sopenharmony_ci " .previous" \ 1018c2ecf20Sopenharmony_ci : "=&r" (err), "=r" (__gu_val) \ 1028c2ecf20Sopenharmony_ci : "r" (addr), "i" (-EFAULT)); \ 1038c2ecf20Sopenharmony_ci val = (__force __typeof__(*(addr)))__gu_val; \ 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ciextern void __get_user_unknown(void); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci#define __get_user_8(val, ptr, err) do { \ 1098c2ecf20Sopenharmony_ci u64 __val = 0; \ 1108c2ecf20Sopenharmony_ci err = 0; \ 1118c2ecf20Sopenharmony_ci if (raw_copy_from_user(&(__val), ptr, sizeof(val))) { \ 1128c2ecf20Sopenharmony_ci err = -EFAULT; \ 1138c2ecf20Sopenharmony_ci } else { \ 1148c2ecf20Sopenharmony_ci val = (typeof(val))(typeof((val) - (val)))__val; \ 1158c2ecf20Sopenharmony_ci } \ 1168c2ecf20Sopenharmony_ci } while (0) 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci#define __get_user_common(val, size, ptr, err) \ 1198c2ecf20Sopenharmony_cido { \ 1208c2ecf20Sopenharmony_ci switch (size) { \ 1218c2ecf20Sopenharmony_ci case 1: \ 1228c2ecf20Sopenharmony_ci __get_user_asm(val, "ldbu", ptr, err); \ 1238c2ecf20Sopenharmony_ci break; \ 1248c2ecf20Sopenharmony_ci case 2: \ 1258c2ecf20Sopenharmony_ci __get_user_asm(val, "ldhu", ptr, err); \ 1268c2ecf20Sopenharmony_ci break; \ 1278c2ecf20Sopenharmony_ci case 4: \ 1288c2ecf20Sopenharmony_ci __get_user_asm(val, "ldw", ptr, err); \ 1298c2ecf20Sopenharmony_ci break; \ 1308c2ecf20Sopenharmony_ci case 8: \ 1318c2ecf20Sopenharmony_ci __get_user_8(val, ptr, err); \ 1328c2ecf20Sopenharmony_ci break; \ 1338c2ecf20Sopenharmony_ci default: \ 1348c2ecf20Sopenharmony_ci __get_user_unknown(); \ 1358c2ecf20Sopenharmony_ci break; \ 1368c2ecf20Sopenharmony_ci } \ 1378c2ecf20Sopenharmony_ci} while (0) 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci#define __get_user(x, ptr) \ 1408c2ecf20Sopenharmony_ci ({ \ 1418c2ecf20Sopenharmony_ci long __gu_err = -EFAULT; \ 1428c2ecf20Sopenharmony_ci const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ 1438c2ecf20Sopenharmony_ci __get_user_common(x, sizeof(*(ptr)), __gu_ptr, __gu_err); \ 1448c2ecf20Sopenharmony_ci __gu_err; \ 1458c2ecf20Sopenharmony_ci }) 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci#define get_user(x, ptr) \ 1488c2ecf20Sopenharmony_ci({ \ 1498c2ecf20Sopenharmony_ci long __gu_err = -EFAULT; \ 1508c2ecf20Sopenharmony_ci const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ 1518c2ecf20Sopenharmony_ci if (access_ok( __gu_ptr, sizeof(*__gu_ptr))) \ 1528c2ecf20Sopenharmony_ci __get_user_common(x, sizeof(*__gu_ptr), \ 1538c2ecf20Sopenharmony_ci __gu_ptr, __gu_err); \ 1548c2ecf20Sopenharmony_ci __gu_err; \ 1558c2ecf20Sopenharmony_ci}) 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci#define __put_user_asm(val, insn, ptr, err) \ 1588c2ecf20Sopenharmony_ci{ \ 1598c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 1608c2ecf20Sopenharmony_ci " movi %0, %3\n" \ 1618c2ecf20Sopenharmony_ci "1: " insn " %1, 0(%2)\n" \ 1628c2ecf20Sopenharmony_ci " movi %0, 0\n" \ 1638c2ecf20Sopenharmony_ci "2:\n" \ 1648c2ecf20Sopenharmony_ci " .section __ex_table,\"a\"\n" \ 1658c2ecf20Sopenharmony_ci " .word 1b, 2b\n" \ 1668c2ecf20Sopenharmony_ci " .previous\n" \ 1678c2ecf20Sopenharmony_ci : "=&r" (err) \ 1688c2ecf20Sopenharmony_ci : "r" (val), "r" (ptr), "i" (-EFAULT)); \ 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci#define put_user(x, ptr) \ 1728c2ecf20Sopenharmony_ci({ \ 1738c2ecf20Sopenharmony_ci long __pu_err = -EFAULT; \ 1748c2ecf20Sopenharmony_ci __typeof__(*(ptr)) __user *__pu_ptr = (ptr); \ 1758c2ecf20Sopenharmony_ci __typeof__(*(ptr)) __pu_val = (__typeof(*ptr))(x); \ 1768c2ecf20Sopenharmony_ci if (access_ok(__pu_ptr, sizeof(*__pu_ptr))) { \ 1778c2ecf20Sopenharmony_ci switch (sizeof(*__pu_ptr)) { \ 1788c2ecf20Sopenharmony_ci case 1: \ 1798c2ecf20Sopenharmony_ci __put_user_asm(__pu_val, "stb", __pu_ptr, __pu_err); \ 1808c2ecf20Sopenharmony_ci break; \ 1818c2ecf20Sopenharmony_ci case 2: \ 1828c2ecf20Sopenharmony_ci __put_user_asm(__pu_val, "sth", __pu_ptr, __pu_err); \ 1838c2ecf20Sopenharmony_ci break; \ 1848c2ecf20Sopenharmony_ci case 4: \ 1858c2ecf20Sopenharmony_ci __put_user_asm(__pu_val, "stw", __pu_ptr, __pu_err); \ 1868c2ecf20Sopenharmony_ci break; \ 1878c2ecf20Sopenharmony_ci default: \ 1888c2ecf20Sopenharmony_ci /* XXX: This looks wrong... */ \ 1898c2ecf20Sopenharmony_ci __pu_err = 0; \ 1908c2ecf20Sopenharmony_ci if (copy_to_user(__pu_ptr, &(__pu_val), \ 1918c2ecf20Sopenharmony_ci sizeof(*__pu_ptr))) \ 1928c2ecf20Sopenharmony_ci __pu_err = -EFAULT; \ 1938c2ecf20Sopenharmony_ci break; \ 1948c2ecf20Sopenharmony_ci } \ 1958c2ecf20Sopenharmony_ci } \ 1968c2ecf20Sopenharmony_ci __pu_err; \ 1978c2ecf20Sopenharmony_ci}) 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci#define __put_user(x, ptr) put_user(x, ptr) 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci#endif /* _ASM_NIOS2_UACCESS_H */ 202