Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tile: add <asm/word-at-a-time.h> and enable support functions

This change enables the generic strncpy_from_user() and strnlen_user()
using word-at-a-time.h. The tile implementation is trivial since
both tilepro and tilegx have SIMD operations that do byte-wise
comparisons against immediate zero for each byte, and return an
0x01 byte in each position where there is a 0x00 byte.

Signed-off-by: Chris Metcalf <cmetcalf@ezchip.com>

+48 -150
+2
arch/tile/Kconfig
··· 28 28 select HAVE_DEBUG_STACKOVERFLOW 29 29 select ARCH_WANT_FRAME_POINTERS 30 30 select HAVE_CONTEXT_TRACKING 31 + select GENERIC_STRNCPY_FROM_USER 32 + select GENERIC_STRNLEN_USER 31 33 32 34 # FIXME: investigate whether we need/want these options. 33 35 # select HAVE_IOREMAP_PROT
+10 -56
arch/tile/include/asm/uaccess.h
··· 65 65 #endif 66 66 67 67 /* 68 + * Note that using this definition ignores is_arch_mappable_range(), 69 + * so on tilepro code that uses user_addr_max() is constrained not 70 + * to reference the tilepro user-interrupt region. 71 + */ 72 + #define user_addr_max() (current_thread_info()->addr_limit.seg) 73 + 74 + /* 68 75 * Test whether a block of memory is a valid user space address. 69 76 * Returns 0 if the range is valid, nonzero otherwise. 70 77 */ ··· 472 465 #endif 473 466 474 467 475 - /** 476 - * strlen_user: - Get the size of a string in user space. 477 - * @str: The string to measure. 478 - * 479 - * Context: User context only. This function may sleep. 480 - * 481 - * Get the size of a NUL-terminated string in user space. 482 - * 483 - * Returns the size of the string INCLUDING the terminating NUL. 484 - * On exception, returns 0. 485 - * 486 - * If there is a limit on the length of a valid string, you may wish to 487 - * consider using strnlen_user() instead. 488 - */ 489 - extern long strnlen_user_asm(const char __user *str, long n); 490 - static inline long __must_check strnlen_user(const char __user *str, long n) 491 - { 492 - might_fault(); 493 - return strnlen_user_asm(str, n); 494 - } 495 - #define strlen_user(str) strnlen_user(str, LONG_MAX) 496 - 497 - /** 498 - * strncpy_from_user: - Copy a NUL terminated string from userspace, with less checking. 499 - * @dst: Destination address, in kernel space. This buffer must be at 500 - * least @count bytes long. 501 - * @src: Source address, in user space. 502 - * @count: Maximum number of bytes to copy, including the trailing NUL. 503 - * 504 - * Copies a NUL-terminated string from userspace to kernel space. 505 - * Caller must check the specified block with access_ok() before calling 506 - * this function. 507 - * 508 - * On success, returns the length of the string (not including the trailing 509 - * NUL). 510 - * 511 - * If access to userspace fails, returns -EFAULT (some data may have been 512 - * copied). 513 - * 514 - * If @count is smaller than the length of the string, copies @count bytes 515 - * and returns @count. 516 - */ 517 - extern long strncpy_from_user_asm(char *dst, const char __user *src, long); 518 - static inline long __must_check __strncpy_from_user( 519 - char *dst, const char __user *src, long count) 520 - { 521 - might_fault(); 522 - return strncpy_from_user_asm(dst, src, count); 523 - } 524 - static inline long __must_check strncpy_from_user( 525 - char *dst, const char __user *src, long count) 526 - { 527 - if (access_ok(VERIFY_READ, src, 1)) 528 - return __strncpy_from_user(dst, src, count); 529 - return -EFAULT; 530 - } 468 + extern long strnlen_user(const char __user *str, long n); 469 + extern long strlen_user(const char __user *str); 470 + extern long strncpy_from_user(char *dst, const char __user *src, long); 531 471 532 472 /** 533 473 * clear_user: - Zero a block of memory in user space.
+36
arch/tile/include/asm/word-at-a-time.h
··· 1 + #ifndef _ASM_WORD_AT_A_TIME_H 2 + #define _ASM_WORD_AT_A_TIME_H 3 + 4 + #include <asm/byteorder.h> 5 + 6 + struct word_at_a_time { /* unused */ }; 7 + #define WORD_AT_A_TIME_CONSTANTS {} 8 + 9 + /* Generate 0x01 byte values for non-zero bytes using a SIMD instruction. */ 10 + static inline unsigned long has_zero(unsigned long val, unsigned long *data, 11 + const struct word_at_a_time *c) 12 + { 13 + #ifdef __tilegx__ 14 + unsigned long mask = __insn_v1cmpeqi(val, 0); 15 + #else /* tilepro */ 16 + unsigned long mask = __insn_seqib(val, 0); 17 + #endif 18 + *data = mask; 19 + return mask; 20 + } 21 + 22 + /* These operations are both nops. */ 23 + #define prep_zero_mask(val, data, c) (data) 24 + #define create_zero_mask(data) (data) 25 + 26 + /* And this operation just depends on endianness. */ 27 + static inline long find_zero(unsigned long mask) 28 + { 29 + #ifdef __BIG_ENDIAN 30 + return __builtin_clzl(mask) >> 3; 31 + #else 32 + return __builtin_ctzl(mask) >> 3; 33 + #endif 34 + } 35 + 36 + #endif /* _ASM_WORD_AT_A_TIME_H */
-2
arch/tile/lib/exports.c
··· 18 18 19 19 /* arch/tile/lib/usercopy.S */ 20 20 #include <linux/uaccess.h> 21 - EXPORT_SYMBOL(strnlen_user_asm); 22 - EXPORT_SYMBOL(strncpy_from_user_asm); 23 21 EXPORT_SYMBOL(clear_user_asm); 24 22 EXPORT_SYMBOL(flush_user_asm); 25 23 EXPORT_SYMBOL(finv_user_asm);
-46
arch/tile/lib/usercopy_32.S
··· 20 20 /* Access user memory, but use MMU to avoid propagating kernel exceptions. */ 21 21 22 22 /* 23 - * strnlen_user_asm takes the pointer in r0, and the length bound in r1. 24 - * It returns the length, including the terminating NUL, or zero on exception. 25 - * If length is greater than the bound, returns one plus the bound. 26 - */ 27 - STD_ENTRY(strnlen_user_asm) 28 - { bz r1, 2f; addi r3, r0, -1 } /* bias down to include NUL */ 29 - 1: { lb_u r4, r0; addi r1, r1, -1 } 30 - bz r4, 2f 31 - { bnzt r1, 1b; addi r0, r0, 1 } 32 - 2: { sub r0, r0, r3; jrp lr } 33 - STD_ENDPROC(strnlen_user_asm) 34 - .pushsection .fixup,"ax" 35 - strnlen_user_fault: 36 - { move r0, zero; jrp lr } 37 - ENDPROC(strnlen_user_fault) 38 - .section __ex_table,"a" 39 - .align 4 40 - .word 1b, strnlen_user_fault 41 - .popsection 42 - 43 - /* 44 - * strncpy_from_user_asm takes the kernel target pointer in r0, 45 - * the userspace source pointer in r1, and the length bound (including 46 - * the trailing NUL) in r2. On success, it returns the string length 47 - * (not including the trailing NUL), or -EFAULT on failure. 48 - */ 49 - STD_ENTRY(strncpy_from_user_asm) 50 - { bz r2, 2f; move r3, r0 } 51 - 1: { lb_u r4, r1; addi r1, r1, 1; addi r2, r2, -1 } 52 - { sb r0, r4; addi r0, r0, 1 } 53 - bz r4, 2f 54 - bnzt r2, 1b 55 - { sub r0, r0, r3; jrp lr } 56 - 2: addi r0, r0, -1 /* don't count the trailing NUL */ 57 - { sub r0, r0, r3; jrp lr } 58 - STD_ENDPROC(strncpy_from_user_asm) 59 - .pushsection .fixup,"ax" 60 - strncpy_from_user_fault: 61 - { movei r0, -EFAULT; jrp lr } 62 - ENDPROC(strncpy_from_user_fault) 63 - .section __ex_table,"a" 64 - .align 4 65 - .word 1b, strncpy_from_user_fault 66 - .popsection 67 - 68 - /* 69 23 * clear_user_asm takes the user target address in r0 and the 70 24 * number of bytes to zero in r1. 71 25 * It returns the number of uncopiable bytes (hopefully zero) in r0.
-46
arch/tile/lib/usercopy_64.S
··· 20 20 /* Access user memory, but use MMU to avoid propagating kernel exceptions. */ 21 21 22 22 /* 23 - * strnlen_user_asm takes the pointer in r0, and the length bound in r1. 24 - * It returns the length, including the terminating NUL, or zero on exception. 25 - * If length is greater than the bound, returns one plus the bound. 26 - */ 27 - STD_ENTRY(strnlen_user_asm) 28 - { beqz r1, 2f; addi r3, r0, -1 } /* bias down to include NUL */ 29 - 1: { ld1u r4, r0; addi r1, r1, -1 } 30 - beqz r4, 2f 31 - { bnezt r1, 1b; addi r0, r0, 1 } 32 - 2: { sub r0, r0, r3; jrp lr } 33 - STD_ENDPROC(strnlen_user_asm) 34 - .pushsection .fixup,"ax" 35 - strnlen_user_fault: 36 - { move r0, zero; jrp lr } 37 - ENDPROC(strnlen_user_fault) 38 - .section __ex_table,"a" 39 - .align 8 40 - .quad 1b, strnlen_user_fault 41 - .popsection 42 - 43 - /* 44 - * strncpy_from_user_asm takes the kernel target pointer in r0, 45 - * the userspace source pointer in r1, and the length bound (including 46 - * the trailing NUL) in r2. On success, it returns the string length 47 - * (not including the trailing NUL), or -EFAULT on failure. 48 - */ 49 - STD_ENTRY(strncpy_from_user_asm) 50 - { beqz r2, 2f; move r3, r0 } 51 - 1: { ld1u r4, r1; addi r1, r1, 1; addi r2, r2, -1 } 52 - { st1 r0, r4; addi r0, r0, 1 } 53 - beqz r4, 2f 54 - bnezt r2, 1b 55 - { sub r0, r0, r3; jrp lr } 56 - 2: addi r0, r0, -1 /* don't count the trailing NUL */ 57 - { sub r0, r0, r3; jrp lr } 58 - STD_ENDPROC(strncpy_from_user_asm) 59 - .pushsection .fixup,"ax" 60 - strncpy_from_user_fault: 61 - { movei r0, -EFAULT; jrp lr } 62 - ENDPROC(strncpy_from_user_fault) 63 - .section __ex_table,"a" 64 - .align 8 65 - .quad 1b, strncpy_from_user_fault 66 - .popsection 67 - 68 - /* 69 23 * clear_user_asm takes the user target address in r0 and the 70 24 * number of bytes to zero in r1. 71 25 * It returns the number of uncopiable bytes (hopefully zero) in r0.