Merge tag 'bitmap-6.0-rc1' of https://github.com/norov/linux
[linux-2.6-microblaze.git] / arch / powerpc / include / asm / inst.h
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 #ifndef _ASM_POWERPC_INST_H
3 #define _ASM_POWERPC_INST_H
4
5 #include <asm/ppc-opcode.h>
6 #include <asm/reg.h>
7 #include <asm/disassemble.h>
8 #include <asm/uaccess.h>
9
10 #define ___get_user_instr(gu_op, dest, ptr)                             \
11 ({                                                                      \
12         long __gui_ret;                                                 \
13         u32 __user *__gui_ptr = (u32 __user *)ptr;                      \
14         ppc_inst_t __gui_inst;                                          \
15         unsigned int __prefix, __suffix;                                \
16                                                                         \
17         __chk_user_ptr(ptr);                                            \
18         __gui_ret = gu_op(__prefix, __gui_ptr);                         \
19         if (__gui_ret == 0) {                                           \
20                 if (IS_ENABLED(CONFIG_PPC64) && (__prefix >> 26) == OP_PREFIX) { \
21                         __gui_ret = gu_op(__suffix, __gui_ptr + 1);     \
22                         __gui_inst = ppc_inst_prefix(__prefix, __suffix); \
23                 } else {                                                \
24                         __gui_inst = ppc_inst(__prefix);                \
25                 }                                                       \
26                 if (__gui_ret == 0)                                     \
27                         (dest) = __gui_inst;                            \
28         }                                                               \
29         __gui_ret;                                                      \
30 })
31
32 #define get_user_instr(x, ptr) ___get_user_instr(get_user, x, ptr)
33
34 #define __get_user_instr(x, ptr) ___get_user_instr(__get_user, x, ptr)
35
36 /*
37  * Instruction data type for POWER
38  */
39
40 #if defined(CONFIG_PPC64) || defined(__CHECKER__)
41 static inline u32 ppc_inst_val(ppc_inst_t x)
42 {
43         return x.val;
44 }
45
46 #define ppc_inst(x) ((ppc_inst_t){ .val = (x) })
47
48 #else
49 static inline u32 ppc_inst_val(ppc_inst_t x)
50 {
51         return x;
52 }
53 #define ppc_inst(x) (x)
54 #endif
55
56 static inline int ppc_inst_primary_opcode(ppc_inst_t x)
57 {
58         return ppc_inst_val(x) >> 26;
59 }
60
61 #ifdef CONFIG_PPC64
62 #define ppc_inst_prefix(x, y) ((ppc_inst_t){ .val = (x), .suffix = (y) })
63
64 static inline u32 ppc_inst_suffix(ppc_inst_t x)
65 {
66         return x.suffix;
67 }
68
69 #else
70 #define ppc_inst_prefix(x, y) ((void)y, ppc_inst(x))
71
72 static inline u32 ppc_inst_suffix(ppc_inst_t x)
73 {
74         return 0;
75 }
76
77 #endif /* CONFIG_PPC64 */
78
79 static inline ppc_inst_t ppc_inst_read(const u32 *ptr)
80 {
81         if (IS_ENABLED(CONFIG_PPC64) && (*ptr >> 26) == OP_PREFIX)
82                 return ppc_inst_prefix(*ptr, *(ptr + 1));
83         else
84                 return ppc_inst(*ptr);
85 }
86
87 static inline bool ppc_inst_prefixed(ppc_inst_t x)
88 {
89         return IS_ENABLED(CONFIG_PPC64) && ppc_inst_primary_opcode(x) == OP_PREFIX;
90 }
91
92 static inline ppc_inst_t ppc_inst_swab(ppc_inst_t x)
93 {
94         return ppc_inst_prefix(swab32(ppc_inst_val(x)), swab32(ppc_inst_suffix(x)));
95 }
96
97 static inline bool ppc_inst_equal(ppc_inst_t x, ppc_inst_t y)
98 {
99         if (ppc_inst_val(x) != ppc_inst_val(y))
100                 return false;
101         if (!ppc_inst_prefixed(x))
102                 return true;
103         return ppc_inst_suffix(x) == ppc_inst_suffix(y);
104 }
105
106 static inline int ppc_inst_len(ppc_inst_t x)
107 {
108         return ppc_inst_prefixed(x) ? 8 : 4;
109 }
110
111 /*
112  * Return the address of the next instruction, if the instruction @value was
113  * located at @location.
114  */
115 static inline u32 *ppc_inst_next(u32 *location, u32 *value)
116 {
117         ppc_inst_t tmp;
118
119         tmp = ppc_inst_read(value);
120
121         return (void *)location + ppc_inst_len(tmp);
122 }
123
124 static inline unsigned long ppc_inst_as_ulong(ppc_inst_t x)
125 {
126         if (IS_ENABLED(CONFIG_PPC32))
127                 return ppc_inst_val(x);
128         else if (IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN))
129                 return (u64)ppc_inst_suffix(x) << 32 | ppc_inst_val(x);
130         else
131                 return (u64)ppc_inst_val(x) << 32 | ppc_inst_suffix(x);
132 }
133
134 static inline void ppc_inst_write(u32 *ptr, ppc_inst_t x)
135 {
136         if (!ppc_inst_prefixed(x))
137                 *ptr = ppc_inst_val(x);
138         else
139                 *(u64 *)ptr = ppc_inst_as_ulong(x);
140 }
141
142 static inline int __copy_inst_from_kernel_nofault(ppc_inst_t *inst, u32 *src)
143 {
144         unsigned int val, suffix;
145
146 /* See https://github.com/ClangBuiltLinux/linux/issues/1521 */
147 #if defined(CONFIG_CC_IS_CLANG) && CONFIG_CLANG_VERSION < 140000
148         val = suffix = 0;
149 #endif
150         __get_kernel_nofault(&val, src, u32, Efault);
151         if (IS_ENABLED(CONFIG_PPC64) && get_op(val) == OP_PREFIX) {
152                 __get_kernel_nofault(&suffix, src + 1, u32, Efault);
153                 *inst = ppc_inst_prefix(val, suffix);
154         } else {
155                 *inst = ppc_inst(val);
156         }
157         return 0;
158 Efault:
159         return -EFAULT;
160 }
161
162 static inline int copy_inst_from_kernel_nofault(ppc_inst_t *inst, u32 *src)
163 {
164         if (unlikely(!is_kernel_addr((unsigned long)src)))
165                 return -ERANGE;
166
167         return __copy_inst_from_kernel_nofault(inst, src);
168 }
169
170 #endif /* _ASM_POWERPC_INST_H */