diff options
Diffstat (limited to 'arch/microblaze/lib')
| -rw-r--r-- | arch/microblaze/lib/Makefile | 21 | ||||
| -rw-r--r-- | arch/microblaze/lib/ashldi3.c | 28 | ||||
| -rw-r--r-- | arch/microblaze/lib/ashrdi3.c | 30 | ||||
| -rw-r--r-- | arch/microblaze/lib/cmpdi2.c | 26 | ||||
| -rw-r--r-- | arch/microblaze/lib/divsi3.S | 73 | ||||
| -rw-r--r-- | arch/microblaze/lib/fastcopy.S | 10 | ||||
| -rw-r--r-- | arch/microblaze/lib/libgcc.h | 32 | ||||
| -rw-r--r-- | arch/microblaze/lib/lshrdi3.c | 28 | ||||
| -rw-r--r-- | arch/microblaze/lib/memcpy.c | 59 | ||||
| -rw-r--r-- | arch/microblaze/lib/memmove.c | 70 | ||||
| -rw-r--r-- | arch/microblaze/lib/memset.c | 39 | ||||
| -rw-r--r-- | arch/microblaze/lib/modsi3.S | 73 | ||||
| -rw-r--r-- | arch/microblaze/lib/muldi3.c | 57 | ||||
| -rw-r--r-- | arch/microblaze/lib/mulsi3.S | 46 | ||||
| -rw-r--r-- | arch/microblaze/lib/uaccess.c | 48 | ||||
| -rw-r--r-- | arch/microblaze/lib/uaccess_old.S | 173 | ||||
| -rw-r--r-- | arch/microblaze/lib/ucmpdi2.c | 20 | ||||
| -rw-r--r-- | arch/microblaze/lib/udivsi3.S | 84 | ||||
| -rw-r--r-- | arch/microblaze/lib/umodsi3.S | 86 |
19 files changed, 891 insertions, 112 deletions
diff --git a/arch/microblaze/lib/Makefile b/arch/microblaze/lib/Makefile index b579db068c0..844960e8ae1 100644 --- a/arch/microblaze/lib/Makefile +++ b/arch/microblaze/lib/Makefile @@ -2,6 +2,12 @@ # Makefile # +ifdef CONFIG_FUNCTION_TRACER +CFLAGS_REMOVE_ashldi3.o = -pg +CFLAGS_REMOVE_ashrdi3.o = -pg +CFLAGS_REMOVE_lshrdi3.o = -pg +endif + lib-y := memset.o ifeq ($(CONFIG_OPT_LIB_ASM),y) @@ -10,5 +16,16 @@ else lib-y += memcpy.o memmove.o endif -lib-$(CONFIG_NO_MMU) += uaccess.o -lib-$(CONFIG_MMU) += uaccess_old.o +lib-y += uaccess_old.o + +lib-y += ashldi3.o +lib-y += ashrdi3.o +lib-y += cmpdi2.o +lib-y += divsi3.o +lib-y += lshrdi3.o +lib-y += modsi3.o +lib-y += muldi3.o +lib-y += mulsi3.o +lib-y += ucmpdi2.o +lib-y += udivsi3.o +lib-y += umodsi3.o diff --git a/arch/microblaze/lib/ashldi3.c b/arch/microblaze/lib/ashldi3.c new file mode 100644 index 00000000000..1af904cd972 --- /dev/null +++ b/arch/microblaze/lib/ashldi3.c @@ -0,0 +1,28 @@ +#include <linux/export.h> + +#include "libgcc.h" + +long long __ashldi3(long long u, word_type b) +{ + DWunion uu, w; + word_type bm; + + if (b == 0) + return u; + + uu.ll = u; + bm = 32 - b; + + if (bm <= 0) { + w.s.low = 0; + w.s.high = (unsigned int) uu.s.low << -bm; + } else { + const unsigned int carries = (unsigned int) uu.s.low >> bm; + + w.s.low = (unsigned int) uu.s.low << b; + w.s.high = ((unsigned int) uu.s.high << b) | carries; + } + + return w.ll; +} +EXPORT_SYMBOL(__ashldi3); diff --git a/arch/microblaze/lib/ashrdi3.c b/arch/microblaze/lib/ashrdi3.c new file mode 100644 index 00000000000..32c334c05d0 --- /dev/null +++ b/arch/microblaze/lib/ashrdi3.c @@ -0,0 +1,30 @@ +#include <linux/export.h> + +#include "libgcc.h" + +long long __ashrdi3(long long u, word_type b) +{ + DWunion uu, w; + word_type bm; + + if (b == 0) + return u; + + uu.ll = u; + bm = 32 - b; + + if (bm <= 0) { + /* w.s.high = 1..1 or 0..0 */ + w.s.high = + uu.s.high >> 31; + w.s.low = uu.s.high >> -bm; + } else { + const unsigned int carries = (unsigned int) uu.s.high << bm; + + w.s.high = uu.s.high >> b; + w.s.low = ((unsigned int) uu.s.low >> b) | carries; + } + + return w.ll; +} +EXPORT_SYMBOL(__ashrdi3); diff --git a/arch/microblaze/lib/cmpdi2.c b/arch/microblaze/lib/cmpdi2.c new file mode 100644 index 00000000000..67abc9ac1bd --- /dev/null +++ b/arch/microblaze/lib/cmpdi2.c @@ -0,0 +1,26 @@ +#include <linux/export.h> + +#include "libgcc.h" + +word_type __cmpdi2(long long a, long long b) +{ + const DWunion au = { + .ll = a + }; + const DWunion bu = { + .ll = b + }; + + if (au.s.high < bu.s.high) + return 0; + else if (au.s.high > bu.s.high) + return 2; + + if ((unsigned int) au.s.low < (unsigned int) bu.s.low) + return 0; + else if ((unsigned int) au.s.low > (unsigned int) bu.s.low) + return 2; + + return 1; +} +EXPORT_SYMBOL(__cmpdi2); diff --git a/arch/microblaze/lib/divsi3.S b/arch/microblaze/lib/divsi3.S new file mode 100644 index 00000000000..595b02d6e86 --- /dev/null +++ b/arch/microblaze/lib/divsi3.S @@ -0,0 +1,73 @@ +#include <linux/linkage.h> + +/* +* Divide operation for 32 bit integers. +* Input : Dividend in Reg r5 +* Divisor in Reg r6 +* Output: Result in Reg r3 +*/ + .text + .globl __divsi3 + .type __divsi3, @function + .ent __divsi3 +__divsi3: + .frame r1, 0, r15 + + addik r1, r1, -16 + swi r28, r1, 0 + swi r29, r1, 4 + swi r30, r1, 8 + swi r31, r1, 12 + + beqi r6, div_by_zero /* div_by_zero - division error */ + beqi r5, result_is_zero /* result is zero */ + bgeid r5, r5_pos + xor r28, r5, r6 /* get the sign of the result */ + rsubi r5, r5, 0 /* make r5 positive */ +r5_pos: + bgei r6, r6_pos + rsubi r6, r6, 0 /* make r6 positive */ +r6_pos: + addik r30, r0, 0 /* clear mod */ + addik r3, r0, 0 /* clear div */ + addik r29, r0, 32 /* initialize the loop count */ + + /* first part try to find the first '1' in the r5 */ +div0: + blti r5, div2 /* this traps r5 == 0x80000000 */ +div1: + add r5, r5, r5 /* left shift logical r5 */ + bgtid r5, div1 + addik r29, r29, -1 +div2: + /* left shift logical r5 get the '1' into the carry */ + add r5, r5, r5 + addc r30, r30, r30 /* move that bit into the mod register */ + rsub r31, r6, r30 /* try to subtract (r30 a r6) */ + blti r31, mod_too_small + /* move the r31 to mod since the result was positive */ + or r30, r0, r31 + addik r3, r3, 1 +mod_too_small: + addik r29, r29, -1 + beqi r29, loop_end + add r3, r3, r3 /* shift in the '1' into div */ + bri div2 /* div2 */ +loop_end: + bgei r28, return_here + brid return_here + rsubi r3, r3, 0 /* negate the result */ +div_by_zero: +result_is_zero: + or r3, r0, r0 /* set result to 0 */ +return_here: +/* restore values of csrs and that of r3 and the divisor and the dividend */ + lwi r28, r1, 0 + lwi r29, r1, 4 + lwi r30, r1, 8 + lwi r31, r1, 12 + rtsd r15, 8 + addik r1, r1, 16 + +.size __divsi3, . - __divsi3 +.end __divsi3 diff --git a/arch/microblaze/lib/fastcopy.S b/arch/microblaze/lib/fastcopy.S index 02e3ab4eddf..62021d7e249 100644 --- a/arch/microblaze/lib/fastcopy.S +++ b/arch/microblaze/lib/fastcopy.S @@ -29,9 +29,14 @@ * between mem locations with size of xfer spec'd in bytes */ -#include <linux/linkage.h> +#ifdef __MICROBLAZEEL__ +#error Microblaze LE not support ASM optimized lib func. Disable OPT_LIB_ASM. +#endif +#include <linux/linkage.h> + .text .globl memcpy + .type memcpy, @function .ent memcpy memcpy: @@ -345,9 +350,11 @@ a_done: rtsd r15, 8 nop +.size memcpy, . - memcpy .end memcpy /*----------------------------------------------------------------------------*/ .globl memmove + .type memmove, @function .ent memmove memmove: @@ -659,4 +666,5 @@ d_done: rtsd r15, 8 nop +.size memmove, . - memmove .end memmove diff --git a/arch/microblaze/lib/libgcc.h b/arch/microblaze/lib/libgcc.h new file mode 100644 index 00000000000..ab077ef7e14 --- /dev/null +++ b/arch/microblaze/lib/libgcc.h @@ -0,0 +1,32 @@ +#ifndef __ASM_LIBGCC_H +#define __ASM_LIBGCC_H + +#include <asm/byteorder.h> + +typedef int word_type __attribute__ ((mode (__word__))); + +#ifdef __BIG_ENDIAN +struct DWstruct { + int high, low; +}; +#elif defined(__LITTLE_ENDIAN) +struct DWstruct { + int low, high; +}; +#else +#error I feel sick. +#endif + +typedef union { + struct DWstruct s; + long long ll; +} DWunion; + +extern long long __ashldi3(long long u, word_type b); +extern long long __ashrdi3(long long u, word_type b); +extern word_type __cmpdi2(long long a, long long b); +extern long long __lshrdi3(long long u, word_type b); +extern long long __muldi3(long long u, long long v); +extern word_type __ucmpdi2(unsigned long long a, unsigned long long b); + +#endif /* __ASM_LIBGCC_H */ diff --git a/arch/microblaze/lib/lshrdi3.c b/arch/microblaze/lib/lshrdi3.c new file mode 100644 index 00000000000..adcb253f11c --- /dev/null +++ b/arch/microblaze/lib/lshrdi3.c @@ -0,0 +1,28 @@ +#include <linux/export.h> + +#include "libgcc.h" + +long long __lshrdi3(long long u, word_type b) +{ + DWunion uu, w; + word_type bm; + + if (b == 0) + return u; + + uu.ll = u; + bm = 32 - b; + + if (bm <= 0) { + w.s.high = 0; + w.s.low = (unsigned int) uu.s.high >> -bm; + } else { + const unsigned int carries = (unsigned int) uu.s.high << bm; + + w.s.high = (unsigned int) uu.s.high >> b; + w.s.low = ((unsigned int) uu.s.low >> b) | carries; + } + + return w.ll; +} +EXPORT_SYMBOL(__lshrdi3); diff --git a/arch/microblaze/lib/memcpy.c b/arch/microblaze/lib/memcpy.c index cc2108b6b26..f536e81b816 100644 --- a/arch/microblaze/lib/memcpy.c +++ b/arch/microblaze/lib/memcpy.c @@ -24,26 +24,32 @@ * not any responsibility to update it. */ +#include <linux/export.h> #include <linux/types.h> #include <linux/stddef.h> #include <linux/compiler.h> -#include <linux/module.h> #include <linux/string.h> -#include <asm/system.h> #ifdef __HAVE_ARCH_MEMCPY +#ifndef CONFIG_OPT_LIB_FUNCTION void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c) { const char *src = v_src; char *dst = v_dst; -#ifndef CONFIG_OPT_LIB_FUNCTION + /* Simple, byte oriented memcpy. */ while (c--) *dst++ = *src++; return v_dst; -#else +} +#else /* CONFIG_OPT_LIB_FUNCTION */ +void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c) +{ + const char *src = v_src; + char *dst = v_dst; + /* The following code tries to optimize the copy by using unsigned * alignment. This will work fine if both source and destination are * aligned on the same boundary. However, if they are aligned on @@ -53,11 +59,11 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c) const uint32_t *i_src; uint32_t *i_dst; - if (c >= 4) { + if (likely(c >= 4)) { unsigned value, buf_hold; - /* Align the dstination to a word boundry. */ - /* This is done in an endian independant manner. */ + /* Align the destination to a word boundary. */ + /* This is done in an endian independent manner. */ switch ((unsigned long)dst & 3) { case 1: *dst++ = *src++; @@ -73,7 +79,7 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c) i_dst = (void *)dst; /* Choose a copy scheme based on the source */ - /* alignment relative to dstination. */ + /* alignment relative to destination. */ switch ((unsigned long)src & 3) { case 0x0: /* Both byte offsets are aligned */ i_src = (const void *)src; @@ -86,7 +92,7 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c) case 0x1: /* Unaligned - Off by 1 */ /* Word align the source */ i_src = (const void *) ((unsigned)src & ~3); - +#ifndef __MICROBLAZEEL__ /* Load the holding buffer */ buf_hold = *i_src++ << 8; @@ -95,7 +101,16 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c) *i_dst++ = buf_hold | value >> 24; buf_hold = value << 8; } +#else + /* Load the holding buffer */ + buf_hold = (*i_src++ & 0xFFFFFF00) >> 8; + for (; c >= 4; c -= 4) { + value = *i_src++; + *i_dst++ = buf_hold | ((value & 0xFF) << 24); + buf_hold = (value & 0xFFFFFF00) >> 8; + } +#endif /* Realign the source */ src = (const void *)i_src; src -= 3; @@ -103,7 +118,7 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c) case 0x2: /* Unaligned - Off by 2 */ /* Word align the source */ i_src = (const void *) ((unsigned)src & ~3); - +#ifndef __MICROBLAZEEL__ /* Load the holding buffer */ buf_hold = *i_src++ << 16; @@ -112,7 +127,16 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c) *i_dst++ = buf_hold | value >> 16; buf_hold = value << 16; } +#else + /* Load the holding buffer */ + buf_hold = (*i_src++ & 0xFFFF0000) >> 16; + for (; c >= 4; c -= 4) { + value = *i_src++; + *i_dst++ = buf_hold | ((value & 0xFFFF) << 16); + buf_hold = (value & 0xFFFF0000) >> 16; + } +#endif /* Realign the source */ src = (const void *)i_src; src -= 2; @@ -120,7 +144,7 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c) case 0x3: /* Unaligned - Off by 3 */ /* Word align the source */ i_src = (const void *) ((unsigned)src & ~3); - +#ifndef __MICROBLAZEEL__ /* Load the holding buffer */ buf_hold = *i_src++ << 24; @@ -129,7 +153,16 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c) *i_dst++ = buf_hold | value >> 8; buf_hold = value << 24; } +#else + /* Load the holding buffer */ + buf_hold = (*i_src++ & 0xFF000000) >> 24; + for (; c >= 4; c -= 4) { + value = *i_src++; + *i_dst++ = buf_hold | ((value & 0xFFFFFF) << 8); + buf_hold = (value & 0xFF000000) >> 24; + } +#endif /* Realign the source */ src = (const void *)i_src; src -= 1; @@ -139,7 +172,7 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c) } /* Finish off any remaining bytes */ - /* simple fast copy, ... unless a cache boundry is crossed */ + /* simple fast copy, ... unless a cache boundary is crossed */ switch (c) { case 3: *dst++ = *src++; @@ -150,7 +183,7 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c) } return v_dst; -#endif } +#endif /* CONFIG_OPT_LIB_FUNCTION */ EXPORT_SYMBOL(memcpy); #endif /* __HAVE_ARCH_MEMCPY */ diff --git a/arch/microblaze/lib/memmove.c b/arch/microblaze/lib/memmove.c index 0929198c5e6..3611ce70415 100644 --- a/arch/microblaze/lib/memmove.c +++ b/arch/microblaze/lib/memmove.c @@ -24,23 +24,19 @@ * not any responsibility to update it. */ +#include <linux/export.h> #include <linux/types.h> #include <linux/stddef.h> #include <linux/compiler.h> -#include <linux/module.h> #include <linux/string.h> #ifdef __HAVE_ARCH_MEMMOVE +#ifndef CONFIG_OPT_LIB_FUNCTION void *memmove(void *v_dst, const void *v_src, __kernel_size_t c) { const char *src = v_src; char *dst = v_dst; -#ifdef CONFIG_OPT_LIB_FUNCTION - const uint32_t *i_src; - uint32_t *i_dst; -#endif - if (!c) return v_dst; @@ -48,7 +44,6 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c) if (v_dst <= v_src) return memcpy(v_dst, v_src, c); -#ifndef CONFIG_OPT_LIB_FUNCTION /* copy backwards, from end to beginning */ src += c; dst += c; @@ -58,7 +53,22 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c) *--dst = *--src; return v_dst; -#else +} +#else /* CONFIG_OPT_LIB_FUNCTION */ +void *memmove(void *v_dst, const void *v_src, __kernel_size_t c) +{ + const char *src = v_src; + char *dst = v_dst; + const uint32_t *i_src; + uint32_t *i_dst; + + if (!c) + return v_dst; + + /* Use memcpy when source is higher than dest */ + if (v_dst <= v_src) + return memcpy(v_dst, v_src, c); + /* The following code tries to optimize the copy by using unsigned * alignment. This will work fine if both source and destination are * aligned on the same boundary. However, if they are aligned on @@ -73,8 +83,8 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c) if (c >= 4) { unsigned value, buf_hold; - /* Align the destination to a word boundry. */ - /* This is done in an endian independant manner. */ + /* Align the destination to a word boundary. */ + /* This is done in an endian independent manner. */ switch ((unsigned long)dst & 3) { case 3: @@ -104,7 +114,7 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c) case 0x1: /* Unaligned - Off by 1 */ /* Word align the source */ i_src = (const void *) (((unsigned)src + 4) & ~3); - +#ifndef __MICROBLAZEEL__ /* Load the holding buffer */ buf_hold = *--i_src >> 24; @@ -113,7 +123,17 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c) *--i_dst = buf_hold << 8 | value; buf_hold = value >> 24; } +#else + /* Load the holding buffer */ + buf_hold = (*--i_src & 0xFF) << 24; + for (; c >= 4; c -= 4) { + value = *--i_src; + *--i_dst = buf_hold | + ((value & 0xFFFFFF00) >> 8); + buf_hold = (value & 0xFF) << 24; + } +#endif /* Realign the source */ src = (const void *)i_src; src += 1; @@ -121,7 +141,7 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c) case 0x2: /* Unaligned - Off by 2 */ /* Word align the source */ i_src = (const void *) (((unsigned)src + 4) & ~3); - +#ifndef __MICROBLAZEEL__ /* Load the holding buffer */ buf_hold = *--i_src >> 16; @@ -130,7 +150,17 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c) *--i_dst = buf_hold << 16 | value; buf_hold = value >> 16; } +#else + /* Load the holding buffer */ + buf_hold = (*--i_src & 0xFFFF) << 16; + for (; c >= 4; c -= 4) { + value = *--i_src; + *--i_dst = buf_hold | + ((value & 0xFFFF0000) >> 16); + buf_hold = (value & 0xFFFF) << 16; + } +#endif /* Realign the source */ src = (const void *)i_src; src += 2; @@ -138,7 +168,7 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c) case 0x3: /* Unaligned - Off by 3 */ /* Word align the source */ i_src = (const void *) (((unsigned)src + 4) & ~3); - +#ifndef __MICROBLAZEEL__ /* Load the holding buffer */ buf_hold = *--i_src >> 8; @@ -147,7 +177,17 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c) *--i_dst = buf_hold << 24 | value; buf_hold = value >> 8; } +#else + /* Load the holding buffer */ + buf_hold = (*--i_src & 0xFFFFFF) << 8; + for (; c >= 4; c -= 4) { + value = *--i_src; + *--i_dst = buf_hold | + ((value & 0xFF000000) >> 24); + buf_hold = (value & 0xFFFFFF) << 8; + } +#endif /* Realign the source */ src = (const void *)i_src; src += 3; @@ -156,7 +196,7 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c) dst = (void *)i_dst; } - /* simple fast copy, ... unless a cache boundry is crossed */ + /* simple fast copy, ... unless a cache boundary is crossed */ /* Finish off any remaining bytes */ switch (c) { case 4: @@ -169,7 +209,7 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c) *--dst = *--src; } return v_dst; -#endif } +#endif /* CONFIG_OPT_LIB_FUNCTION */ EXPORT_SYMBOL(memmove); #endif /* __HAVE_ARCH_MEMMOVE */ diff --git a/arch/microblaze/lib/memset.c b/arch/microblaze/lib/memset.c index 4df851d41a2..04ea72c8a81 100644 --- a/arch/microblaze/lib/memset.c +++ b/arch/microblaze/lib/memset.c @@ -24,33 +24,47 @@ * not any responsibility to update it. */ +#include <linux/export.h> #include <linux/types.h> #include <linux/stddef.h> #include <linux/compiler.h> -#include <linux/module.h> #include <linux/string.h> #ifdef __HAVE_ARCH_MEMSET +#ifndef CONFIG_OPT_LIB_FUNCTION void *memset(void *v_src, int c, __kernel_size_t n) { + char *src = v_src; + + /* Truncate c to 8 bits */ + c = (c & 0xFF); + + /* Simple, byte oriented memset or the rest of count. */ + while (n--) + *src++ = c; + return v_src; +} +#else /* CONFIG_OPT_LIB_FUNCTION */ +void *memset(void *v_src, int c, __kernel_size_t n) +{ char *src = v_src; -#ifdef CONFIG_OPT_LIB_FUNCTION uint32_t *i_src; - uint32_t w32; -#endif + uint32_t w32 = 0; + /* Truncate c to 8 bits */ c = (c & 0xFF); -#ifdef CONFIG_OPT_LIB_FUNCTION - /* Make a repeating word out of it */ - w32 = c; - w32 |= w32 << 8; - w32 |= w32 << 16; + if (unlikely(c)) { + /* Make a repeating word out of it */ + w32 = c; + w32 |= w32 << 8; + w32 |= w32 << 16; + } - if (n >= 4) { + if (likely(n >= 4)) { /* Align the destination to a word boundary */ - /* This is done in an endian independant manner */ + /* This is done in an endian independent manner */ switch ((unsigned) src & 3) { case 1: *src++ = c; @@ -71,12 +85,13 @@ void *memset(void *v_src, int c, __kernel_size_t n) src = (void *)i_src; } -#endif + /* Simple, byte oriented memset or the rest of count. */ while (n--) *src++ = c; return v_src; } +#endif /* CONFIG_OPT_LIB_FUNCTION */ EXPORT_SYMBOL(memset); #endif /* __HAVE_ARCH_MEMSET */ diff --git a/arch/microblaze/lib/modsi3.S b/arch/microblaze/lib/modsi3.S new file mode 100644 index 00000000000..84e0bee6e8c --- /dev/null +++ b/arch/microblaze/lib/modsi3.S @@ -0,0 +1,73 @@ +#include <linux/linkage.h> + +/* +* modulo operation for 32 bit integers. +* Input : op1 in Reg r5 +* op2 in Reg r6 +* Output: op1 mod op2 in Reg r3 +*/ + + .text + .globl __modsi3 + .type __modsi3, @function + .ent __modsi3 + +__modsi3: + .frame r1, 0, r15 + + addik r1, r1, -16 + swi r28, r1, 0 + swi r29, r1, 4 + swi r30, r1, 8 + swi r31, r1, 12 + + beqi r6, div_by_zero /* div_by_zero division error */ + beqi r5, result_is_zero /* result is zero */ + bgeid r5, r5_pos + /* get the sign of the result [ depends only on the first arg] */ + add r28, r5, r0 + rsubi r5, r5, 0 /* make r5 positive */ +r5_pos: + bgei r6, r6_pos + rsubi r6, r6, 0 /* make r6 positive */ +r6_pos: + addik r3, r0, 0 /* clear mod */ + addik r30, r0, 0 /* clear div */ + addik r29, r0, 32 /* initialize the loop count */ +/* first part try to find the first '1' in the r5 */ +div1: + add r5, r5, r5 /* left shift logical r5 */ + bgeid r5, div1 + addik r29, r29, -1 +div2: + /* left shift logical r5 get the '1' into the carry */ + add r5, r5, r5 + addc r3, r3, r3 /* move that bit into the mod register */ + rsub r31, r6, r3 /* try to subtract (r30 a r6) */ + blti r31, mod_too_small + /* move the r31 to mod since the result was positive */ + or r3, r0, r31 + addik r30, r30, 1 +mod_too_small: + addik r29, r29, -1 + beqi r29, loop_end + add r30, r30, r30 /* shift in the '1' into div */ + bri div2 /* div2 */ +loop_end: + bgei r28, return_here + brid return_here + rsubi r3, r3, 0 /* negate the result */ +div_by_zero: +result_is_zero: + or r3, r0, r0 /* set result to 0 [both mod as well as div are 0] */ +return_here: +/* restore values of csrs and that of r3 and the divisor and the dividend */ + lwi r28, r1, 0 + lwi r29, r1, 4 + lwi r30, r1, 8 + lwi r31, r1, 12 + rtsd r15, 8 + addik r1, r1, 16 + +.size __modsi3, . - __modsi3 +.end __modsi3 diff --git a/arch/microblaze/lib/muldi3.c b/arch/microblaze/lib/muldi3.c new file mode 100644 index 00000000000..a3f9a03acdc --- /dev/null +++ b/arch/microblaze/lib/muldi3.c @@ -0,0 +1,57 @@ +#include <linux/export.h> + +#include "libgcc.h" + +#define W_TYPE_SIZE 32 + +#define __ll_B ((unsigned long) 1 << (W_TYPE_SIZE / 2)) +#define __ll_lowpart(t) ((unsigned long) (t) & (__ll_B - 1)) +#define __ll_highpart(t) ((unsigned long) (t) >> (W_TYPE_SIZE / 2)) + +/* If we still don't have umul_ppmm, define it using plain C. */ +#if !defined(umul_ppmm) +#define umul_ppmm(w1, w0, u, v) \ + do { \ + unsigned long __x0, __x1, __x2, __x3; \ + unsigned short __ul, __vl, __uh, __vh; \ + \ + __ul = __ll_lowpart(u); \ + __uh = __ll_highpart(u); \ + __vl = __ll_lowpart(v); \ + __vh = __ll_highpart(v); \ + \ + __x0 = (unsigned long) __ul * __vl; \ + __x1 = (unsigned long) __ul * __vh; \ + __x2 = (unsigned long) __uh * __vl; \ + __x3 = (unsigned long) __uh * __vh; \ + \ + __x1 += __ll_highpart(__x0); /* this can't give carry */\ + __x1 += __x2; /* but this indeed can */ \ + if (__x1 < __x2) /* did we get it? */ \ + __x3 += __ll_B; /* yes, add it in the proper pos */ \ + \ + (w1) = __x3 + __ll_highpart(__x1); \ + (w0) = __ll_lowpart(__x1) * __ll_B + __ll_lowpart(__x0);\ + } while (0) +#endif + +#if !defined(__umulsidi3) +#define __umulsidi3(u, v) ({ \ + DWunion __w; \ + umul_ppmm(__w.s.high, __w.s.low, u, v); \ + __w.ll; \ + }) +#endif + +long long __muldi3(long long u, long long v) +{ + const DWunion uu = {.ll = u}; + const DWunion vv = {.ll = v}; + DWunion w = {.ll = __umulsidi3(uu.s.low, vv.s.low)}; + + w.s.high += ((unsigned long) uu.s.low * (unsigned long) vv.s.high + + (unsigned long) uu.s.high * (unsigned long) vv.s.low); + + return w.ll; +} +EXPORT_SYMBOL(__muldi3); diff --git a/arch/microblaze/lib/mulsi3.S b/arch/microblaze/lib/mulsi3.S new file mode 100644 index 00000000000..90bd7b93afe --- /dev/null +++ b/arch/microblaze/lib/mulsi3.S @@ -0,0 +1,46 @@ +#include <linux/linkage.h> + +/* + * Multiply operation for 32 bit integers. + * Input : Operand1 in Reg r5 + * Operand2 in Reg r6 + * Output: Result [op1 * op2] in Reg r3 + */ + .text + .globl __mulsi3 + .type __mulsi3, @function + .ent __mulsi3 + +__mulsi3: + .frame r1, 0, r15 + add r3, r0, r0 + beqi r5, result_is_zero /* multiply by zero */ + beqi r6, result_is_zero /* multiply by zero */ + bgeid r5, r5_pos + xor r4, r5, r6 /* get the sign of the result */ + rsubi r5, r5, 0 /* make r5 positive */ +r5_pos: + bgei r6, r6_pos + rsubi r6, r6, 0 /* make r6 positive */ +r6_pos: + bri l1 +l2: + add r5, r5, r5 +l1: + srl r6, r6 + addc r7, r0, r0 + beqi r7, l2 + bneid r6, l2 + add r3, r3, r5 + blti r4, negateresult + rtsd r15, 8 + nop +negateresult: + rtsd r15, 8 + rsub r3, r3, r0 +result_is_zero: + rtsd r15, 8 + addi r3, r0, 0 + +.size __mulsi3, . - __mulsi3 +.end __mulsi3 diff --git a/arch/microblaze/lib/uaccess.c b/arch/microblaze/lib/uaccess.c deleted file mode 100644 index a853fe089c4..00000000000 --- a/arch/microblaze/lib/uaccess.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2006 Atmark Techno, Inc. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#include <linux/string.h> -#include <asm/uaccess.h> - -#include <asm/bug.h> - -long strnlen_user(const char __user *src, long count) -{ - return strlen(src) + 1; -} - -#define __do_strncpy_from_user(dst, src, count, res) \ - do { \ - char *tmp; \ - strncpy(dst, src, count); \ - for (tmp = dst; *tmp && count > 0; tmp++, count--) \ - ; \ - res = (tmp - dst); \ - } while (0) - -long __strncpy_from_user(char *dst, const char __user *src, long count) -{ - long res; - __do_strncpy_from_user(dst, src, count, res); - return res; -} - -long strncpy_from_user(char *dst, const char __user *src, long count) -{ - long res = -EFAULT; - if (access_ok(VERIFY_READ, src, 1)) - __do_strncpy_from_user(dst, src, count, res); - return res; -} - -unsigned long __copy_tofrom_user(void __user *to, - const void __user *from, unsigned long size) -{ - memcpy(to, from, size); - return 0; -} diff --git a/arch/microblaze/lib/uaccess_old.S b/arch/microblaze/lib/uaccess_old.S index 67f991c14b8..0e8cc2710c2 100644 --- a/arch/microblaze/lib/uaccess_old.S +++ b/arch/microblaze/lib/uaccess_old.S @@ -10,6 +10,7 @@ #include <linux/errno.h> #include <linux/linkage.h> +#include <asm/page.h> /* * int __strncpy_user(char *to, char *from, int len); @@ -22,6 +23,7 @@ .text .globl __strncpy_user; +.type __strncpy_user, @function .align 4; __strncpy_user: @@ -32,25 +34,24 @@ __strncpy_user: * r3 - temp count * r4 - temp val */ + beqid r7,3f addik r3,r7,0 /* temp_count = len */ - beqi r3,3f 1: lbu r4,r6,r0 + beqid r4,2f sb r4,r5,r0 - addik r3,r3,-1 - beqi r3,2f /* break on len */ - addik r5,r5,1 - bneid r4,1b addik r6,r6,1 /* delay slot */ - addik r3,r3,1 /* undo "temp_count--" */ + + addik r3,r3,-1 + bnei r3,1b /* break on len */ 2: rsubk r3,r3,r7 /* temp_count = len - temp_count */ 3: rtsd r15,8 nop - + .size __strncpy_user, . - __strncpy_user .section .fixup, "ax" .align 2 @@ -72,10 +73,11 @@ __strncpy_user: .text .globl __strnlen_user; +.type __strnlen_user, @function .align 4; __strnlen_user: + beqid r6,3f addik r3,r6,0 - beqi r3,3f 1: lbu r4,r5,r0 beqid r4,2f /* break on NUL */ @@ -90,7 +92,7 @@ __strnlen_user: 3: rtsd r15,8 nop - + .size __strnlen_user, . - __strnlen_user .section .fixup,"ax" 4: @@ -100,6 +102,49 @@ __strnlen_user: .section __ex_table,"a" .word 1b,4b +/* Loop unrolling for __copy_tofrom_user */ +#define COPY(offset) \ +1: lwi r4 , r6, 0x0000 + offset; \ +2: lwi r19, r6, 0x0004 + offset; \ +3: lwi r20, r6, 0x0008 + offset; \ +4: lwi r21, r6, 0x000C + offset; \ +5: lwi r22, r6, 0x0010 + offset; \ +6: lwi r23, r6, 0x0014 + offset; \ +7: lwi r24, r6, 0x0018 + offset; \ +8: lwi r25, r6, 0x001C + offset; \ +9: swi r4 , r5, 0x0000 + offset; \ +10: swi r19, r5, 0x0004 + offset; \ +11: swi r20, r5, 0x0008 + offset; \ +12: swi r21, r5, 0x000C + offset; \ +13: swi r22, r5, 0x0010 + offset; \ +14: swi r23, r5, 0x0014 + offset; \ +15: swi r24, r5, 0x0018 + offset; \ +16: swi r25, r5, 0x001C + offset; \ + .section __ex_table,"a"; \ + .word 1b, 33f; \ + .word 2b, 33f; \ + .word 3b, 33f; \ + .word 4b, 33f; \ + .word 5b, 33f; \ + .word 6b, 33f; \ + .word 7b, 33f; \ + .word 8b, 33f; \ + .word 9b, 33f; \ + .word 10b, 33f; \ + .word 11b, 33f; \ + .word 12b, 33f; \ + .word 13b, 33f; \ + .word 14b, 33f; \ + .word 15b, 33f; \ + .word 16b, 33f; \ + .text + +#define COPY_80(offset) \ + COPY(0x00 + offset);\ + COPY(0x20 + offset);\ + COPY(0x40 + offset);\ + COPY(0x60 + offset); + /* * int __copy_tofrom_user(char *to, char *from, int len) * Return: @@ -108,6 +153,7 @@ __strnlen_user: */ .text .globl __copy_tofrom_user; +.type __copy_tofrom_user, @function .align 4; __copy_tofrom_user: /* @@ -116,20 +162,105 @@ __copy_tofrom_user: * r7, r3 - count * r4 - tempval */ + beqid r7, 0f /* zero size is not likely */ + or r3, r5, r6 /* find if is any to/from unaligned */ + or r3, r3, r7 /* find if count is unaligned */ + andi r3, r3, 0x3 /* mask last 3 bits */ + bneid r3, bu1 /* if r3 is not zero then byte copying */ + or r3, r0, r0 + + rsubi r3, r7, PAGE_SIZE /* detect PAGE_SIZE */ + beqid r3, page; + or r3, r0, r0 + +w1: lw r4, r6, r3 /* at least one 4 byte copy */ +w2: sw r4, r5, r3 + addik r7, r7, -4 + bneid r7, w1 + addik r3, r3, 4 + addik r3, r7, 0 + rtsd r15, 8 + nop + + .section __ex_table,"a" + .word w1, 0f; + .word w2, 0f; + .text + +.align 4 /* Alignment is important to keep icache happy */ +page: /* Create room on stack and save registers for storign values */ + addik r1, r1, -40 + swi r5, r1, 0 + swi r6, r1, 4 + swi r7, r1, 8 + swi r19, r1, 12 + swi r20, r1, 16 + swi r21, r1, 20 + swi r22, r1, 24 + swi r23, r1, 28 + swi r24, r1, 32 + swi r25, r1, 36 +loop: /* r4, r19, r20, r21, r22, r23, r24, r25 are used for storing values */ + /* Loop unrolling to get performance boost */ + COPY_80(0x000); + COPY_80(0x080); + COPY_80(0x100); + COPY_80(0x180); + /* copy loop */ + addik r6, r6, 0x200 + addik r7, r7, -0x200 + bneid r7, loop + addik r5, r5, 0x200 + + /* Restore register content */ + lwi r5, r1, 0 + lwi r6, r1, 4 + lwi r7, r1, 8 + lwi r19, r1, 12 + lwi r20, r1, 16 + lwi r21, r1, 20 + lwi r22, r1, 24 + lwi r23, r1, 28 + lwi r24, r1, 32 + lwi r25, r1, 36 + addik r1, r1, 40 + /* return back */ + addik r3, r0, 0 + rtsd r15, 8 + nop + +/* Fault case - return temp count */ +33: + addik r3, r7, 0 + /* Restore register content */ + lwi r5, r1, 0 + lwi r6, r1, 4 + lwi r7, r1, 8 + lwi r19, r1, 12 + lwi r20, r1, 16 + lwi r21, r1, 20 + lwi r22, r1, 24 + lwi r23, r1, 28 + lwi r24, r1, 32 + lwi r25, r1, 36 + addik r1, r1, 40 + /* return back */ + rtsd r15, 8 + nop + +.align 4 /* Alignment is important to keep icache happy */ +bu1: lbu r4,r6,r3 +bu2: sb r4,r5,r3 + addik r7,r7,-1 + bneid r7,bu1 + addik r3,r3,1 /* delay slot */ +0: addik r3,r7,0 - beqi r3,3f -1: - lbu r4,r6,r0 - addik r6,r6,1 -2: - sb r4,r5,r0 - addik r3,r3,-1 - bneid r3,1b - addik r5,r5,1 /* delay slot */ -3: rtsd r15,8 nop - + .size __copy_tofrom_user, . - __copy_tofrom_user .section __ex_table,"a" - .word 1b,3b,2b,3b + .word bu1, 0b; + .word bu2, 0b; + .text diff --git a/arch/microblaze/lib/ucmpdi2.c b/arch/microblaze/lib/ucmpdi2.c new file mode 100644 index 00000000000..d05f1585121 --- /dev/null +++ b/arch/microblaze/lib/ucmpdi2.c @@ -0,0 +1,20 @@ +#include <linux/export.h> + +#include "libgcc.h" + +word_type __ucmpdi2(unsigned long long a, unsigned long long b) +{ + const DWunion au = {.ll = a}; + const DWunion bu = {.ll = b}; + + if ((unsigned int) au.s.high < (unsigned int) bu.s.high) + return 0; + else if ((unsigned int) au.s.high > (unsigned int) bu.s.high) + return 2; + if ((unsigned int) au.s.low < (unsigned int) bu.s.low) + return 0; + else if ((unsigned int) au.s.low > (unsigned int) bu.s.low) + return 2; + return 1; +} +EXPORT_SYMBOL(__ucmpdi2); diff --git a/arch/microblaze/lib/udivsi3.S b/arch/microblaze/lib/udivsi3.S new file mode 100644 index 00000000000..64cf57e4bb8 --- /dev/null +++ b/arch/microblaze/lib/udivsi3.S @@ -0,0 +1,84 @@ +#include <linux/linkage.h> + +/* +* Unsigned divide operation. +* Input : Divisor in Reg r5 +* Dividend in Reg r6 +* Output: Result in Reg r3 +*/ + + .text + .globl __udivsi3 + .type __udivsi3, @function + .ent __udivsi3 + +__udivsi3: + + .frame r1, 0, r15 + + addik r1, r1, -12 + swi r29, r1, 0 + swi r30, r1, 4 + swi r31, r1, 8 + + beqi r6, div_by_zero /* div_by_zero /* division error */ + beqid r5, result_is_zero /* result is zero */ + addik r30, r0, 0 /* clear mod */ + addik r29, r0, 32 /* initialize the loop count */ + +/* check if r6 and r5 are equal - if yes, return 1 */ + rsub r18, r5, r6 + beqid r18, return_here + addik r3, r0, 1 + +/* check if (uns)r6 is greater than (uns)r5. in that case, just return 0 */ + xor r18, r5, r6 + bgeid r18, 16 + add r3, r0, r0 /* we would anyways clear r3 */ + blti r6, return_here /* r6[bit 31 = 1] hence is greater */ + bri checkr6 + rsub r18, r6, r5 /* microblazecmp */ + blti r18, return_here + +/* if r6 [bit 31] is set, then return result as 1 */ +checkr6: + bgti r6, div0 + brid return_here + addik r3, r0, 1 + +/* first part try to find the first '1' in the r5 */ +div0: + blti r5, div2 +div1: + add r5, r5, r5 /* left shift logical r5 */ + bgtid r5, div1 + addik r29, r29, -1 +div2: +/* left shift logical r5 get the '1' into the carry */ + add r5, r5, r5 + addc r30, r30, r30 /* move that bit into the mod register */ + rsub r31, r6, r30 /* try to subtract (r30 a r6) */ + blti r31, mod_too_small +/* move the r31 to mod since the result was positive */ + or r30, r0, r31 + addik r3, r3, 1 +mod_too_small: + addik r29, r29, -1 + beqi r29, loop_end + add r3, r3, r3 /* shift in the '1' into div */ + bri div2 /* div2 */ +loop_end: + bri return_here +div_by_zero: +result_is_zero: + or r3, r0, r0 /* set result to 0 */ +return_here: +/* restore values of csrs and that of r3 and the divisor and the dividend */ + lwi r29, r1, 0 + lwi r30, r1, 4 + lwi r31, r1, 8 + rtsd r15, 8 + addik r1, r1, 12 + +.size __udivsi3, . - __udivsi3 +.end __udivsi3 diff --git a/arch/microblaze/lib/umodsi3.S b/arch/microblaze/lib/umodsi3.S new file mode 100644 index 00000000000..17d16bafae5 --- /dev/null +++ b/arch/microblaze/lib/umodsi3.S @@ -0,0 +1,86 @@ +#include <linux/linkage.h> + +/* + * Unsigned modulo operation for 32 bit integers. + * Input : op1 in Reg r5 + * op2 in Reg r6 + * Output: op1 mod op2 in Reg r3 + */ + + .text + .globl __umodsi3 + .type __umodsi3, @function + .ent __umodsi3 + +__umodsi3: + .frame r1, 0, r15 + + addik r1, r1, -12 + swi r29, r1, 0 + swi r30, r1, 4 + swi r31, r1, 8 + + beqi r6, div_by_zero /* div_by_zero - division error */ + beqid r5, result_is_zero /* result is zero */ + addik r3, r0, 0 /* clear div */ + addik r30, r0, 0 /* clear mod */ + addik r29, r0, 32 /* initialize the loop count */ + +/* check if r6 and r5 are equal /* if yes, return 0 */ + rsub r18, r5, r6 + beqi r18, return_here + +/* check if (uns)r6 is greater than (uns)r5. in that case, just return r5 */ + xor r18, r5, r6 + bgeid r18, 16 + addik r3, r5, 0 + blti r6, return_here + bri $lcheckr6 + rsub r18, r5, r6 /* microblazecmp */ + bgti r18, return_here + +/* if r6 [bit 31] is set, then return result as r5-r6 */ +$lcheckr6: + bgtid r6, div0 + addik r3, r0, 0 + addik r18, r0, 0x7fffffff + and r5, r5, r18 + and r6, r6, r18 + brid return_here + rsub r3, r6, r5 +/* first part: try to find the first '1' in the r5 */ +div0: + blti r5, div2 +div1: + add r5, r5, r5 /* left shift logical r5 */ + bgeid r5, div1 + addik r29, r29, -1 +div2: + /* left shift logical r5 get the '1' into the carry */ + add r5, r5, r5 + addc r3, r3, r3 /* move that bit into the mod register */ + rsub r31, r6, r3 /* try to subtract (r3 a r6) */ + blti r31, mod_too_small + /* move the r31 to mod since the result was positive */ + or r3, r0, r31 + addik r30, r30, 1 +mod_too_small: + addik r29, r29, -1 + beqi r29, loop_end + add r30, r30, r30 /* shift in the '1' into div */ + bri div2 /* div2 */ +loop_end: + bri return_here +div_by_zero: +result_is_zero: + or r3, r0, r0 /* set result to 0 */ +return_here: +/* restore values of csrs and that of r3 and the divisor and the dividend */ + lwi r29, r1, 0 + lwi r30, r1, 4 + lwi r31, r1, 8 + rtsd r15, 8 + addik r1, r1, 12 + +.size __umodsi3, . - __umodsi3 +.end __umodsi3 |
