diff options
author | Michael Cree <mcree@orcon.net.nz> | 2012-08-18 22:40:58 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-08-19 11:41:18 -0400 |
commit | f2db633d301b4b50f5f93de0e8314cc81e9bc7de (patch) | |
tree | aafa01b17e83221ca92ee58e66d7e6783808a224 /arch/alpha/include | |
parent | d8d5da129857bfd54b603771fca5409062167392 (diff) |
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: Michael Cree <mcree@orcon.net.nz>
Acked-by: Matt Turner <mattst88@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/alpha/include')
-rw-r--r-- | arch/alpha/include/asm/uaccess.h | 34 | ||||
-rw-r--r-- | arch/alpha/include/asm/word-at-a-time.h | 55 |
2 files changed, 60 insertions, 29 deletions
diff --git a/arch/alpha/include/asm/uaccess.h b/arch/alpha/include/asm/uaccess.h index b49ec2f8d6e3..766fdfde2b7a 100644 --- a/arch/alpha/include/asm/uaccess.h +++ b/arch/alpha/include/asm/uaccess.h | |||
@@ -433,36 +433,12 @@ clear_user(void __user *to, long len) | |||
433 | #undef __module_address | 433 | #undef __module_address |
434 | #undef __module_call | 434 | #undef __module_call |
435 | 435 | ||
436 | /* Returns: -EFAULT if exception before terminator, N if the entire | 436 | #define user_addr_max() \ |
437 | buffer filled, else strlen. */ | 437 | (segment_eq(get_fs(), USER_DS) ? TASK_SIZE : ~0UL) |
438 | 438 | ||
439 | extern long __strncpy_from_user(char *__to, const char __user *__from, long __to_len); | 439 | extern long strncpy_from_user(char *dest, const char __user *src, long count); |
440 | 440 | extern __must_check long strlen_user(const char __user *str); | |
441 | extern inline long | 441 | extern __must_check long strnlen_user(const char __user *str, long n); |
442 | strncpy_from_user(char *to, const char __user *from, long n) | ||
443 | { | ||
444 | long ret = -EFAULT; | ||
445 | if (__access_ok((unsigned long)from, 0, get_fs())) | ||
446 | ret = __strncpy_from_user(to, from, n); | ||
447 | return ret; | ||
448 | } | ||
449 | |||
450 | /* Returns: 0 if bad, string length+1 (memory size) of string if ok */ | ||
451 | extern long __strlen_user(const char __user *); | ||
452 | |||
453 | extern inline long strlen_user(const char __user *str) | ||
454 | { | ||
455 | return access_ok(VERIFY_READ,str,0) ? __strlen_user(str) : 0; | ||
456 | } | ||
457 | |||
458 | /* Returns: 0 if exception before NUL or reaching the supplied limit (N), | ||
459 | * a value greater than N if the limit would be exceeded, else strlen. */ | ||
460 | extern long __strnlen_user(const char __user *, long); | ||
461 | |||
462 | extern inline long strnlen_user(const char __user *str, long n) | ||
463 | { | ||
464 | return access_ok(VERIFY_READ,str,0) ? __strnlen_user(str, n) : 0; | ||
465 | } | ||
466 | 442 | ||
467 | /* | 443 | /* |
468 | * About the exception table: | 444 | * About the exception table: |
diff --git a/arch/alpha/include/asm/word-at-a-time.h b/arch/alpha/include/asm/word-at-a-time.h new file mode 100644 index 000000000000..6b340d0f1521 --- /dev/null +++ b/arch/alpha/include/asm/word-at-a-time.h | |||
@@ -0,0 +1,55 @@ | |||
1 | #ifndef _ASM_WORD_AT_A_TIME_H | ||
2 | #define _ASM_WORD_AT_A_TIME_H | ||
3 | |||
4 | #include <asm/compiler.h> | ||
5 | |||
6 | /* | ||
7 | * word-at-a-time interface for Alpha. | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * We do not use the word_at_a_time struct on Alpha, but it needs to be | ||
12 | * implemented to humour the generic code. | ||
13 | */ | ||
14 | struct word_at_a_time { | ||
15 | const unsigned long unused; | ||
16 | }; | ||
17 | |||
18 | #define WORD_AT_A_TIME_CONSTANTS { 0 } | ||
19 | |||
20 | /* Return nonzero if val has a zero */ | ||
21 | static inline unsigned long has_zero(unsigned long val, unsigned long *bits, const struct word_at_a_time *c) | ||
22 | { | ||
23 | unsigned long zero_locations = __kernel_cmpbge(0, val); | ||
24 | *bits = zero_locations; | ||
25 | return zero_locations; | ||
26 | } | ||
27 | |||
28 | static inline unsigned long prep_zero_mask(unsigned long val, unsigned long bits, const struct word_at_a_time *c) | ||
29 | { | ||
30 | return bits; | ||
31 | } | ||
32 | |||
33 | #define create_zero_mask(bits) (bits) | ||
34 | |||
35 | static inline unsigned long find_zero(unsigned long bits) | ||
36 | { | ||
37 | #if defined(CONFIG_ALPHA_EV6) && defined(CONFIG_ALPHA_EV67) | ||
38 | /* Simple if have CIX instructions */ | ||
39 | return __kernel_cttz(bits); | ||
40 | #else | ||
41 | unsigned long t1, t2, t3; | ||
42 | /* Retain lowest set bit only */ | ||
43 | bits &= -bits; | ||
44 | /* Binary search for lowest set bit */ | ||
45 | t1 = bits & 0xf0; | ||
46 | t2 = bits & 0xcc; | ||
47 | t3 = bits & 0xaa; | ||
48 | if (t1) t1 = 4; | ||
49 | if (t2) t2 = 2; | ||
50 | if (t3) t3 = 1; | ||
51 | return t1 + t2 + t3; | ||
52 | #endif | ||
53 | } | ||
54 | |||
55 | #endif /* _ASM_WORD_AT_A_TIME_H */ | ||