Esempio n. 1
0
/**
 * strnlen_user: - Get the size of a string in user space.
 * @s: The string to measure.
 * @n: The maximum valid length
 *
 * Get the size of a NUL-terminated string in user space.
 *
 * Returns the size of the string INCLUDING the terminating NUL.
 * On exception, returns 0.
 * If the string is too long, returns a value greater than @n.
 */
long strnlen_user(const char __user *s, long n)
{
	unsigned long mask = -__addr_ok(s);
	unsigned long res, tmp;

	might_fault();

	__asm__ __volatile__(
		"	testl %0, %0\n"
		"	jz 3f\n"
		"	andl %0,%%ecx\n"
		"0:	repne; scasb\n"
		"	setne %%al\n"
		"	subl %%ecx,%0\n"
		"	addl %0,%%eax\n"
		"1:\n"
		".section .fixup,\"ax\"\n"
		"2:	xorl %%eax,%%eax\n"
		"	jmp 1b\n"
		"3:	movb $1,%%al\n"
		"	jmp 1b\n"
		".previous\n"
		".section __ex_table,\"a\"\n"
		"	.align 4\n"
		"	.long 0b,2b\n"
		".previous"
		:"=&r" (n), "=&D" (s), "=&a" (res), "=&c" (tmp)
		:"0" (n), "1" (s), "2" (0), "3" (mask)
		:"cc");
	return res & mask;
}
Esempio n. 2
0
long strnlen_user(const char __user *s, long n)
{
	unsigned long mask = -__addr_ok(s);
	unsigned long res;

	__asm__ __volatile__(
		"	and	%0, %5\n"
		"	mv	r1, %1\n"
		"	beqz	%0, strnlen_exit\n"
		"	and3	r0, %1, #3\n"
		"	bnez	r0, strnlen_byte_loop\n"
		"	cmpui	%0, #4\n"
		"	bc	strnlen_byte_loop\n"
		"	sll3	r3, %6, #7\n"
		"strnlen_word_loop:\n"
		"0:	ld	r0, @%1+\n"
		"	not	r2, r0\n"
		"	sub	r0, %6\n"
		"	and	r2, r3\n"
		"	and	r2, r0\n"
		"	bnez	r2, strnlen_last_bytes_fixup\n"
		"	addi	%0, #-4\n"
		"	beqz	%0, strnlen_exit\n"
		"	bgtz	%0, strnlen_word_loop\n"
		"strnlen_last_bytes:\n"
		"	mv	%0, %4\n"
		"strnlen_last_bytes_fixup:\n"
		"	addi	%1, #-4\n"
		"strnlen_byte_loop:\n"
		"1:	ldb	r0, @%1\n"
		"	addi	%0, #-1\n"
		"	beqz	r0, strnlen_exit\n"
long strnlen_user(const char __user *s, long n)
{
	unsigned long mask = -__addr_ok(s);
	unsigned long res;

	__asm__ __volatile__(
		"	and	%0, %5\n"
		"	mv	r1, %1\n"
		"	beqz	%0, strnlen_exit\n"
		"	and3	r0, %1, #3\n"
		"	bnez	r0, strnlen_byte_loop\n"
		"	cmpui	%0, #4\n"
		"	bc	strnlen_byte_loop\n"
		"	sll3	r3, %6, #7\n"
		"strnlen_word_loop:\n"
		"0:	ld	r0, @%1+\n"
		"	not	r2, r0\n"
		"	sub	r0, %6\n"
		"	and	r2, r3\n"
		"	and	r2, r0\n"
		"	bnez	r2, strnlen_last_bytes_fixup\n"
		"	addi	%0, #-4\n"
		"	beqz	%0, strnlen_exit\n"
		"	bgtz	%0, strnlen_word_loop\n"
		"strnlen_last_bytes:\n"
		"	mv	%0, %4\n"
		"strnlen_last_bytes_fixup:\n"
		"	addi	%1, #-4\n"
		"strnlen_byte_loop:\n"
		"1:	ldb	r0, @%1\n"
		"	addi	%0, #-1\n"
		"	beqz	r0, strnlen_exit\n"
		"	addi	%1, #1\n"
		"	bnez	%0, strnlen_byte_loop\n"
		"strnlen_exit:\n"
		"	sub	%1, r1\n"
		"	add3	%0, %1, #1\n"
		"	.fillinsn\n"
		"9:\n"
		".section .fixup,\"ax\"\n"
		"	.balign 4\n"
		"4:	addi	%1, #-4\n"
		"	.fillinsn\n"
		"5:	ldi	%0, #0\n"
		"	seth	r1, #high(9b)\n"
		"	or3	r1, r1, #low(9b)\n"
		"	jmp	r1\n"
		".previous\n"
		".section __ex_table,\"a\"\n"
		"	.balign 4\n"
		"	.long 0b,4b\n"
		"	.long 1b,5b\n"
		".previous"
		: "=&r" (res), "=r" (s)
		: "0" (n), "1" (s), "r" (n & 3), "r" (mask), "r"(0x01010101)
		: "r0", "r1", "r2", "r3", "cbit");

	/* NOTE: strnlen_user() algorithm:
	 * {
	 *   char *p;
	 *   for (p = s; n-- && *p != '\0'; ++p)
	 *     ;
	 *   return p - s + 1;
	 * }
	 */

	/* NOTE: If a null char. exists, return 0.
	 * if ((x - 0x01010101) & ~x & 0x80808080)\n"
	 *   return 0;\n"
	 */

	return res & mask;
}