xref: /linux/arch/arm64/include/asm/word-at-a-time.h (revision 55d0969c451159cff86949b38c39171cab962069)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Copyright (C) 2013 ARM Ltd.
4  */
5 #ifndef __ASM_WORD_AT_A_TIME_H
6 #define __ASM_WORD_AT_A_TIME_H
7 
8 #include <linux/uaccess.h>
9 
10 #ifndef __AARCH64EB__
11 
12 #include <linux/bitops.h>
13 #include <linux/wordpart.h>
14 
15 struct word_at_a_time {
16 	const unsigned long one_bits, high_bits;
17 };
18 
19 #define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
20 
21 static inline unsigned long has_zero(unsigned long a, unsigned long *bits,
22 				     const struct word_at_a_time *c)
23 {
24 	unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits;
25 	*bits = mask;
26 	return mask;
27 }
28 
29 #define prep_zero_mask(a, bits, c) (bits)
30 #define create_zero_mask(bits) (bits)
31 #define find_zero(bits) (__ffs(bits) >> 3)
32 
33 static inline unsigned long zero_bytemask(unsigned long bits)
34 {
35 	bits = (bits - 1) & ~bits;
36 	return bits >> 7;
37 }
38 
39 #else	/* __AARCH64EB__ */
40 #include <asm-generic/word-at-a-time.h>
41 #endif
42 
43 /*
44  * Load an unaligned word from kernel space.
45  *
46  * In the (very unlikely) case of the word being a page-crosser
47  * and the next page not being mapped, take the exception and
48  * return zeroes in the non-existing part.
49  */
50 static inline unsigned long load_unaligned_zeropad(const void *addr)
51 {
52 	unsigned long ret;
53 
54 	__mte_enable_tco_async();
55 
56 	/* Load word from unaligned pointer addr */
57 	asm(
58 	"1:	ldr	%0, %2\n"
59 	"2:\n"
60 	_ASM_EXTABLE_LOAD_UNALIGNED_ZEROPAD(1b, 2b, %0, %1)
61 	: "=&r" (ret)
62 	: "r" (addr), "Q" (*(unsigned long *)addr));
63 
64 	__mte_disable_tco_async();
65 
66 	return ret;
67 }
68 
69 #endif /* __ASM_WORD_AT_A_TIME_H */
70