Skip to content

Commit

Permalink
alpha: Use new generic strncpy_from_user() and strnlen_user()
Browse files Browse the repository at this point in the history
Similar to x86/sparc/powerpc implementations except:
1) we implement an extremely efficient has_zero()/find_zero()
   sequence with both prep_zero_mask() and create_zero_mask()
   no-operations.
2) Our output from prep_zero_mask() differs in that only the
   lowest eight bits are used to represent the zero bytes
   nevertheless it can be safely ORed with other similar masks
   from prep_zero_mask() and forms input to create_zero_mask(),
   the two fundamental properties prep_zero_mask() must satisfy.

Tests on EV67 and EV68 CPUs revealed that the generic code is
essentially as fast (to within 0.5% of CPU cycles) of the old
Alpha specific code for large quadword-aligned strings, despite
the 30% extra CPU instructions executed.  In contrast, the
generic code for unaligned strings is substantially slower (by
more than a factor of 3) than the old Alpha specific code.

Signed-off-by: Michael Cree <[email protected]>
Acked-by: Matt Turner <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Michael Cree authored and torvalds committed Aug 19, 2012
1 parent d8d5da1 commit f2db633
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 994 deletions.
2 changes: 2 additions & 0 deletions arch/alpha/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ config ALPHA
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select GENERIC_SMP_IDLE_THREAD
select GENERIC_CMOS_UPDATE
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
help
The Alpha is a 64-bit general-purpose processor designed and
marketed by the Digital Equipment Corporation of blessed memory,
Expand Down
34 changes: 5 additions & 29 deletions arch/alpha/include/asm/uaccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -433,36 +433,12 @@ clear_user(void __user *to, long len)
#undef __module_address
#undef __module_call

/* Returns: -EFAULT if exception before terminator, N if the entire
buffer filled, else strlen. */
#define user_addr_max() \
(segment_eq(get_fs(), USER_DS) ? TASK_SIZE : ~0UL)

extern long __strncpy_from_user(char *__to, const char __user *__from, long __to_len);

extern inline long
strncpy_from_user(char *to, const char __user *from, long n)
{
long ret = -EFAULT;
if (__access_ok((unsigned long)from, 0, get_fs()))
ret = __strncpy_from_user(to, from, n);
return ret;
}

/* Returns: 0 if bad, string length+1 (memory size) of string if ok */
extern long __strlen_user(const char __user *);

extern inline long strlen_user(const char __user *str)
{
return access_ok(VERIFY_READ,str,0) ? __strlen_user(str) : 0;
}

/* Returns: 0 if exception before NUL or reaching the supplied limit (N),
* a value greater than N if the limit would be exceeded, else strlen. */
extern long __strnlen_user(const char __user *, long);

extern inline long strnlen_user(const char __user *str, long n)
{
return access_ok(VERIFY_READ,str,0) ? __strnlen_user(str, n) : 0;
}
extern long strncpy_from_user(char *dest, const char __user *src, long count);
extern __must_check long strlen_user(const char __user *str);
extern __must_check long strnlen_user(const char __user *str, long n);

/*
* About the exception table:
Expand Down
55 changes: 55 additions & 0 deletions arch/alpha/include/asm/word-at-a-time.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#ifndef _ASM_WORD_AT_A_TIME_H
#define _ASM_WORD_AT_A_TIME_H

#include <asm/compiler.h>

/*
* word-at-a-time interface for Alpha.
*/

/*
* We do not use the word_at_a_time struct on Alpha, but it needs to be
* implemented to humour the generic code.
*/
struct word_at_a_time {
const unsigned long unused;
};

#define WORD_AT_A_TIME_CONSTANTS { 0 }

/* Return nonzero if val has a zero */
static inline unsigned long has_zero(unsigned long val, unsigned long *bits, const struct word_at_a_time *c)
{
unsigned long zero_locations = __kernel_cmpbge(0, val);
*bits = zero_locations;
return zero_locations;
}

static inline unsigned long prep_zero_mask(unsigned long val, unsigned long bits, const struct word_at_a_time *c)
{
return bits;
}

#define create_zero_mask(bits) (bits)

static inline unsigned long find_zero(unsigned long bits)
{
#if defined(CONFIG_ALPHA_EV6) && defined(CONFIG_ALPHA_EV67)
/* Simple if have CIX instructions */
return __kernel_cttz(bits);
#else
unsigned long t1, t2, t3;
/* Retain lowest set bit only */
bits &= -bits;
/* Binary search for lowest set bit */
t1 = bits & 0xf0;
t2 = bits & 0xcc;
t3 = bits & 0xaa;
if (t1) t1 = 4;
if (t2) t2 = 2;
if (t3) t3 = 1;
return t1 + t2 + t3;
#endif
}

#endif /* _ASM_WORD_AT_A_TIME_H */
2 changes: 0 additions & 2 deletions arch/alpha/kernel/alpha_ksyms.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,6 @@ EXPORT_SYMBOL(alpha_fp_emul);
*/
EXPORT_SYMBOL(__copy_user);
EXPORT_SYMBOL(__do_clear_user);
EXPORT_SYMBOL(__strncpy_from_user);
EXPORT_SYMBOL(__strnlen_user);

/*
* SMP-specific symbols.
Expand Down
2 changes: 0 additions & 2 deletions arch/alpha/lib/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ lib-y = __divqu.o __remqu.o __divlu.o __remlu.o \
$(ev6-y)memchr.o \
$(ev6-y)copy_user.o \
$(ev6-y)clear_user.o \
$(ev6-y)strncpy_from_user.o \
$(ev67-y)strlen_user.o \
$(ev6-y)csum_ipv6_magic.o \
$(ev6-y)clear_page.o \
$(ev6-y)copy_page.o \
Expand Down
Loading

0 comments on commit f2db633

Please sign in to comment.