diff options
author | Will Deacon <will.deacon@arm.com> | 2013-11-06 12:20:22 -0500 |
---|---|---|
committer | Catalin Marinas <catalin.marinas@arm.com> | 2013-12-19 12:43:06 -0500 |
commit | 12a0ef7b0ac38677bd2d85f33df5ca0a57868819 (patch) | |
tree | 59b4be2d48b136aac65c7201a975a9463917e020 /arch/arm64/include | |
parent | 7158627686f02319c50c8d9d78f75d4c8d126ff2 (diff) |
arm64: use generic strnlen_user and strncpy_from_user functions
This patch implements the word-at-a-time interface for arm64 using the
same algorithm as ARM. We use the fls64 macro, which expands to a clz
instruction via a compiler builtin. Big-endian configurations make use
of the implementation from asm-generic.
With this implemented, we can replace our byte-at-a-time strnlen_user
and strncpy_from_user functions with the optimised generic versions.
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Diffstat (limited to 'arch/arm64/include')
-rw-r--r-- | arch/arm64/include/asm/uaccess.h | 25 | ||||
-rw-r--r-- | arch/arm64/include/asm/word-at-a-time.h | 54 |
2 files changed, 58 insertions, 21 deletions
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index 7ecc2b23882e..6c0f684aca81 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h | |||
@@ -100,6 +100,7 @@ static inline void set_fs(mm_segment_t fs) | |||
100 | }) | 100 | }) |
101 | 101 | ||
102 | #define access_ok(type, addr, size) __range_ok(addr, size) | 102 | #define access_ok(type, addr, size) __range_ok(addr, size) |
103 | #define user_addr_max get_fs | ||
103 | 104 | ||
104 | /* | 105 | /* |
105 | * The "__xxx" versions of the user access functions do not verify the address | 106 | * The "__xxx" versions of the user access functions do not verify the address |
@@ -240,9 +241,6 @@ extern unsigned long __must_check __copy_to_user(void __user *to, const void *fr | |||
240 | extern unsigned long __must_check __copy_in_user(void __user *to, const void __user *from, unsigned long n); | 241 | extern unsigned long __must_check __copy_in_user(void __user *to, const void __user *from, unsigned long n); |
241 | extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n); | 242 | extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n); |
242 | 243 | ||
243 | extern unsigned long __must_check __strncpy_from_user(char *to, const char __user *from, unsigned long count); | ||
244 | extern unsigned long __must_check __strnlen_user(const char __user *s, long n); | ||
245 | |||
246 | static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) | 244 | static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) |
247 | { | 245 | { |
248 | if (access_ok(VERIFY_READ, from, n)) | 246 | if (access_ok(VERIFY_READ, from, n)) |
@@ -276,24 +274,9 @@ static inline unsigned long __must_check clear_user(void __user *to, unsigned lo | |||
276 | return n; | 274 | return n; |
277 | } | 275 | } |
278 | 276 | ||
279 | static inline long __must_check strncpy_from_user(char *dst, const char __user *src, long count) | 277 | extern long strncpy_from_user(char *dest, const char __user *src, long count); |
280 | { | ||
281 | long res = -EFAULT; | ||
282 | if (access_ok(VERIFY_READ, src, 1)) | ||
283 | res = __strncpy_from_user(dst, src, count); | ||
284 | return res; | ||
285 | } | ||
286 | |||
287 | #define strlen_user(s) strnlen_user(s, ~0UL >> 1) | ||
288 | 278 | ||
289 | static inline long __must_check strnlen_user(const char __user *s, long n) | 279 | extern __must_check long strlen_user(const char __user *str); |
290 | { | 280 | extern __must_check long strnlen_user(const char __user *str, long n); |
291 | unsigned long res = 0; | ||
292 | |||
293 | if (__addr_ok(s)) | ||
294 | res = __strnlen_user(s, n); | ||
295 | |||
296 | return res; | ||
297 | } | ||
298 | 281 | ||
299 | #endif /* __ASM_UACCESS_H */ | 282 | #endif /* __ASM_UACCESS_H */ |
diff --git a/arch/arm64/include/asm/word-at-a-time.h b/arch/arm64/include/asm/word-at-a-time.h new file mode 100644 index 000000000000..27a167d044d9 --- /dev/null +++ b/arch/arm64/include/asm/word-at-a-time.h | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 ARM Ltd. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | #ifndef __ASM_WORD_AT_A_TIME_H | ||
17 | #define __ASM_WORD_AT_A_TIME_H | ||
18 | |||
19 | #ifndef __AARCH64EB__ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | |||
23 | struct word_at_a_time { | ||
24 | const unsigned long one_bits, high_bits; | ||
25 | }; | ||
26 | |||
27 | #define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) } | ||
28 | |||
29 | static inline unsigned long has_zero(unsigned long a, unsigned long *bits, | ||
30 | const struct word_at_a_time *c) | ||
31 | { | ||
32 | unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits; | ||
33 | *bits = mask; | ||
34 | return mask; | ||
35 | } | ||
36 | |||
37 | #define prep_zero_mask(a, bits, c) (bits) | ||
38 | |||
39 | static inline unsigned long create_zero_mask(unsigned long bits) | ||
40 | { | ||
41 | bits = (bits - 1) & ~bits; | ||
42 | return bits >> 7; | ||
43 | } | ||
44 | |||
45 | static inline unsigned long find_zero(unsigned long mask) | ||
46 | { | ||
47 | return fls64(mask) >> 3; | ||
48 | } | ||
49 | |||
50 | #else /* __AARCH64EB__ */ | ||
51 | #include <asm-generic/word-at-a-time.h> | ||
52 | #endif | ||
53 | |||
54 | #endif /* __ASM_WORD_AT_A_TIME_H */ | ||