summaryrefslogtreecommitdiffstats
path: root/arch/mn10300/lib
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mn10300/lib')
-rw-r--r--arch/mn10300/lib/Makefile7
-rw-r--r--arch/mn10300/lib/__ashldi3.S51
-rw-r--r--arch/mn10300/lib/__ashrdi3.S52
-rw-r--r--arch/mn10300/lib/__lshrdi3.S52
-rw-r--r--arch/mn10300/lib/ashrdi3.c61
-rw-r--r--arch/mn10300/lib/bitops.c51
-rw-r--r--arch/mn10300/lib/checksum.c99
-rw-r--r--arch/mn10300/lib/delay.c50
-rw-r--r--arch/mn10300/lib/do_csum.S162
-rw-r--r--arch/mn10300/lib/internal.h15
-rw-r--r--arch/mn10300/lib/lshrdi3.c60
-rw-r--r--arch/mn10300/lib/memcpy.S135
-rw-r--r--arch/mn10300/lib/memmove.S160
-rw-r--r--arch/mn10300/lib/memset.S121
-rw-r--r--arch/mn10300/lib/negdi2.c57
-rw-r--r--arch/mn10300/lib/usercopy.c166
16 files changed, 1299 insertions, 0 deletions
diff --git a/arch/mn10300/lib/Makefile b/arch/mn10300/lib/Makefile
new file mode 100644
index 000000000000..fdfa9ec5b5bb
--- /dev/null
+++ b/arch/mn10300/lib/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the MN10300-specific library files..
+#
+
+lib-y = delay.o usercopy.o checksum.o bitops.o memcpy.o memmove.o memset.o
+lib-y += do_csum.o
+lib-y += __ashldi3.o __ashrdi3.o __lshrdi3.o negdi2.o
diff --git a/arch/mn10300/lib/__ashldi3.S b/arch/mn10300/lib/__ashldi3.S
new file mode 100644
index 000000000000..a51a9506f00c
--- /dev/null
+++ b/arch/mn10300/lib/__ashldi3.S
@@ -0,0 +1,51 @@
+/* MN10300 64-bit arithmetic left shift
+ *
+ * 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/cache.h>
+
+ .text
+ .balign L1_CACHE_BYTES
+
+###############################################################################
+#
+# unsigned long long __ashldi3(unsigned long long value [D1:D0],
+# unsigned by [(12,SP)])
+#
+###############################################################################
+ .globl __ashldi3
+ .type __ashldi3,@function
+__ashldi3:
+ mov (12,sp),a0
+ and +63,a0
+ beq __ashldi3_zero
+
+ cmp +31,a0
+ bhi __ashldi3_32plus
+
+ # the count is in the range 1-31
+ asl a0,d1
+
+ mov +32,a1
+ sub a0,a1,a1 # a1 = 32 - count
+ lsr a1,d0,a1 # get overflow from LSW -> MSW
+
+ or_asl a1,d1,a0,d0 # insert overflow into MSW and
+ # shift the LSW
+ rets
+
+ .balign L1_CACHE_BYTES
+ # the count is in the range 32-63
+__ashldi3_32plus:
+ asl a0,d0,d1
+ clr d0
+__ashldi3_zero:
+ rets
+
+ .size __ashldi3, .-__ashldi3
diff --git a/arch/mn10300/lib/__ashrdi3.S b/arch/mn10300/lib/__ashrdi3.S
new file mode 100644
index 000000000000..6f42382728cb
--- /dev/null
+++ b/arch/mn10300/lib/__ashrdi3.S
@@ -0,0 +1,52 @@
+/* MN10300 64-bit arithmetic right shift
+ *
+ * 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/cache.h>
+
+ .text
+ .balign L1_CACHE_BYTES
+
+###############################################################################
+#
+# unsigned long long __ashrdi3(unsigned long long value [D1:D0],
+# unsigned by [(12,SP)])
+#
+###############################################################################
+ .globl __ashrdi3
+ .type __ashrdi3,@function
+__ashrdi3:
+ mov (12,sp),a0
+ and +63,a0
+ beq __ashrdi3_zero
+
+ cmp +31,a0
+ bhi __ashrdi3_32plus
+
+ # the count is in the range 1-31
+ lsr a0,d0
+
+ mov +32,a1
+ sub a0,a1,a1 # a1 = 32 - count
+ asl a1,d1,a1 # get underflow from MSW -> LSW
+
+ or_asr a1,d0,a0,d1 # insert underflow into LSW and
+ # shift the MSW
+ rets
+
+ .balign L1_CACHE_BYTES
+ # the count is in the range 32-63
+__ashrdi3_32plus:
+ asr a0,d1,d0
+ ext d0 # sign-extend result through MDR
+ mov mdr,d1
+__ashrdi3_zero:
+ rets
+
+ .size __ashrdi3, .-__ashrdi3
diff --git a/arch/mn10300/lib/__lshrdi3.S b/arch/mn10300/lib/__lshrdi3.S
new file mode 100644
index 000000000000..a686aef31e90
--- /dev/null
+++ b/arch/mn10300/lib/__lshrdi3.S
@@ -0,0 +1,52 @@
+/* MN10300 64-bit logical right shift
+ *
+ * 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/cache.h>
+
+ .text
+ .balign L1_CACHE_BYTES
+
+###############################################################################
+#
+# unsigned long long __lshrdi3(unsigned long long value [D1:D0],
+# unsigned by [(12,SP)])
+#
+###############################################################################
+ .globl __lshrdi3
+ .type __lshrdi3,@function
+__lshrdi3:
+ mov (12,sp),a0
+ and +63,a0
+ beq __lshrdi3_zero
+
+ cmp +31,a0
+ bhi __lshrdi3_32plus
+
+ # the count is in the range 1-31
+ lsr a0,d0
+
+ mov +32,a1
+ sub a0,a1,a1 # a1 = 32 - count
+ asl a1,d1,a1 # get underflow from MSW -> LSW
+
+ or_lsr a1,d0,a0,d1 # insert underflow into LSW and
+ # shift the MSW
+ rets
+
+ .balign L1_CACHE_BYTES
+ # the count is in the range 32-63
+__lshrdi3_32plus:
+ lsr a0,d1,d0
+ clr d1
+__lshrdi3_zero:
+ rets
+
+ .size __lshrdi3, .-__lshrdi3
diff --git a/arch/mn10300/lib/ashrdi3.c b/arch/mn10300/lib/ashrdi3.c
new file mode 100644
index 000000000000..c54f61ddf0b5
--- /dev/null
+++ b/arch/mn10300/lib/ashrdi3.c
@@ -0,0 +1,61 @@
+/* ashrdi3.c extracted from gcc-2.7.2/libgcc2.c which is: */
+/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 Licence for more details.
+
+You should have received a copy of the GNU General Public Licence
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#define BITS_PER_UNIT 8
+
+typedef int SItype __attribute__((mode(SI)));
+typedef unsigned int USItype __attribute__((mode(SI)));
+typedef int DItype __attribute__((mode(DI)));
+typedef int word_type __attribute__((mode(__word__)));
+
+struct DIstruct {
+ SItype low;
+ SItype high;
+};
+
+union DIunion {
+ struct DIstruct s;
+ DItype ll;
+};
+
+DItype __ashrdi3(DItype u, word_type b)
+{
+ union DIunion w;
+ union DIunion uu;
+ word_type bm;
+
+ if (b == 0)
+ return u;
+
+ uu.ll = u;
+
+ bm = (sizeof(SItype) * BITS_PER_UNIT) - b;
+ if (bm <= 0) {
+ /* w.s.high = 1..1 or 0..0 */
+ w.s.high = uu.s.high >> (sizeof(SItype) * BITS_PER_UNIT - 1);
+ w.s.low = uu.s.high >> -bm;
+ } else {
+ USItype carries = (USItype)uu.s.high << bm;
+ w.s.high = uu.s.high >> b;
+ w.s.low = ((USItype)uu.s.low >> b) | carries;
+ }
+
+ return w.ll;
+}
diff --git a/arch/mn10300/lib/bitops.c b/arch/mn10300/lib/bitops.c
new file mode 100644
index 000000000000..440a7dcbf87b
--- /dev/null
+++ b/arch/mn10300/lib/bitops.c
@@ -0,0 +1,51 @@
+/* MN10300 Non-trivial bit operations
+ *
+ * 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 <linux/module.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+
+/*
+ * try flipping a bit using BSET and BCLR
+ */
+void change_bit(int nr, volatile void *addr)
+{
+ if (test_bit(nr, addr))
+ goto try_clear_bit;
+
+try_set_bit:
+ if (!test_and_set_bit(nr, addr))
+ return;
+
+try_clear_bit:
+ if (test_and_clear_bit(nr, addr))
+ return;
+
+ goto try_set_bit;
+}
+
+/*
+ * try flipping a bit using BSET and BCLR and returning the old value
+ */
+int test_and_change_bit(int nr, volatile void *addr)
+{
+ if (test_bit(nr, addr))
+ goto try_clear_bit;
+
+try_set_bit:
+ if (!test_and_set_bit(nr, addr))
+ return 0;
+
+try_clear_bit:
+ if (test_and_clear_bit(nr, addr))
+ return 1;
+
+ goto try_set_bit;
+}
diff --git a/arch/mn10300/lib/checksum.c b/arch/mn10300/lib/checksum.c
new file mode 100644
index 000000000000..274f29ec33c1
--- /dev/null
+++ b/arch/mn10300/lib/checksum.c
@@ -0,0 +1,99 @@
+/* MN10300 Optimised checksumming wrappers
+ *
+ * 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 <linux/module.h>
+#include <linux/errno.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+#include <asm/checksum.h>
+#include "internal.h"
+
+static inline unsigned short from32to16(__wsum sum)
+{
+ asm(" add %1,%0 \n"
+ " addc 0xffff,%0 \n"
+ : "=r" (sum)
+ : "r" (sum << 16), "0" (sum & 0xffff0000)
+ );
+ return sum >> 16;
+}
+
+__sum16 ip_fast_csum(const void *iph, unsigned int ihl)
+{
+ return ~do_csum(iph, ihl * 4);
+}
+EXPORT_SYMBOL(ip_fast_csum);
+
+__wsum csum_partial(const void *buff, int len, __wsum sum)
+{
+ __wsum result;
+
+ result = do_csum(buff, len);
+ result += sum;
+ if (sum > result)
+ result++;
+ return result;
+}
+EXPORT_SYMBOL(csum_partial);
+
+__sum16 ip_compute_csum(const void *buff, int len)
+{
+ return ~from32to16(do_csum(buff, len));
+}
+EXPORT_SYMBOL(ip_compute_csum);
+
+__wsum csum_partial_copy(const void *src, void *dst, int len, __wsum sum)
+{
+ copy_from_user(dst, src, len);
+ return csum_partial(dst, len, sum);
+}
+EXPORT_SYMBOL(csum_partial_copy);
+
+__wsum csum_partial_copy_nocheck(const void *src, void *dst,
+ int len, __wsum sum)
+{
+ sum = csum_partial(src, len, sum);
+ memcpy(dst, src, len);
+ return sum;
+}
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
+
+__wsum csum_partial_copy_from_user(const void *src, void *dst,
+ int len, __wsum sum,
+ int *err_ptr)
+{
+ int missing;
+
+ missing = copy_from_user(dst, src, len);
+ if (missing) {
+ memset(dst + len - missing, 0, missing);
+ *err_ptr = -EFAULT;
+ }
+
+ return csum_partial(dst, len, sum);
+}
+EXPORT_SYMBOL(csum_partial_copy_from_user);
+
+__wsum csum_and_copy_to_user(const void *src, void *dst,
+ int len, __wsum sum,
+ int *err_ptr)
+{
+ int missing;
+
+ missing = copy_to_user(dst, src, len);
+ if (missing) {
+ memset(dst + len - missing, 0, missing);
+ *err_ptr = -EFAULT;
+ }
+
+ return csum_partial(src, len, sum);
+}
+EXPORT_SYMBOL(csum_and_copy_to_user);
diff --git a/arch/mn10300/lib/delay.c b/arch/mn10300/lib/delay.c
new file mode 100644
index 000000000000..cce66bc0822d
--- /dev/null
+++ b/arch/mn10300/lib/delay.c
@@ -0,0 +1,50 @@
+/* MN10300 Short delay interpolation routines
+ *
+ * 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 <linux/module.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <asm/div64.h>
+
+/*
+ * basic delay loop
+ */
+void __delay(unsigned long loops)
+{
+ int d0;
+
+ asm volatile(
+ " bra 1f \n"
+ " .align 4 \n"
+ "1: bra 2f \n"
+ " .align 4 \n"
+ "2: add -1,%0 \n"
+ " bne 2b \n"
+ : "=&d" (d0)
+ : "0" (loops));
+}
+EXPORT_SYMBOL(__delay);
+
+/*
+ * handle a delay specified in terms of microseconds
+ */
+void __udelay(unsigned long usecs)
+{
+ signed long ioclk, stop;
+
+ /* usecs * CLK / 1E6 */
+ stop = __muldiv64u(usecs, MN10300_TSCCLK, 1000000);
+ stop = TMTSCBC - stop;
+
+ do {
+ ioclk = TMTSCBC;
+ } while (stop < ioclk);
+}
+EXPORT_SYMBOL(__udelay);
diff --git a/arch/mn10300/lib/do_csum.S b/arch/mn10300/lib/do_csum.S
new file mode 100644
index 000000000000..e138994e1667
--- /dev/null
+++ b/arch/mn10300/lib/do_csum.S
@@ -0,0 +1,162 @@
+/* Optimised simple memory checksum
+ *
+ * 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/cache.h>
+
+ .section .text
+ .balign L1_CACHE_BYTES
+
+###############################################################################
+#
+# unsigned int do_csum(const unsigned char *buff, size_t len)
+#
+###############################################################################
+ .globl do_csum
+ .type do_csum,@function
+do_csum:
+ movm [d2,d3],(sp)
+ mov d0,(12,sp)
+ mov d1,(16,sp)
+ mov d1,d2 # count
+ mov d0,a0 # buff
+ clr d1 # accumulator
+
+ cmp +0,d2
+ beq do_csum_done # return if zero-length buffer
+
+ # 4-byte align the buffer pointer
+ btst +3,a0
+ beq do_csum_now_4b_aligned
+
+ btst +1,a0
+ beq do_csum_addr_not_odd
+ movbu (a0),d0
+ inc a0
+ asl +8,d0
+ add d0,d1
+ addc +0,d1
+ add -1,d2
+do_csum_addr_not_odd:
+
+ cmp +2,d2
+ bcs do_csum_fewer_than_4
+ btst +2,a0
+ beq do_csum_now_4b_aligned
+ movhu (a0+),d0
+ add d0,d1
+ addc +0,d1
+ add -2,d2
+ cmp +4,d2
+ bcs do_csum_fewer_than_4
+
+do_csum_now_4b_aligned:
+ # we want to checksum as much as we can in chunks of 32 bytes
+ cmp +31,d2
+ bls do_csum_remainder # 4-byte aligned remainder
+
+ add -32,d2
+ mov +32,d3
+
+do_csum_loop:
+ mov (a0+),d0
+ add d0,d1
+ mov (a0+),e0
+ addc e0,d1
+ mov (a0+),e1
+ addc e1,d1
+ mov (a0+),e3
+ addc e3,d1
+ mov (a0+),d0
+ addc d0,d1
+ mov (a0+),e0
+ addc e0,d1
+ mov (a0+),e1
+ addc e1,d1
+ mov (a0+),e3
+ addc e3,d1
+ addc +0,d1
+
+ sub d3,d2
+ bcc do_csum_loop
+
+ add d3,d2
+ beq do_csum_done
+
+do_csum_remainder:
+ # cut 16-31 bytes down to 0-15
+ cmp +16,d2
+ bcs do_csum_fewer_than_16
+ mov (a0+),d0
+ add d0,d1
+ mov (a0+),e0
+ addc e0,d1
+ mov (a0+),e1
+ addc e1,d1
+ mov (a0+),e3
+ addc e3,d1
+ addc +0,d1
+ add -16,d2
+ beq do_csum_done
+
+do_csum_fewer_than_16:
+ # copy the remaining whole words
+ cmp +4,d2
+ bcs do_csum_fewer_than_4
+ cmp +8,d2
+ bcs do_csum_one_word
+ cmp +12,d2
+ bcs do_csum_two_words
+ mov (a0+),d0
+ add d0,d1
+ addc +0,d1
+do_csum_two_words:
+ mov (a0+),d0
+ add d0,d1
+ addc +0,d1
+do_csum_one_word:
+ mov (a0+),d0
+ add d0,d1
+ addc +0,d1
+
+do_csum_fewer_than_4:
+ and +3,d2
+ beq do_csum_done
+ xor_cmp d0,d0,+2,d2
+ bcs do_csum_fewer_than_2
+ movhu (a0+),d0
+do_csum_fewer_than_2:
+ and +1,d2
+ beq do_csum_add_last_bit
+ movbu (a0),d3
+ add d3,d0
+do_csum_add_last_bit:
+ add d0,d1
+ addc +0,d1
+
+do_csum_done:
+ # compress the checksum down to 16 bits
+ mov +0xffff0000,d2
+ and d1,d2
+ asl +16,d1
+ add d2,d1,d0
+ addc +0xffff,d0
+ lsr +16,d0
+
+ # flip the halves of the word result if the buffer was oddly aligned
+ mov (12,sp),d1
+ and +1,d1
+ beq do_csum_not_oddly_aligned
+ swaph d0,d0 # exchange bits 15:8 with 7:0
+
+do_csum_not_oddly_aligned:
+ ret [d2,d3],8
+
+do_csum_end:
+ .size do_csum, do_csum_end-do_csum
diff --git a/arch/mn10300/lib/internal.h b/arch/mn10300/lib/internal.h
new file mode 100644
index 000000000000..0014eee5f04f
--- /dev/null
+++ b/arch/mn10300/lib/internal.h
@@ -0,0 +1,15 @@
+/* Internal definitions for the arch part of the kernel library
+ *
+ * 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.
+ */
+
+/*
+ * do_csum.S
+ */
+extern unsigned int do_csum(const unsigned char *, size_t);
diff --git a/arch/mn10300/lib/lshrdi3.c b/arch/mn10300/lib/lshrdi3.c
new file mode 100644
index 000000000000..e05e64e9ce96
--- /dev/null
+++ b/arch/mn10300/lib/lshrdi3.c
@@ -0,0 +1,60 @@
+/* lshrdi3.c extracted from gcc-2.7.2/libgcc2.c which is: */
+/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 Licence for more details.
+
+You should have received a copy of the GNU General Public Licence
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#define BITS_PER_UNIT 8
+
+typedef int SItype __attribute__((mode(SI)));
+typedef unsigned int USItype __attribute__((mode(SI)));
+typedef int DItype __attribute__((mode(DI)));
+typedef int word_type __attribute__((mode(__word__)));
+
+struct DIstruct {
+ SItype low;
+ SItype high;
+};
+
+union DIunion {
+ struct DIstruct s;
+ DItype ll;
+};
+
+DItype __lshrdi3(DItype u, word_type b)
+{
+ union DIunion w;
+ word_type bm;
+ union DIunion uu;
+
+ if (b == 0)
+ return u;
+
+ uu.ll = u;
+
+ bm = (sizeof(SItype) * BITS_PER_UNIT) - b;
+ if (bm <= 0) {
+ w.s.high = 0;
+ w.s.low = (USItype) uu.s.high >> -bm;
+ } else {
+ USItype carries = (USItype) uu.s.high << bm;
+ w.s.high = (USItype) uu.s.high >> b;
+ w.s.low = ((USItype) uu.s.low >> b) | carries;
+ }
+
+ return w.ll;
+}
diff --git a/arch/mn10300/lib/memcpy.S b/arch/mn10300/lib/memcpy.S
new file mode 100644
index 000000000000..25fb9bb2604f
--- /dev/null
+++ b/arch/mn10300/lib/memcpy.S
@@ -0,0 +1,135 @@
+/* MN10300 Optimised simple memory to memory copy
+ *
+ * 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/cache.h>
+
+ .section .text
+ .balign L1_CACHE_BYTES
+
+###############################################################################
+#
+# void *memcpy(void *dst, const void *src, size_t n)
+#
+###############################################################################
+ .globl memcpy
+ .type memcpy,@function
+memcpy:
+ movm [d2,d3],(sp)
+ mov d0,(12,sp)
+ mov d1,(16,sp)
+ mov (20,sp),d2 # count
+ mov d0,a0 # dst
+ mov d1,a1 # src
+ mov d0,e3 # the return value
+
+ cmp +0,d2
+ beq memcpy_done # return if zero-length copy
+
+ # see if the three parameters are all four-byte aligned
+ or d0,d1,d3
+ or d2,d3
+ and +3,d3
+ bne memcpy_1 # jump if not
+
+ # we want to transfer as much as we can in chunks of 32 bytes
+ cmp +31,d2
+ bls memcpy_4_remainder # 4-byte aligned remainder
+
+ movm [exreg1],(sp)
+ add -32,d2
+ mov +32,d3
+
+memcpy_4_loop:
+ mov (a1+),d0
+ mov (a1+),d1
+ mov (a1+),e0
+ mov (a1+),e1
+ mov (a1+),e4
+ mov (a1+),e5
+ mov (a1+),e6
+ mov (a1+),e7
+ mov d0,(a0+)
+ mov d1,(a0+)
+ mov e0,(a0+)
+ mov e1,(a0+)
+ mov e4,(a0+)
+ mov e5,(a0+)
+ mov e6,(a0+)
+ mov e7,(a0+)
+
+ sub d3,d2
+ bcc memcpy_4_loop
+
+ movm (sp),[exreg1]
+ add d3,d2
+ beq memcpy_4_no_remainder
+
+memcpy_4_remainder:
+ # cut 4-7 words down to 0-3
+ cmp +16,d2
+ bcs memcpy_4_three_or_fewer_words
+ mov (a1+),d0
+ mov (a1+),d1
+ mov (a1+),e0
+ mov (a1+),e1
+ mov d0,(a0+)
+ mov d1,(a0+)
+ mov e0,(a0+)
+ mov e1,(a0+)
+ add -16,d2
+ beq memcpy_4_no_remainder
+
+ # copy the remaining 1, 2 or 3 words
+memcpy_4_three_or_fewer_words:
+ cmp +8,d2
+ bcs memcpy_4_one_word
+ beq memcpy_4_two_words
+ mov (a1+),d0
+ mov d0,(a0+)
+memcpy_4_two_words:
+ mov (a1+),d0
+ mov d0,(a0+)
+memcpy_4_one_word:
+ mov (a1+),d0
+ mov d0,(a0+)
+
+memcpy_4_no_remainder:
+ # check we copied the correct amount
+ # TODO: REMOVE CHECK
+ sub e3,a0,d2
+ mov (20,sp),d1
+ cmp d2,d1
+ beq memcpy_done
+ break
+ break
+ break
+
+memcpy_done:
+ mov e3,a0
+ ret [d2,d3],8
+
+ # handle misaligned copying
+memcpy_1:
+ add -1,d2
+ mov +1,d3
+ setlb # setlb requires the next insns
+ # to occupy exactly 4 bytes
+
+ sub d3,d2
+ movbu (a1),d0
+ movbu d0,(a0)
+ add_add d3,a1,d3,a0
+ lcc
+
+ mov e3,a0
+ ret [d2,d3],8
+
+memcpy_end:
+ .size memcpy, memcpy_end-memcpy
diff --git a/arch/mn10300/lib/memmove.S b/arch/mn10300/lib/memmove.S
new file mode 100644
index 000000000000..20b07b62b77c
--- /dev/null
+++ b/arch/mn10300/lib/memmove.S
@@ -0,0 +1,160 @@
+/* MN10300 Optimised simple memory to memory copy, with support for overlapping
+ * regions
+ *
+ * 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/cache.h>
+
+ .section .text
+ .balign L1_CACHE_BYTES
+
+###############################################################################
+#
+# void *memmove(void *dst, const void *src, size_t n)
+#
+###############################################################################
+ .globl memmove
+ .type memmove,@function
+memmove:
+ # fall back to memcpy if dst < src to work bottom up
+ cmp d1,d0
+ bcs memmove_memcpy
+
+ # work top down
+ movm [d2,d3],(sp)
+ mov d0,(12,sp)
+ mov d1,(16,sp)
+ mov (20,sp),d2 # count
+ add d0,d2,a0 # dst end
+ add d1,d2,a1 # src end
+ mov d0,e3 # the return value
+
+ cmp +0,d2
+ beq memmove_done # return if zero-length copy
+
+ # see if the three parameters are all four-byte aligned
+ or d0,d1,d3
+ or d2,d3
+ and +3,d3
+ bne memmove_1 # jump if not
+
+ # we want to transfer as much as we can in chunks of 32 bytes
+ add -4,a1
+ cmp +31,d2
+ bls memmove_4_remainder # 4-byte aligned remainder
+
+ add -32,d2
+ mov +32,d3
+
+memmove_4_loop:
+ mov (a1),d0
+ sub_sub +4,a1,+4,a0
+ mov d0,(a0)
+ mov (a1),d1
+ sub_sub +4,a1,+4,a0
+ mov d1,(a0)
+
+ mov (a1),d0
+ sub_sub +4,a1,+4,a0
+ mov d0,(a0)
+ mov (a1),d1
+ sub_sub +4,a1,+4,a0
+ mov d1,(a0)
+
+ mov (a1),d0
+ sub_sub +4,a1,+4,a0
+ mov d0,(a0)
+ mov (a1),d1
+ sub_sub +4,a1,+4,a0
+ mov d1,(a0)
+
+ mov (a1),d0
+ sub_sub +4,a1,+4,a0
+ mov d0,(a0)
+ mov (a1),d1
+ sub_sub +4,a1,+4,a0
+ mov d1,(a0)
+
+ sub d3,d2
+ bcc memmove_4_loop
+
+ add d3,d2
+ beq memmove_4_no_remainder
+
+memmove_4_remainder:
+ # cut 4-7 words down to 0-3
+ cmp +16,d2
+ bcs memmove_4_three_or_fewer_words
+ mov (a1),d0
+ sub_sub +4,a1,+4,a0
+ mov d0,(a0)
+ mov (a1),d1
+ sub_sub +4,a1,+4,a0
+ mov d1,(a0)
+ mov (a1),e0
+ sub_sub +4,a1,+4,a0
+ mov e0,(a0)
+ mov (a1),e1
+ sub_sub +4,a1,+4,a0
+ mov e1,(a0)
+ add -16,d2
+ beq memmove_4_no_remainder
+
+ # copy the remaining 1, 2 or 3 words
+memmove_4_three_or_fewer_words:
+ cmp +8,d2
+ bcs memmove_4_one_word
+ beq memmove_4_two_words
+ mov (a1),d0
+ sub_sub +4,a1,+4,a0
+ mov d0,(a0)
+memmove_4_two_words:
+ mov (a1),d0
+ sub_sub +4,a1,+4,a0
+ mov d0,(a0)
+memmove_4_one_word:
+ mov (a1),d0
+ sub_sub +4,a1,+4,a0
+ mov d0,(a0)
+
+memmove_4_no_remainder:
+ # check we copied the correct amount
+ # TODO: REMOVE CHECK
+ sub e3,a0,d2
+ beq memmove_done
+ break
+ break
+ break
+
+memmove_done:
+ mov e3,a0
+ ret [d2,d3],8
+
+ # handle misaligned copying
+memmove_1:
+ add -1,a1
+ add -1,d2
+ mov +1,d3
+ setlb # setlb requires the next insns
+ # to occupy exactly 4 bytes
+
+ sub d3,d2
+ movbu (a1),d0
+ sub_sub d3,a1,d3,a0
+ movbu d0,(a0)
+ lcc
+
+ mov e3,a0
+ ret [d2,d3],8
+
+memmove_memcpy:
+ jmp memcpy
+
+memmove_end:
+ .size memmove, memmove_end-memmove
diff --git a/arch/mn10300/lib/memset.S b/arch/mn10300/lib/memset.S
new file mode 100644
index 000000000000..bc02e39629b7
--- /dev/null
+++ b/arch/mn10300/lib/memset.S
@@ -0,0 +1,121 @@
+/* Optimised simple memory fill
+ *
+ * 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/cache.h>
+
+ .section .text
+ .balign L1_CACHE_BYTES
+
+###############################################################################
+#
+# void *memset(void *dst, int c, size_t n)
+#
+###############################################################################
+ .globl memset
+ .type memset,@function
+memset:
+ movm [d2,d3],(sp)
+ mov d0,(12,sp)
+ mov d1,(16,sp)
+ mov (20,sp),d2 # count
+ mov d0,a0 # dst
+ mov d0,e3 # the return value
+
+ cmp +0,d2
+ beq memset_done # return if zero-length fill
+
+ # see if the region parameters are four-byte aligned
+ or d0,d2,d3
+ and +3,d3
+ bne memset_1 # jump if not
+
+ extbu d1
+ mov_asl d1,d3,8,d1
+ or_asl d1,d3,8,d1
+ or_asl d1,d3,8,d1
+ or d3,d1
+
+ # we want to transfer as much as we can in chunks of 32 bytes
+ cmp +31,d2
+ bls memset_4_remainder # 4-byte aligned remainder
+
+ add -32,d2
+ mov +32,d3
+
+memset_4_loop:
+ mov d1,(a0+)
+ mov d1,(a0+)
+ mov d1,(a0+)
+ mov d1,(a0+)
+ mov d1,(a0+)
+ mov d1,(a0+)
+ mov d1,(a0+)
+ mov d1,(a0+)
+
+ sub d3,d2
+ bcc memset_4_loop
+
+ add d3,d2
+ beq memset_4_no_remainder
+
+memset_4_remainder:
+ # cut 4-7 words down to 0-3
+ cmp +16,d2
+ bcs memset_4_three_or_fewer_words
+ mov d1,(a0+)
+ mov d1,(a0+)
+ mov d1,(a0+)
+ mov d1,(a0+)
+ add -16,d2
+ beq memset_4_no_remainder
+
+ # copy the remaining 1, 2 or 3 words
+memset_4_three_or_fewer_words:
+ cmp +8,d2
+ bcs memset_4_one_word
+ beq memset_4_two_words
+ mov d1,(a0+)
+memset_4_two_words:
+ mov d1,(a0+)
+memset_4_one_word:
+ mov d1,(a0+)
+
+memset_4_no_remainder:
+ # check we set the correct amount
+ # TODO: REMOVE CHECK
+ sub e3,a0,d2
+ mov (20,sp),d1
+ cmp d2,d1
+ beq memset_done
+ break
+ break
+ break
+
+memset_done:
+ mov e3,a0
+ ret [d2,d3],8
+
+ # handle misaligned copying
+memset_1:
+ add -1,d2
+ mov +1,d3
+ setlb # setlb requires the next insns
+ # to occupy exactly 4 bytes
+
+ sub d3,d2
+ movbu d1,(a0)
+ inc a0
+ lcc
+
+ mov e3,a0
+ ret [d2,d3],8
+
+memset_end:
+ .size memset, memset_end-memset
diff --git a/arch/mn10300/lib/negdi2.c b/arch/mn10300/lib/negdi2.c
new file mode 100644
index 000000000000..eae4ecdd5f69
--- /dev/null
+++ b/arch/mn10300/lib/negdi2.c
@@ -0,0 +1,57 @@
+/* More subroutines needed by GCC output code on some machines. */
+/* Compile this one with gcc. */
+/* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+In addition to the permissions in the GNU General Public Licence, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file. (The General Public Licence restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+GNU CC 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 Licence for more details.
+
+You should have received a copy of the GNU General Public Licence
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* It is incorrect to include config.h here, because this file is being
+ compiled for the target, and hence definitions concerning only the host
+ do not apply. */
+
+#include <linux/types.h>
+
+union DWunion {
+ s64 ll;
+ struct {
+ s32 low;
+ s32 high;
+ } s;
+};
+
+s64 __negdi2(s64 u)
+{
+ union DWunion w;
+ union DWunion uu;
+
+ uu.ll = u;
+
+ w.s.low = -uu.s.low;
+ w.s.high = -uu.s.high - ((u32) w.s.low > 0);
+
+ return w.ll;
+}
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;
+}