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