mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 19:00:25 +00:00
Blackfin: move string functions to normal lib/ assembly
Since 'extern inline' doesn't work correctly in the context of the Linux kernel (too many overriding defines), move the string functions to normal lib/ assembly files (like the existing mem funcs). This avoids the forced inline all over the kernel and allows us to place them constantly in L1. This also avoids some module failures when gcc inserts calls to string functions but the kernel build system doesn't fully consult the library archives. Signed-off-by: Robin Getz <robin.getz@analog.com> Signed-off-by: Mike Frysinger <vapier@gentoo.org>
This commit is contained in:
parent
80fcdb9593
commit
479ba60358
11 changed files with 226 additions and 184 deletions
|
@ -791,6 +791,34 @@ config MEMCPY_L1
|
|||
If enabled, the memcpy function is linked
|
||||
into L1 instruction memory. (less latency)
|
||||
|
||||
config STRCMP_L1
|
||||
bool "locate strcmp function in L1 Memory"
|
||||
default y
|
||||
help
|
||||
If enabled, the strcmp function is linked
|
||||
into L1 instruction memory (less latency).
|
||||
|
||||
config STRNCMP_L1
|
||||
bool "locate strncmp function in L1 Memory"
|
||||
default y
|
||||
help
|
||||
If enabled, the strncmp function is linked
|
||||
into L1 instruction memory (less latency).
|
||||
|
||||
config STRCPY_L1
|
||||
bool "locate strcpy function in L1 Memory"
|
||||
default y
|
||||
help
|
||||
If enabled, the strcpy function is linked
|
||||
into L1 instruction memory (less latency).
|
||||
|
||||
config STRNCPY_L1
|
||||
bool "locate strncpy function in L1 Memory"
|
||||
default y
|
||||
help
|
||||
If enabled, the strncpy function is linked
|
||||
into L1 instruction memory (less latency).
|
||||
|
||||
config SYS_BFIN_SPINLOCK_L1
|
||||
bool "Locate sys_bfin_spinlock function in L1 Memory"
|
||||
default y
|
||||
|
|
|
@ -12,121 +12,16 @@
|
|||
#ifdef __KERNEL__ /* only set these up for kernel code */
|
||||
|
||||
#define __HAVE_ARCH_STRCPY
|
||||
extern inline char *strcpy(char *dest, const char *src)
|
||||
{
|
||||
char *xdest = dest;
|
||||
char temp = 0;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"1:"
|
||||
"%2 = B [%1++] (Z);"
|
||||
"B [%0++] = %2;"
|
||||
"CC = %2;"
|
||||
"if cc jump 1b (bp);"
|
||||
: "+&a" (dest), "+&a" (src), "=&d" (temp)
|
||||
:
|
||||
: "memory", "CC");
|
||||
|
||||
return xdest;
|
||||
}
|
||||
extern char *strcpy(char *dest, const char *src);
|
||||
|
||||
#define __HAVE_ARCH_STRNCPY
|
||||
extern inline char *strncpy(char *dest, const char *src, size_t n)
|
||||
{
|
||||
char *xdest = dest;
|
||||
char temp = 0;
|
||||
|
||||
if (n == 0)
|
||||
return xdest;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"1:"
|
||||
"%3 = B [%1++] (Z);"
|
||||
"B [%0++] = %3;"
|
||||
"CC = %3;"
|
||||
"if ! cc jump 2f;"
|
||||
"%2 += -1;"
|
||||
"CC = %2 == 0;"
|
||||
"if ! cc jump 1b (bp);"
|
||||
"jump 4f;"
|
||||
"2:"
|
||||
/* if src is shorter than n, we need to null pad bytes now */
|
||||
"%3 = 0;"
|
||||
"3:"
|
||||
"%2 += -1;"
|
||||
"CC = %2 == 0;"
|
||||
"if cc jump 4f;"
|
||||
"B [%0++] = %3;"
|
||||
"jump 3b;"
|
||||
"4:"
|
||||
: "+&a" (dest), "+&a" (src), "+&da" (n), "=&d" (temp)
|
||||
:
|
||||
: "memory", "CC");
|
||||
|
||||
return xdest;
|
||||
}
|
||||
extern char *strncpy(char *dest, const char *src, size_t n);
|
||||
|
||||
#define __HAVE_ARCH_STRCMP
|
||||
extern inline int strcmp(const char *cs, const char *ct)
|
||||
{
|
||||
/* need to use int's here so the char's in the assembly don't get
|
||||
* sign extended incorrectly when we don't want them to be
|
||||
*/
|
||||
int __res1, __res2;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"1:"
|
||||
"%2 = B[%0++] (Z);" /* get *cs */
|
||||
"%3 = B[%1++] (Z);" /* get *ct */
|
||||
"CC = %2 == %3;" /* compare a byte */
|
||||
"if ! cc jump 2f;" /* not equal, break out */
|
||||
"CC = %2;" /* at end of cs? */
|
||||
"if cc jump 1b (bp);" /* no, keep going */
|
||||
"jump.s 3f;" /* strings are equal */
|
||||
"2:"
|
||||
"%2 = %2 - %3;" /* *cs - *ct */
|
||||
"3:"
|
||||
: "+&a" (cs), "+&a" (ct), "=&d" (__res1), "=&d" (__res2)
|
||||
:
|
||||
: "memory", "CC");
|
||||
|
||||
return __res1;
|
||||
}
|
||||
extern int strcmp(const char *cs, const char *ct);
|
||||
|
||||
#define __HAVE_ARCH_STRNCMP
|
||||
extern inline int strncmp(const char *cs, const char *ct, size_t count)
|
||||
{
|
||||
/* need to use int's here so the char's in the assembly don't get
|
||||
* sign extended incorrectly when we don't want them to be
|
||||
*/
|
||||
int __res1, __res2;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"1:"
|
||||
"%3 = B[%0++] (Z);" /* get *cs */
|
||||
"%4 = B[%1++] (Z);" /* get *ct */
|
||||
"CC = %3 == %4;" /* compare a byte */
|
||||
"if ! cc jump 3f;" /* not equal, break out */
|
||||
"CC = %3;" /* at end of cs? */
|
||||
"if ! cc jump 4f;" /* yes, all done */
|
||||
"%2 += -1;" /* no, adjust count */
|
||||
"CC = %2 == 0;"
|
||||
"if ! cc jump 1b;" /* more to do, keep going */
|
||||
"2:"
|
||||
"%3 = 0;" /* strings are equal */
|
||||
"jump.s 4f;"
|
||||
"3:"
|
||||
"%3 = %3 - %4;" /* *cs - *ct */
|
||||
"4:"
|
||||
: "+&a" (cs), "+&a" (ct), "+&da" (count), "=&d" (__res1), "=&d" (__res2)
|
||||
:
|
||||
: "memory", "CC");
|
||||
|
||||
return __res1;
|
||||
}
|
||||
extern int strncmp(const char *cs, const char *ct, size_t count);
|
||||
|
||||
#define __HAVE_ARCH_MEMSET
|
||||
extern void *memset(void *s, int c, size_t count);
|
||||
|
|
|
@ -32,6 +32,18 @@ EXPORT_SYMBOL(memcmp);
|
|||
EXPORT_SYMBOL(memmove);
|
||||
EXPORT_SYMBOL(memchr);
|
||||
|
||||
/*
|
||||
* Because string functions are both inline and exported functions and
|
||||
* folder arch/blackfin/lib is configured as a library path in Makefile,
|
||||
* symbols exported in folder lib is not linked into built-in.o but
|
||||
* inlined only. In order to export string symbols to kernel module
|
||||
* properly, they should be exported here.
|
||||
*/
|
||||
EXPORT_SYMBOL(strcpy);
|
||||
EXPORT_SYMBOL(strncpy);
|
||||
EXPORT_SYMBOL(strcmp);
|
||||
EXPORT_SYMBOL(strncmp);
|
||||
|
||||
/*
|
||||
* libgcc functions - functions that are used internally by the
|
||||
* compiler... (prototypes are not correct though, but that
|
||||
|
|
43
arch/blackfin/lib/strcmp.S
Normal file
43
arch/blackfin/lib/strcmp.S
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2005-2010 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the ADI BSD license or the GPL-2 (or later)
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
||||
/* void *strcmp(char *s1, const char *s2);
|
||||
* R0 = address (s1)
|
||||
* R1 = address (s2)
|
||||
*
|
||||
* Returns an integer less than, equal to, or greater than zero if s1
|
||||
* (or the first n bytes thereof) is found, respectively, to be less
|
||||
* than, to match, or be greater than s2.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_STRCMP_L1
|
||||
.section .l1.text
|
||||
#else
|
||||
.text
|
||||
#endif
|
||||
|
||||
.align 2
|
||||
|
||||
ENTRY(_strcmp)
|
||||
P0 = R0 ; /* s1 */
|
||||
P1 = R1 ; /* s2 */
|
||||
|
||||
1:
|
||||
R0 = B[P0++] (Z); /* get *s1 */
|
||||
R1 = B[P1++] (Z); /* get *s2 */
|
||||
CC = R0 == R1; /* compare a byte */
|
||||
if ! cc jump 2f; /* not equal, break out */
|
||||
CC = R0; /* at end of s1? */
|
||||
if cc jump 1b (bp); /* no, keep going */
|
||||
jump.s 3f; /* strings are equal */
|
||||
2:
|
||||
R0 = R0 - R1; /* *s1 - *s2 */
|
||||
3:
|
||||
RTS;
|
||||
|
||||
ENDPROC(_strcmp)
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* Provide symbol in case str func is not inlined.
|
||||
*
|
||||
* Copyright (c) 2006-2007 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#define strcmp __inline_strcmp
|
||||
#include <asm/string.h>
|
||||
#undef strcmp
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
int strcmp(const char *dest, const char *src)
|
||||
{
|
||||
return __inline_strcmp(dest, src);
|
||||
}
|
||||
EXPORT_SYMBOL(strcmp);
|
35
arch/blackfin/lib/strcpy.S
Normal file
35
arch/blackfin/lib/strcpy.S
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright 2005-2010 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the ADI BSD license or the GPL-2 (or later)
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
||||
/* void *strcpy(char *dest, const char *src);
|
||||
* R0 = address (dest)
|
||||
* R1 = address (src)
|
||||
*
|
||||
* Returns a pointer to the destination string dest
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_STRCPY_L1
|
||||
.section .l1.text
|
||||
#else
|
||||
.text
|
||||
#endif
|
||||
|
||||
.align 2
|
||||
|
||||
ENTRY(_strcpy)
|
||||
P0 = R0 ; /* dst*/
|
||||
P1 = R1 ; /* src*/
|
||||
|
||||
1:
|
||||
R1 = B [P1++] (Z);
|
||||
B [P0++] = R1;
|
||||
CC = R1;
|
||||
if cc jump 1b (bp);
|
||||
RTS;
|
||||
|
||||
ENDPROC(_strcpy)
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* Provide symbol in case str func is not inlined.
|
||||
*
|
||||
* Copyright (c) 2006-2007 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#define strcpy __inline_strcpy
|
||||
#include <asm/string.h>
|
||||
#undef strcpy
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
char *strcpy(char *dest, const char *src)
|
||||
{
|
||||
return __inline_strcpy(dest, src);
|
||||
}
|
||||
EXPORT_SYMBOL(strcpy);
|
52
arch/blackfin/lib/strncmp.S
Normal file
52
arch/blackfin/lib/strncmp.S
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright 2005-2010 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the ADI BSD license or the GPL-2 (or later)
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
||||
/* void *strncpy(char *s1, const char *s2, size_t n);
|
||||
* R0 = address (dest)
|
||||
* R1 = address (src)
|
||||
* R2 = size (n)
|
||||
* Returns a pointer to the destination string dest
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_STRNCMP_L1
|
||||
.section .l1.text
|
||||
#else
|
||||
.text
|
||||
#endif
|
||||
|
||||
.align 2
|
||||
|
||||
ENTRY(_strncmp)
|
||||
CC = R2 == 0;
|
||||
if CC JUMP 5f;
|
||||
|
||||
P0 = R0 ; /* s1 */
|
||||
P1 = R1 ; /* s2 */
|
||||
1:
|
||||
R0 = B[P0++] (Z); /* get *s1 */
|
||||
R1 = B[P1++] (Z); /* get *s2 */
|
||||
CC = R0 == R1; /* compare a byte */
|
||||
if ! cc jump 3f; /* not equal, break out */
|
||||
CC = R0; /* at end of s1? */
|
||||
if ! cc jump 4f; /* yes, all done */
|
||||
R2 += -1; /* no, adjust count */
|
||||
CC = R2 == 0;
|
||||
if ! cc jump 1b (bp); /* more to do, keep going */
|
||||
2:
|
||||
R0 = 0; /* strings are equal */
|
||||
jump.s 4f;
|
||||
3:
|
||||
R0 = R0 - R1; /* *s1 - *s2 */
|
||||
4:
|
||||
RTS;
|
||||
|
||||
5:
|
||||
R0 = 0;
|
||||
RTS;
|
||||
|
||||
ENDPROC(_strncmp)
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
* Provide symbol in case str func is not inlined.
|
||||
*
|
||||
* Copyright (c) 2006-2007 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#define strncmp __inline_strncmp
|
||||
#include <asm/string.h>
|
||||
#include <linux/module.h>
|
||||
#undef strncmp
|
||||
|
||||
int strncmp(const char *cs, const char *ct, size_t count)
|
||||
{
|
||||
return __inline_strncmp(cs, ct, count);
|
||||
}
|
||||
EXPORT_SYMBOL(strncmp);
|
52
arch/blackfin/lib/strncpy.S
Normal file
52
arch/blackfin/lib/strncpy.S
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright 2005-2010 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the ADI BSD license or the GPL-2 (or later)
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
||||
/* void *strncpy(char *dest, const char *src, size_t n);
|
||||
* R0 = address (dest)
|
||||
* R1 = address (src)
|
||||
* R2 = size
|
||||
* Returns a pointer to the destination string dest
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_STRNCPY_L1
|
||||
.section .l1.text
|
||||
#else
|
||||
.text
|
||||
#endif
|
||||
|
||||
.align 2
|
||||
|
||||
ENTRY(_strncpy)
|
||||
CC = R2 == 0;
|
||||
if CC JUMP 4f;
|
||||
P0 = R0 ; /* dst*/
|
||||
P1 = R1 ; /* src*/
|
||||
|
||||
1:
|
||||
R1 = B [P1++] (Z);
|
||||
B [P0++] = R1;
|
||||
CC = R1;
|
||||
if ! cc jump 2f;
|
||||
R2 += -1;
|
||||
CC = R2 == 0;
|
||||
if ! cc jump 1b (bp);
|
||||
jump 4f;
|
||||
2:
|
||||
/* if src is shorter than n, we need to null pad bytes in dest */
|
||||
R1 = 0;
|
||||
3:
|
||||
R2 += -1;
|
||||
CC = R2 == 0;
|
||||
if cc jump 4f;
|
||||
B [P0++] = R1;
|
||||
jump 3b;
|
||||
|
||||
4:
|
||||
RTS;
|
||||
|
||||
ENDPROC(_strncpy)
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* Provide symbol in case str func is not inlined.
|
||||
*
|
||||
* Copyright (c) 2006-2007 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#define strncpy __inline_strncpy
|
||||
#include <asm/string.h>
|
||||
#undef strncpy
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
char *strncpy(char *dest, const char *src, size_t n)
|
||||
{
|
||||
return __inline_strncpy(dest, src, n);
|
||||
}
|
||||
EXPORT_SYMBOL(strncpy);
|
Loading…
Reference in a new issue