162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> 462306a36Sopenharmony_ci * Copyright (C) 2008-2009 PetaLogix 562306a36Sopenharmony_ci * Copyright (C) 2006 Atmark Techno, Inc. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#ifndef _ASM_MICROBLAZE_UACCESS_H 962306a36Sopenharmony_ci#define _ASM_MICROBLAZE_UACCESS_H 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <asm/mmu.h> 1462306a36Sopenharmony_ci#include <asm/page.h> 1562306a36Sopenharmony_ci#include <linux/pgtable.h> 1662306a36Sopenharmony_ci#include <asm/extable.h> 1762306a36Sopenharmony_ci#include <linux/string.h> 1862306a36Sopenharmony_ci#include <asm-generic/access_ok.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci# define __FIXUP_SECTION ".section .fixup,\"ax\"\n" 2162306a36Sopenharmony_ci# define __EX_TABLE_SECTION ".section __ex_table,\"a\"\n" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ciextern unsigned long __copy_tofrom_user(void __user *to, 2462306a36Sopenharmony_ci const void __user *from, unsigned long size); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* Return: number of not copied bytes, i.e. 0 if OK or non-zero if fail. */ 2762306a36Sopenharmony_cistatic inline unsigned long __must_check __clear_user(void __user *to, 2862306a36Sopenharmony_ci unsigned long n) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci /* normal memset with two words to __ex_table */ 3162306a36Sopenharmony_ci __asm__ __volatile__ ( \ 3262306a36Sopenharmony_ci "1: sb r0, %1, r0;" \ 3362306a36Sopenharmony_ci " addik %0, %0, -1;" \ 3462306a36Sopenharmony_ci " bneid %0, 1b;" \ 3562306a36Sopenharmony_ci " addik %1, %1, 1;" \ 3662306a36Sopenharmony_ci "2: " \ 3762306a36Sopenharmony_ci __EX_TABLE_SECTION \ 3862306a36Sopenharmony_ci ".word 1b,2b;" \ 3962306a36Sopenharmony_ci ".previous;" \ 4062306a36Sopenharmony_ci : "=r"(n), "=r"(to) \ 4162306a36Sopenharmony_ci : "0"(n), "1"(to) 4262306a36Sopenharmony_ci ); 4362306a36Sopenharmony_ci return n; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic inline unsigned long __must_check clear_user(void __user *to, 4762306a36Sopenharmony_ci unsigned long n) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci might_fault(); 5062306a36Sopenharmony_ci if (unlikely(!access_ok(to, n))) 5162306a36Sopenharmony_ci return n; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci return __clear_user(to, n); 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* put_user and get_user macros */ 5762306a36Sopenharmony_ciextern long __user_bad(void); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define __get_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \ 6062306a36Sopenharmony_ci({ \ 6162306a36Sopenharmony_ci __asm__ __volatile__ ( \ 6262306a36Sopenharmony_ci "1:" insn " %1, %2, r0;" \ 6362306a36Sopenharmony_ci " addk %0, r0, r0;" \ 6462306a36Sopenharmony_ci "2: " \ 6562306a36Sopenharmony_ci __FIXUP_SECTION \ 6662306a36Sopenharmony_ci "3: brid 2b;" \ 6762306a36Sopenharmony_ci " addik %0, r0, %3;" \ 6862306a36Sopenharmony_ci ".previous;" \ 6962306a36Sopenharmony_ci __EX_TABLE_SECTION \ 7062306a36Sopenharmony_ci ".word 1b,3b;" \ 7162306a36Sopenharmony_ci ".previous;" \ 7262306a36Sopenharmony_ci : "=&r"(__gu_err), "=r"(__gu_val) \ 7362306a36Sopenharmony_ci : "r"(__gu_ptr), "i"(-EFAULT) \ 7462306a36Sopenharmony_ci ); \ 7562306a36Sopenharmony_ci}) 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/** 7862306a36Sopenharmony_ci * get_user: - Get a simple variable from user space. 7962306a36Sopenharmony_ci * @x: Variable to store result. 8062306a36Sopenharmony_ci * @ptr: Source address, in user space. 8162306a36Sopenharmony_ci * 8262306a36Sopenharmony_ci * Context: User context only. This function may sleep if pagefaults are 8362306a36Sopenharmony_ci * enabled. 8462306a36Sopenharmony_ci * 8562306a36Sopenharmony_ci * This macro copies a single simple variable from user space to kernel 8662306a36Sopenharmony_ci * space. It supports simple types like char and int, but not larger 8762306a36Sopenharmony_ci * data types like structures or arrays. 8862306a36Sopenharmony_ci * 8962306a36Sopenharmony_ci * @ptr must have pointer-to-simple-variable type, and the result of 9062306a36Sopenharmony_ci * dereferencing @ptr must be assignable to @x without a cast. 9162306a36Sopenharmony_ci * 9262306a36Sopenharmony_ci * Returns zero on success, or -EFAULT on error. 9362306a36Sopenharmony_ci * On error, the variable @x is set to zero. 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_ci#define get_user(x, ptr) ({ \ 9662306a36Sopenharmony_ci const typeof(*(ptr)) __user *__gu_ptr = (ptr); \ 9762306a36Sopenharmony_ci access_ok(__gu_ptr, sizeof(*__gu_ptr)) ? \ 9862306a36Sopenharmony_ci __get_user(x, __gu_ptr) : -EFAULT; \ 9962306a36Sopenharmony_ci}) 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#define __get_user(x, ptr) \ 10262306a36Sopenharmony_ci({ \ 10362306a36Sopenharmony_ci long __gu_err; \ 10462306a36Sopenharmony_ci switch (sizeof(*(ptr))) { \ 10562306a36Sopenharmony_ci case 1: \ 10662306a36Sopenharmony_ci __get_user_asm("lbu", (ptr), x, __gu_err); \ 10762306a36Sopenharmony_ci break; \ 10862306a36Sopenharmony_ci case 2: \ 10962306a36Sopenharmony_ci __get_user_asm("lhu", (ptr), x, __gu_err); \ 11062306a36Sopenharmony_ci break; \ 11162306a36Sopenharmony_ci case 4: \ 11262306a36Sopenharmony_ci __get_user_asm("lw", (ptr), x, __gu_err); \ 11362306a36Sopenharmony_ci break; \ 11462306a36Sopenharmony_ci case 8: { \ 11562306a36Sopenharmony_ci __u64 __x = 0; \ 11662306a36Sopenharmony_ci __gu_err = raw_copy_from_user(&__x, ptr, 8) ? \ 11762306a36Sopenharmony_ci -EFAULT : 0; \ 11862306a36Sopenharmony_ci (x) = (typeof(x))(typeof((x) - (x)))__x; \ 11962306a36Sopenharmony_ci break; \ 12062306a36Sopenharmony_ci } \ 12162306a36Sopenharmony_ci default: \ 12262306a36Sopenharmony_ci /* __gu_val = 0; __gu_err = -EINVAL;*/ __gu_err = __user_bad();\ 12362306a36Sopenharmony_ci } \ 12462306a36Sopenharmony_ci __gu_err; \ 12562306a36Sopenharmony_ci}) 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci#define __put_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \ 12962306a36Sopenharmony_ci({ \ 13062306a36Sopenharmony_ci __asm__ __volatile__ ( \ 13162306a36Sopenharmony_ci "1:" insn " %1, %2, r0;" \ 13262306a36Sopenharmony_ci " addk %0, r0, r0;" \ 13362306a36Sopenharmony_ci "2: " \ 13462306a36Sopenharmony_ci __FIXUP_SECTION \ 13562306a36Sopenharmony_ci "3: brid 2b;" \ 13662306a36Sopenharmony_ci " addik %0, r0, %3;" \ 13762306a36Sopenharmony_ci ".previous;" \ 13862306a36Sopenharmony_ci __EX_TABLE_SECTION \ 13962306a36Sopenharmony_ci ".word 1b,3b;" \ 14062306a36Sopenharmony_ci ".previous;" \ 14162306a36Sopenharmony_ci : "=&r"(__gu_err) \ 14262306a36Sopenharmony_ci : "r"(__gu_val), "r"(__gu_ptr), "i"(-EFAULT) \ 14362306a36Sopenharmony_ci ); \ 14462306a36Sopenharmony_ci}) 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci#define __put_user_asm_8(__gu_ptr, __gu_val, __gu_err) \ 14762306a36Sopenharmony_ci({ \ 14862306a36Sopenharmony_ci __asm__ __volatile__ (" lwi %0, %1, 0;" \ 14962306a36Sopenharmony_ci "1: swi %0, %2, 0;" \ 15062306a36Sopenharmony_ci " lwi %0, %1, 4;" \ 15162306a36Sopenharmony_ci "2: swi %0, %2, 4;" \ 15262306a36Sopenharmony_ci " addk %0, r0, r0;" \ 15362306a36Sopenharmony_ci "3: " \ 15462306a36Sopenharmony_ci __FIXUP_SECTION \ 15562306a36Sopenharmony_ci "4: brid 3b;" \ 15662306a36Sopenharmony_ci " addik %0, r0, %3;" \ 15762306a36Sopenharmony_ci ".previous;" \ 15862306a36Sopenharmony_ci __EX_TABLE_SECTION \ 15962306a36Sopenharmony_ci ".word 1b,4b,2b,4b;" \ 16062306a36Sopenharmony_ci ".previous;" \ 16162306a36Sopenharmony_ci : "=&r"(__gu_err) \ 16262306a36Sopenharmony_ci : "r"(&__gu_val), "r"(__gu_ptr), "i"(-EFAULT) \ 16362306a36Sopenharmony_ci ); \ 16462306a36Sopenharmony_ci}) 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci/** 16762306a36Sopenharmony_ci * put_user: - Write a simple value into user space. 16862306a36Sopenharmony_ci * @x: Value to copy to user space. 16962306a36Sopenharmony_ci * @ptr: Destination address, in user space. 17062306a36Sopenharmony_ci * 17162306a36Sopenharmony_ci * Context: User context only. This function may sleep if pagefaults are 17262306a36Sopenharmony_ci * enabled. 17362306a36Sopenharmony_ci * 17462306a36Sopenharmony_ci * This macro copies a single simple value from kernel space to user 17562306a36Sopenharmony_ci * space. It supports simple types like char and int, but not larger 17662306a36Sopenharmony_ci * data types like structures or arrays. 17762306a36Sopenharmony_ci * 17862306a36Sopenharmony_ci * @ptr must have pointer-to-simple-variable type, and @x must be assignable 17962306a36Sopenharmony_ci * to the result of dereferencing @ptr. 18062306a36Sopenharmony_ci * 18162306a36Sopenharmony_ci * Returns zero on success, or -EFAULT on error. 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_ci#define put_user(x, ptr) \ 18462306a36Sopenharmony_ci __put_user_check((x), (ptr), sizeof(*(ptr))) 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci#define __put_user_check(x, ptr, size) \ 18762306a36Sopenharmony_ci({ \ 18862306a36Sopenharmony_ci typeof(*(ptr)) volatile __pu_val = x; \ 18962306a36Sopenharmony_ci typeof(*(ptr)) __user *__pu_addr = (ptr); \ 19062306a36Sopenharmony_ci int __pu_err = 0; \ 19162306a36Sopenharmony_ci \ 19262306a36Sopenharmony_ci if (access_ok(__pu_addr, size)) { \ 19362306a36Sopenharmony_ci switch (size) { \ 19462306a36Sopenharmony_ci case 1: \ 19562306a36Sopenharmony_ci __put_user_asm("sb", __pu_addr, __pu_val, \ 19662306a36Sopenharmony_ci __pu_err); \ 19762306a36Sopenharmony_ci break; \ 19862306a36Sopenharmony_ci case 2: \ 19962306a36Sopenharmony_ci __put_user_asm("sh", __pu_addr, __pu_val, \ 20062306a36Sopenharmony_ci __pu_err); \ 20162306a36Sopenharmony_ci break; \ 20262306a36Sopenharmony_ci case 4: \ 20362306a36Sopenharmony_ci __put_user_asm("sw", __pu_addr, __pu_val, \ 20462306a36Sopenharmony_ci __pu_err); \ 20562306a36Sopenharmony_ci break; \ 20662306a36Sopenharmony_ci case 8: \ 20762306a36Sopenharmony_ci __put_user_asm_8(__pu_addr, __pu_val, __pu_err);\ 20862306a36Sopenharmony_ci break; \ 20962306a36Sopenharmony_ci default: \ 21062306a36Sopenharmony_ci __pu_err = __user_bad(); \ 21162306a36Sopenharmony_ci break; \ 21262306a36Sopenharmony_ci } \ 21362306a36Sopenharmony_ci } else { \ 21462306a36Sopenharmony_ci __pu_err = -EFAULT; \ 21562306a36Sopenharmony_ci } \ 21662306a36Sopenharmony_ci __pu_err; \ 21762306a36Sopenharmony_ci}) 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci#define __put_user(x, ptr) \ 22062306a36Sopenharmony_ci({ \ 22162306a36Sopenharmony_ci __typeof__(*(ptr)) volatile __gu_val = (x); \ 22262306a36Sopenharmony_ci long __gu_err = 0; \ 22362306a36Sopenharmony_ci switch (sizeof(__gu_val)) { \ 22462306a36Sopenharmony_ci case 1: \ 22562306a36Sopenharmony_ci __put_user_asm("sb", (ptr), __gu_val, __gu_err); \ 22662306a36Sopenharmony_ci break; \ 22762306a36Sopenharmony_ci case 2: \ 22862306a36Sopenharmony_ci __put_user_asm("sh", (ptr), __gu_val, __gu_err); \ 22962306a36Sopenharmony_ci break; \ 23062306a36Sopenharmony_ci case 4: \ 23162306a36Sopenharmony_ci __put_user_asm("sw", (ptr), __gu_val, __gu_err); \ 23262306a36Sopenharmony_ci break; \ 23362306a36Sopenharmony_ci case 8: \ 23462306a36Sopenharmony_ci __put_user_asm_8((ptr), __gu_val, __gu_err); \ 23562306a36Sopenharmony_ci break; \ 23662306a36Sopenharmony_ci default: \ 23762306a36Sopenharmony_ci /*__gu_err = -EINVAL;*/ __gu_err = __user_bad(); \ 23862306a36Sopenharmony_ci } \ 23962306a36Sopenharmony_ci __gu_err; \ 24062306a36Sopenharmony_ci}) 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic inline unsigned long 24362306a36Sopenharmony_ciraw_copy_from_user(void *to, const void __user *from, unsigned long n) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci return __copy_tofrom_user((__force void __user *)to, from, n); 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic inline unsigned long 24962306a36Sopenharmony_ciraw_copy_to_user(void __user *to, const void *from, unsigned long n) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci return __copy_tofrom_user(to, (__force const void __user *)from, n); 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci#define INLINE_COPY_FROM_USER 25462306a36Sopenharmony_ci#define INLINE_COPY_TO_USER 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci/* 25762306a36Sopenharmony_ci * Copy a null terminated string from userspace. 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_ci__must_check long strncpy_from_user(char *dst, const char __user *src, 26062306a36Sopenharmony_ci long count); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci/* 26362306a36Sopenharmony_ci * Return the size of a string (including the ending 0) 26462306a36Sopenharmony_ci * 26562306a36Sopenharmony_ci * Return 0 on exception, a value greater than N if too long 26662306a36Sopenharmony_ci */ 26762306a36Sopenharmony_ci__must_check long strnlen_user(const char __user *sstr, long len); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci#endif /* _ASM_MICROBLAZE_UACCESS_H */ 270