diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-15 10:49:15 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-15 10:49:15 -0800 |
commit | b293fca43be544483b6488d33ad4b3ed55881064 (patch) | |
tree | bf9f51967cd3a9fae3a8c1254b715b9c31aa56a6 /arch/riscv/include/asm/uaccess.h | |
parent | 0ef76878cfcf4d6b64972b283021f576a95d9216 (diff) | |
parent | fbe934d69eb7ed22b59514e9c1fe8871b8b198ec (diff) |
Merge tag 'riscv-for-linus-4.15-arch-v9-premerge' of git://git.kernel.org/pub/scm/linux/kernel/git/palmer/linux
Pull RISC-V architecture support from Palmer Dabbelt:
"This contains the core RISC-V Linux port, which has been through nine
rounds of review on various mailing lists. The port is not complete:
there's some cleanup patches moving through the review process, a
whole bunch of drivers that need some work, and a lot of feature
additions that will be needed.
The patches contained in this tag have been through nine rounds of
review on the various mailing lists. I have some outstanding cleanup
patches, but since there's been so much review on these patches I
thought it would be best to submit them as-is and then submit explicit
cleanup patches so everyone can review them. This first patch set is
big enough that it's a bit of a pain to constantly rewrite, and it's
caused a few headaches with various contributors.
The port is definately a work in progress. While what's there builds
and boots with 4.14, it's a bit hard to actually see anything happen
because there are no device drivers yet. I maintain a staging branch
that contains all the device drivers and cleanup that actually works,
but those patches won't all be ready for a while. I'd like to get what
we currently have into your tree so everyone can start working from a
single base -- of particular importance is allowing the glibc
upstreaming process to proceed so we can sort out any possibly
lingering user-visible ABI problems we might have.
Copied below is the ChangeLog that contains the history of this patch
set:
(v9) As per suggestions on our v8 patch set, I've split the core
architecture code out from our drivers and would like to submit
this patch set to be included into linux-next, with the goal
being to be merged in during the next merge window. This patch
set is based on 4.14-rc2, but if it's better to have it based on
something else then I can change it around.
This patch set contains just the core arch code for RISC-V, so
while it builds an nominally boots, you can't print or take an
interrupt so it's not that useful. If you're looking to actually
boot a system it would probably be better to use the full patch
set listed below.
We've collected a handful of tags from reviewers, and the
remainder of the patch set only got minimal feedback last time.
Here's what changed:
- We now use the device tree to initialize the timer driver so
it's less tighly coupled with the arch port.
- I cleaned up the defconfigs -- there's actually now just one,
and it's empty. For now I think we're OK with what the kernel
sets as defaults, but I anticipate we'll begin to expand this
as people start to use the port more.
- The VDSO symbols version is sane.
- We WFI while spinning in the boot loop.
- A handful of comments have been added.
While there are still a handful of FIXMEs in this patch set,
we've started to get enough interest from various users and
contributors that maintaining an out of tree patch set is
starting to become a big burden. Hopefully the patches are good
enough to merge now, which will at least get everyone working in
a more reasonable manner as we clean up the remaining issues.
(v8) I know it may not be the ideal time to submit a patch set right
now, as it's the middle of the merge window, but things have
calmed down quite a bit in the last month so I thought it would
be good to get everyone on the same page. There's been a handful
of changes since the last patch set, but most of them are fairly
minor:
- We changed PAGE_OFFSET to allowing mapping more physical
memory on 64-bit systems. This is user configurable, as it
triggers a different code model that generates slightly less
efficient code.
- The device tree binding documentation is back, I'd managed to
lose it at some point.
- We now pass the atomic64 test suite
- The SBI timer driver has been refactored.
(v7) It's been a while since my last patch set, but the changes han
been fairly minimal:
- The PCI cleanup patches have been dropped, we'll do them as a
separate patch set later.
- We've the Kconfig entries from CONFIG_ISA_* to
CONFIG_RISCV_ISA_*, to make grep easier.
- There have been a handful of memory model related tweaks in
I/O land, particularly relating the PCI and the upcoming
platform specification. There are significant comments in the
relevant files. This is still a WIP, but I think we're close
to getting as good as we're going to get until we end up with
some more specifications.
(v6) As it's been only a day since the v5 patch set, the changes are
pretty minimal:
- The patch set is now based on linux-next/master, which I
believe is a better base now that we're getting closer to
upstream.
- EARLY_PRINTK is no longer an option. Since the SBI console is
reasonable, there's no penalty to enabling it (and thus no
benefit to disabling it).
- The mmap syscalls were refactored a bit.
(v5) Things have really started to calm down, so this is fairly
similar to the v4 patch set. The most interesting changes
include:
- We've moved back to a single patch set.
- SMP support has been fixed, I was accidentally running on a
non-SMP configuration. There were various mistakes all over
the tree as a result of this.
- The cmpxchg syscalls have been removed, as they were deemed a
bad idea. As a result, RISC-V Linux systems mandate the A
extension. The corresponding Kconfig entry to enable builds
on non-A systems has been removed.
- A few more atomic fixes: mostly fence changes, but those
resulted in a handful of additional macros that were no
longer necessary.
- riscv_early_sie has been removed.
(v4) There have only been a few changes since the v3 patch set:
- The cmpxchg64 syscall is no longer enabled on 32-bit systems.
It's not possible to provide this on SMP systems, and it's
not necessary as glibc knows not to call it.
- We provide a ELF_HWCAP so users can determine the ISA of the
machine the kernel is running on.
- The multi-line comments are in a better form.
- There were a handful of headers that could be replaced with
the asm-generic versions, and a few unnecessary definitions.
- We no longer use printk, but instead use pr_*.
- A few Kconfig and defconfig entries have been cleaned up.
(v3) A highlight of the changes since the v2 patch set includes:
- We've split out all our drivers into separate patch sets,
which I've already sent out to the relevant maintainers. I
haven't included those patches in this patch set, but some of
them are necessary to build our port.
- The patch set is now split up differently: rather than being
split per directory it is split per topic. Hopefully this
will make it easier to review the port on the mailing list.
The split is a bit rough, so you probably still want to look
at the patch set as a whole.
- atomic.h has been completely rewritten and is hopefully now
correct. I've attempted to sanitize the various other memory
model related code as well, and I think it should all be sane
now aside from a handful of FIXMEs commented in the code.
- We've changed the cmpexchg syscall to always exist and to not
be multiplexed. There is also a VDSO entry for compare and
exchange, which allows kernels with the A extension to
execute user code without the A extension reasonably fast.
- Our user-visible register state now contains enough space for
the Q extension for 128-bit floating point, as well as a few
words to allow extensibility to future ISA extensions like
the eventual V extension for vectors.
- A handful of driver cleanups, but these have been split into
separate patch sets now so I won't duplicate them here.
(v2) A highlight of the changes since the v1 patch set includes:
- We've split out our drivers into the right places, which
means now there's a lot more patches. I'll be submitting
these patches to various subsystem maintainers and including
them in any future RISC-V patch sets until they've been
merged.
- The SBI console driver has been completely rewritten to use
the HVC helpers and is now significantly smaller.
- We've begun to use weaker barriers as opposed to just the big
"fence". There's still some work to do here, specifically:
- We need fences in the relaxed MMIO functions.
- The non-relaxed MMIO functions are missing R/W bits on their fences.
- Many AMOs need the aq and rl bits set.
- We now have thread_info in task_struct. As a result, sscratch
now contains TP instead of SP. This was necessary because
thread_info is no longer on the stack.
- A few shared routines have been added that we use instead of
creating another arch copy"
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
* tag 'riscv-for-linus-4.15-arch-v9-premerge' of git://git.kernel.org/pub/scm/linux/kernel/git/palmer/linux:
RISC-V: Build Infrastructure
RISC-V: User-facing API
RISC-V: Paging and MMU
RISC-V: Device, timer, IRQs, and the SBI
RISC-V: Task implementation
RISC-V: ELF and module implementation
RISC-V: Generic library routines and assembly
RISC-V: Atomic and Locking Code
RISC-V: Init and Halt Code
dt-bindings: RISC-V CPU Bindings
lib: Add shared copies of some GCC library routines
MAINTAINERS: Add RISC-V
Diffstat (limited to 'arch/riscv/include/asm/uaccess.h')
-rw-r--r-- | arch/riscv/include/asm/uaccess.h | 513 |
1 files changed, 513 insertions, 0 deletions
diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h new file mode 100644 index 000000000000..27b90d64814b --- /dev/null +++ b/arch/riscv/include/asm/uaccess.h @@ -0,0 +1,513 @@ +/* + * Copyright (C) 2012 Regents of the University of California + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This file was copied from include/asm-generic/uaccess.h + */ + +#ifndef _ASM_RISCV_UACCESS_H +#define _ASM_RISCV_UACCESS_H + +/* + * User space memory access functions + */ +#include <linux/errno.h> +#include <linux/compiler.h> +#include <linux/thread_info.h> +#include <asm/byteorder.h> +#include <asm/asm.h> + +#define __enable_user_access() \ + __asm__ __volatile__ ("csrs sstatus, %0" : : "r" (SR_SUM) : "memory") +#define __disable_user_access() \ + __asm__ __volatile__ ("csrc sstatus, %0" : : "r" (SR_SUM) : "memory") + +/* + * The fs value determines whether argument validity checking should be + * performed or not. If get_fs() == USER_DS, checking is performed, with + * get_fs() == KERNEL_DS, checking is bypassed. + * + * For historical reasons, these macros are grossly misnamed. + */ + +#define KERNEL_DS (~0UL) +#define USER_DS (TASK_SIZE) + +#define get_ds() (KERNEL_DS) +#define get_fs() (current_thread_info()->addr_limit) + +static inline void set_fs(mm_segment_t fs) +{ + current_thread_info()->addr_limit = fs; +} + +#define segment_eq(a, b) ((a) == (b)) + +#define user_addr_max() (get_fs()) + + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +/** + * access_ok: - Checks if a user space pointer is valid + * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE. Note that + * %VERIFY_WRITE is a superset of %VERIFY_READ - if it is safe + * to write to a block, it is always safe to read from it. + * @addr: User space pointer to start of block to check + * @size: Size of block to check + * + * Context: User context only. This function may sleep. + * + * Checks if a pointer to a block of memory in user space is valid. + * + * Returns true (nonzero) if the memory block may be valid, false (zero) + * if it is definitely invalid. + * + * Note that, depending on architecture, this function probably just + * checks that the pointer is in the user space range - after calling + * this function, memory access functions may still return -EFAULT. + */ +#define access_ok(type, addr, size) ({ \ + __chk_user_ptr(addr); \ + likely(__access_ok((unsigned long __force)(addr), (size))); \ +}) + +/* + * Ensure that the range [addr, addr+size) is within the process's + * address space + */ +static inline int __access_ok(unsigned long addr, unsigned long size) +{ + const mm_segment_t fs = get_fs(); + + return (size <= fs) && (addr <= (fs - size)); +} + +/* + * The exception table consists of pairs of addresses: the first is the + * address of an instruction that is allowed to fault, and the second is + * the address at which the program should continue. No registers are + * modified, so it is entirely up to the continuation code to figure out + * what to do. + * + * All the routines below use bits of fixup code that are out of line + * with the main instruction path. This means when everything is well, + * we don't even have to jump over them. Further, they do not intrude + * on our cache or tlb entries. + */ + +struct exception_table_entry { + unsigned long insn, fixup; +}; + +extern int fixup_exception(struct pt_regs *state); + +#if defined(__LITTLE_ENDIAN) +#define __MSW 1 +#define __LSW 0 +#elif defined(__BIG_ENDIAN) +#define __MSW 0 +#define __LSW 1 +#else +#error "Unknown endianness" +#endif + +/* + * The "__xxx" versions of the user access functions do not verify the address + * space - it must have been done previously with a separate "access_ok()" + * call. + */ + +#ifdef CONFIG_MMU +#define __get_user_asm(insn, x, ptr, err) \ +do { \ + uintptr_t __tmp; \ + __typeof__(x) __x; \ + __enable_user_access(); \ + __asm__ __volatile__ ( \ + "1:\n" \ + " " insn " %1, %3\n" \ + "2:\n" \ + " .section .fixup,\"ax\"\n" \ + " .balign 4\n" \ + "3:\n" \ + " li %0, %4\n" \ + " li %1, 0\n" \ + " jump 2b, %2\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + " .balign " RISCV_SZPTR "\n" \ + " " RISCV_PTR " 1b, 3b\n" \ + " .previous" \ + : "+r" (err), "=&r" (__x), "=r" (__tmp) \ + : "m" (*(ptr)), "i" (-EFAULT)); \ + __disable_user_access(); \ + (x) = __x; \ +} while (0) +#endif /* CONFIG_MMU */ + +#ifdef CONFIG_64BIT +#define __get_user_8(x, ptr, err) \ + __get_user_asm("ld", x, ptr, err) +#else /* !CONFIG_64BIT */ +#ifdef CONFIG_MMU +#define __get_user_8(x, ptr, err) \ +do { \ + u32 __user *__ptr = (u32 __user *)(ptr); \ + u32 __lo, __hi; \ + uintptr_t __tmp; \ + __enable_user_access(); \ + __asm__ __volatile__ ( \ + "1:\n" \ + " lw %1, %4\n" \ + "2:\n" \ + " lw %2, %5\n" \ + "3:\n" \ + " .section .fixup,\"ax\"\n" \ + " .balign 4\n" \ + "4:\n" \ + " li %0, %6\n" \ + " li %1, 0\n" \ + " li %2, 0\n" \ + " jump 3b, %3\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + " .balign " RISCV_SZPTR "\n" \ + " " RISCV_PTR " 1b, 4b\n" \ + " " RISCV_PTR " 2b, 4b\n" \ + " .previous" \ + : "+r" (err), "=&r" (__lo), "=r" (__hi), \ + "=r" (__tmp) \ + : "m" (__ptr[__LSW]), "m" (__ptr[__MSW]), \ + "i" (-EFAULT)); \ + __disable_user_access(); \ + (x) = (__typeof__(x))((__typeof__((x)-(x)))( \ + (((u64)__hi << 32) | __lo))); \ +} while (0) +#endif /* CONFIG_MMU */ +#endif /* CONFIG_64BIT */ + + +/** + * __get_user: - Get a simple variable from user space, with less checking. + * @x: Variable to store result. + * @ptr: Source address, in user space. + * + * Context: User context only. This function may sleep. + * + * This macro copies a single simple variable from user space to kernel + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and the result of + * dereferencing @ptr must be assignable to @x without a cast. + * + * Caller must check the pointer with access_ok() before calling this + * function. + * + * Returns zero on success, or -EFAULT on error. + * On error, the variable @x is set to zero. + */ +#define __get_user(x, ptr) \ +({ \ + register long __gu_err = 0; \ + const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ + __chk_user_ptr(__gu_ptr); \ + switch (sizeof(*__gu_ptr)) { \ + case 1: \ + __get_user_asm("lb", (x), __gu_ptr, __gu_err); \ + break; \ + case 2: \ + __get_user_asm("lh", (x), __gu_ptr, __gu_err); \ + break; \ + case 4: \ + __get_user_asm("lw", (x), __gu_ptr, __gu_err); \ + break; \ + case 8: \ + __get_user_8((x), __gu_ptr, __gu_err); \ + break; \ + default: \ + BUILD_BUG(); \ + } \ + __gu_err; \ +}) + +/** + * get_user: - Get a simple variable from user space. + * @x: Variable to store result. + * @ptr: Source address, in user space. + * + * Context: User context only. This function may sleep. + * + * This macro copies a single simple variable from user space to kernel + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and the result of + * dereferencing @ptr must be assignable to @x without a cast. + * + * Returns zero on success, or -EFAULT on error. + * On error, the variable @x is set to zero. + */ +#define get_user(x, ptr) \ +({ \ + const __typeof__(*(ptr)) __user *__p = (ptr); \ + might_fault(); \ + access_ok(VERIFY_READ, __p, sizeof(*__p)) ? \ + __get_user((x), __p) : \ + ((x) = 0, -EFAULT); \ +}) + + +#ifdef CONFIG_MMU +#define __put_user_asm(insn, x, ptr, err) \ +do { \ + uintptr_t __tmp; \ + __typeof__(*(ptr)) __x = x; \ + __enable_user_access(); \ + __asm__ __volatile__ ( \ + "1:\n" \ + " " insn " %z3, %2\n" \ + "2:\n" \ + " .section .fixup,\"ax\"\n" \ + " .balign 4\n" \ + "3:\n" \ + " li %0, %4\n" \ + " jump 2b, %1\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + " .balign " RISCV_SZPTR "\n" \ + " " RISCV_PTR " 1b, 3b\n" \ + " .previous" \ + : "+r" (err), "=r" (__tmp), "=m" (*(ptr)) \ + : "rJ" (__x), "i" (-EFAULT)); \ + __disable_user_access(); \ +} while (0) +#endif /* CONFIG_MMU */ + + +#ifdef CONFIG_64BIT +#define __put_user_8(x, ptr, err) \ + __put_user_asm("sd", x, ptr, err) +#else /* !CONFIG_64BIT */ +#ifdef CONFIG_MMU +#define __put_user_8(x, ptr, err) \ +do { \ + u32 __user *__ptr = (u32 __user *)(ptr); \ + u64 __x = (__typeof__((x)-(x)))(x); \ + uintptr_t __tmp; \ + __enable_user_access(); \ + __asm__ __volatile__ ( \ + "1:\n" \ + " sw %z4, %2\n" \ + "2:\n" \ + " sw %z5, %3\n" \ + "3:\n" \ + " .section .fixup,\"ax\"\n" \ + " .balign 4\n" \ + "4:\n" \ + " li %0, %6\n" \ + " jump 2b, %1\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + " .balign " RISCV_SZPTR "\n" \ + " " RISCV_PTR " 1b, 4b\n" \ + " " RISCV_PTR " 2b, 4b\n" \ + " .previous" \ + : "+r" (err), "=r" (__tmp), \ + "=m" (__ptr[__LSW]), \ + "=m" (__ptr[__MSW]) \ + : "rJ" (__x), "rJ" (__x >> 32), "i" (-EFAULT)); \ + __disable_user_access(); \ +} while (0) +#endif /* CONFIG_MMU */ +#endif /* CONFIG_64BIT */ + + +/** + * __put_user: - Write a simple value into user space, with less checking. + * @x: Value to copy to user space. + * @ptr: Destination address, in user space. + * + * Context: User context only. This function may sleep. + * + * This macro copies a single simple value from kernel space to user + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and @x must be assignable + * to the result of dereferencing @ptr. + * + * Caller must check the pointer with access_ok() before calling this + * function. + * + * Returns zero on success, or -EFAULT on error. + */ +#define __put_user(x, ptr) \ +({ \ + register long __pu_err = 0; \ + __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ + __chk_user_ptr(__gu_ptr); \ + switch (sizeof(*__gu_ptr)) { \ + case 1: \ + __put_user_asm("sb", (x), __gu_ptr, __pu_err); \ + break; \ + case 2: \ + __put_user_asm("sh", (x), __gu_ptr, __pu_err); \ + break; \ + case 4: \ + __put_user_asm("sw", (x), __gu_ptr, __pu_err); \ + break; \ + case 8: \ + __put_user_8((x), __gu_ptr, __pu_err); \ + break; \ + default: \ + BUILD_BUG(); \ + } \ + __pu_err; \ +}) + +/** + * put_user: - Write a simple value into user space. + * @x: Value to copy to user space. + * @ptr: Destination address, in user space. + * + * Context: User context only. This function may sleep. + * + * This macro copies a single simple value from kernel space to user + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and @x must be assignable + * to the result of dereferencing @ptr. + * + * Returns zero on success, or -EFAULT on error. + */ +#define put_user(x, ptr) \ +({ \ + __typeof__(*(ptr)) __user *__p = (ptr); \ + might_fault(); \ + access_ok(VERIFY_WRITE, __p, sizeof(*__p)) ? \ + __put_user((x), __p) : \ + -EFAULT; \ +}) + + +extern unsigned long __must_check __copy_user(void __user *to, + const void __user *from, unsigned long n); + +static inline unsigned long +raw_copy_from_user(void *to, const void __user *from, unsigned long n) +{ + return __copy_user(to, from, n); +} + +static inline unsigned long +raw_copy_to_user(void __user *to, const void *from, unsigned long n) +{ + return __copy_user(to, from, n); +} + +extern long strncpy_from_user(char *dest, const char __user *src, long count); + +extern long __must_check strlen_user(const char __user *str); +extern long __must_check strnlen_user(const char __user *str, long n); + +extern +unsigned long __must_check __clear_user(void __user *addr, unsigned long n); + +static inline +unsigned long __must_check clear_user(void __user *to, unsigned long n) +{ + might_fault(); + return access_ok(VERIFY_WRITE, to, n) ? + __clear_user(to, n) : n; +} + +/* + * Atomic compare-and-exchange, but with a fixup for userspace faults. Faults + * will set "err" to -EFAULT, while successful accesses return the previous + * value. + */ +#ifdef CONFIG_MMU +#define __cmpxchg_user(ptr, old, new, err, size, lrb, scb) \ +({ \ + __typeof__(ptr) __ptr = (ptr); \ + __typeof__(*(ptr)) __old = (old); \ + __typeof__(*(ptr)) __new = (new); \ + __typeof__(*(ptr)) __ret; \ + __typeof__(err) __err = 0; \ + register unsigned int __rc; \ + __enable_user_access(); \ + switch (size) { \ + case 4: \ + __asm__ __volatile__ ( \ + "0:\n" \ + " lr.w" #scb " %[ret], %[ptr]\n" \ + " bne %[ret], %z[old], 1f\n" \ + " sc.w" #lrb " %[rc], %z[new], %[ptr]\n" \ + " bnez %[rc], 0b\n" \ + "1:\n" \ + ".section .fixup,\"ax\"\n" \ + ".balign 4\n" \ + "2:\n" \ + " li %[err], %[efault]\n" \ + " jump 1b, %[rc]\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + ".balign " RISCV_SZPTR "\n" \ + " " RISCV_PTR " 1b, 2b\n" \ + ".previous\n" \ + : [ret] "=&r" (__ret), \ + [rc] "=&r" (__rc), \ + [ptr] "+A" (*__ptr), \ + [err] "=&r" (__err) \ + : [old] "rJ" (__old), \ + [new] "rJ" (__new), \ + [efault] "i" (-EFAULT)); \ + break; \ + case 8: \ + __asm__ __volatile__ ( \ + "0:\n" \ + " lr.d" #scb " %[ret], %[ptr]\n" \ + " bne %[ret], %z[old], 1f\n" \ + " sc.d" #lrb " %[rc], %z[new], %[ptr]\n" \ + " bnez %[rc], 0b\n" \ + "1:\n" \ + ".section .fixup,\"ax\"\n" \ + ".balign 4\n" \ + "2:\n" \ + " li %[err], %[efault]\n" \ + " jump 1b, %[rc]\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + ".balign " RISCV_SZPTR "\n" \ + " " RISCV_PTR " 1b, 2b\n" \ + ".previous\n" \ + : [ret] "=&r" (__ret), \ + [rc] "=&r" (__rc), \ + [ptr] "+A" (*__ptr), \ + [err] "=&r" (__err) \ + : [old] "rJ" (__old), \ + [new] "rJ" (__new), \ + [efault] "i" (-EFAULT)); \ + break; \ + default: \ + BUILD_BUG(); \ + } \ + __disable_user_access(); \ + (err) = __err; \ + __ret; \ +}) +#endif /* CONFIG_MMU */ + +#endif /* _ASM_RISCV_UACCESS_H */ |