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 JN |
5 | #include <asm/ppc-opcode.h> |
6 | ||
35506a3e CL |
7 | #ifdef CONFIG_PPC64 |
8 | ||
9 | #define ___get_user_instr(gu_op, dest, ptr) \ | |
10 | ({ \ | |
11 | long __gui_ret = 0; \ | |
12 | unsigned long __gui_ptr = (unsigned long)ptr; \ | |
13 | struct ppc_inst __gui_inst; \ | |
14 | unsigned int __prefix, __suffix; \ | |
b3a9e523 CL |
15 | \ |
16 | __chk_user_ptr(ptr); \ | |
35506a3e CL |
17 | __gui_ret = gu_op(__prefix, (unsigned int __user *)__gui_ptr); \ |
18 | if (__gui_ret == 0) { \ | |
19 | if ((__prefix >> 26) == OP_PREFIX) { \ | |
20 | __gui_ret = gu_op(__suffix, \ | |
21 | (unsigned int __user *)__gui_ptr + 1); \ | |
22 | __gui_inst = ppc_inst_prefix(__prefix, \ | |
23 | __suffix); \ | |
24 | } else { \ | |
25 | __gui_inst = ppc_inst(__prefix); \ | |
26 | } \ | |
27 | if (__gui_ret == 0) \ | |
28 | (dest) = __gui_inst; \ | |
29 | } \ | |
30 | __gui_ret; \ | |
31 | }) | |
32 | #else /* !CONFIG_PPC64 */ | |
33 | #define ___get_user_instr(gu_op, dest, ptr) \ | |
b3a9e523 CL |
34 | ({ \ |
35 | __chk_user_ptr(ptr); \ | |
36 | gu_op((dest).val, (u32 __user *)(ptr)); \ | |
37 | }) | |
35506a3e CL |
38 | #endif /* CONFIG_PPC64 */ |
39 | ||
40 | #define get_user_instr(x, ptr) \ | |
41 | ___get_user_instr(get_user, x, ptr) | |
42 | ||
43 | #define __get_user_instr(x, ptr) \ | |
44 | ___get_user_instr(__get_user, x, ptr) | |
45 | ||
75346251 JN |
46 | /* |
47 | * Instruction data type for POWER | |
48 | */ | |
49 | ||
94afd069 JN |
50 | struct ppc_inst { |
51 | u32 val; | |
650b55b7 JN |
52 | #ifdef CONFIG_PPC64 |
53 | u32 suffix; | |
54 | #endif | |
94afd069 | 55 | } __packed; |
75346251 | 56 | |
94afd069 | 57 | static inline u32 ppc_inst_val(struct ppc_inst x) |
777e26f0 | 58 | { |
94afd069 | 59 | return x.val; |
777e26f0 JN |
60 | } |
61 | ||
650b55b7 | 62 | static inline int ppc_inst_primary_opcode(struct ppc_inst x) |
622cf6f4 | 63 | { |
650b55b7 | 64 | return ppc_inst_val(x) >> 26; |
622cf6f4 JN |
65 | } |
66 | ||
650b55b7 JN |
67 | #ifdef CONFIG_PPC64 |
68 | #define ppc_inst(x) ((struct ppc_inst){ .val = (x), .suffix = 0xff }) | |
69 | ||
70 | #define ppc_inst_prefix(x, y) ((struct ppc_inst){ .val = (x), .suffix = (y) }) | |
71 | ||
72 | static inline u32 ppc_inst_suffix(struct ppc_inst x) | |
8094892d | 73 | { |
650b55b7 JN |
74 | return x.suffix; |
75 | } | |
76 | ||
77 | static inline bool ppc_inst_prefixed(struct ppc_inst x) | |
78 | { | |
79 | return (ppc_inst_primary_opcode(x) == 1) && ppc_inst_suffix(x) != 0xff; | |
80 | } | |
81 | ||
82 | static inline struct ppc_inst ppc_inst_swab(struct ppc_inst x) | |
83 | { | |
84 | return ppc_inst_prefix(swab32(ppc_inst_val(x)), | |
85 | swab32(ppc_inst_suffix(x))); | |
86 | } | |
87 | ||
88 | static inline struct ppc_inst ppc_inst_read(const struct ppc_inst *ptr) | |
89 | { | |
90 | u32 val, suffix; | |
91 | ||
92 | val = *(u32 *)ptr; | |
93 | if ((val >> 26) == OP_PREFIX) { | |
94 | suffix = *((u32 *)ptr + 1); | |
95 | return ppc_inst_prefix(val, suffix); | |
96 | } else { | |
97 | return ppc_inst(val); | |
98 | } | |
99 | } | |
100 | ||
101 | static inline bool ppc_inst_equal(struct ppc_inst x, struct ppc_inst y) | |
102 | { | |
103 | return *(u64 *)&x == *(u64 *)&y; | |
104 | } | |
105 | ||
106 | #else | |
107 | ||
108 | #define ppc_inst(x) ((struct ppc_inst){ .val = x }) | |
109 | ||
6449078d CL |
110 | #define ppc_inst_prefix(x, y) ppc_inst(x) |
111 | ||
650b55b7 JN |
112 | static inline bool ppc_inst_prefixed(struct ppc_inst x) |
113 | { | |
114 | return false; | |
115 | } | |
116 | ||
117 | static inline u32 ppc_inst_suffix(struct ppc_inst x) | |
118 | { | |
119 | return 0; | |
8094892d JN |
120 | } |
121 | ||
94afd069 | 122 | static inline struct ppc_inst ppc_inst_swab(struct ppc_inst x) |
aabd2233 JN |
123 | { |
124 | return ppc_inst(swab32(ppc_inst_val(x))); | |
125 | } | |
126 | ||
f8faaffa JN |
127 | static inline struct ppc_inst ppc_inst_read(const struct ppc_inst *ptr) |
128 | { | |
129 | return *ptr; | |
130 | } | |
131 | ||
94afd069 | 132 | static inline bool ppc_inst_equal(struct ppc_inst x, struct ppc_inst y) |
217862d9 | 133 | { |
94afd069 | 134 | return ppc_inst_val(x) == ppc_inst_val(y); |
217862d9 JN |
135 | } |
136 | ||
650b55b7 JN |
137 | #endif /* CONFIG_PPC64 */ |
138 | ||
139 | static inline int ppc_inst_len(struct ppc_inst x) | |
140 | { | |
141 | return ppc_inst_prefixed(x) ? 8 : 4; | |
142 | } | |
143 | ||
c5ff46d6 ME |
144 | /* |
145 | * Return the address of the next instruction, if the instruction @value was | |
146 | * located at @location. | |
147 | */ | |
148 | static inline struct ppc_inst *ppc_inst_next(void *location, struct ppc_inst *value) | |
149 | { | |
150 | struct ppc_inst tmp; | |
151 | ||
152 | tmp = ppc_inst_read(value); | |
153 | ||
154 | return location + ppc_inst_len(tmp); | |
155 | } | |
156 | ||
693557eb | 157 | static inline unsigned long ppc_inst_as_ulong(struct ppc_inst x) |
16ef9767 | 158 | { |
693557eb CL |
159 | if (IS_ENABLED(CONFIG_PPC32)) |
160 | return ppc_inst_val(x); | |
161 | else if (IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN)) | |
162 | return (u64)ppc_inst_suffix(x) << 32 | ppc_inst_val(x); | |
163 | else | |
164 | return (u64)ppc_inst_val(x) << 32 | ppc_inst_suffix(x); | |
16ef9767 ME |
165 | } |
166 | ||
50428fdc JN |
167 | #define PPC_INST_STR_LEN sizeof("00000000 00000000") |
168 | ||
169 | static inline char *__ppc_inst_as_str(char str[PPC_INST_STR_LEN], struct ppc_inst x) | |
170 | { | |
171 | if (ppc_inst_prefixed(x)) | |
172 | sprintf(str, "%08x %08x", ppc_inst_val(x), ppc_inst_suffix(x)); | |
173 | else | |
174 | sprintf(str, "%08x", ppc_inst_val(x)); | |
175 | ||
176 | return str; | |
177 | } | |
178 | ||
179 | #define ppc_inst_as_str(x) \ | |
180 | ({ \ | |
181 | char __str[PPC_INST_STR_LEN]; \ | |
182 | __ppc_inst_as_str(__str, x); \ | |
183 | __str; \ | |
184 | }) | |
185 | ||
41d6cf68 | 186 | int copy_inst_from_kernel_nofault(struct ppc_inst *inst, struct ppc_inst *src); |
95b980a0 | 187 | |
75346251 | 188 | #endif /* _ASM_POWERPC_INST_H */ |