diff options
Diffstat (limited to 'kernel/arch/mn10300/lib')
-rw-r--r-- | kernel/arch/mn10300/lib/Makefile | 7 | ||||
-rw-r--r-- | kernel/arch/mn10300/lib/__ashldi3.S | 51 | ||||
-rw-r--r-- | kernel/arch/mn10300/lib/__ashrdi3.S | 52 | ||||
-rw-r--r-- | kernel/arch/mn10300/lib/__lshrdi3.S | 52 | ||||
-rw-r--r-- | kernel/arch/mn10300/lib/__ucmpdi2.S | 43 | ||||
-rw-r--r-- | kernel/arch/mn10300/lib/ashrdi3.c | 61 | ||||
-rw-r--r-- | kernel/arch/mn10300/lib/bitops.c | 50 | ||||
-rw-r--r-- | kernel/arch/mn10300/lib/checksum.c | 100 | ||||
-rw-r--r-- | kernel/arch/mn10300/lib/delay.c | 51 | ||||
-rw-r--r-- | kernel/arch/mn10300/lib/do_csum.S | 157 | ||||
-rw-r--r-- | kernel/arch/mn10300/lib/internal.h | 15 | ||||
-rw-r--r-- | kernel/arch/mn10300/lib/lshrdi3.c | 60 | ||||
-rw-r--r-- | kernel/arch/mn10300/lib/memcpy.S | 135 | ||||
-rw-r--r-- | kernel/arch/mn10300/lib/memmove.S | 160 | ||||
-rw-r--r-- | kernel/arch/mn10300/lib/memset.S | 121 | ||||
-rw-r--r-- | kernel/arch/mn10300/lib/negdi2.c | 57 | ||||
-rw-r--r-- | kernel/arch/mn10300/lib/usercopy.c | 166 |
17 files changed, 1338 insertions, 0 deletions
diff --git a/kernel/arch/mn10300/lib/Makefile b/kernel/arch/mn10300/lib/Makefile new file mode 100644 index 000000000..0cd2346f4 --- /dev/null +++ b/kernel/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 __ucmpdi2.o diff --git a/kernel/arch/mn10300/lib/__ashldi3.S b/kernel/arch/mn10300/lib/__ashldi3.S new file mode 100644 index 000000000..a51a9506f --- /dev/null +++ b/kernel/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/kernel/arch/mn10300/lib/__ashrdi3.S b/kernel/arch/mn10300/lib/__ashrdi3.S new file mode 100644 index 000000000..6f4238272 --- /dev/null +++ b/kernel/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/kernel/arch/mn10300/lib/__lshrdi3.S b/kernel/arch/mn10300/lib/__lshrdi3.S new file mode 100644 index 000000000..a686aef31 --- /dev/null +++ b/kernel/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/kernel/arch/mn10300/lib/__ucmpdi2.S b/kernel/arch/mn10300/lib/__ucmpdi2.S new file mode 100644 index 000000000..60dcbdfe3 --- /dev/null +++ b/kernel/arch/mn10300/lib/__ucmpdi2.S @@ -0,0 +1,43 @@ +/* __ucmpdi2.S: 64-bit unsigned compare + * + * Copyright (C) 2008 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 License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + + + .text + .p2align 4 + +############################################################################### +# +# int __ucmpdi2(unsigned long long a [D0:D1], +# unsigned long long b [(SP,12),(SP,16)]) +# +# - returns 0, 1, or 2 as a <, =, > b respectively. +# +############################################################################### + .globl __ucmpdi2 + .type __ucmpdi2,@function +__ucmpdi2: + mov (12,sp),a0 # b.lsw + mov (16,sp),a1 # b.msw + + sub a0,d0 + subc a1,d1 # may clear Z, never sets it + bne __ucmpdi2_differ # a.msw != b.msw + mov +1,d0 + rets + +__ucmpdi2_differ: + # C flag is set if LE, clear if GE + subc d0,d0 # -1 if LE, 0 if GE + add +1,d0 # 0 if LE, 1 if GE + add d0,d0 # 0 if LE, 2 if GE + rets + + .size __ucmpdi2, .-__ucmpdi2 diff --git a/kernel/arch/mn10300/lib/ashrdi3.c b/kernel/arch/mn10300/lib/ashrdi3.c new file mode 100644 index 000000000..c54f61ddf --- /dev/null +++ b/kernel/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/kernel/arch/mn10300/lib/bitops.c b/kernel/arch/mn10300/lib/bitops.c new file mode 100644 index 000000000..37309cdb7 --- /dev/null +++ b/kernel/arch/mn10300/lib/bitops.c @@ -0,0 +1,50 @@ +/* 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> + +/* + * try flipping a bit using BSET and BCLR + */ +void change_bit(unsigned long 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(unsigned long 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/kernel/arch/mn10300/lib/checksum.c b/kernel/arch/mn10300/lib/checksum.c new file mode 100644 index 000000000..b6580f5d8 --- /dev/null +++ b/kernel/arch/mn10300/lib/checksum.c @@ -0,0 +1,100 @@ +/* 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) + : "cc" + ); + 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/kernel/arch/mn10300/lib/delay.c b/kernel/arch/mn10300/lib/delay.c new file mode 100644 index 000000000..8e7ceb8ba --- /dev/null +++ b/kernel/arch/mn10300/lib/delay.c @@ -0,0 +1,51 @@ +/* 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) + : "cc"); +} +EXPORT_SYMBOL(__delay); + +/* + * handle a delay specified in terms of microseconds + */ +void __udelay(unsigned long usecs) +{ + unsigned long start, stop, cnt; + + /* usecs * CLK / 1E6 */ + stop = __muldiv64u(usecs, MN10300_TSCCLK, 1000000); + start = TMTSCBC; + + do { + cnt = start - TMTSCBC; + } while (cnt < stop); +} +EXPORT_SYMBOL(__udelay); diff --git a/kernel/arch/mn10300/lib/do_csum.S b/kernel/arch/mn10300/lib/do_csum.S new file mode 100644 index 000000000..1d27bba0c --- /dev/null +++ b/kernel/arch/mn10300/lib/do_csum.S @@ -0,0 +1,157 @@ +/* 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, int len) +# +############################################################################### + .globl do_csum + .type do_csum,@function +do_csum: + movm [d2,d3],(sp) + mov d1,d2 # count + mov d0,a0 # buff + mov a0,a1 + clr d1 # accumulator + + cmp +0,d2 + ble do_csum_done # check for zero length or negative + + # 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 + 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 + 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 + mov (a0+),e0 + mov (a0+),e1 + mov (a0+),e3 + add d0,d1 + addc e0,d1 + addc e1,d1 + addc e3,d1 + mov (a0+),d0 + mov (a0+),e0 + mov (a0+),e1 + mov (a0+),e3 + addc d0,d1 + addc e0,d1 + addc e1,d1 + 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 + mov (a0+),e0 + mov (a0+),e1 + mov (a0+),e3 + add d0,d1 + addc e0,d1 + addc e1,d1 + 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 + and +1,d2 + beq do_csum_add_last_bit +do_csum_fewer_than_2: + 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,d0 + and d1,d0 + asl +16,d1 + add d1,d0 + addc +0xffff,d0 + lsr +16,d0 + + # flip the halves of the word result if the buffer was oddly aligned + and +1,a1 + 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 + + .size do_csum, .-do_csum diff --git a/kernel/arch/mn10300/lib/internal.h b/kernel/arch/mn10300/lib/internal.h new file mode 100644 index 000000000..0014eee5f --- /dev/null +++ b/kernel/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/kernel/arch/mn10300/lib/lshrdi3.c b/kernel/arch/mn10300/lib/lshrdi3.c new file mode 100644 index 000000000..e05e64e9c --- /dev/null +++ b/kernel/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/kernel/arch/mn10300/lib/memcpy.S b/kernel/arch/mn10300/lib/memcpy.S new file mode 100644 index 000000000..25fb9bb26 --- /dev/null +++ b/kernel/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/kernel/arch/mn10300/lib/memmove.S b/kernel/arch/mn10300/lib/memmove.S new file mode 100644 index 000000000..20b07b62b --- /dev/null +++ b/kernel/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/kernel/arch/mn10300/lib/memset.S b/kernel/arch/mn10300/lib/memset.S new file mode 100644 index 000000000..bc02e3962 --- /dev/null +++ b/kernel/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/kernel/arch/mn10300/lib/negdi2.c b/kernel/arch/mn10300/lib/negdi2.c new file mode 100644 index 000000000..eae4ecdd5 --- /dev/null +++ b/kernel/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/kernel/arch/mn10300/lib/usercopy.c b/kernel/arch/mn10300/lib/usercopy.c new file mode 100644 index 000000000..7826e6c36 --- /dev/null +++ b/kernel/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", "cc"); \ +} 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", "cc"); \ +} 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", "cc"); + return res; +} |