162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 362306a36Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 462306a36Sopenharmony_ci * for more details. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 1996, 1997, 1998, 1999, 2000, 03, 04 by Ralf Baechle 762306a36Sopenharmony_ci * Copyright (C) 1999, 2000 Silicon Graphics, Inc. 862306a36Sopenharmony_ci * Copyright (C) 2007 Maciej W. Rozycki 962306a36Sopenharmony_ci * Copyright (C) 2014, Imagination Technologies Ltd. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci#ifndef _ASM_UACCESS_H 1262306a36Sopenharmony_ci#define _ASM_UACCESS_H 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/string.h> 1662306a36Sopenharmony_ci#include <asm/asm-eva.h> 1762306a36Sopenharmony_ci#include <asm/extable.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#ifdef CONFIG_32BIT 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define __UA_LIMIT 0x80000000UL 2262306a36Sopenharmony_ci#define TASK_SIZE_MAX KSEG0 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define __UA_ADDR ".word" 2562306a36Sopenharmony_ci#define __UA_LA "la" 2662306a36Sopenharmony_ci#define __UA_ADDU "addu" 2762306a36Sopenharmony_ci#define __UA_t0 "$8" 2862306a36Sopenharmony_ci#define __UA_t1 "$9" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#endif /* CONFIG_32BIT */ 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#ifdef CONFIG_64BIT 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ciextern u64 __ua_limit; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define __UA_LIMIT __ua_limit 3762306a36Sopenharmony_ci#define TASK_SIZE_MAX XKSSEG 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define __UA_ADDR ".dword" 4062306a36Sopenharmony_ci#define __UA_LA "dla" 4162306a36Sopenharmony_ci#define __UA_ADDU "daddu" 4262306a36Sopenharmony_ci#define __UA_t0 "$12" 4362306a36Sopenharmony_ci#define __UA_t1 "$13" 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#endif /* CONFIG_64BIT */ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#include <asm-generic/access_ok.h> 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* 5062306a36Sopenharmony_ci * put_user: - Write a simple value into user space. 5162306a36Sopenharmony_ci * @x: Value to copy to user space. 5262306a36Sopenharmony_ci * @ptr: Destination address, in user space. 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * Context: User context only. This function may sleep if pagefaults are 5562306a36Sopenharmony_ci * enabled. 5662306a36Sopenharmony_ci * 5762306a36Sopenharmony_ci * This macro copies a single simple value from kernel space to user 5862306a36Sopenharmony_ci * space. It supports simple types like char and int, but not larger 5962306a36Sopenharmony_ci * data types like structures or arrays. 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * @ptr must have pointer-to-simple-variable type, and @x must be assignable 6262306a36Sopenharmony_ci * to the result of dereferencing @ptr. 6362306a36Sopenharmony_ci * 6462306a36Sopenharmony_ci * Returns zero on success, or -EFAULT on error. 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_ci#define put_user(x, ptr) \ 6762306a36Sopenharmony_ci({ \ 6862306a36Sopenharmony_ci __typeof__(*(ptr)) __user *__p = (ptr); \ 6962306a36Sopenharmony_ci \ 7062306a36Sopenharmony_ci might_fault(); \ 7162306a36Sopenharmony_ci access_ok(__p, sizeof(*__p)) ? __put_user((x), __p) : -EFAULT; \ 7262306a36Sopenharmony_ci}) 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* 7562306a36Sopenharmony_ci * get_user: - Get a simple variable from user space. 7662306a36Sopenharmony_ci * @x: Variable to store result. 7762306a36Sopenharmony_ci * @ptr: Source address, in user space. 7862306a36Sopenharmony_ci * 7962306a36Sopenharmony_ci * Context: User context only. This function may sleep if pagefaults are 8062306a36Sopenharmony_ci * enabled. 8162306a36Sopenharmony_ci * 8262306a36Sopenharmony_ci * This macro copies a single simple variable from user space to kernel 8362306a36Sopenharmony_ci * space. It supports simple types like char and int, but not larger 8462306a36Sopenharmony_ci * data types like structures or arrays. 8562306a36Sopenharmony_ci * 8662306a36Sopenharmony_ci * @ptr must have pointer-to-simple-variable type, and the result of 8762306a36Sopenharmony_ci * dereferencing @ptr must be assignable to @x without a cast. 8862306a36Sopenharmony_ci * 8962306a36Sopenharmony_ci * Returns zero on success, or -EFAULT on error. 9062306a36Sopenharmony_ci * On error, the variable @x is set to zero. 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_ci#define get_user(x, ptr) \ 9362306a36Sopenharmony_ci({ \ 9462306a36Sopenharmony_ci const __typeof__(*(ptr)) __user *__p = (ptr); \ 9562306a36Sopenharmony_ci \ 9662306a36Sopenharmony_ci might_fault(); \ 9762306a36Sopenharmony_ci access_ok(__p, sizeof(*__p)) ? __get_user((x), __p) : \ 9862306a36Sopenharmony_ci ((x) = 0, -EFAULT); \ 9962306a36Sopenharmony_ci}) 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/* 10262306a36Sopenharmony_ci * __put_user: - Write a simple value into user space, with less checking. 10362306a36Sopenharmony_ci * @x: Value to copy to user space. 10462306a36Sopenharmony_ci * @ptr: Destination address, in user space. 10562306a36Sopenharmony_ci * 10662306a36Sopenharmony_ci * Context: User context only. This function may sleep if pagefaults are 10762306a36Sopenharmony_ci * enabled. 10862306a36Sopenharmony_ci * 10962306a36Sopenharmony_ci * This macro copies a single simple value from kernel space to user 11062306a36Sopenharmony_ci * space. It supports simple types like char and int, but not larger 11162306a36Sopenharmony_ci * data types like structures or arrays. 11262306a36Sopenharmony_ci * 11362306a36Sopenharmony_ci * @ptr must have pointer-to-simple-variable type, and @x must be assignable 11462306a36Sopenharmony_ci * to the result of dereferencing @ptr. 11562306a36Sopenharmony_ci * 11662306a36Sopenharmony_ci * Caller must check the pointer with access_ok() before calling this 11762306a36Sopenharmony_ci * function. 11862306a36Sopenharmony_ci * 11962306a36Sopenharmony_ci * Returns zero on success, or -EFAULT on error. 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_ci#define __put_user(x, ptr) \ 12262306a36Sopenharmony_ci({ \ 12362306a36Sopenharmony_ci __typeof__(*(ptr)) __user *__pu_ptr = (ptr); \ 12462306a36Sopenharmony_ci __typeof__(*(ptr)) __pu_val = (x); \ 12562306a36Sopenharmony_ci int __pu_err = 0; \ 12662306a36Sopenharmony_ci \ 12762306a36Sopenharmony_ci __chk_user_ptr(__pu_ptr); \ 12862306a36Sopenharmony_ci switch (sizeof(*__pu_ptr)) { \ 12962306a36Sopenharmony_ci case 1: \ 13062306a36Sopenharmony_ci __put_data_asm(user_sb, __pu_ptr); \ 13162306a36Sopenharmony_ci break; \ 13262306a36Sopenharmony_ci case 2: \ 13362306a36Sopenharmony_ci __put_data_asm(user_sh, __pu_ptr); \ 13462306a36Sopenharmony_ci break; \ 13562306a36Sopenharmony_ci case 4: \ 13662306a36Sopenharmony_ci __put_data_asm(user_sw, __pu_ptr); \ 13762306a36Sopenharmony_ci break; \ 13862306a36Sopenharmony_ci case 8: \ 13962306a36Sopenharmony_ci __PUT_DW(user_sd, __pu_ptr); \ 14062306a36Sopenharmony_ci break; \ 14162306a36Sopenharmony_ci default: \ 14262306a36Sopenharmony_ci BUILD_BUG(); \ 14362306a36Sopenharmony_ci } \ 14462306a36Sopenharmony_ci \ 14562306a36Sopenharmony_ci __pu_err; \ 14662306a36Sopenharmony_ci}) 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci/* 14962306a36Sopenharmony_ci * __get_user: - Get a simple variable from user space, with less checking. 15062306a36Sopenharmony_ci * @x: Variable to store result. 15162306a36Sopenharmony_ci * @ptr: Source address, in user space. 15262306a36Sopenharmony_ci * 15362306a36Sopenharmony_ci * Context: User context only. This function may sleep if pagefaults are 15462306a36Sopenharmony_ci * enabled. 15562306a36Sopenharmony_ci * 15662306a36Sopenharmony_ci * This macro copies a single simple variable from user space to kernel 15762306a36Sopenharmony_ci * space. It supports simple types like char and int, but not larger 15862306a36Sopenharmony_ci * data types like structures or arrays. 15962306a36Sopenharmony_ci * 16062306a36Sopenharmony_ci * @ptr must have pointer-to-simple-variable type, and the result of 16162306a36Sopenharmony_ci * dereferencing @ptr must be assignable to @x without a cast. 16262306a36Sopenharmony_ci * 16362306a36Sopenharmony_ci * Caller must check the pointer with access_ok() before calling this 16462306a36Sopenharmony_ci * function. 16562306a36Sopenharmony_ci * 16662306a36Sopenharmony_ci * Returns zero on success, or -EFAULT on error. 16762306a36Sopenharmony_ci * On error, the variable @x is set to zero. 16862306a36Sopenharmony_ci */ 16962306a36Sopenharmony_ci#define __get_user(x, ptr) \ 17062306a36Sopenharmony_ci({ \ 17162306a36Sopenharmony_ci const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ 17262306a36Sopenharmony_ci int __gu_err = 0; \ 17362306a36Sopenharmony_ci \ 17462306a36Sopenharmony_ci __chk_user_ptr(__gu_ptr); \ 17562306a36Sopenharmony_ci switch (sizeof(*__gu_ptr)) { \ 17662306a36Sopenharmony_ci case 1: \ 17762306a36Sopenharmony_ci __get_data_asm((x), user_lb, __gu_ptr); \ 17862306a36Sopenharmony_ci break; \ 17962306a36Sopenharmony_ci case 2: \ 18062306a36Sopenharmony_ci __get_data_asm((x), user_lh, __gu_ptr); \ 18162306a36Sopenharmony_ci break; \ 18262306a36Sopenharmony_ci case 4: \ 18362306a36Sopenharmony_ci __get_data_asm((x), user_lw, __gu_ptr); \ 18462306a36Sopenharmony_ci break; \ 18562306a36Sopenharmony_ci case 8: \ 18662306a36Sopenharmony_ci __GET_DW((x), user_ld, __gu_ptr); \ 18762306a36Sopenharmony_ci break; \ 18862306a36Sopenharmony_ci default: \ 18962306a36Sopenharmony_ci BUILD_BUG(); \ 19062306a36Sopenharmony_ci } \ 19162306a36Sopenharmony_ci \ 19262306a36Sopenharmony_ci __gu_err; \ 19362306a36Sopenharmony_ci}) 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistruct __large_struct { unsigned long buf[100]; }; 19662306a36Sopenharmony_ci#define __m(x) (*(struct __large_struct __user *)(x)) 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci#ifdef CONFIG_32BIT 19962306a36Sopenharmony_ci#define __GET_DW(val, insn, ptr) __get_data_asm_ll32(val, insn, ptr) 20062306a36Sopenharmony_ci#endif 20162306a36Sopenharmony_ci#ifdef CONFIG_64BIT 20262306a36Sopenharmony_ci#define __GET_DW(val, insn, ptr) __get_data_asm(val, insn, ptr) 20362306a36Sopenharmony_ci#endif 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci#define __get_data_asm(val, insn, addr) \ 20662306a36Sopenharmony_ci{ \ 20762306a36Sopenharmony_ci long __gu_tmp; \ 20862306a36Sopenharmony_ci \ 20962306a36Sopenharmony_ci __asm__ __volatile__( \ 21062306a36Sopenharmony_ci "1: "insn("%1", "%3")" \n" \ 21162306a36Sopenharmony_ci "2: \n" \ 21262306a36Sopenharmony_ci " .insn \n" \ 21362306a36Sopenharmony_ci " .section .fixup,\"ax\" \n" \ 21462306a36Sopenharmony_ci "3: li %0, %4 \n" \ 21562306a36Sopenharmony_ci " move %1, $0 \n" \ 21662306a36Sopenharmony_ci " j 2b \n" \ 21762306a36Sopenharmony_ci " .previous \n" \ 21862306a36Sopenharmony_ci " .section __ex_table,\"a\" \n" \ 21962306a36Sopenharmony_ci " "__UA_ADDR "\t1b, 3b \n" \ 22062306a36Sopenharmony_ci " .previous \n" \ 22162306a36Sopenharmony_ci : "=r" (__gu_err), "=r" (__gu_tmp) \ 22262306a36Sopenharmony_ci : "0" (0), "o" (__m(addr)), "i" (-EFAULT)); \ 22362306a36Sopenharmony_ci \ 22462306a36Sopenharmony_ci (val) = (__typeof__(*(addr))) __gu_tmp; \ 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci/* 22862306a36Sopenharmony_ci * Get a long long 64 using 32 bit registers. 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_ci#define __get_data_asm_ll32(val, insn, addr) \ 23162306a36Sopenharmony_ci{ \ 23262306a36Sopenharmony_ci union { \ 23362306a36Sopenharmony_ci unsigned long long l; \ 23462306a36Sopenharmony_ci __typeof__(*(addr)) t; \ 23562306a36Sopenharmony_ci } __gu_tmp; \ 23662306a36Sopenharmony_ci \ 23762306a36Sopenharmony_ci __asm__ __volatile__( \ 23862306a36Sopenharmony_ci "1: " insn("%1", "(%3)")" \n" \ 23962306a36Sopenharmony_ci "2: " insn("%D1", "4(%3)")" \n" \ 24062306a36Sopenharmony_ci "3: \n" \ 24162306a36Sopenharmony_ci " .insn \n" \ 24262306a36Sopenharmony_ci " .section .fixup,\"ax\" \n" \ 24362306a36Sopenharmony_ci "4: li %0, %4 \n" \ 24462306a36Sopenharmony_ci " move %1, $0 \n" \ 24562306a36Sopenharmony_ci " move %D1, $0 \n" \ 24662306a36Sopenharmony_ci " j 3b \n" \ 24762306a36Sopenharmony_ci " .previous \n" \ 24862306a36Sopenharmony_ci " .section __ex_table,\"a\" \n" \ 24962306a36Sopenharmony_ci " " __UA_ADDR " 1b, 4b \n" \ 25062306a36Sopenharmony_ci " " __UA_ADDR " 2b, 4b \n" \ 25162306a36Sopenharmony_ci " .previous \n" \ 25262306a36Sopenharmony_ci : "=r" (__gu_err), "=&r" (__gu_tmp.l) \ 25362306a36Sopenharmony_ci : "0" (0), "r" (addr), "i" (-EFAULT)); \ 25462306a36Sopenharmony_ci \ 25562306a36Sopenharmony_ci (val) = __gu_tmp.t; \ 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci#define __get_kernel_nofault(dst, src, type, err_label) \ 25962306a36Sopenharmony_cido { \ 26062306a36Sopenharmony_ci int __gu_err; \ 26162306a36Sopenharmony_ci \ 26262306a36Sopenharmony_ci switch (sizeof(type)) { \ 26362306a36Sopenharmony_ci case 1: \ 26462306a36Sopenharmony_ci __get_data_asm(*(type *)(dst), kernel_lb, \ 26562306a36Sopenharmony_ci (__force type *)(src)); \ 26662306a36Sopenharmony_ci break; \ 26762306a36Sopenharmony_ci case 2: \ 26862306a36Sopenharmony_ci __get_data_asm(*(type *)(dst), kernel_lh, \ 26962306a36Sopenharmony_ci (__force type *)(src)); \ 27062306a36Sopenharmony_ci break; \ 27162306a36Sopenharmony_ci case 4: \ 27262306a36Sopenharmony_ci __get_data_asm(*(type *)(dst), kernel_lw, \ 27362306a36Sopenharmony_ci (__force type *)(src)); \ 27462306a36Sopenharmony_ci break; \ 27562306a36Sopenharmony_ci case 8: \ 27662306a36Sopenharmony_ci __GET_DW(*(type *)(dst), kernel_ld, \ 27762306a36Sopenharmony_ci (__force type *)(src)); \ 27862306a36Sopenharmony_ci break; \ 27962306a36Sopenharmony_ci default: \ 28062306a36Sopenharmony_ci BUILD_BUG(); \ 28162306a36Sopenharmony_ci break; \ 28262306a36Sopenharmony_ci } \ 28362306a36Sopenharmony_ci if (unlikely(__gu_err)) \ 28462306a36Sopenharmony_ci goto err_label; \ 28562306a36Sopenharmony_ci} while (0) 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci/* 28862306a36Sopenharmony_ci * Yuck. We need two variants, one for 64bit operation and one 28962306a36Sopenharmony_ci * for 32 bit mode and old iron. 29062306a36Sopenharmony_ci */ 29162306a36Sopenharmony_ci#ifdef CONFIG_32BIT 29262306a36Sopenharmony_ci#define __PUT_DW(insn, ptr) __put_data_asm_ll32(insn, ptr) 29362306a36Sopenharmony_ci#endif 29462306a36Sopenharmony_ci#ifdef CONFIG_64BIT 29562306a36Sopenharmony_ci#define __PUT_DW(insn, ptr) __put_data_asm(insn, ptr) 29662306a36Sopenharmony_ci#endif 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci#define __put_data_asm(insn, ptr) \ 29962306a36Sopenharmony_ci{ \ 30062306a36Sopenharmony_ci __asm__ __volatile__( \ 30162306a36Sopenharmony_ci "1: "insn("%z2", "%3")" # __put_data_asm \n" \ 30262306a36Sopenharmony_ci "2: \n" \ 30362306a36Sopenharmony_ci " .insn \n" \ 30462306a36Sopenharmony_ci " .section .fixup,\"ax\" \n" \ 30562306a36Sopenharmony_ci "3: li %0, %4 \n" \ 30662306a36Sopenharmony_ci " j 2b \n" \ 30762306a36Sopenharmony_ci " .previous \n" \ 30862306a36Sopenharmony_ci " .section __ex_table,\"a\" \n" \ 30962306a36Sopenharmony_ci " " __UA_ADDR " 1b, 3b \n" \ 31062306a36Sopenharmony_ci " .previous \n" \ 31162306a36Sopenharmony_ci : "=r" (__pu_err) \ 31262306a36Sopenharmony_ci : "0" (0), "Jr" (__pu_val), "o" (__m(ptr)), \ 31362306a36Sopenharmony_ci "i" (-EFAULT)); \ 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci#define __put_data_asm_ll32(insn, ptr) \ 31762306a36Sopenharmony_ci{ \ 31862306a36Sopenharmony_ci __asm__ __volatile__( \ 31962306a36Sopenharmony_ci "1: "insn("%2", "(%3)")" # __put_data_asm_ll32 \n" \ 32062306a36Sopenharmony_ci "2: "insn("%D2", "4(%3)")" \n" \ 32162306a36Sopenharmony_ci "3: \n" \ 32262306a36Sopenharmony_ci " .insn \n" \ 32362306a36Sopenharmony_ci " .section .fixup,\"ax\" \n" \ 32462306a36Sopenharmony_ci "4: li %0, %4 \n" \ 32562306a36Sopenharmony_ci " j 3b \n" \ 32662306a36Sopenharmony_ci " .previous \n" \ 32762306a36Sopenharmony_ci " .section __ex_table,\"a\" \n" \ 32862306a36Sopenharmony_ci " " __UA_ADDR " 1b, 4b \n" \ 32962306a36Sopenharmony_ci " " __UA_ADDR " 2b, 4b \n" \ 33062306a36Sopenharmony_ci " .previous" \ 33162306a36Sopenharmony_ci : "=r" (__pu_err) \ 33262306a36Sopenharmony_ci : "0" (0), "r" (__pu_val), "r" (ptr), \ 33362306a36Sopenharmony_ci "i" (-EFAULT)); \ 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci#define __put_kernel_nofault(dst, src, type, err_label) \ 33762306a36Sopenharmony_cido { \ 33862306a36Sopenharmony_ci type __pu_val; \ 33962306a36Sopenharmony_ci int __pu_err = 0; \ 34062306a36Sopenharmony_ci \ 34162306a36Sopenharmony_ci __pu_val = *(__force type *)(src); \ 34262306a36Sopenharmony_ci switch (sizeof(type)) { \ 34362306a36Sopenharmony_ci case 1: \ 34462306a36Sopenharmony_ci __put_data_asm(kernel_sb, (type *)(dst)); \ 34562306a36Sopenharmony_ci break; \ 34662306a36Sopenharmony_ci case 2: \ 34762306a36Sopenharmony_ci __put_data_asm(kernel_sh, (type *)(dst)); \ 34862306a36Sopenharmony_ci break; \ 34962306a36Sopenharmony_ci case 4: \ 35062306a36Sopenharmony_ci __put_data_asm(kernel_sw, (type *)(dst)) \ 35162306a36Sopenharmony_ci break; \ 35262306a36Sopenharmony_ci case 8: \ 35362306a36Sopenharmony_ci __PUT_DW(kernel_sd, (type *)(dst)); \ 35462306a36Sopenharmony_ci break; \ 35562306a36Sopenharmony_ci default: \ 35662306a36Sopenharmony_ci BUILD_BUG(); \ 35762306a36Sopenharmony_ci break; \ 35862306a36Sopenharmony_ci } \ 35962306a36Sopenharmony_ci if (unlikely(__pu_err)) \ 36062306a36Sopenharmony_ci goto err_label; \ 36162306a36Sopenharmony_ci} while (0) 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci/* 36562306a36Sopenharmony_ci * We're generating jump to subroutines which will be outside the range of 36662306a36Sopenharmony_ci * jump instructions 36762306a36Sopenharmony_ci */ 36862306a36Sopenharmony_ci#ifdef MODULE 36962306a36Sopenharmony_ci#define __MODULE_JAL(destination) \ 37062306a36Sopenharmony_ci ".set\tnoat\n\t" \ 37162306a36Sopenharmony_ci __UA_LA "\t$1, " #destination "\n\t" \ 37262306a36Sopenharmony_ci "jalr\t$1\n\t" \ 37362306a36Sopenharmony_ci ".set\tat\n\t" 37462306a36Sopenharmony_ci#else 37562306a36Sopenharmony_ci#define __MODULE_JAL(destination) \ 37662306a36Sopenharmony_ci "jal\t" #destination "\n\t" 37762306a36Sopenharmony_ci#endif 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci#if defined(CONFIG_CPU_DADDI_WORKAROUNDS) || (defined(CONFIG_EVA) && \ 38062306a36Sopenharmony_ci defined(CONFIG_CPU_HAS_PREFETCH)) 38162306a36Sopenharmony_ci#define DADDI_SCRATCH "$3" 38262306a36Sopenharmony_ci#else 38362306a36Sopenharmony_ci#define DADDI_SCRATCH "$0" 38462306a36Sopenharmony_ci#endif 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ciextern size_t __raw_copy_from_user(void *__to, const void *__from, size_t __n); 38762306a36Sopenharmony_ciextern size_t __raw_copy_to_user(void *__to, const void *__from, size_t __n); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_cistatic inline unsigned long 39062306a36Sopenharmony_ciraw_copy_from_user(void *to, const void __user *from, unsigned long n) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci register void *__cu_to_r __asm__("$4"); 39362306a36Sopenharmony_ci register const void __user *__cu_from_r __asm__("$5"); 39462306a36Sopenharmony_ci register long __cu_len_r __asm__("$6"); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci __cu_to_r = to; 39762306a36Sopenharmony_ci __cu_from_r = from; 39862306a36Sopenharmony_ci __cu_len_r = n; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci __asm__ __volatile__( 40162306a36Sopenharmony_ci ".set\tnoreorder\n\t" 40262306a36Sopenharmony_ci __MODULE_JAL(__raw_copy_from_user) 40362306a36Sopenharmony_ci ".set\tnoat\n\t" 40462306a36Sopenharmony_ci __UA_ADDU "\t$1, %1, %2\n\t" 40562306a36Sopenharmony_ci ".set\tat\n\t" 40662306a36Sopenharmony_ci ".set\treorder" 40762306a36Sopenharmony_ci : "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r) 40862306a36Sopenharmony_ci : 40962306a36Sopenharmony_ci : "$8", "$9", "$10", "$11", "$12", "$14", "$15", "$24", "$31", 41062306a36Sopenharmony_ci DADDI_SCRATCH, "memory"); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci return __cu_len_r; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic inline unsigned long 41662306a36Sopenharmony_ciraw_copy_to_user(void __user *to, const void *from, unsigned long n) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci register void __user *__cu_to_r __asm__("$4"); 41962306a36Sopenharmony_ci register const void *__cu_from_r __asm__("$5"); 42062306a36Sopenharmony_ci register long __cu_len_r __asm__("$6"); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci __cu_to_r = (to); 42362306a36Sopenharmony_ci __cu_from_r = (from); 42462306a36Sopenharmony_ci __cu_len_r = (n); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci __asm__ __volatile__( 42762306a36Sopenharmony_ci __MODULE_JAL(__raw_copy_to_user) 42862306a36Sopenharmony_ci : "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r) 42962306a36Sopenharmony_ci : 43062306a36Sopenharmony_ci : "$8", "$9", "$10", "$11", "$12", "$14", "$15", "$24", "$31", 43162306a36Sopenharmony_ci DADDI_SCRATCH, "memory"); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci return __cu_len_r; 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci#define INLINE_COPY_FROM_USER 43762306a36Sopenharmony_ci#define INLINE_COPY_TO_USER 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ciextern __kernel_size_t __bzero(void __user *addr, __kernel_size_t size); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci/* 44262306a36Sopenharmony_ci * __clear_user: - Zero a block of memory in user space, with less checking. 44362306a36Sopenharmony_ci * @to: Destination address, in user space. 44462306a36Sopenharmony_ci * @n: Number of bytes to zero. 44562306a36Sopenharmony_ci * 44662306a36Sopenharmony_ci * Zero a block of memory in user space. Caller must check 44762306a36Sopenharmony_ci * the specified block with access_ok() before calling this function. 44862306a36Sopenharmony_ci * 44962306a36Sopenharmony_ci * Returns number of bytes that could not be cleared. 45062306a36Sopenharmony_ci * On success, this will be zero. 45162306a36Sopenharmony_ci */ 45262306a36Sopenharmony_cistatic inline __kernel_size_t 45362306a36Sopenharmony_ci__clear_user(void __user *addr, __kernel_size_t size) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci __kernel_size_t res; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci#ifdef CONFIG_CPU_MICROMIPS 45862306a36Sopenharmony_ci/* micromips memset / bzero also clobbers t7 & t8 */ 45962306a36Sopenharmony_ci#define bzero_clobbers "$4", "$5", "$6", __UA_t0, __UA_t1, "$15", "$24", "$31" 46062306a36Sopenharmony_ci#else 46162306a36Sopenharmony_ci#define bzero_clobbers "$4", "$5", "$6", __UA_t0, __UA_t1, "$31" 46262306a36Sopenharmony_ci#endif /* CONFIG_CPU_MICROMIPS */ 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci might_fault(); 46562306a36Sopenharmony_ci __asm__ __volatile__( 46662306a36Sopenharmony_ci "move\t$4, %1\n\t" 46762306a36Sopenharmony_ci "move\t$5, $0\n\t" 46862306a36Sopenharmony_ci "move\t$6, %2\n\t" 46962306a36Sopenharmony_ci __MODULE_JAL(__bzero) 47062306a36Sopenharmony_ci "move\t%0, $6" 47162306a36Sopenharmony_ci : "=r" (res) 47262306a36Sopenharmony_ci : "r" (addr), "r" (size) 47362306a36Sopenharmony_ci : bzero_clobbers); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci return res; 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci#define clear_user(addr,n) \ 47962306a36Sopenharmony_ci({ \ 48062306a36Sopenharmony_ci void __user * __cl_addr = (addr); \ 48162306a36Sopenharmony_ci unsigned long __cl_size = (n); \ 48262306a36Sopenharmony_ci if (__cl_size && access_ok(__cl_addr, __cl_size)) \ 48362306a36Sopenharmony_ci __cl_size = __clear_user(__cl_addr, __cl_size); \ 48462306a36Sopenharmony_ci __cl_size; \ 48562306a36Sopenharmony_ci}) 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ciextern long __strncpy_from_user_asm(char *__to, const char __user *__from, long __len); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci/* 49062306a36Sopenharmony_ci * strncpy_from_user: - Copy a NUL terminated string from userspace. 49162306a36Sopenharmony_ci * @dst: Destination address, in kernel space. This buffer must be at 49262306a36Sopenharmony_ci * least @count bytes long. 49362306a36Sopenharmony_ci * @src: Source address, in user space. 49462306a36Sopenharmony_ci * @count: Maximum number of bytes to copy, including the trailing NUL. 49562306a36Sopenharmony_ci * 49662306a36Sopenharmony_ci * Copies a NUL-terminated string from userspace to kernel space. 49762306a36Sopenharmony_ci * 49862306a36Sopenharmony_ci * On success, returns the length of the string (not including the trailing 49962306a36Sopenharmony_ci * NUL). 50062306a36Sopenharmony_ci * 50162306a36Sopenharmony_ci * If access to userspace fails, returns -EFAULT (some data may have been 50262306a36Sopenharmony_ci * copied). 50362306a36Sopenharmony_ci * 50462306a36Sopenharmony_ci * If @count is smaller than the length of the string, copies @count bytes 50562306a36Sopenharmony_ci * and returns @count. 50662306a36Sopenharmony_ci */ 50762306a36Sopenharmony_cistatic inline long 50862306a36Sopenharmony_cistrncpy_from_user(char *__to, const char __user *__from, long __len) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci long res; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci if (!access_ok(__from, __len)) 51362306a36Sopenharmony_ci return -EFAULT; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci might_fault(); 51662306a36Sopenharmony_ci __asm__ __volatile__( 51762306a36Sopenharmony_ci "move\t$4, %1\n\t" 51862306a36Sopenharmony_ci "move\t$5, %2\n\t" 51962306a36Sopenharmony_ci "move\t$6, %3\n\t" 52062306a36Sopenharmony_ci __MODULE_JAL(__strncpy_from_user_asm) 52162306a36Sopenharmony_ci "move\t%0, $2" 52262306a36Sopenharmony_ci : "=r" (res) 52362306a36Sopenharmony_ci : "r" (__to), "r" (__from), "r" (__len) 52462306a36Sopenharmony_ci : "$2", "$3", "$4", "$5", "$6", __UA_t0, "$31", "memory"); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci return res; 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ciextern long __strnlen_user_asm(const char __user *s, long n); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci/* 53262306a36Sopenharmony_ci * strnlen_user: - Get the size of a string in user space. 53362306a36Sopenharmony_ci * @str: The string to measure. 53462306a36Sopenharmony_ci * 53562306a36Sopenharmony_ci * Context: User context only. This function may sleep if pagefaults are 53662306a36Sopenharmony_ci * enabled. 53762306a36Sopenharmony_ci * 53862306a36Sopenharmony_ci * Get the size of a NUL-terminated string in user space. 53962306a36Sopenharmony_ci * 54062306a36Sopenharmony_ci * Returns the size of the string INCLUDING the terminating NUL. 54162306a36Sopenharmony_ci * On exception, returns 0. 54262306a36Sopenharmony_ci * If the string is too long, returns a value greater than @n. 54362306a36Sopenharmony_ci */ 54462306a36Sopenharmony_cistatic inline long strnlen_user(const char __user *s, long n) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci long res; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci if (!access_ok(s, 1)) 54962306a36Sopenharmony_ci return 0; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci might_fault(); 55262306a36Sopenharmony_ci __asm__ __volatile__( 55362306a36Sopenharmony_ci "move\t$4, %1\n\t" 55462306a36Sopenharmony_ci "move\t$5, %2\n\t" 55562306a36Sopenharmony_ci __MODULE_JAL(__strnlen_user_asm) 55662306a36Sopenharmony_ci "move\t%0, $2" 55762306a36Sopenharmony_ci : "=r" (res) 55862306a36Sopenharmony_ci : "r" (s), "r" (n) 55962306a36Sopenharmony_ci : "$2", "$4", "$5", __UA_t0, "$31"); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci return res; 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci#endif /* _ASM_UACCESS_H */ 565