cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

uaccess.h (7126B)


      1/* SPDX-License-Identifier: GPL-2.0 */
      2/*
      3 * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
      4 * Copyright (C) 2008-2009 PetaLogix
      5 * Copyright (C) 2006 Atmark Techno, Inc.
      6 */
      7
      8#ifndef _ASM_MICROBLAZE_UACCESS_H
      9#define _ASM_MICROBLAZE_UACCESS_H
     10
     11#include <linux/kernel.h>
     12
     13#include <asm/mmu.h>
     14#include <asm/page.h>
     15#include <linux/pgtable.h>
     16#include <asm/extable.h>
     17#include <linux/string.h>
     18#include <asm-generic/access_ok.h>
     19
     20# define __FIXUP_SECTION	".section .fixup,\"ax\"\n"
     21# define __EX_TABLE_SECTION	".section __ex_table,\"a\"\n"
     22
     23extern unsigned long __copy_tofrom_user(void __user *to,
     24		const void __user *from, unsigned long size);
     25
     26/* Return: number of not copied bytes, i.e. 0 if OK or non-zero if fail. */
     27static inline unsigned long __must_check __clear_user(void __user *to,
     28							unsigned long n)
     29{
     30	/* normal memset with two words to __ex_table */
     31	__asm__ __volatile__ (				\
     32			"1:	sb	r0, %1, r0;"	\
     33			"	addik	%0, %0, -1;"	\
     34			"	bneid	%0, 1b;"	\
     35			"	addik	%1, %1, 1;"	\
     36			"2:			"	\
     37			__EX_TABLE_SECTION		\
     38			".word	1b,2b;"			\
     39			".previous;"			\
     40		: "=r"(n), "=r"(to)			\
     41		: "0"(n), "1"(to)
     42	);
     43	return n;
     44}
     45
     46static inline unsigned long __must_check clear_user(void __user *to,
     47							unsigned long n)
     48{
     49	might_fault();
     50	if (unlikely(!access_ok(to, n)))
     51		return n;
     52
     53	return __clear_user(to, n);
     54}
     55
     56/* put_user and get_user macros */
     57extern long __user_bad(void);
     58
     59#define __get_user_asm(insn, __gu_ptr, __gu_val, __gu_err)	\
     60({								\
     61	__asm__ __volatile__ (					\
     62			"1:"	insn	" %1, %2, r0;"		\
     63			"	addk	%0, r0, r0;"		\
     64			"2:			"		\
     65			__FIXUP_SECTION				\
     66			"3:	brid	2b;"			\
     67			"	addik	%0, r0, %3;"		\
     68			".previous;"				\
     69			__EX_TABLE_SECTION			\
     70			".word	1b,3b;"				\
     71			".previous;"				\
     72		: "=&r"(__gu_err), "=r"(__gu_val)		\
     73		: "r"(__gu_ptr), "i"(-EFAULT)			\
     74	);							\
     75})
     76
     77/**
     78 * get_user: - Get a simple variable from user space.
     79 * @x:   Variable to store result.
     80 * @ptr: Source address, in user space.
     81 *
     82 * Context: User context only. This function may sleep if pagefaults are
     83 *          enabled.
     84 *
     85 * This macro copies a single simple variable from user space to kernel
     86 * space.  It supports simple types like char and int, but not larger
     87 * data types like structures or arrays.
     88 *
     89 * @ptr must have pointer-to-simple-variable type, and the result of
     90 * dereferencing @ptr must be assignable to @x without a cast.
     91 *
     92 * Returns zero on success, or -EFAULT on error.
     93 * On error, the variable @x is set to zero.
     94 */
     95#define get_user(x, ptr) ({				\
     96	const typeof(*(ptr)) __user *__gu_ptr = (ptr);	\
     97	access_ok(__gu_ptr, sizeof(*__gu_ptr)) ?	\
     98		__get_user(x, __gu_ptr) : -EFAULT;	\
     99})
    100
    101#define __get_user(x, ptr)						\
    102({									\
    103	long __gu_err;							\
    104	switch (sizeof(*(ptr))) {					\
    105	case 1:								\
    106		__get_user_asm("lbu", (ptr), x, __gu_err);		\
    107		break;							\
    108	case 2:								\
    109		__get_user_asm("lhu", (ptr), x, __gu_err);		\
    110		break;							\
    111	case 4:								\
    112		__get_user_asm("lw", (ptr), x, __gu_err);		\
    113		break;							\
    114	case 8: {							\
    115		__u64 __x = 0;						\
    116		__gu_err = raw_copy_from_user(&__x, ptr, 8) ?		\
    117							-EFAULT : 0;	\
    118		(x) = (typeof(x))(typeof((x) - (x)))__x;		\
    119		break;							\
    120	}								\
    121	default:							\
    122		/* __gu_val = 0; __gu_err = -EINVAL;*/ __gu_err = __user_bad();\
    123	}								\
    124	__gu_err;							\
    125})
    126
    127
    128#define __put_user_asm(insn, __gu_ptr, __gu_val, __gu_err)	\
    129({								\
    130	__asm__ __volatile__ (					\
    131			"1:"	insn	" %1, %2, r0;"		\
    132			"	addk	%0, r0, r0;"		\
    133			"2:			"		\
    134			__FIXUP_SECTION				\
    135			"3:	brid	2b;"			\
    136			"	addik	%0, r0, %3;"		\
    137			".previous;"				\
    138			__EX_TABLE_SECTION			\
    139			".word	1b,3b;"				\
    140			".previous;"				\
    141		: "=&r"(__gu_err)				\
    142		: "r"(__gu_val), "r"(__gu_ptr), "i"(-EFAULT)	\
    143	);							\
    144})
    145
    146#define __put_user_asm_8(__gu_ptr, __gu_val, __gu_err)		\
    147({								\
    148	__asm__ __volatile__ ("	lwi	%0, %1, 0;"		\
    149			"1:	swi	%0, %2, 0;"		\
    150			"	lwi	%0, %1, 4;"		\
    151			"2:	swi	%0, %2, 4;"		\
    152			"	addk	%0, r0, r0;"		\
    153			"3:			"		\
    154			__FIXUP_SECTION				\
    155			"4:	brid	3b;"			\
    156			"	addik	%0, r0, %3;"		\
    157			".previous;"				\
    158			__EX_TABLE_SECTION			\
    159			".word	1b,4b,2b,4b;"			\
    160			".previous;"				\
    161		: "=&r"(__gu_err)				\
    162		: "r"(&__gu_val), "r"(__gu_ptr), "i"(-EFAULT)	\
    163		);						\
    164})
    165
    166/**
    167 * put_user: - Write a simple value into user space.
    168 * @x:   Value to copy to user space.
    169 * @ptr: Destination address, in user space.
    170 *
    171 * Context: User context only. This function may sleep if pagefaults are
    172 *          enabled.
    173 *
    174 * This macro copies a single simple value from kernel space to user
    175 * space.  It supports simple types like char and int, but not larger
    176 * data types like structures or arrays.
    177 *
    178 * @ptr must have pointer-to-simple-variable type, and @x must be assignable
    179 * to the result of dereferencing @ptr.
    180 *
    181 * Returns zero on success, or -EFAULT on error.
    182 */
    183#define put_user(x, ptr)						\
    184	__put_user_check((x), (ptr), sizeof(*(ptr)))
    185
    186#define __put_user_check(x, ptr, size)					\
    187({									\
    188	typeof(*(ptr)) volatile __pu_val = x;				\
    189	typeof(*(ptr)) __user *__pu_addr = (ptr);			\
    190	int __pu_err = 0;						\
    191									\
    192	if (access_ok(__pu_addr, size)) {			\
    193		switch (size) {						\
    194		case 1:							\
    195			__put_user_asm("sb", __pu_addr, __pu_val,	\
    196				       __pu_err);			\
    197			break;						\
    198		case 2:							\
    199			__put_user_asm("sh", __pu_addr, __pu_val,	\
    200				       __pu_err);			\
    201			break;						\
    202		case 4:							\
    203			__put_user_asm("sw", __pu_addr, __pu_val,	\
    204				       __pu_err);			\
    205			break;						\
    206		case 8:							\
    207			__put_user_asm_8(__pu_addr, __pu_val, __pu_err);\
    208			break;						\
    209		default:						\
    210			__pu_err = __user_bad();			\
    211			break;						\
    212		}							\
    213	} else {							\
    214		__pu_err = -EFAULT;					\
    215	}								\
    216	__pu_err;							\
    217})
    218
    219#define __put_user(x, ptr)						\
    220({									\
    221	__typeof__(*(ptr)) volatile __gu_val = (x);			\
    222	long __gu_err = 0;						\
    223	switch (sizeof(__gu_val)) {					\
    224	case 1:								\
    225		__put_user_asm("sb", (ptr), __gu_val, __gu_err);	\
    226		break;							\
    227	case 2:								\
    228		__put_user_asm("sh", (ptr), __gu_val, __gu_err);	\
    229		break;							\
    230	case 4:								\
    231		__put_user_asm("sw", (ptr), __gu_val, __gu_err);	\
    232		break;							\
    233	case 8:								\
    234		__put_user_asm_8((ptr), __gu_val, __gu_err);		\
    235		break;							\
    236	default:							\
    237		/*__gu_err = -EINVAL;*/	__gu_err = __user_bad();	\
    238	}								\
    239	__gu_err;							\
    240})
    241
    242static inline unsigned long
    243raw_copy_from_user(void *to, const void __user *from, unsigned long n)
    244{
    245	return __copy_tofrom_user((__force void __user *)to, from, n);
    246}
    247
    248static inline unsigned long
    249raw_copy_to_user(void __user *to, const void *from, unsigned long n)
    250{
    251	return __copy_tofrom_user(to, (__force const void __user *)from, n);
    252}
    253#define INLINE_COPY_FROM_USER
    254#define INLINE_COPY_TO_USER
    255
    256/*
    257 * Copy a null terminated string from userspace.
    258 */
    259__must_check long strncpy_from_user(char *dst, const char __user *src,
    260				    long count);
    261
    262/*
    263 * Return the size of a string (including the ending 0)
    264 *
    265 * Return 0 on exception, a value greater than N if too long
    266 */
    267__must_check long strnlen_user(const char __user *sstr, long len);
    268
    269#endif /* _ASM_MICROBLAZE_UACCESS_H */