Re: [PATCH V9 14/21] csky: User access

2018-10-17 Thread Arnd Bergmann
On Tue, Oct 16, 2018 at 5:05 AM Guo Ren  wrote:
>
> The patch adds "user access from kernel" codes.
>
> Signed-off-by: Guo Ren 
> Cc: Arnd Bergmann 
> ---
>  arch/csky/include/asm/uaccess.h | 416 
> 
>  arch/csky/lib/usercopy.c| 262 +
>  2 files changed, 678 insertions(+)
>  create mode 100644 arch/csky/include/asm/uaccess.h
>  create mode 100644 arch/csky/lib/usercopy.c

Reviewed-by: Arnd Bergmann 

The 64-bit __put_user() is usually what everyone gets wrong, but
your version seems fine. Also the access_ok() checks and
the copy_to_user() result value all look correct.

Arnd


[PATCH V9 14/21] csky: User access

2018-10-15 Thread Guo Ren
The patch adds "user access from kernel" codes.

Signed-off-by: Guo Ren 
Cc: Arnd Bergmann 
---
 arch/csky/include/asm/uaccess.h | 416 
 arch/csky/lib/usercopy.c| 262 +
 2 files changed, 678 insertions(+)
 create mode 100644 arch/csky/include/asm/uaccess.h
 create mode 100644 arch/csky/lib/usercopy.c

diff --git a/arch/csky/include/asm/uaccess.h b/arch/csky/include/asm/uaccess.h
new file mode 100644
index 000..acaf0e210
--- /dev/null
+++ b/arch/csky/include/asm/uaccess.h
@@ -0,0 +1,416 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#ifndef __ASM_CSKY_UACCESS_H
+#define __ASM_CSKY_UACCESS_H
+
+/*
+ * User space memory access functions
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define VERIFY_READ0
+#define VERIFY_WRITE   1
+
+static inline int access_ok(int type, const void *addr, unsigned long size)
+{
+   unsigned long limit = current_thread_info()->addr_limit.seg;
+
+   return (((unsigned long)addr < limit) &&
+   ((unsigned long)(addr + size) < limit));
+}
+
+static inline int verify_area(int type, const void *addr, unsigned long size)
+{
+   return access_ok(type, addr, size) ? 0 : -EFAULT;
+}
+
+#define __addr_ok(addr) (access_ok(VERIFY_READ, addr, 0))
+
+extern int __put_user_bad(void);
+
+/*
+ * Tell gcc we read from memory instead of writing: this is because
+ * we do not write to any memory gcc knows about, so there are no
+ * aliasing issues.
+ */
+
+/*
+ * 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
+ * Ckcore, 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) \
+   __put_user_check((x), (ptr), sizeof(*(ptr)))
+
+#define __put_user(x, ptr) \
+   __put_user_nocheck((x), (ptr), sizeof(*(ptr)))
+
+#define __ptr(x) ((unsigned long *)(x))
+
+#define get_user(x, ptr) \
+   __get_user_check((x), (ptr), sizeof(*(ptr)))
+
+#define __get_user(x, ptr) \
+   __get_user_nocheck((x), (ptr), sizeof(*(ptr)))
+
+#define __put_user_nocheck(x, ptr, size)   \
+({ \
+   long __pu_err = 0;  \
+   typeof(*(ptr)) *__pu_addr = (ptr);  \
+   typeof(*(ptr)) __pu_val = (typeof(*(ptr)))(x);  \
+   if (__pu_addr)  \
+   __put_user_size(__pu_val, (__pu_addr), (size),  \
+   __pu_err);  \
+   __pu_err;   \
+})
+
+#define __put_user_check(x, ptr, size) \
+({ \
+   long __pu_err = -EFAULT;\
+   typeof(*(ptr)) *__pu_addr = (ptr);  \
+   typeof(*(ptr)) __pu_val = (typeof(*(ptr)))(x);  \
+   if (access_ok(VERIFY_WRITE, __pu_addr, size) && __pu_addr)  \
+   __put_user_size(__pu_val, __pu_addr, (size), __pu_err); \
+   __pu_err;   \
+})
+
+#define __put_user_size(x, ptr, size, retval)  \
+do {   \
+   retval = 0; \
+   switch (size) { \
+   case 1: \
+   __put_user_asm_b(x, ptr, retval);   \
+   break;  \
+   case 2: \
+   __put_user_asm_h(x, ptr, retval);   \
+   break;  \
+   case 4: \
+   __put_user_asm_w(x, ptr, retval);   \
+   break;  \
+   case 8: \
+   __put_user_asm_64(x, ptr, retval