Skip to content

Commit

Permalink
ARM: 7449/1: use generic strnlen_user and strncpy_from_user functions
Browse files Browse the repository at this point in the history
This patch implements the word-at-a-time interface for ARM using the
same algorithm as x86. We use the fls macro from ARMv5 onwards, where
we have a clz instruction available which saves us a mov instruction
when targetting Thumb-2. For older CPUs, we use the magic 0x0ff0001
constant. 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.

Reviewed-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Will Deacon authored and Russell King committed Jul 9, 2012
1 parent 4295b89 commit 8c56cc8
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 109 deletions.
2 changes: 2 additions & 0 deletions arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ config ARM
select GENERIC_SMP_IDLE_THREAD
select KTIME_SCALAR
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
help
The ARM series is a line of low-power-consumption RISC chip designs
licensed by ARM Ltd and targeted at embedded applications and
Expand Down
27 changes: 6 additions & 21 deletions arch/arm/include/asm/uaccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ static inline void set_fs(mm_segment_t fs)

#define access_ok(type,addr,size) (__range_ok(addr,size) == 0)

#define user_addr_max() \
(segment_eq(get_fs(), USER_DS) ? TASK_SIZE : ~0UL)

/*
* The "__xxx" versions of the user access functions do not verify the
* address space - it must have been done previously with a separate
Expand Down Expand Up @@ -398,9 +401,6 @@ extern unsigned long __must_check __clear_user_std(void __user *addr, unsigned l
#define __clear_user(addr,n) (memset((void __force *)addr, 0, n), 0)
#endif

extern unsigned long __must_check __strncpy_from_user(char *to, const char __user *from, unsigned long count);
extern unsigned long __must_check __strnlen_user(const char __user *s, long n);

static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n)
{
if (access_ok(VERIFY_READ, from, n))
Expand All @@ -427,24 +427,9 @@ static inline unsigned long __must_check clear_user(void __user *to, unsigned lo
return n;
}

static inline long __must_check strncpy_from_user(char *dst, const char __user *src, long count)
{
long res = -EFAULT;
if (access_ok(VERIFY_READ, src, 1))
res = __strncpy_from_user(dst, src, count);
return res;
}

#define strlen_user(s) strnlen_user(s, ~0UL >> 1)
extern long strncpy_from_user(char *dest, const char __user *src, long count);

static inline long __must_check strnlen_user(const char __user *s, long n)
{
unsigned long res = 0;

if (__addr_ok(s))
res = __strnlen_user(s, n);

return res;
}
extern __must_check long strlen_user(const char __user *str);
extern __must_check long strnlen_user(const char __user *str, long n);

#endif /* _ASMARM_UACCESS_H */
55 changes: 55 additions & 0 deletions arch/arm/include/asm/word-at-a-time.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#ifndef __ASM_ARM_WORD_AT_A_TIME_H
#define __ASM_ARM_WORD_AT_A_TIME_H

#ifndef __ARMEB__

/*
* Little-endian word-at-a-time zero byte handling.
* Heavily based on the x86 algorithm.
*/
#include <linux/kernel.h>

struct word_at_a_time {
const unsigned long one_bits, high_bits;
};

#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }

static inline unsigned long has_zero(unsigned long a, unsigned long *bits,
const struct word_at_a_time *c)
{
unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits;
*bits = mask;
return mask;
}

#define prep_zero_mask(a, bits, c) (bits)

static inline unsigned long create_zero_mask(unsigned long bits)
{
bits = (bits - 1) & ~bits;
return bits >> 7;
}

static inline unsigned long find_zero(unsigned long mask)
{
unsigned long ret;

#if __LINUX_ARM_ARCH__ >= 5
/* We have clz available. */
ret = fls(mask) >> 3;
#else
/* (000000 0000ff 00ffff ffffff) -> ( 1 1 2 3 ) */
ret = (0x0ff0001 + mask) >> 23;
/* Fix the 1 for 00 case */
ret &= mask;
#endif

return ret;
}

#else /* __ARMEB__ */
#include <asm-generic/word-at-a-time.h>
#endif

#endif /* __ASM_ARM_WORD_AT_A_TIME_H */
4 changes: 0 additions & 4 deletions arch/arm/kernel/armksyms.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,6 @@ EXPORT_SYMBOL(memmove);
EXPORT_SYMBOL(memchr);
EXPORT_SYMBOL(__memzero);

/* user mem (segment) */
EXPORT_SYMBOL(__strnlen_user);
EXPORT_SYMBOL(__strncpy_from_user);

#ifdef CONFIG_MMU
EXPORT_SYMBOL(copy_page);

Expand Down
1 change: 0 additions & 1 deletion arch/arm/lib/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \
csumpartialcopy.o csumpartialcopyuser.o clearbit.o \
delay.o findbit.o memchr.o memcpy.o \
memmove.o memset.o memzero.o setbit.o \
strncpy_from_user.o strnlen_user.o \
strchr.o strrchr.o \
testchangebit.o testclearbit.o testsetbit.o \
ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
Expand Down
43 changes: 0 additions & 43 deletions arch/arm/lib/strncpy_from_user.S

This file was deleted.

40 changes: 0 additions & 40 deletions arch/arm/lib/strnlen_user.S

This file was deleted.

0 comments on commit 8c56cc8

Please sign in to comment.