Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f2db633d authored by Michael Cree's avatar Michael Cree Committed by Linus Torvalds
Browse files

alpha: Use new generic strncpy_from_user() and strnlen_user()



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: default avatarMichael Cree <mcree@orcon.net.nz>
Acked-by: default avatarMatt Turner <mattst88@gmail.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent d8d5da12
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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,
+5 −29
Original line number Diff line number Diff line
@@ -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:
+55 −0
Original line number Diff line number Diff line
#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 */
+0 −2
Original line number Diff line number Diff line
@@ -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.
+0 −2
Original line number Diff line number Diff line
@@ -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 \
Loading