Files
linux/arch/powerpc/include/asm/uaccess.h
Christophe Leroy 861574d51b powerpc/uaccess: Implement masked user access
Masked user access avoids the address/size verification by access_ok().
Allthough its main purpose is to skip the speculation in the
verification of user address and size hence avoid the need of spec
mitigation, it also has the advantage of reducing the amount of
instructions required so it even benefits to platforms that don't
need speculation mitigation, especially when the size of the copy is
not know at build time.

So implement masked user access on powerpc. The only requirement is
to have memory gap that faults between the top user space and the
real start of kernel area.

On 64 bits platforms the address space is divided that way:

	0xffffffffffffffff	+------------------+
				|                  |
				|   kernel space   |
 		 		|                  |
	0xc000000000000000	+------------------+  <== PAGE_OFFSET
				|//////////////////|
				|//////////////////|
	0x8000000000000000	|//////////////////|
				|//////////////////|
				|//////////////////|
	0x0010000000000000	+------------------+  <== TASK_SIZE_MAX
				|                  |
				|    user space    |
				|                  |
	0x0000000000000000	+------------------+

Kernel is always above 0x8000000000000000 and user always
below, with a gap in-between. It leads to a 3 instructions sequence:

 150:	7c 69 fe 76 	sradi   r9,r3,63
 154:	79 29 00 40 	clrldi  r9,r9,1
 158:	7c 63 48 78 	andc    r3,r3,r9

This sequence leaves r3 unmodified when it is below 0x8000000000000000
and clamps it to 0x8000000000000000 if it is above.

On 32 bits it is more tricky. In theory user space can go up to
0xbfffffff while kernel will usually start at 0xc0000000. So a gap
needs to be added in-between. Allthough in theory a single 4k page
would suffice, it is easier and more efficient to enforce a 128k gap
below kernel, as it simplifies the masking.

e500 has the isel instruction which allows selecting one value or
the other without branch and that instruction is not speculative, so
use it. Allthough GCC usually generates code using that instruction,
it is safer to use inline assembly to be sure. The result is:

  14:	3d 20 bf fe 	lis     r9,-16386
  18:	7c 03 48 40 	cmplw   r3,r9
  1c:	7c 69 18 5e 	iselgt  r3,r9,r3

On other ones, when kernel space is over 0x80000000 and user space
is below, the logic in mask_user_address_simple() leads to a
3 instruction sequence:

  64:	7c 69 fe 70 	srawi   r9,r3,31
  68:	55 29 00 7e 	clrlwi  r9,r9,1
  6c:	7c 63 48 78 	andc    r3,r3,r9

This is the default on powerpc 8xx.

When the limit between user space and kernel space is not 0x80000000,
mask_user_address_32() is used and a 6 instructions sequence is
generated:

  24:	54 69 7c 7e 	srwi    r9,r3,17
  28:	21 29 57 ff 	subfic  r9,r9,22527
  2c:	7d 29 fe 70 	srawi   r9,r9,31
  30:	75 2a b0 00 	andis.  r10,r9,45056
  34:	7c 63 48 78 	andc    r3,r3,r9
  38:	7c 63 53 78 	or      r3,r3,r10

The constraint is that TASK_SIZE be aligned to 128K in order to get
the most optimal number of instructions.

When CONFIG_PPC_BARRIER_NOSPEC is not defined, fallback on the
test-based masking as it is quicker than the 6 instructions sequence
but not quicker than the 3 instructions sequences above.

As an exemple, allthough barrier_nospec() voids on the 8xx, this
change has the following impact on strncpy_from_user(): the length of
the function is reduced from 488 to 340 bytes:

Start of the function with the patch:

00000000 <strncpy_from_user>:
   0:	7c ab 2b 79 	mr.     r11,r5
   4:	40 81 01 40 	ble     144 <strncpy_from_user+0x144>
   8:	7c 89 fe 70 	srawi   r9,r4,31
   c:	55 29 00 7e 	clrlwi  r9,r9,1
  10:	7c 84 48 78 	andc    r4,r4,r9
  14:	3d 20 dc 00 	lis     r9,-9216
  18:	7d 3a c3 a6 	mtspr   794,r9
  1c:	2f 8b 00 03 	cmpwi   cr7,r11,3
  20:	40 9d 00 b4 	ble     cr7,d4 <strncpy_from_user+0xd4>
...

Start of the function without the patch:

00000000 <strncpy_from_user>:
   0:	7c a0 2b 79 	mr.     r0,r5
   4:	40 81 01 10 	ble     114 <strncpy_from_user+0x114>
   8:	2f 84 00 00 	cmpwi   cr7,r4,0
   c:	41 9c 01 30 	blt     cr7,13c <strncpy_from_user+0x13c>
  10:	3d 20 80 00 	lis     r9,-32768
  14:	7d 24 48 50 	subf    r9,r4,r9
  18:	7f 80 48 40 	cmplw   cr7,r0,r9
  1c:	7c 05 03 78 	mr      r5,r0
  20:	41 9d 01 00 	bgt     cr7,120 <strncpy_from_user+0x120>
  24:	3d 20 80 00 	lis     r9,-32768
  28:	7d 25 48 50 	subf    r9,r5,r9
  2c:	7f 84 48 40 	cmplw   cr7,r4,r9
  30:	38 e0 ff f2 	li      r7,-14
  34:	41 9d 00 e4 	bgt     cr7,118 <strncpy_from_user+0x118>
  38:	94 21 ff e0 	stwu    r1,-32(r1)
  3c:	3d 20 dc 00 	lis     r9,-9216
  40:	7d 3a c3 a6 	mtspr   794,r9
  44:	2b 85 00 03 	cmplwi  cr7,r5,3
  48:	40 9d 01 6c 	ble     cr7,1b4 <strncpy_from_user+0x1b4>
...
 118:	7c e3 3b 78 	mr      r3,r7
 11c:	4e 80 00 20 	blr
 120:	7d 25 4b 78 	mr      r5,r9
 124:	3d 20 80 00 	lis     r9,-32768
 128:	7d 25 48 50 	subf    r9,r5,r9
 12c:	7f 84 48 40 	cmplw   cr7,r4,r9
 130:	38 e0 ff f2 	li      r7,-14
 134:	41 bd ff e4 	bgt     cr7,118 <strncpy_from_user+0x118>
 138:	4b ff ff 00 	b       38 <strncpy_from_user+0x38>
 13c:	38 e0 ff f2 	li      r7,-14
 140:	4b ff ff d8 	b       118 <strncpy_from_user+0x118>
...

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com>
Link: https://patch.msgid.link/8f418183d9125cc0bf23922bc2ef2a1130d8b63a.1766574657.git.chleroy@kernel.org
2026-01-07 09:31:05 +05:30

576 lines
16 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ARCH_POWERPC_UACCESS_H
#define _ARCH_POWERPC_UACCESS_H
#include <linux/sizes.h>
#include <asm/processor.h>
#include <asm/page.h>
#include <asm/extable.h>
#include <asm/kup.h>
#include <asm/asm-compat.h>
#ifdef __powerpc64__
/* We use TASK_SIZE_USER64 as TASK_SIZE is not constant */
#define TASK_SIZE_MAX TASK_SIZE_USER64
#endif
#include <asm-generic/access_ok.h>
/*
* These are the main single-value transfer routines. They automatically
* use the right size if we just have the right pointer type.
*
* This gets kind of ugly. We want to return _two_ values in "get_user()"
* and yet we don't want to do any pointers, because that is too much
* of a performance impact. Thus we have a few rather ugly macros here,
* and hide all the ugliness from the user.
*
* The "__xxx" versions of the user access functions are versions that
* do not verify the address space, that must have been done previously
* with a separate "access_ok()" call (this is used when we do multiple
* accesses to the same area of user memory).
*
* As we use the same address space for kernel and user data on the
* PowerPC, we can just do these as direct assignments. (Of course, the
* exception handling means that it's no longer "just"...)
*
*/
#define __put_user(x, ptr) \
({ \
long __pu_err; \
__typeof__(*(ptr)) __user *__pu_addr = (ptr); \
__typeof__(*(ptr)) __pu_val = (__typeof__(*(ptr)))(x); \
__typeof__(sizeof(*(ptr))) __pu_size = sizeof(*(ptr)); \
\
might_fault(); \
do { \
__label__ __pu_failed; \
\
allow_user_access(__pu_addr, KUAP_WRITE); \
__put_user_size_goto(__pu_val, __pu_addr, __pu_size, __pu_failed); \
prevent_user_access(KUAP_WRITE); \
__pu_err = 0; \
break; \
\
__pu_failed: \
prevent_user_access(KUAP_WRITE); \
__pu_err = -EFAULT; \
} while (0); \
\
__pu_err; \
})
#define put_user(x, ptr) \
({ \
__typeof__(*(ptr)) __user *_pu_addr = (ptr); \
\
access_ok(_pu_addr, sizeof(*(ptr))) ? \
__put_user(x, _pu_addr) : -EFAULT; \
})
/*
* We don't tell gcc that we are accessing memory, but this is OK
* because we do not write to any memory gcc knows about, so there
* are no aliasing issues.
*/
/* -mprefixed can generate offsets beyond range, fall back hack */
#ifdef CONFIG_PPC_KERNEL_PREFIXED
#define __put_user_asm_goto(x, addr, label, op) \
asm goto( \
"1: " op " %0,0(%1) # put_user\n" \
EX_TABLE(1b, %l2) \
: \
: "r" (x), "b" (addr) \
: \
: label)
#else
#define __put_user_asm_goto(x, addr, label, op) \
asm goto( \
"1: " op "%U1%X1 %0,%1 # put_user\n" \
EX_TABLE(1b, %l2) \
: \
: "r" (x), "m<>" (*addr) \
: \
: label)
#endif
#ifdef __powerpc64__
#ifdef CONFIG_PPC_KERNEL_PREFIXED
#define __put_user_asm2_goto(x, ptr, label) \
__put_user_asm_goto(x, ptr, label, "std")
#else
#define __put_user_asm2_goto(x, addr, label) \
asm goto ("1: std%U1%X1 %0,%1 # put_user\n" \
EX_TABLE(1b, %l2) \
: \
: "r" (x), DS_FORM_CONSTRAINT (*addr) \
: \
: label)
#endif // CONFIG_PPC_KERNEL_PREFIXED
#else /* __powerpc64__ */
#define __put_user_asm2_goto(x, addr, label) \
asm goto( \
"1: stw%X1 %0, %1\n" \
"2: stw%X1 %L0, %L1\n" \
EX_TABLE(1b, %l2) \
EX_TABLE(2b, %l2) \
: \
: "r" (x), "m" (*addr) \
: \
: label)
#endif /* __powerpc64__ */
#define __put_user_size_goto(x, ptr, size, label) \
do { \
__typeof__(*(ptr)) __user *__pus_addr = (ptr); \
\
switch (size) { \
case 1: __put_user_asm_goto(x, __pus_addr, label, "stb"); break; \
case 2: __put_user_asm_goto(x, __pus_addr, label, "sth"); break; \
case 4: __put_user_asm_goto(x, __pus_addr, label, "stw"); break; \
case 8: __put_user_asm2_goto(x, __pus_addr, label); break; \
default: BUILD_BUG(); \
} \
} while (0)
/*
* This does an atomic 128 byte aligned load from userspace.
* Upto caller to do enable_kernel_vmx() before calling!
*/
#define __get_user_atomic_128_aligned(kaddr, uaddr, err) \
__asm__ __volatile__( \
".machine push\n" \
".machine altivec\n" \
"1: lvx 0,0,%1 # get user\n" \
" stvx 0,0,%2 # put kernel\n" \
".machine pop\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: li %0,%3\n" \
" b 2b\n" \
".previous\n" \
EX_TABLE(1b, 3b) \
: "=r" (err) \
: "b" (uaddr), "b" (kaddr), "i" (-EFAULT), "0" (err))
#ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
/* -mprefixed can generate offsets beyond range, fall back hack */
#ifdef CONFIG_PPC_KERNEL_PREFIXED
#define __get_user_asm_goto(x, addr, label, op) \
asm_goto_output( \
"1: "op" %0,0(%1) # get_user\n" \
EX_TABLE(1b, %l2) \
: "=r" (x) \
: "b" (addr) \
: \
: label)
#else
#define __get_user_asm_goto(x, addr, label, op) \
asm_goto_output( \
"1: "op"%U1%X1 %0, %1 # get_user\n" \
EX_TABLE(1b, %l2) \
: "=r" (x) \
: "m<>" (*addr) \
: \
: label)
#endif
#ifdef __powerpc64__
#ifdef CONFIG_PPC_KERNEL_PREFIXED
#define __get_user_asm2_goto(x, addr, label) \
__get_user_asm_goto(x, addr, label, "ld")
#else
#define __get_user_asm2_goto(x, addr, label) \
asm_goto_output( \
"1: ld%U1%X1 %0, %1 # get_user\n" \
EX_TABLE(1b, %l2) \
: "=r" (x) \
: DS_FORM_CONSTRAINT (*addr) \
: \
: label)
#endif // CONFIG_PPC_KERNEL_PREFIXED
#else /* __powerpc64__ */
#define __get_user_asm2_goto(x, addr, label) \
asm_goto_output( \
"1: lwz%X1 %0, %1\n" \
"2: lwz%X1 %L0, %L1\n" \
EX_TABLE(1b, %l2) \
EX_TABLE(2b, %l2) \
: "=&r" (x) \
: "m" (*addr) \
: \
: label)
#endif /* __powerpc64__ */
#define __get_user_size_goto(x, ptr, size, label) \
do { \
BUILD_BUG_ON(size > sizeof(x)); \
switch (size) { \
case 1: __get_user_asm_goto(x, (u8 __user *)ptr, label, "lbz"); break; \
case 2: __get_user_asm_goto(x, (u16 __user *)ptr, label, "lhz"); break; \
case 4: __get_user_asm_goto(x, (u32 __user *)ptr, label, "lwz"); break; \
case 8: __get_user_asm2_goto(x, (u64 __user *)ptr, label); break; \
default: x = 0; BUILD_BUG(); \
} \
} while (0)
#define __get_user_size_allowed(x, ptr, size, retval) \
do { \
__label__ __gus_failed; \
\
__get_user_size_goto(x, ptr, size, __gus_failed); \
retval = 0; \
break; \
__gus_failed: \
x = 0; \
retval = -EFAULT; \
} while (0)
#else /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
#define __get_user_asm(x, addr, err, op) \
__asm__ __volatile__( \
"1: "op"%U2%X2 %1, %2 # get_user\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: li %0,%3\n" \
" li %1,0\n" \
" b 2b\n" \
".previous\n" \
EX_TABLE(1b, 3b) \
: "=r" (err), "=r" (x) \
: "m<>" (*addr), "i" (-EFAULT), "0" (err))
#ifdef __powerpc64__
#define __get_user_asm2(x, addr, err) \
__get_user_asm(x, addr, err, "ld")
#else /* __powerpc64__ */
#define __get_user_asm2(x, addr, err) \
__asm__ __volatile__( \
"1: lwz%X2 %1, %2\n" \
"2: lwz%X2 %L1, %L2\n" \
"3:\n" \
".section .fixup,\"ax\"\n" \
"4: li %0,%3\n" \
" li %1,0\n" \
" li %1+1,0\n" \
" b 3b\n" \
".previous\n" \
EX_TABLE(1b, 4b) \
EX_TABLE(2b, 4b) \
: "=r" (err), "=&r" (x) \
: "m" (*addr), "i" (-EFAULT), "0" (err))
#endif /* __powerpc64__ */
#define __get_user_size_allowed(x, ptr, size, retval) \
do { \
retval = 0; \
BUILD_BUG_ON(size > sizeof(x)); \
switch (size) { \
case 1: __get_user_asm(x, (u8 __user *)ptr, retval, "lbz"); break; \
case 2: __get_user_asm(x, (u16 __user *)ptr, retval, "lhz"); break; \
case 4: __get_user_asm(x, (u32 __user *)ptr, retval, "lwz"); break; \
case 8: __get_user_asm2(x, (u64 __user *)ptr, retval); break; \
default: x = 0; BUILD_BUG(); \
} \
} while (0)
#define __get_user_size_goto(x, ptr, size, label) \
do { \
long __gus_retval; \
\
__get_user_size_allowed(x, ptr, size, __gus_retval); \
if (__gus_retval) \
goto label; \
} while (0)
#endif /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
/*
* This is a type: either unsigned long, if the argument fits into
* that type, or otherwise unsigned long long.
*/
#define __long_type(x) \
__typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
#define __get_user(x, ptr) \
({ \
long __gu_err; \
__long_type(*(ptr)) __gu_val; \
__typeof__(*(ptr)) __user *__gu_addr = (ptr); \
__typeof__(sizeof(*(ptr))) __gu_size = sizeof(*(ptr)); \
\
might_fault(); \
barrier_nospec(); \
allow_user_access(NULL, KUAP_READ); \
__get_user_size_allowed(__gu_val, __gu_addr, __gu_size, __gu_err); \
prevent_user_access(KUAP_READ); \
(x) = (__typeof__(*(ptr)))__gu_val; \
\
__gu_err; \
})
#define get_user(x, ptr) \
({ \
__typeof__(*(ptr)) __user *_gu_addr = (ptr); \
\
access_ok(_gu_addr, sizeof(*(ptr))) ? \
__get_user(x, _gu_addr) : \
((x) = (__force __typeof__(*(ptr)))0, -EFAULT); \
})
/* more complex routines */
extern unsigned long __copy_tofrom_user(void __user *to,
const void __user *from, unsigned long size);
#ifdef __powerpc64__
static inline unsigned long
raw_copy_in_user(void __user *to, const void __user *from, unsigned long n)
{
unsigned long ret;
barrier_nospec();
allow_user_access(to, KUAP_READ_WRITE);
ret = __copy_tofrom_user(to, from, n);
prevent_user_access(KUAP_READ_WRITE);
return ret;
}
#endif /* __powerpc64__ */
static inline unsigned long raw_copy_from_user(void *to,
const void __user *from, unsigned long n)
{
unsigned long ret;
allow_user_access(NULL, KUAP_READ);
ret = __copy_tofrom_user((__force void __user *)to, from, n);
prevent_user_access(KUAP_READ);
return ret;
}
static inline unsigned long
raw_copy_to_user(void __user *to, const void *from, unsigned long n)
{
unsigned long ret;
allow_user_access(to, KUAP_WRITE);
ret = __copy_tofrom_user(to, (__force const void __user *)from, n);
prevent_user_access(KUAP_WRITE);
return ret;
}
unsigned long __arch_clear_user(void __user *addr, unsigned long size);
static inline unsigned long __clear_user(void __user *addr, unsigned long size)
{
unsigned long ret;
might_fault();
allow_user_access(addr, KUAP_WRITE);
ret = __arch_clear_user(addr, size);
prevent_user_access(KUAP_WRITE);
return ret;
}
static inline unsigned long clear_user(void __user *addr, unsigned long size)
{
return likely(access_ok(addr, size)) ? __clear_user(addr, size) : size;
}
extern long strncpy_from_user(char *dst, const char __user *src, long count);
extern __must_check long strnlen_user(const char __user *str, long n);
#ifdef CONFIG_ARCH_HAS_COPY_MC
unsigned long __must_check
copy_mc_generic(void *to, const void *from, unsigned long size);
static inline unsigned long __must_check
copy_mc_to_kernel(void *to, const void *from, unsigned long size)
{
return copy_mc_generic(to, from, size);
}
#define copy_mc_to_kernel copy_mc_to_kernel
static inline unsigned long __must_check
copy_mc_to_user(void __user *to, const void *from, unsigned long n)
{
if (check_copy_size(from, n, true)) {
if (access_ok(to, n)) {
allow_user_access(to, KUAP_WRITE);
n = copy_mc_generic((void __force *)to, from, n);
prevent_user_access(KUAP_WRITE);
}
}
return n;
}
#endif
extern long __copy_from_user_flushcache(void *dst, const void __user *src,
unsigned size);
static __must_check __always_inline bool __user_access_begin(const void __user *ptr, size_t len,
unsigned long dir)
{
if (unlikely(!access_ok(ptr, len)))
return false;
might_fault();
if (dir & KUAP_READ)
barrier_nospec();
allow_user_access((void __user *)ptr, dir);
return true;
}
#define user_access_begin(p, l) __user_access_begin(p, l, KUAP_READ_WRITE)
#define user_read_access_begin(p, l) __user_access_begin(p, l, KUAP_READ)
#define user_write_access_begin(p, l) __user_access_begin(p, l, KUAP_WRITE)
#define user_access_end() prevent_user_access(KUAP_READ_WRITE)
#define user_read_access_end() prevent_user_access(KUAP_READ)
#define user_write_access_end() prevent_user_access(KUAP_WRITE)
#define user_access_save prevent_user_access_return
#define user_access_restore restore_user_access
/*
* Masking the user address is an alternative to a conditional
* user_access_begin that can avoid the fencing. This only works
* for dense accesses starting at the address.
*/
static inline void __user *mask_user_address_simple(const void __user *ptr)
{
unsigned long addr = (unsigned long)ptr;
unsigned long mask = (unsigned long)(((long)addr >> (BITS_PER_LONG - 1)) & LONG_MAX);
return (void __user *)(addr & ~mask);
}
static inline void __user *mask_user_address_isel(const void __user *ptr)
{
unsigned long addr;
asm("cmplw %1, %2; iselgt %0, %2, %1" : "=r"(addr) : "r"(ptr), "r"(TASK_SIZE) : "cr0");
return (void __user *)addr;
}
/* TASK_SIZE is a multiple of 128K for shifting by 17 to the right */
static inline void __user *mask_user_address_32(const void __user *ptr)
{
unsigned long addr = (unsigned long)ptr;
unsigned long mask = (unsigned long)((long)((TASK_SIZE >> 17) - 1 - (addr >> 17)) >> 31);
addr = (addr & ~mask) | (TASK_SIZE & mask);
return (void __user *)addr;
}
static inline void __user *mask_user_address_fallback(const void __user *ptr)
{
unsigned long addr = (unsigned long)ptr;
return (void __user *)(likely(addr < TASK_SIZE) ? addr : TASK_SIZE);
}
static inline void __user *mask_user_address(const void __user *ptr)
{
#ifdef MODULES_VADDR
const unsigned long border = MODULES_VADDR;
#else
const unsigned long border = PAGE_OFFSET;
#endif
if (IS_ENABLED(CONFIG_PPC64))
return mask_user_address_simple(ptr);
if (IS_ENABLED(CONFIG_E500))
return mask_user_address_isel(ptr);
if (TASK_SIZE <= UL(SZ_2G) && border >= UL(SZ_2G))
return mask_user_address_simple(ptr);
if (IS_ENABLED(CONFIG_PPC_BARRIER_NOSPEC))
return mask_user_address_32(ptr);
return mask_user_address_fallback(ptr);
}
static __always_inline void __user *__masked_user_access_begin(const void __user *p,
unsigned long dir)
{
void __user *ptr = mask_user_address(p);
might_fault();
allow_user_access(ptr, dir);
return ptr;
}
#define masked_user_access_begin(p) __masked_user_access_begin(p, KUAP_READ_WRITE)
#define masked_user_read_access_begin(p) __masked_user_access_begin(p, KUAP_READ)
#define masked_user_write_access_begin(p) __masked_user_access_begin(p, KUAP_WRITE)
#define arch_unsafe_get_user(x, p, e) do { \
__long_type(*(p)) __gu_val; \
__typeof__(*(p)) __user *__gu_addr = (p); \
\
__get_user_size_goto(__gu_val, __gu_addr, sizeof(*(p)), e); \
(x) = (__typeof__(*(p)))__gu_val; \
} while (0)
#define arch_unsafe_put_user(x, p, e) \
__put_user_size_goto((__typeof__(*(p)))(x), (p), sizeof(*(p)), e)
#define unsafe_copy_from_user(d, s, l, e) \
do { \
u8 *_dst = (u8 *)(d); \
const u8 __user *_src = (const u8 __user *)(s); \
size_t _len = (l); \
int _i; \
\
for (_i = 0; _i < (_len & ~(sizeof(u64) - 1)); _i += sizeof(u64)) \
unsafe_get_user(*(u64 *)(_dst + _i), (u64 __user *)(_src + _i), e); \
if (_len & 4) { \
unsafe_get_user(*(u32 *)(_dst + _i), (u32 __user *)(_src + _i), e); \
_i += 4; \
} \
if (_len & 2) { \
unsafe_get_user(*(u16 *)(_dst + _i), (u16 __user *)(_src + _i), e); \
_i += 2; \
} \
if (_len & 1) \
unsafe_get_user(*(u8 *)(_dst + _i), (u8 __user *)(_src + _i), e); \
} while (0)
#define unsafe_copy_to_user(d, s, l, e) \
do { \
u8 __user *_dst = (u8 __user *)(d); \
const u8 *_src = (const u8 *)(s); \
size_t _len = (l); \
int _i; \
\
for (_i = 0; _i < (_len & ~(sizeof(u64) - 1)); _i += sizeof(u64)) \
unsafe_put_user(*(u64 *)(_src + _i), (u64 __user *)(_dst + _i), e); \
if (_len & 4) { \
unsafe_put_user(*(u32*)(_src + _i), (u32 __user *)(_dst + _i), e); \
_i += 4; \
} \
if (_len & 2) { \
unsafe_put_user(*(u16*)(_src + _i), (u16 __user *)(_dst + _i), e); \
_i += 2; \
} \
if (_len & 1) \
unsafe_put_user(*(u8*)(_src + _i), (u8 __user *)(_dst + _i), e); \
} while (0)
#define arch_get_kernel_nofault(dst, src, type, err_label) \
__get_user_size_goto(*((type *)(dst)), \
(__force type __user *)(src), sizeof(type), err_label)
#define arch_put_kernel_nofault(dst, src, type, err_label) \
__put_user_size_goto(*((type *)(src)), \
(__force type __user *)(dst), sizeof(type), err_label)
#endif /* _ARCH_POWERPC_UACCESS_H */