cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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 */