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