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 (12221B)


      1/* SPDX-License-Identifier: GPL-2.0 */
      2#ifndef __M68K_UACCESS_H
      3#define __M68K_UACCESS_H
      4
      5#ifdef CONFIG_MMU
      6
      7/*
      8 * User space memory access functions
      9 */
     10#include <linux/compiler.h>
     11#include <linux/types.h>
     12#include <asm/extable.h>
     13#include <asm-generic/access_ok.h>
     14
     15/*
     16 * Not all varients of the 68k family support the notion of address spaces.
     17 * The traditional 680x0 parts do, and they use the sfc/dfc registers and
     18 * the "moves" instruction to access user space from kernel space. Other
     19 * family members like ColdFire don't support this, and only have a single
     20 * address space, and use the usual "move" instruction for user space access.
     21 *
     22 * Outside of this difference the user space access functions are the same.
     23 * So lets keep the code simple and just define in what we need to use.
     24 */
     25#ifdef CONFIG_CPU_HAS_ADDRESS_SPACES
     26#define	MOVES	"moves"
     27#else
     28#define	MOVES	"move"
     29#endif
     30
     31#define __put_user_asm(inst, res, x, ptr, bwl, reg, err) \
     32asm volatile ("\n"					\
     33	"1:	"inst"."#bwl"	%2,%1\n"		\
     34	"2:\n"						\
     35	"	.section .fixup,\"ax\"\n"		\
     36	"	.even\n"				\
     37	"10:	moveq.l	%3,%0\n"			\
     38	"	jra 2b\n"				\
     39	"	.previous\n"				\
     40	"\n"						\
     41	"	.section __ex_table,\"a\"\n"		\
     42	"	.align	4\n"				\
     43	"	.long	1b,10b\n"			\
     44	"	.long	2b,10b\n"			\
     45	"	.previous"				\
     46	: "+d" (res), "=m" (*(ptr))			\
     47	: #reg (x), "i" (err))
     48
     49#define __put_user_asm8(inst, res, x, ptr)			\
     50do {								\
     51	const void *__pu_ptr = (const void __force *)(ptr);	\
     52								\
     53	asm volatile ("\n"					\
     54		"1:	"inst".l %2,(%1)+\n"			\
     55		"2:	"inst".l %R2,(%1)\n"			\
     56		"3:\n"						\
     57		"	.section .fixup,\"ax\"\n"		\
     58		"	.even\n"				\
     59		"10:	movel %3,%0\n"				\
     60		"	jra 3b\n"				\
     61		"	.previous\n"				\
     62		"\n"						\
     63		"	.section __ex_table,\"a\"\n"		\
     64		"	.align 4\n"				\
     65		"	.long 1b,10b\n"				\
     66		"	.long 2b,10b\n"				\
     67		"	.long 3b,10b\n"				\
     68		"	.previous"				\
     69		: "+d" (res), "+a" (__pu_ptr)			\
     70		: "r" (x), "i" (-EFAULT)			\
     71		: "memory");					\
     72} while (0)
     73
     74/*
     75 * These are the main single-value transfer routines.  They automatically
     76 * use the right size if we just have the right pointer type.
     77 */
     78
     79#define __put_user(x, ptr)						\
     80({									\
     81	typeof(*(ptr)) __pu_val = (x);					\
     82	int __pu_err = 0;						\
     83	__chk_user_ptr(ptr);						\
     84	switch (sizeof (*(ptr))) {					\
     85	case 1:								\
     86		__put_user_asm(MOVES, __pu_err, __pu_val, ptr, b, d, -EFAULT); \
     87		break;							\
     88	case 2:								\
     89		__put_user_asm(MOVES, __pu_err, __pu_val, ptr, w, r, -EFAULT); \
     90		break;							\
     91	case 4:								\
     92		__put_user_asm(MOVES, __pu_err, __pu_val, ptr, l, r, -EFAULT); \
     93		break;							\
     94	case 8:								\
     95		__put_user_asm8(MOVES, __pu_err, __pu_val, ptr);	\
     96		break;							\
     97	default:							\
     98		BUILD_BUG();						\
     99	}								\
    100	__pu_err;							\
    101})
    102#define put_user(x, ptr)	__put_user(x, ptr)
    103
    104
    105#define __get_user_asm(inst, res, x, ptr, type, bwl, reg, err) ({	\
    106	type __gu_val;							\
    107	asm volatile ("\n"						\
    108		"1:	"inst"."#bwl"	%2,%1\n"			\
    109		"2:\n"							\
    110		"	.section .fixup,\"ax\"\n"			\
    111		"	.even\n"					\
    112		"10:	move.l	%3,%0\n"				\
    113		"	sub.l	%1,%1\n"				\
    114		"	jra	2b\n"					\
    115		"	.previous\n"					\
    116		"\n"							\
    117		"	.section __ex_table,\"a\"\n"			\
    118		"	.align	4\n"					\
    119		"	.long	1b,10b\n"				\
    120		"	.previous"					\
    121		: "+d" (res), "=&" #reg (__gu_val)			\
    122		: "m" (*(ptr)), "i" (err));				\
    123	(x) = (__force typeof(*(ptr)))(__force unsigned long)__gu_val;	\
    124})
    125
    126#define __get_user_asm8(inst, res, x, ptr) 				\
    127do {									\
    128	const void *__gu_ptr = (const void __force *)(ptr);		\
    129	union {								\
    130		u64 l;							\
    131		__typeof__(*(ptr)) t;					\
    132	} __gu_val;							\
    133									\
    134	asm volatile ("\n"						\
    135		"1:	"inst".l (%2)+,%1\n"				\
    136		"2:	"inst".l (%2),%R1\n"				\
    137		"3:\n"							\
    138		"	.section .fixup,\"ax\"\n"			\
    139		"	.even\n"					\
    140		"10:	move.l	%3,%0\n"				\
    141		"	sub.l	%1,%1\n"				\
    142		"	sub.l	%R1,%R1\n"				\
    143		"	jra	3b\n"					\
    144		"	.previous\n"					\
    145		"\n"							\
    146		"	.section __ex_table,\"a\"\n"			\
    147		"	.align	4\n"					\
    148		"	.long	1b,10b\n"				\
    149		"	.long	2b,10b\n"				\
    150		"	.previous"					\
    151		: "+d" (res), "=&r" (__gu_val.l),			\
    152		  "+a" (__gu_ptr)					\
    153		: "i" (-EFAULT)						\
    154		: "memory");						\
    155	(x) = __gu_val.t;						\
    156} while (0)
    157
    158#define __get_user(x, ptr)						\
    159({									\
    160	int __gu_err = 0;						\
    161	__chk_user_ptr(ptr);						\
    162	switch (sizeof(*(ptr))) {					\
    163	case 1:								\
    164		__get_user_asm(MOVES, __gu_err, x, ptr, u8, b, d, -EFAULT); \
    165		break;							\
    166	case 2:								\
    167		__get_user_asm(MOVES, __gu_err, x, ptr, u16, w, r, -EFAULT); \
    168		break;							\
    169	case 4:								\
    170		__get_user_asm(MOVES, __gu_err, x, ptr, u32, l, r, -EFAULT); \
    171		break;							\
    172	case 8:								\
    173		__get_user_asm8(MOVES, __gu_err, x, ptr);		\
    174		break;							\
    175	default:							\
    176		BUILD_BUG();						\
    177	}								\
    178	__gu_err;							\
    179})
    180#define get_user(x, ptr) __get_user(x, ptr)
    181
    182unsigned long __generic_copy_from_user(void *to, const void __user *from, unsigned long n);
    183unsigned long __generic_copy_to_user(void __user *to, const void *from, unsigned long n);
    184
    185#define __suffix0
    186#define __suffix1 b
    187#define __suffix2 w
    188#define __suffix4 l
    189
    190#define ____constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3, s1, s2, s3)\
    191	asm volatile ("\n"						\
    192		"1:	"MOVES"."#s1"	(%2)+,%3\n"			\
    193		"	move."#s1"	%3,(%1)+\n"			\
    194		"	.ifnc	\""#s2"\",\"\"\n"			\
    195		"2:	"MOVES"."#s2"	(%2)+,%3\n"			\
    196		"	move."#s2"	%3,(%1)+\n"			\
    197		"	.ifnc	\""#s3"\",\"\"\n"			\
    198		"3:	"MOVES"."#s3"	(%2)+,%3\n"			\
    199		"	move."#s3"	%3,(%1)+\n"			\
    200		"	.endif\n"					\
    201		"	.endif\n"					\
    202		"4:\n"							\
    203		"	.section __ex_table,\"a\"\n"			\
    204		"	.align	4\n"					\
    205		"	.long	1b,10f\n"				\
    206		"	.ifnc	\""#s2"\",\"\"\n"			\
    207		"	.long	2b,20f\n"				\
    208		"	.ifnc	\""#s3"\",\"\"\n"			\
    209		"	.long	3b,30f\n"				\
    210		"	.endif\n"					\
    211		"	.endif\n"					\
    212		"	.previous\n"					\
    213		"\n"							\
    214		"	.section .fixup,\"ax\"\n"			\
    215		"	.even\n"					\
    216		"10:	addq.l #"#n1",%0\n"				\
    217		"	.ifnc	\""#s2"\",\"\"\n"			\
    218		"20:	addq.l #"#n2",%0\n"				\
    219		"	.ifnc	\""#s3"\",\"\"\n"			\
    220		"30:	addq.l #"#n3",%0\n"				\
    221		"	.endif\n"					\
    222		"	.endif\n"					\
    223		"	jra	4b\n"					\
    224		"	.previous\n"					\
    225		: "+d" (res), "+&a" (to), "+a" (from), "=&d" (tmp)	\
    226		: : "memory")
    227
    228#define ___constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3, s1, s2, s3)\
    229	____constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3, s1, s2, s3)
    230#define __constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3)	\
    231	___constant_copy_from_user_asm(res, to, from, tmp, n1, n2, n3,  \
    232					__suffix##n1, __suffix##n2, __suffix##n3)
    233
    234static __always_inline unsigned long
    235__constant_copy_from_user(void *to, const void __user *from, unsigned long n)
    236{
    237	unsigned long res = 0, tmp;
    238
    239	switch (n) {
    240	case 1:
    241		__constant_copy_from_user_asm(res, to, from, tmp, 1, 0, 0);
    242		break;
    243	case 2:
    244		__constant_copy_from_user_asm(res, to, from, tmp, 2, 0, 0);
    245		break;
    246	case 3:
    247		__constant_copy_from_user_asm(res, to, from, tmp, 2, 1, 0);
    248		break;
    249	case 4:
    250		__constant_copy_from_user_asm(res, to, from, tmp, 4, 0, 0);
    251		break;
    252	case 5:
    253		__constant_copy_from_user_asm(res, to, from, tmp, 4, 1, 0);
    254		break;
    255	case 6:
    256		__constant_copy_from_user_asm(res, to, from, tmp, 4, 2, 0);
    257		break;
    258	case 7:
    259		__constant_copy_from_user_asm(res, to, from, tmp, 4, 2, 1);
    260		break;
    261	case 8:
    262		__constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 0);
    263		break;
    264	case 9:
    265		__constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 1);
    266		break;
    267	case 10:
    268		__constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 2);
    269		break;
    270	case 12:
    271		__constant_copy_from_user_asm(res, to, from, tmp, 4, 4, 4);
    272		break;
    273	default:
    274		/* we limit the inlined version to 3 moves */
    275		return __generic_copy_from_user(to, from, n);
    276	}
    277
    278	return res;
    279}
    280
    281#define __constant_copy_to_user_asm(res, to, from, tmp, n, s1, s2, s3)	\
    282	asm volatile ("\n"						\
    283		"	move."#s1"	(%2)+,%3\n"			\
    284		"11:	"MOVES"."#s1"	%3,(%1)+\n"			\
    285		"12:	move."#s2"	(%2)+,%3\n"			\
    286		"21:	"MOVES"."#s2"	%3,(%1)+\n"			\
    287		"22:\n"							\
    288		"	.ifnc	\""#s3"\",\"\"\n"			\
    289		"	move."#s3"	(%2)+,%3\n"			\
    290		"31:	"MOVES"."#s3"	%3,(%1)+\n"			\
    291		"32:\n"							\
    292		"	.endif\n"					\
    293		"4:\n"							\
    294		"\n"							\
    295		"	.section __ex_table,\"a\"\n"			\
    296		"	.align	4\n"					\
    297		"	.long	11b,5f\n"				\
    298		"	.long	12b,5f\n"				\
    299		"	.long	21b,5f\n"				\
    300		"	.long	22b,5f\n"				\
    301		"	.ifnc	\""#s3"\",\"\"\n"			\
    302		"	.long	31b,5f\n"				\
    303		"	.long	32b,5f\n"				\
    304		"	.endif\n"					\
    305		"	.previous\n"					\
    306		"\n"							\
    307		"	.section .fixup,\"ax\"\n"			\
    308		"	.even\n"					\
    309		"5:	moveq.l	#"#n",%0\n"				\
    310		"	jra	4b\n"					\
    311		"	.previous\n"					\
    312		: "+d" (res), "+a" (to), "+a" (from), "=&d" (tmp)	\
    313		: : "memory")
    314
    315static __always_inline unsigned long
    316__constant_copy_to_user(void __user *to, const void *from, unsigned long n)
    317{
    318	unsigned long res = 0, tmp;
    319
    320	switch (n) {
    321	case 1:
    322		__put_user_asm(MOVES, res, *(u8 *)from, (u8 __user *)to,
    323				b, d, 1);
    324		break;
    325	case 2:
    326		__put_user_asm(MOVES, res, *(u16 *)from, (u16 __user *)to,
    327				w, r, 2);
    328		break;
    329	case 3:
    330		__constant_copy_to_user_asm(res, to, from, tmp, 3, w, b,);
    331		break;
    332	case 4:
    333		__put_user_asm(MOVES, res, *(u32 *)from, (u32 __user *)to,
    334				l, r, 4);
    335		break;
    336	case 5:
    337		__constant_copy_to_user_asm(res, to, from, tmp, 5, l, b,);
    338		break;
    339	case 6:
    340		__constant_copy_to_user_asm(res, to, from, tmp, 6, l, w,);
    341		break;
    342	case 7:
    343		__constant_copy_to_user_asm(res, to, from, tmp, 7, l, w, b);
    344		break;
    345	case 8:
    346		__constant_copy_to_user_asm(res, to, from, tmp, 8, l, l,);
    347		break;
    348	case 9:
    349		__constant_copy_to_user_asm(res, to, from, tmp, 9, l, l, b);
    350		break;
    351	case 10:
    352		__constant_copy_to_user_asm(res, to, from, tmp, 10, l, l, w);
    353		break;
    354	case 12:
    355		__constant_copy_to_user_asm(res, to, from, tmp, 12, l, l, l);
    356		break;
    357	default:
    358		/* limit the inlined version to 3 moves */
    359		return __generic_copy_to_user(to, from, n);
    360	}
    361
    362	return res;
    363}
    364
    365static inline unsigned long
    366raw_copy_from_user(void *to, const void __user *from, unsigned long n)
    367{
    368	if (__builtin_constant_p(n))
    369		return __constant_copy_from_user(to, from, n);
    370	return __generic_copy_from_user(to, from, n);
    371}
    372
    373static inline unsigned long
    374raw_copy_to_user(void __user *to, const void *from, unsigned long n)
    375{
    376	if (__builtin_constant_p(n))
    377		return __constant_copy_to_user(to, from, n);
    378	return __generic_copy_to_user(to, from, n);
    379}
    380#define INLINE_COPY_FROM_USER
    381#define INLINE_COPY_TO_USER
    382
    383#define __get_kernel_nofault(dst, src, type, err_label)			\
    384do {									\
    385	type *__gk_dst = (type *)(dst);					\
    386	type *__gk_src = (type *)(src);					\
    387	int __gk_err = 0;						\
    388									\
    389	switch (sizeof(type)) {						\
    390	case 1:								\
    391		__get_user_asm("move", __gk_err, *__gk_dst, __gk_src,	\
    392				u8, b, d, -EFAULT);			\
    393		break;							\
    394	case 2:								\
    395		__get_user_asm("move", __gk_err, *__gk_dst, __gk_src,	\
    396				u16, w, r, -EFAULT);			\
    397		break;							\
    398	case 4:								\
    399		__get_user_asm("move", __gk_err, *__gk_dst, __gk_src,	\
    400				u32, l, r, -EFAULT);			\
    401		break;							\
    402	case 8:								\
    403		__get_user_asm8("move", __gk_err, *__gk_dst, __gk_src);	\
    404		break;							\
    405	default:							\
    406		BUILD_BUG();						\
    407	}								\
    408	if (unlikely(__gk_err))						\
    409		goto err_label;						\
    410} while (0)
    411
    412#define __put_kernel_nofault(dst, src, type, err_label)			\
    413do {									\
    414	type __pk_src = *(type *)(src);					\
    415	type *__pk_dst = (type *)(dst);					\
    416	int __pk_err = 0;						\
    417									\
    418	switch (sizeof(type)) {						\
    419	case 1:								\
    420		__put_user_asm("move", __pk_err, __pk_src, __pk_dst,	\
    421				b, d, -EFAULT);				\
    422		break;							\
    423	case 2:								\
    424		__put_user_asm("move", __pk_err, __pk_src, __pk_dst,	\
    425				w, r, -EFAULT);				\
    426		break;							\
    427	case 4:								\
    428		__put_user_asm("move", __pk_err, __pk_src, __pk_dst,	\
    429				l, r, -EFAULT);				\
    430		break;							\
    431	case 8:								\
    432		__put_user_asm8("move", __pk_err, __pk_src, __pk_dst);	\
    433		break;							\
    434	default:							\
    435		BUILD_BUG();						\
    436	}								\
    437	if (unlikely(__pk_err))						\
    438		goto err_label;						\
    439} while (0)
    440
    441extern long strncpy_from_user(char *dst, const char __user *src, long count);
    442extern __must_check long strnlen_user(const char __user *str, long n);
    443
    444unsigned long __clear_user(void __user *to, unsigned long n);
    445
    446#define clear_user	__clear_user
    447
    448#else /* !CONFIG_MMU */
    449#include <asm-generic/uaccess.h>
    450#endif
    451
    452#endif /* _M68K_UACCESS_H */