18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef __ASM_SH_UACCESS_H 38c2ecf20Sopenharmony_ci#define __ASM_SH_UACCESS_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <asm/segment.h> 68c2ecf20Sopenharmony_ci#include <asm/extable.h> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#define __addr_ok(addr) \ 98c2ecf20Sopenharmony_ci ((unsigned long __force)(addr) < current_thread_info()->addr_limit.seg) 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci/* 128c2ecf20Sopenharmony_ci * __access_ok: Check if address with size is OK or not. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Uhhuh, this needs 33-bit arithmetic. We have a carry.. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * sum := addr + size; carry? --> flag = true; 178c2ecf20Sopenharmony_ci * if (sum >= addr_limit) flag = true; 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci#define __access_ok(addr, size) ({ \ 208c2ecf20Sopenharmony_ci unsigned long __ao_a = (addr), __ao_b = (size); \ 218c2ecf20Sopenharmony_ci unsigned long __ao_end = __ao_a + __ao_b - !!__ao_b; \ 228c2ecf20Sopenharmony_ci __ao_end >= __ao_a && __addr_ok(__ao_end); }) 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define access_ok(addr, size) \ 258c2ecf20Sopenharmony_ci (__chk_user_ptr(addr), \ 268c2ecf20Sopenharmony_ci __access_ok((unsigned long __force)(addr), (size))) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define user_addr_max() (current_thread_info()->addr_limit.seg) 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* 318c2ecf20Sopenharmony_ci * Uh, these should become the main single-value transfer routines ... 328c2ecf20Sopenharmony_ci * They automatically use the right size if we just have the right 338c2ecf20Sopenharmony_ci * pointer type ... 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * As SuperH uses the same address space for kernel and user data, we 368c2ecf20Sopenharmony_ci * can just do these as direct assignments. 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * Careful to not 398c2ecf20Sopenharmony_ci * (a) re-use the arguments for side effects (sizeof is ok) 408c2ecf20Sopenharmony_ci * (b) require any knowledge of processes at this stage 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_ci#define put_user(x,ptr) __put_user_check((x), (ptr), sizeof(*(ptr))) 438c2ecf20Sopenharmony_ci#define get_user(x,ptr) __get_user_check((x), (ptr), sizeof(*(ptr))) 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* 468c2ecf20Sopenharmony_ci * The "__xxx" versions do not do address space checking, useful when 478c2ecf20Sopenharmony_ci * doing multiple accesses to the same area (the user has to do the 488c2ecf20Sopenharmony_ci * checks by hand with "access_ok()") 498c2ecf20Sopenharmony_ci */ 508c2ecf20Sopenharmony_ci#define __put_user(x,ptr) __put_user_nocheck((x), (ptr), sizeof(*(ptr))) 518c2ecf20Sopenharmony_ci#define __get_user(x,ptr) __get_user_nocheck((x), (ptr), sizeof(*(ptr))) 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistruct __large_struct { unsigned long buf[100]; }; 548c2ecf20Sopenharmony_ci#define __m(x) (*(struct __large_struct __user *)(x)) 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define __get_user_nocheck(x,ptr,size) \ 578c2ecf20Sopenharmony_ci({ \ 588c2ecf20Sopenharmony_ci long __gu_err; \ 598c2ecf20Sopenharmony_ci unsigned long __gu_val; \ 608c2ecf20Sopenharmony_ci const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ 618c2ecf20Sopenharmony_ci __chk_user_ptr(ptr); \ 628c2ecf20Sopenharmony_ci __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ 638c2ecf20Sopenharmony_ci (x) = (__force __typeof__(*(ptr)))__gu_val; \ 648c2ecf20Sopenharmony_ci __gu_err; \ 658c2ecf20Sopenharmony_ci}) 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define __get_user_check(x,ptr,size) \ 688c2ecf20Sopenharmony_ci({ \ 698c2ecf20Sopenharmony_ci long __gu_err = -EFAULT; \ 708c2ecf20Sopenharmony_ci unsigned long __gu_val = 0; \ 718c2ecf20Sopenharmony_ci const __typeof__(*(ptr)) *__gu_addr = (ptr); \ 728c2ecf20Sopenharmony_ci if (likely(access_ok(__gu_addr, (size)))) \ 738c2ecf20Sopenharmony_ci __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ 748c2ecf20Sopenharmony_ci (x) = (__force __typeof__(*(ptr)))__gu_val; \ 758c2ecf20Sopenharmony_ci __gu_err; \ 768c2ecf20Sopenharmony_ci}) 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci#define __put_user_nocheck(x,ptr,size) \ 798c2ecf20Sopenharmony_ci({ \ 808c2ecf20Sopenharmony_ci long __pu_err; \ 818c2ecf20Sopenharmony_ci __typeof__(*(ptr)) __user *__pu_addr = (ptr); \ 828c2ecf20Sopenharmony_ci __typeof__(*(ptr)) __pu_val = x; \ 838c2ecf20Sopenharmony_ci __chk_user_ptr(ptr); \ 848c2ecf20Sopenharmony_ci __put_user_size(__pu_val, __pu_addr, (size), __pu_err); \ 858c2ecf20Sopenharmony_ci __pu_err; \ 868c2ecf20Sopenharmony_ci}) 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci#define __put_user_check(x,ptr,size) \ 898c2ecf20Sopenharmony_ci({ \ 908c2ecf20Sopenharmony_ci long __pu_err = -EFAULT; \ 918c2ecf20Sopenharmony_ci __typeof__(*(ptr)) __user *__pu_addr = (ptr); \ 928c2ecf20Sopenharmony_ci __typeof__(*(ptr)) __pu_val = x; \ 938c2ecf20Sopenharmony_ci if (likely(access_ok(__pu_addr, size))) \ 948c2ecf20Sopenharmony_ci __put_user_size(__pu_val, __pu_addr, (size), \ 958c2ecf20Sopenharmony_ci __pu_err); \ 968c2ecf20Sopenharmony_ci __pu_err; \ 978c2ecf20Sopenharmony_ci}) 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci# include <asm/uaccess_32.h> 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ciextern long strncpy_from_user(char *dest, const char __user *src, long count); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ciextern __must_check long strnlen_user(const char __user *str, long n); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/* Generic arbitrary sized copy. */ 1068c2ecf20Sopenharmony_ci/* Return the number of bytes NOT copied */ 1078c2ecf20Sopenharmony_ci__kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic __always_inline unsigned long 1108c2ecf20Sopenharmony_ciraw_copy_from_user(void *to, const void __user *from, unsigned long n) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci return __copy_user(to, (__force void *)from, n); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic __always_inline unsigned long __must_check 1168c2ecf20Sopenharmony_ciraw_copy_to_user(void __user *to, const void *from, unsigned long n) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci return __copy_user((__force void *)to, from, n); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci#define INLINE_COPY_FROM_USER 1218c2ecf20Sopenharmony_ci#define INLINE_COPY_TO_USER 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* 1248c2ecf20Sopenharmony_ci * Clear the area and return remaining number of bytes 1258c2ecf20Sopenharmony_ci * (on failure. Usually it's 0.) 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_ci__kernel_size_t __clear_user(void *addr, __kernel_size_t size); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci#define clear_user(addr,n) \ 1308c2ecf20Sopenharmony_ci({ \ 1318c2ecf20Sopenharmony_ci void __user * __cl_addr = (addr); \ 1328c2ecf20Sopenharmony_ci unsigned long __cl_size = (n); \ 1338c2ecf20Sopenharmony_ci \ 1348c2ecf20Sopenharmony_ci if (__cl_size && access_ok(__cl_addr, __cl_size)) \ 1358c2ecf20Sopenharmony_ci __cl_size = __clear_user(__cl_addr, __cl_size); \ 1368c2ecf20Sopenharmony_ci \ 1378c2ecf20Sopenharmony_ci __cl_size; \ 1388c2ecf20Sopenharmony_ci}) 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ciextern void *set_exception_table_vec(unsigned int vec, void *handler); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic inline void *set_exception_table_evt(unsigned int evt, void *handler) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci return set_exception_table_vec(evt >> 5, handler); 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistruct mem_access { 1488c2ecf20Sopenharmony_ci unsigned long (*from)(void *dst, const void __user *src, unsigned long cnt); 1498c2ecf20Sopenharmony_ci unsigned long (*to)(void __user *dst, const void *src, unsigned long cnt); 1508c2ecf20Sopenharmony_ci}; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ciint handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, 1538c2ecf20Sopenharmony_ci struct mem_access *ma, int, unsigned long address); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci#endif /* __ASM_SH_UACCESS_H */ 156