Commit | Line | Data |
---|---|---|
75346251 JN |
1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
2 | #ifndef _ASM_POWERPC_INST_H | |
3 | #define _ASM_POWERPC_INST_H | |
4 | ||
650b55b7 | 5 | #include <asm/ppc-opcode.h> |
9b307576 | 6 | #include <asm/reg.h> |
0d76914a CL |
7 | #include <asm/disassemble.h> |
8 | #include <asm/uaccess.h> | |
650b55b7 | 9 | |
35506a3e CL |
10 | #define ___get_user_instr(gu_op, dest, ptr) \ |
11 | ({ \ | |
042e0860 | 12 | long __gui_ret; \ |
9134806e | 13 | u32 __user *__gui_ptr = (u32 __user *)ptr; \ |
c545b9f0 | 14 | ppc_inst_t __gui_inst; \ |
35506a3e | 15 | unsigned int __prefix, __suffix; \ |
b3a9e523 CL |
16 | \ |
17 | __chk_user_ptr(ptr); \ | |
9134806e | 18 | __gui_ret = gu_op(__prefix, __gui_ptr); \ |
35506a3e | 19 | if (__gui_ret == 0) { \ |
3261d99a | 20 | if (IS_ENABLED(CONFIG_PPC64) && (__prefix >> 26) == OP_PREFIX) { \ |
9134806e | 21 | __gui_ret = gu_op(__suffix, __gui_ptr + 1); \ |
042e0860 | 22 | __gui_inst = ppc_inst_prefix(__prefix, __suffix); \ |
35506a3e CL |
23 | } else { \ |
24 | __gui_inst = ppc_inst(__prefix); \ | |
25 | } \ | |
26 | if (__gui_ret == 0) \ | |
27 | (dest) = __gui_inst; \ | |
28 | } \ | |
29 | __gui_ret; \ | |
30 | }) | |
35506a3e | 31 | |
042e0860 | 32 | #define get_user_instr(x, ptr) ___get_user_instr(get_user, x, ptr) |
35506a3e | 33 | |
042e0860 | 34 | #define __get_user_instr(x, ptr) ___get_user_instr(__get_user, x, ptr) |
35506a3e | 35 | |
75346251 JN |
36 | /* |
37 | * Instruction data type for POWER | |
38 | */ | |
39 | ||
07b863ae | 40 | #if defined(CONFIG_PPC64) || defined(__CHECKER__) |
c545b9f0 | 41 | static inline u32 ppc_inst_val(ppc_inst_t x) |
777e26f0 | 42 | { |
94afd069 | 43 | return x.val; |
777e26f0 JN |
44 | } |
45 | ||
07b863ae CL |
46 | #define ppc_inst(x) ((ppc_inst_t){ .val = (x) }) |
47 | ||
48 | #else | |
07b863ae CL |
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 | ||
c545b9f0 | 56 | static inline int ppc_inst_primary_opcode(ppc_inst_t x) |
622cf6f4 | 57 | { |
650b55b7 | 58 | return ppc_inst_val(x) >> 26; |
622cf6f4 JN |
59 | } |
60 | ||
077c4ded | 61 | #ifdef CONFIG_PPC64 |
c545b9f0 | 62 | #define ppc_inst_prefix(x, y) ((ppc_inst_t){ .val = (x), .suffix = (y) }) |
650b55b7 | 63 | |
c545b9f0 | 64 | static inline u32 ppc_inst_suffix(ppc_inst_t x) |
8094892d | 65 | { |
650b55b7 JN |
66 | return x.suffix; |
67 | } | |
68 | ||
077c4ded | 69 | #else |
3261d99a | 70 | #define ppc_inst_prefix(x, y) ((void)y, ppc_inst(x)) |
650b55b7 | 71 | |
c545b9f0 | 72 | static inline u32 ppc_inst_suffix(ppc_inst_t x) |
650b55b7 | 73 | { |
077c4ded | 74 | return 0; |
650b55b7 JN |
75 | } |
76 | ||
077c4ded CL |
77 | #endif /* CONFIG_PPC64 */ |
78 | ||
c545b9f0 | 79 | static inline ppc_inst_t ppc_inst_read(const u32 *ptr) |
650b55b7 | 80 | { |
077c4ded CL |
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); | |
650b55b7 JN |
85 | } |
86 | ||
c545b9f0 | 87 | static inline bool ppc_inst_prefixed(ppc_inst_t x) |
650b55b7 | 88 | { |
077c4ded | 89 | return IS_ENABLED(CONFIG_PPC64) && ppc_inst_primary_opcode(x) == OP_PREFIX; |
8094892d JN |
90 | } |
91 | ||
c545b9f0 | 92 | static inline ppc_inst_t ppc_inst_swab(ppc_inst_t x) |
aabd2233 | 93 | { |
077c4ded | 94 | return ppc_inst_prefix(swab32(ppc_inst_val(x)), swab32(ppc_inst_suffix(x))); |
f8faaffa JN |
95 | } |
96 | ||
c545b9f0 | 97 | static inline bool ppc_inst_equal(ppc_inst_t x, ppc_inst_t y) |
217862d9 | 98 | { |
036b5560 CL |
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); | |
217862d9 JN |
104 | } |
105 | ||
c545b9f0 | 106 | static inline int ppc_inst_len(ppc_inst_t x) |
650b55b7 JN |
107 | { |
108 | return ppc_inst_prefixed(x) ? 8 : 4; | |
109 | } | |
110 | ||
c5ff46d6 ME |
111 | /* |
112 | * Return the address of the next instruction, if the instruction @value was | |
113 | * located at @location. | |
114 | */ | |
69d4d6e5 | 115 | static inline u32 *ppc_inst_next(u32 *location, u32 *value) |
c5ff46d6 | 116 | { |
c545b9f0 | 117 | ppc_inst_t tmp; |
c5ff46d6 ME |
118 | |
119 | tmp = ppc_inst_read(value); | |
120 | ||
69d4d6e5 | 121 | return (void *)location + ppc_inst_len(tmp); |
c5ff46d6 ME |
122 | } |
123 | ||
c545b9f0 | 124 | static inline unsigned long ppc_inst_as_ulong(ppc_inst_t x) |
16ef9767 | 125 | { |
693557eb CL |
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); | |
16ef9767 ME |
132 | } |
133 | ||
309a0a60 CL |
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 | ||
8dfdbe43 | 142 | static inline int __copy_inst_from_kernel_nofault(ppc_inst_t *inst, u32 *src) |
0d76914a CL |
143 | { |
144 | unsigned int val, suffix; | |
145 | ||
0d76914a CL |
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 | } | |
95b980a0 | 161 | |
8dfdbe43 CL |
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 | ||
75346251 | 170 | #endif /* _ASM_POWERPC_INST_H */ |