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>
This commit is contained in:
parent
7158627686
commit
12a0ef7b0a
|
@ -17,6 +17,8 @@ config ARM64
|
||||||
select GENERIC_IRQ_SHOW
|
select GENERIC_IRQ_SHOW
|
||||||
select GENERIC_SCHED_CLOCK
|
select GENERIC_SCHED_CLOCK
|
||||||
select GENERIC_SMP_IDLE_THREAD
|
select GENERIC_SMP_IDLE_THREAD
|
||||||
|
select GENERIC_STRNCPY_FROM_USER
|
||||||
|
select GENERIC_STRNLEN_USER
|
||||||
select GENERIC_TIME_VSYSCALL
|
select GENERIC_TIME_VSYSCALL
|
||||||
select HARDIRQS_SW_RESEND
|
select HARDIRQS_SW_RESEND
|
||||||
select HAVE_ARCH_TRACEHOOK
|
select HAVE_ARCH_TRACEHOOK
|
||||||
|
|
|
@ -100,6 +100,7 @@ static inline void set_fs(mm_segment_t fs)
|
||||||
})
|
})
|
||||||
|
|
||||||
#define access_ok(type, addr, size) __range_ok(addr, size)
|
#define access_ok(type, addr, size) __range_ok(addr, size)
|
||||||
|
#define user_addr_max get_fs
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The "__xxx" versions of the user access functions do not verify the address
|
* 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
|
||||||
extern unsigned long __must_check __copy_in_user(void __user *to, const void __user *from, unsigned long n);
|
extern unsigned long __must_check __copy_in_user(void __user *to, const void __user *from, unsigned long n);
|
||||||
extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n);
|
extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n);
|
||||||
|
|
||||||
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)
|
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))
|
if (access_ok(VERIFY_READ, from, n))
|
||||||
|
@ -276,24 +274,9 @@ static inline unsigned long __must_check clear_user(void __user *to, unsigned lo
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline long __must_check strncpy_from_user(char *dst, const char __user *src, long count)
|
extern long strncpy_from_user(char *dest, 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 __must_check long strlen_user(const char __user *str);
|
||||||
|
extern __must_check long strnlen_user(const char __user *str, long n);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* __ASM_UACCESS_H */
|
#endif /* __ASM_UACCESS_H */
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 ARM Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef __ASM_WORD_AT_A_TIME_H
|
||||||
|
#define __ASM_WORD_AT_A_TIME_H
|
||||||
|
|
||||||
|
#ifndef __AARCH64EB__
|
||||||
|
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
return fls64(mask) >> 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* __AARCH64EB__ */
|
||||||
|
#include <asm-generic/word-at-a-time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __ASM_WORD_AT_A_TIME_H */
|
|
@ -29,13 +29,10 @@
|
||||||
|
|
||||||
#include <asm/checksum.h>
|
#include <asm/checksum.h>
|
||||||
|
|
||||||
/* user mem (segment) */
|
|
||||||
EXPORT_SYMBOL(__strnlen_user);
|
|
||||||
EXPORT_SYMBOL(__strncpy_from_user);
|
|
||||||
|
|
||||||
EXPORT_SYMBOL(copy_page);
|
EXPORT_SYMBOL(copy_page);
|
||||||
EXPORT_SYMBOL(clear_page);
|
EXPORT_SYMBOL(clear_page);
|
||||||
|
|
||||||
|
/* user mem (segment) */
|
||||||
EXPORT_SYMBOL(__copy_from_user);
|
EXPORT_SYMBOL(__copy_from_user);
|
||||||
EXPORT_SYMBOL(__copy_to_user);
|
EXPORT_SYMBOL(__copy_to_user);
|
||||||
EXPORT_SYMBOL(__clear_user);
|
EXPORT_SYMBOL(__clear_user);
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
lib-y := bitops.o delay.o \
|
lib-y := bitops.o clear_user.o delay.o copy_from_user.o \
|
||||||
strncpy_from_user.o strnlen_user.o clear_user.o \
|
copy_to_user.o copy_in_user.o copy_page.o \
|
||||||
copy_from_user.o copy_to_user.o copy_in_user.o \
|
clear_page.o memchr.o memcpy.o memmove.o memset.o \
|
||||||
copy_page.o clear_page.o \
|
|
||||||
memchr.o memcpy.o memmove.o memset.o \
|
|
||||||
strchr.o strrchr.o
|
strchr.o strrchr.o
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* Based on arch/arm/lib/strncpy_from_user.S
|
|
||||||
*
|
|
||||||
* Copyright (C) 1995-2000 Russell King
|
|
||||||
* Copyright (C) 2012 ARM Ltd.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/linkage.h>
|
|
||||||
#include <asm/assembler.h>
|
|
||||||
#include <asm/errno.h>
|
|
||||||
|
|
||||||
.text
|
|
||||||
.align 5
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copy a string from user space to kernel space.
|
|
||||||
* x0 = dst, x1 = src, x2 = byte length
|
|
||||||
* returns the number of characters copied (strlen of copied string),
|
|
||||||
* -EFAULT on exception, or "len" if we fill the whole buffer
|
|
||||||
*/
|
|
||||||
ENTRY(__strncpy_from_user)
|
|
||||||
mov x4, x1
|
|
||||||
1: subs x2, x2, #1
|
|
||||||
bmi 2f
|
|
||||||
USER(9f, ldrb w3, [x1], #1 )
|
|
||||||
strb w3, [x0], #1
|
|
||||||
cbnz w3, 1b
|
|
||||||
sub x1, x1, #1 // take NUL character out of count
|
|
||||||
2: sub x0, x1, x4
|
|
||||||
ret
|
|
||||||
ENDPROC(__strncpy_from_user)
|
|
||||||
|
|
||||||
.section .fixup,"ax"
|
|
||||||
.align 0
|
|
||||||
9: strb wzr, [x0] // null terminate
|
|
||||||
mov x0, #-EFAULT
|
|
||||||
ret
|
|
||||||
.previous
|
|
|
@ -1,47 +0,0 @@
|
||||||
/*
|
|
||||||
* Based on arch/arm/lib/strnlen_user.S
|
|
||||||
*
|
|
||||||
* Copyright (C) 1995-2000 Russell King
|
|
||||||
* Copyright (C) 2012 ARM Ltd.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/linkage.h>
|
|
||||||
#include <asm/assembler.h>
|
|
||||||
#include <asm/errno.h>
|
|
||||||
|
|
||||||
.text
|
|
||||||
.align 5
|
|
||||||
|
|
||||||
/* Prototype: unsigned long __strnlen_user(const char *str, long n)
|
|
||||||
* Purpose : get length of a string in user memory
|
|
||||||
* Params : str - address of string in user memory
|
|
||||||
* Returns : length of string *including terminator*
|
|
||||||
* or zero on exception, or n if too long
|
|
||||||
*/
|
|
||||||
ENTRY(__strnlen_user)
|
|
||||||
mov x2, x0
|
|
||||||
1: subs x1, x1, #1
|
|
||||||
b.mi 2f
|
|
||||||
USER(9f, ldrb w3, [x0], #1 )
|
|
||||||
cbnz w3, 1b
|
|
||||||
2: sub x0, x0, x2
|
|
||||||
ret
|
|
||||||
ENDPROC(__strnlen_user)
|
|
||||||
|
|
||||||
.section .fixup,"ax"
|
|
||||||
.align 0
|
|
||||||
9: mov x0, #0
|
|
||||||
ret
|
|
||||||
.previous
|
|
Loading…
Reference in New Issue