inst.h (4403B)
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__) 41static 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 49static inline u32 ppc_inst_val(ppc_inst_t x) 50{ 51 return x; 52} 53#define ppc_inst(x) (x) 54#endif 55 56static 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 64static 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 72static inline u32 ppc_inst_suffix(ppc_inst_t x) 73{ 74 return 0; 75} 76 77#endif /* CONFIG_PPC64 */ 78 79static 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 87static 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 92static 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 97static 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 106static 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 */ 115static 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 124static 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 134static 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#define PPC_INST_STR_LEN sizeof("00000000 00000000") 143 144static inline char *__ppc_inst_as_str(char str[PPC_INST_STR_LEN], ppc_inst_t x) 145{ 146 if (ppc_inst_prefixed(x)) 147 sprintf(str, "%08x %08x", ppc_inst_val(x), ppc_inst_suffix(x)); 148 else 149 sprintf(str, "%08x", ppc_inst_val(x)); 150 151 return str; 152} 153 154#define ppc_inst_as_str(x) \ 155({ \ 156 char __str[PPC_INST_STR_LEN]; \ 157 __ppc_inst_as_str(__str, x); \ 158 __str; \ 159}) 160 161static inline int __copy_inst_from_kernel_nofault(ppc_inst_t *inst, u32 *src) 162{ 163 unsigned int val, suffix; 164 165/* See https://github.com/ClangBuiltLinux/linux/issues/1521 */ 166#if defined(CONFIG_CC_IS_CLANG) && CONFIG_CLANG_VERSION < 140000 167 val = suffix = 0; 168#endif 169 __get_kernel_nofault(&val, src, u32, Efault); 170 if (IS_ENABLED(CONFIG_PPC64) && get_op(val) == OP_PREFIX) { 171 __get_kernel_nofault(&suffix, src + 1, u32, Efault); 172 *inst = ppc_inst_prefix(val, suffix); 173 } else { 174 *inst = ppc_inst(val); 175 } 176 return 0; 177Efault: 178 return -EFAULT; 179} 180 181static inline int copy_inst_from_kernel_nofault(ppc_inst_t *inst, u32 *src) 182{ 183 if (unlikely(!is_kernel_addr((unsigned long)src))) 184 return -ERANGE; 185 186 return __copy_inst_from_kernel_nofault(inst, src); 187} 188 189#endif /* _ASM_POWERPC_INST_H */