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

simulate-insn.c (8148B)


      1// SPDX-License-Identifier: GPL-2.0+
      2
      3#include <linux/bitops.h>
      4#include <linux/kernel.h>
      5#include <linux/kprobes.h>
      6
      7#include "decode-insn.h"
      8#include "simulate-insn.h"
      9
     10static inline bool csky_insn_reg_get_val(struct pt_regs *regs,
     11					 unsigned long index,
     12					 unsigned long *ptr)
     13{
     14	if (index < 14)
     15		*ptr = *(&regs->a0 + index);
     16
     17	if (index > 15 && index < 31)
     18		*ptr = *(&regs->exregs[0] + index - 16);
     19
     20	switch (index) {
     21	case 14:
     22		*ptr = regs->usp;
     23		break;
     24	case 15:
     25		*ptr = regs->lr;
     26		break;
     27	case 31:
     28		*ptr = regs->tls;
     29		break;
     30	default:
     31		goto fail;
     32	}
     33
     34	return true;
     35fail:
     36	return false;
     37}
     38
     39static inline bool csky_insn_reg_set_val(struct pt_regs *regs,
     40					 unsigned long index,
     41					 unsigned long val)
     42{
     43	if (index < 14)
     44		*(&regs->a0 + index) = val;
     45
     46	if (index > 15 && index < 31)
     47		*(&regs->exregs[0] + index - 16) = val;
     48
     49	switch (index) {
     50	case 14:
     51		regs->usp = val;
     52		break;
     53	case 15:
     54		regs->lr = val;
     55		break;
     56	case 31:
     57		regs->tls = val;
     58		break;
     59	default:
     60		goto fail;
     61	}
     62
     63	return true;
     64fail:
     65	return false;
     66}
     67
     68void __kprobes
     69simulate_br16(u32 opcode, long addr, struct pt_regs *regs)
     70{
     71	instruction_pointer_set(regs,
     72		addr + sign_extend32((opcode & 0x3ff) << 1, 9));
     73}
     74
     75void __kprobes
     76simulate_br32(u32 opcode, long addr, struct pt_regs *regs)
     77{
     78	instruction_pointer_set(regs,
     79		addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
     80}
     81
     82void __kprobes
     83simulate_bt16(u32 opcode, long addr, struct pt_regs *regs)
     84{
     85	if (regs->sr & 1)
     86		instruction_pointer_set(regs,
     87			addr + sign_extend32((opcode & 0x3ff) << 1, 9));
     88	else
     89		instruction_pointer_set(regs, addr + 2);
     90}
     91
     92void __kprobes
     93simulate_bt32(u32 opcode, long addr, struct pt_regs *regs)
     94{
     95	if (regs->sr & 1)
     96		instruction_pointer_set(regs,
     97			addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
     98	else
     99		instruction_pointer_set(regs, addr + 4);
    100}
    101
    102void __kprobes
    103simulate_bf16(u32 opcode, long addr, struct pt_regs *regs)
    104{
    105	if (!(regs->sr & 1))
    106		instruction_pointer_set(regs,
    107			addr + sign_extend32((opcode & 0x3ff) << 1, 9));
    108	else
    109		instruction_pointer_set(regs, addr + 2);
    110}
    111
    112void __kprobes
    113simulate_bf32(u32 opcode, long addr, struct pt_regs *regs)
    114{
    115	if (!(regs->sr & 1))
    116		instruction_pointer_set(regs,
    117			addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
    118	else
    119		instruction_pointer_set(regs, addr + 4);
    120}
    121
    122void __kprobes
    123simulate_jmp16(u32 opcode, long addr, struct pt_regs *regs)
    124{
    125	unsigned long tmp = (opcode >> 2) & 0xf;
    126
    127	csky_insn_reg_get_val(regs, tmp, &tmp);
    128
    129	instruction_pointer_set(regs, tmp & 0xfffffffe);
    130}
    131
    132void __kprobes
    133simulate_jmp32(u32 opcode, long addr, struct pt_regs *regs)
    134{
    135	unsigned long tmp = opcode & 0x1f;
    136
    137	csky_insn_reg_get_val(regs, tmp, &tmp);
    138
    139	instruction_pointer_set(regs, tmp & 0xfffffffe);
    140}
    141
    142void __kprobes
    143simulate_jsr16(u32 opcode, long addr, struct pt_regs *regs)
    144{
    145	unsigned long tmp = (opcode >> 2) & 0xf;
    146
    147	csky_insn_reg_get_val(regs, tmp, &tmp);
    148
    149	regs->lr = addr + 2;
    150
    151	instruction_pointer_set(regs, tmp & 0xfffffffe);
    152}
    153
    154void __kprobes
    155simulate_jsr32(u32 opcode, long addr, struct pt_regs *regs)
    156{
    157	unsigned long tmp = opcode & 0x1f;
    158
    159	csky_insn_reg_get_val(regs, tmp, &tmp);
    160
    161	regs->lr = addr + 4;
    162
    163	instruction_pointer_set(regs, tmp & 0xfffffffe);
    164}
    165
    166void __kprobes
    167simulate_lrw16(u32 opcode, long addr, struct pt_regs *regs)
    168{
    169	unsigned long val;
    170	unsigned long tmp = (opcode & 0x300) >> 3;
    171	unsigned long offset = ((opcode & 0x1f) | tmp) << 2;
    172
    173	tmp = (opcode & 0xe0) >> 5;
    174
    175	val = *(unsigned int *)(instruction_pointer(regs) + offset);
    176
    177	csky_insn_reg_set_val(regs, tmp, val);
    178}
    179
    180void __kprobes
    181simulate_lrw32(u32 opcode, long addr, struct pt_regs *regs)
    182{
    183	unsigned long val;
    184	unsigned long offset = (opcode & 0xffff0000) >> 14;
    185	unsigned long tmp = opcode & 0x0000001f;
    186
    187	val = *(unsigned int *)
    188		((instruction_pointer(regs) + offset) & 0xfffffffc);
    189
    190	csky_insn_reg_set_val(regs, tmp, val);
    191}
    192
    193void __kprobes
    194simulate_pop16(u32 opcode, long addr, struct pt_regs *regs)
    195{
    196	unsigned long *tmp = (unsigned long *)regs->usp;
    197	int i;
    198
    199	for (i = 0; i < (opcode & 0xf); i++) {
    200		csky_insn_reg_set_val(regs, i + 4, *tmp);
    201		tmp += 1;
    202	}
    203
    204	if (opcode & 0x10) {
    205		csky_insn_reg_set_val(regs, 15, *tmp);
    206		tmp += 1;
    207	}
    208
    209	regs->usp = (unsigned long)tmp;
    210
    211	instruction_pointer_set(regs, regs->lr);
    212}
    213
    214void __kprobes
    215simulate_pop32(u32 opcode, long addr, struct pt_regs *regs)
    216{
    217	unsigned long *tmp = (unsigned long *)regs->usp;
    218	int i;
    219
    220	for (i = 0; i < ((opcode & 0xf0000) >> 16); i++) {
    221		csky_insn_reg_set_val(regs, i + 4, *tmp);
    222		tmp += 1;
    223	}
    224
    225	if (opcode & 0x100000) {
    226		csky_insn_reg_set_val(regs, 15, *tmp);
    227		tmp += 1;
    228	}
    229
    230	for (i = 0; i < ((opcode & 0xe00000) >> 21); i++) {
    231		csky_insn_reg_set_val(regs, i + 16, *tmp);
    232		tmp += 1;
    233	}
    234
    235	if (opcode & 0x1000000) {
    236		csky_insn_reg_set_val(regs, 29, *tmp);
    237		tmp += 1;
    238	}
    239
    240	regs->usp = (unsigned long)tmp;
    241
    242	instruction_pointer_set(regs, regs->lr);
    243}
    244
    245void __kprobes
    246simulate_bez32(u32 opcode, long addr, struct pt_regs *regs)
    247{
    248	unsigned long tmp = opcode & 0x1f;
    249
    250	csky_insn_reg_get_val(regs, tmp, &tmp);
    251
    252	if (tmp == 0) {
    253		instruction_pointer_set(regs,
    254			addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
    255	} else
    256		instruction_pointer_set(regs, addr + 4);
    257}
    258
    259void __kprobes
    260simulate_bnez32(u32 opcode, long addr, struct pt_regs *regs)
    261{
    262	unsigned long tmp = opcode & 0x1f;
    263
    264	csky_insn_reg_get_val(regs, tmp, &tmp);
    265
    266	if (tmp != 0) {
    267		instruction_pointer_set(regs,
    268			addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
    269	} else
    270		instruction_pointer_set(regs, addr + 4);
    271}
    272
    273void __kprobes
    274simulate_bnezad32(u32 opcode, long addr, struct pt_regs *regs)
    275{
    276	unsigned long tmp = opcode & 0x1f;
    277	long val;
    278
    279	csky_insn_reg_get_val(regs, tmp, (unsigned long *)&val);
    280
    281	val -= 1;
    282
    283	if (val > 0) {
    284		instruction_pointer_set(regs,
    285			addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
    286	} else
    287		instruction_pointer_set(regs, addr + 4);
    288
    289	csky_insn_reg_set_val(regs, tmp, (unsigned long)val);
    290}
    291
    292void __kprobes
    293simulate_bhsz32(u32 opcode, long addr, struct pt_regs *regs)
    294{
    295	unsigned long tmp = opcode & 0x1f;
    296	unsigned long val;
    297
    298	csky_insn_reg_get_val(regs, tmp, &val);
    299
    300	if ((long) val >= 0) {
    301		instruction_pointer_set(regs,
    302			addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
    303	} else
    304		instruction_pointer_set(regs, addr + 4);
    305}
    306
    307void __kprobes
    308simulate_bhz32(u32 opcode, long addr, struct pt_regs *regs)
    309{
    310	unsigned long tmp = opcode & 0x1f;
    311	unsigned long val;
    312
    313	csky_insn_reg_get_val(regs, tmp, &val);
    314
    315	if ((long) val > 0) {
    316		instruction_pointer_set(regs,
    317			addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
    318	} else
    319		instruction_pointer_set(regs, addr + 4);
    320}
    321
    322void __kprobes
    323simulate_blsz32(u32 opcode, long addr, struct pt_regs *regs)
    324{
    325	unsigned long tmp = opcode & 0x1f;
    326	unsigned long val;
    327
    328	csky_insn_reg_get_val(regs, tmp, &val);
    329
    330	if ((long) val <= 0) {
    331		instruction_pointer_set(regs,
    332			addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
    333	} else
    334		instruction_pointer_set(regs, addr + 4);
    335}
    336
    337void __kprobes
    338simulate_blz32(u32 opcode, long addr, struct pt_regs *regs)
    339{
    340	unsigned long tmp = opcode & 0x1f;
    341	unsigned long val;
    342
    343	csky_insn_reg_get_val(regs, tmp, &val);
    344
    345	if ((long) val < 0) {
    346		instruction_pointer_set(regs,
    347			addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));
    348	} else
    349		instruction_pointer_set(regs, addr + 4);
    350}
    351
    352void __kprobes
    353simulate_bsr32(u32 opcode, long addr, struct pt_regs *regs)
    354{
    355	unsigned long tmp;
    356
    357	tmp = (opcode & 0xffff) << 16;
    358	tmp |= (opcode & 0xffff0000) >> 16;
    359
    360	instruction_pointer_set(regs,
    361		addr + sign_extend32((tmp & 0x3ffffff) << 1, 15));
    362
    363	regs->lr = addr + 4;
    364}
    365
    366void __kprobes
    367simulate_jmpi32(u32 opcode, long addr, struct pt_regs *regs)
    368{
    369	unsigned long val;
    370	unsigned long offset = ((opcode & 0xffff0000) >> 14);
    371
    372	val = *(unsigned int *)
    373		((instruction_pointer(regs) + offset) & 0xfffffffc);
    374
    375	instruction_pointer_set(regs, val);
    376}
    377
    378void __kprobes
    379simulate_jsri32(u32 opcode, long addr, struct pt_regs *regs)
    380{
    381	unsigned long val;
    382	unsigned long offset = ((opcode & 0xffff0000) >> 14);
    383
    384	val = *(unsigned int *)
    385		((instruction_pointer(regs) + offset) & 0xfffffffc);
    386
    387	regs->lr = addr + 4;
    388
    389	instruction_pointer_set(regs, val);
    390}