aboutsummaryrefslogtreecommitdiff
path: root/arch/mn10300/lib/usercopy.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mn10300/lib/usercopy.c')
-rw-r--r--arch/mn10300/lib/usercopy.c166
1 files changed, 166 insertions, 0 deletions
diff --git a/arch/mn10300/lib/usercopy.c b/arch/mn10300/lib/usercopy.c
new file mode 100644
index 000000000000..a75b203059c1
--- /dev/null
+++ b/arch/mn10300/lib/usercopy.c
@@ -0,0 +1,166 @@
+/* MN10300 Userspace accessor functions
+ *
+ * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <asm/uaccess.h>
+
+unsigned long
+__generic_copy_to_user(void *to, const void *from, unsigned long n)
+{
+ if (access_ok(VERIFY_WRITE, to, n))
+ __copy_user(to, from, n);
+ return n;
+}
+
+unsigned long
+__generic_copy_from_user(void *to, const void *from, unsigned long n)
+{
+ if (access_ok(VERIFY_READ, from, n))
+ __copy_user_zeroing(to, from, n);
+ return n;
+}
+
+/*
+ * Copy a null terminated string from userspace.
+ */
+#define __do_strncpy_from_user(dst, src, count, res) \
+do { \
+ int w; \
+ asm volatile( \
+ " mov %1,%0\n" \
+ " cmp 0,%1\n" \
+ " beq 2f\n" \
+ "0:\n" \
+ " movbu (%5),%2\n" \
+ "1:\n" \
+ " movbu %2,(%6)\n" \
+ " inc %5\n" \
+ " inc %6\n" \
+ " cmp 0,%2\n" \
+ " beq 2f\n" \
+ " add -1,%1\n" \
+ " bne 0b\n" \
+ "2:\n" \
+ " sub %1,%0\n" \
+ "3:\n" \
+ " .section .fixup,\"ax\"\n" \
+ "4:\n" \
+ " mov %3,%0\n" \
+ " jmp 3b\n" \
+ " .previous\n" \
+ " .section __ex_table,\"a\"\n" \
+ " .balign 4\n" \
+ " .long 0b,4b\n" \
+ " .long 1b,4b\n" \
+ " .previous" \
+ :"=&r"(res), "=r"(count), "=&r"(w) \
+ :"i"(-EFAULT), "1"(count), "a"(src), "a"(dst) \
+ :"memory"); \
+} while (0)
+
+long
+__strncpy_from_user(char *dst, const char *src, long count)
+{
+ long res;
+ __do_strncpy_from_user(dst, src, count, res);
+ return res;
+}
+
+long
+strncpy_from_user(char *dst, const char *src, long count)
+{
+ long res = -EFAULT;
+ if (access_ok(VERIFY_READ, src, 1))
+ __do_strncpy_from_user(dst, src, count, res);
+ return res;
+}
+
+
+/*
+ * Clear a userspace memory
+ */
+#define __do_clear_user(addr, size) \
+do { \
+ int w; \
+ asm volatile( \
+ " cmp 0,%0\n" \
+ " beq 1f\n" \
+ " clr %1\n" \
+ "0: movbu %1,(%3,%2)\n" \
+ " inc %3\n" \
+ " cmp %0,%3\n" \
+ " bne 0b\n" \
+ "1:\n" \
+ " sub %3,%0\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: jmp 2b\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .balign 4\n" \
+ " .long 0b,3b\n" \
+ ".previous\n" \
+ : "+r"(size), "=&r"(w) \
+ : "a"(addr), "d"(0) \
+ : "memory"); \
+} while (0)
+
+unsigned long
+__clear_user(void *to, unsigned long n)
+{
+ __do_clear_user(to, n);
+ return n;
+}
+
+unsigned long
+clear_user(void *to, unsigned long n)
+{
+ if (access_ok(VERIFY_WRITE, to, n))
+ __do_clear_user(to, n);
+ return n;
+}
+
+/*
+ * Return the size of a string (including the ending 0)
+ *
+ * Return 0 on exception, a value greater than N if too long
+ */
+long strnlen_user(const char *s, long n)
+{
+ unsigned long res, w;
+
+ if (!__addr_ok(s))
+ return 0;
+
+ if (n < 0 || n + (u_long) s > current_thread_info()->addr_limit.seg)
+ n = current_thread_info()->addr_limit.seg - (u_long)s;
+
+ asm volatile(
+ "0: cmp %4,%0\n"
+ " beq 2f\n"
+ "1: movbu (%0,%3),%1\n"
+ " inc %0\n"
+ " cmp 0,%1\n"
+ " beq 3f\n"
+ " bra 0b\n"
+ "2: clr %0\n"
+ "3:\n"
+ ".section .fixup,\"ax\"\n"
+ "4: jmp 2b\n"
+ ".previous\n"
+ ".section __ex_table,\"a\"\n"
+ " .balign 4\n"
+ " .long 1b,4b\n"
+ ".previous\n"
+ :"=d"(res), "=&r"(w)
+ :"0"(0), "a"(s), "r"(n)
+ :"memory");
+ return res;
+}