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

pf_in.c (10068B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Fault Injection Test harness (FI)
      4 *  Copyright (C) Intel Crop.
      5 */
      6
      7/*  Id: pf_in.c,v 1.1.1.1 2002/11/12 05:56:32 brlock Exp
      8 *  Copyright by Intel Crop., 2002
      9 *  Louis Zhuang (louis.zhuang@intel.com)
     10 *
     11 *  Bjorn Steinbrink (B.Steinbrink@gmx.de), 2007
     12 */
     13
     14#include <linux/ptrace.h> /* struct pt_regs */
     15#include "pf_in.h"
     16
     17#ifdef __i386__
     18/* IA32 Manual 3, 2-1 */
     19static unsigned char prefix_codes[] = {
     20	0xF0, 0xF2, 0xF3, 0x2E, 0x36, 0x3E, 0x26, 0x64,
     21	0x65, 0x66, 0x67
     22};
     23/* IA32 Manual 3, 3-432*/
     24static unsigned int reg_rop[] = {
     25	0x8A, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F
     26};
     27static unsigned int reg_wop[] = { 0x88, 0x89, 0xAA, 0xAB };
     28static unsigned int imm_wop[] = { 0xC6, 0xC7 };
     29/* IA32 Manual 3, 3-432*/
     30static unsigned int rw8[] = { 0x88, 0x8A, 0xC6, 0xAA };
     31static unsigned int rw32[] = {
     32	0x89, 0x8B, 0xC7, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F, 0xAB
     33};
     34static unsigned int mw8[] = { 0x88, 0x8A, 0xC6, 0xB60F, 0xBE0F, 0xAA };
     35static unsigned int mw16[] = { 0xB70F, 0xBF0F };
     36static unsigned int mw32[] = { 0x89, 0x8B, 0xC7, 0xAB };
     37static unsigned int mw64[] = {};
     38#else /* not __i386__ */
     39static unsigned char prefix_codes[] = {
     40	0x66, 0x67, 0x2E, 0x3E, 0x26, 0x64, 0x65, 0x36,
     41	0xF0, 0xF3, 0xF2,
     42	/* REX Prefixes */
     43	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
     44	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
     45};
     46/* AMD64 Manual 3, Appendix A*/
     47static unsigned int reg_rop[] = {
     48	0x8A, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F
     49};
     50static unsigned int reg_wop[] = { 0x88, 0x89, 0xAA, 0xAB };
     51static unsigned int imm_wop[] = { 0xC6, 0xC7 };
     52static unsigned int rw8[] = { 0xC6, 0x88, 0x8A, 0xAA };
     53static unsigned int rw32[] = {
     54	0xC7, 0x89, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F, 0xAB
     55};
     56/* 8 bit only */
     57static unsigned int mw8[] = { 0xC6, 0x88, 0x8A, 0xB60F, 0xBE0F, 0xAA };
     58/* 16 bit only */
     59static unsigned int mw16[] = { 0xB70F, 0xBF0F };
     60/* 16 or 32 bit */
     61static unsigned int mw32[] = { 0xC7 };
     62/* 16, 32 or 64 bit */
     63static unsigned int mw64[] = { 0x89, 0x8B, 0xAB };
     64#endif /* not __i386__ */
     65
     66struct prefix_bits {
     67	unsigned shorted:1;
     68	unsigned enlarged:1;
     69	unsigned rexr:1;
     70	unsigned rex:1;
     71};
     72
     73static int skip_prefix(unsigned char *addr, struct prefix_bits *prf)
     74{
     75	int i;
     76	unsigned char *p = addr;
     77	prf->shorted = 0;
     78	prf->enlarged = 0;
     79	prf->rexr = 0;
     80	prf->rex = 0;
     81
     82restart:
     83	for (i = 0; i < ARRAY_SIZE(prefix_codes); i++) {
     84		if (*p == prefix_codes[i]) {
     85			if (*p == 0x66)
     86				prf->shorted = 1;
     87#ifdef __amd64__
     88			if ((*p & 0xf8) == 0x48)
     89				prf->enlarged = 1;
     90			if ((*p & 0xf4) == 0x44)
     91				prf->rexr = 1;
     92			if ((*p & 0xf0) == 0x40)
     93				prf->rex = 1;
     94#endif
     95			p++;
     96			goto restart;
     97		}
     98	}
     99
    100	return (p - addr);
    101}
    102
    103static int get_opcode(unsigned char *addr, unsigned int *opcode)
    104{
    105	int len;
    106
    107	if (*addr == 0x0F) {
    108		/* 0x0F is extension instruction */
    109		*opcode = *(unsigned short *)addr;
    110		len = 2;
    111	} else {
    112		*opcode = *addr;
    113		len = 1;
    114	}
    115
    116	return len;
    117}
    118
    119#define CHECK_OP_TYPE(opcode, array, type) \
    120	for (i = 0; i < ARRAY_SIZE(array); i++) { \
    121		if (array[i] == opcode) { \
    122			rv = type; \
    123			goto exit; \
    124		} \
    125	}
    126
    127enum reason_type get_ins_type(unsigned long ins_addr)
    128{
    129	unsigned int opcode;
    130	unsigned char *p;
    131	struct prefix_bits prf;
    132	int i;
    133	enum reason_type rv = OTHERS;
    134
    135	p = (unsigned char *)ins_addr;
    136	p += skip_prefix(p, &prf);
    137	p += get_opcode(p, &opcode);
    138
    139	CHECK_OP_TYPE(opcode, reg_rop, REG_READ);
    140	CHECK_OP_TYPE(opcode, reg_wop, REG_WRITE);
    141	CHECK_OP_TYPE(opcode, imm_wop, IMM_WRITE);
    142
    143exit:
    144	return rv;
    145}
    146#undef CHECK_OP_TYPE
    147
    148static unsigned int get_ins_reg_width(unsigned long ins_addr)
    149{
    150	unsigned int opcode;
    151	unsigned char *p;
    152	struct prefix_bits prf;
    153	int i;
    154
    155	p = (unsigned char *)ins_addr;
    156	p += skip_prefix(p, &prf);
    157	p += get_opcode(p, &opcode);
    158
    159	for (i = 0; i < ARRAY_SIZE(rw8); i++)
    160		if (rw8[i] == opcode)
    161			return 1;
    162
    163	for (i = 0; i < ARRAY_SIZE(rw32); i++)
    164		if (rw32[i] == opcode)
    165			return prf.shorted ? 2 : (prf.enlarged ? 8 : 4);
    166
    167	printk(KERN_ERR "mmiotrace: Unknown opcode 0x%02x\n", opcode);
    168	return 0;
    169}
    170
    171unsigned int get_ins_mem_width(unsigned long ins_addr)
    172{
    173	unsigned int opcode;
    174	unsigned char *p;
    175	struct prefix_bits prf;
    176	int i;
    177
    178	p = (unsigned char *)ins_addr;
    179	p += skip_prefix(p, &prf);
    180	p += get_opcode(p, &opcode);
    181
    182	for (i = 0; i < ARRAY_SIZE(mw8); i++)
    183		if (mw8[i] == opcode)
    184			return 1;
    185
    186	for (i = 0; i < ARRAY_SIZE(mw16); i++)
    187		if (mw16[i] == opcode)
    188			return 2;
    189
    190	for (i = 0; i < ARRAY_SIZE(mw32); i++)
    191		if (mw32[i] == opcode)
    192			return prf.shorted ? 2 : 4;
    193
    194	for (i = 0; i < ARRAY_SIZE(mw64); i++)
    195		if (mw64[i] == opcode)
    196			return prf.shorted ? 2 : (prf.enlarged ? 8 : 4);
    197
    198	printk(KERN_ERR "mmiotrace: Unknown opcode 0x%02x\n", opcode);
    199	return 0;
    200}
    201
    202/*
    203 * Define register ident in mod/rm byte.
    204 * Note: these are NOT the same as in ptrace-abi.h.
    205 */
    206enum {
    207	arg_AL = 0,
    208	arg_CL = 1,
    209	arg_DL = 2,
    210	arg_BL = 3,
    211	arg_AH = 4,
    212	arg_CH = 5,
    213	arg_DH = 6,
    214	arg_BH = 7,
    215
    216	arg_AX = 0,
    217	arg_CX = 1,
    218	arg_DX = 2,
    219	arg_BX = 3,
    220	arg_SP = 4,
    221	arg_BP = 5,
    222	arg_SI = 6,
    223	arg_DI = 7,
    224#ifdef __amd64__
    225	arg_R8  = 8,
    226	arg_R9  = 9,
    227	arg_R10 = 10,
    228	arg_R11 = 11,
    229	arg_R12 = 12,
    230	arg_R13 = 13,
    231	arg_R14 = 14,
    232	arg_R15 = 15
    233#endif
    234};
    235
    236static unsigned char *get_reg_w8(int no, int rex, struct pt_regs *regs)
    237{
    238	unsigned char *rv = NULL;
    239
    240	switch (no) {
    241	case arg_AL:
    242		rv = (unsigned char *)&regs->ax;
    243		break;
    244	case arg_BL:
    245		rv = (unsigned char *)&regs->bx;
    246		break;
    247	case arg_CL:
    248		rv = (unsigned char *)&regs->cx;
    249		break;
    250	case arg_DL:
    251		rv = (unsigned char *)&regs->dx;
    252		break;
    253#ifdef __amd64__
    254	case arg_R8:
    255		rv = (unsigned char *)&regs->r8;
    256		break;
    257	case arg_R9:
    258		rv = (unsigned char *)&regs->r9;
    259		break;
    260	case arg_R10:
    261		rv = (unsigned char *)&regs->r10;
    262		break;
    263	case arg_R11:
    264		rv = (unsigned char *)&regs->r11;
    265		break;
    266	case arg_R12:
    267		rv = (unsigned char *)&regs->r12;
    268		break;
    269	case arg_R13:
    270		rv = (unsigned char *)&regs->r13;
    271		break;
    272	case arg_R14:
    273		rv = (unsigned char *)&regs->r14;
    274		break;
    275	case arg_R15:
    276		rv = (unsigned char *)&regs->r15;
    277		break;
    278#endif
    279	default:
    280		break;
    281	}
    282
    283	if (rv)
    284		return rv;
    285
    286	if (rex) {
    287		/*
    288		 * If REX prefix exists, access low bytes of SI etc.
    289		 * instead of AH etc.
    290		 */
    291		switch (no) {
    292		case arg_SI:
    293			rv = (unsigned char *)&regs->si;
    294			break;
    295		case arg_DI:
    296			rv = (unsigned char *)&regs->di;
    297			break;
    298		case arg_BP:
    299			rv = (unsigned char *)&regs->bp;
    300			break;
    301		case arg_SP:
    302			rv = (unsigned char *)&regs->sp;
    303			break;
    304		default:
    305			break;
    306		}
    307	} else {
    308		switch (no) {
    309		case arg_AH:
    310			rv = 1 + (unsigned char *)&regs->ax;
    311			break;
    312		case arg_BH:
    313			rv = 1 + (unsigned char *)&regs->bx;
    314			break;
    315		case arg_CH:
    316			rv = 1 + (unsigned char *)&regs->cx;
    317			break;
    318		case arg_DH:
    319			rv = 1 + (unsigned char *)&regs->dx;
    320			break;
    321		default:
    322			break;
    323		}
    324	}
    325
    326	if (!rv)
    327		printk(KERN_ERR "mmiotrace: Error reg no# %d\n", no);
    328
    329	return rv;
    330}
    331
    332static unsigned long *get_reg_w32(int no, struct pt_regs *regs)
    333{
    334	unsigned long *rv = NULL;
    335
    336	switch (no) {
    337	case arg_AX:
    338		rv = &regs->ax;
    339		break;
    340	case arg_BX:
    341		rv = &regs->bx;
    342		break;
    343	case arg_CX:
    344		rv = &regs->cx;
    345		break;
    346	case arg_DX:
    347		rv = &regs->dx;
    348		break;
    349	case arg_SP:
    350		rv = &regs->sp;
    351		break;
    352	case arg_BP:
    353		rv = &regs->bp;
    354		break;
    355	case arg_SI:
    356		rv = &regs->si;
    357		break;
    358	case arg_DI:
    359		rv = &regs->di;
    360		break;
    361#ifdef __amd64__
    362	case arg_R8:
    363		rv = &regs->r8;
    364		break;
    365	case arg_R9:
    366		rv = &regs->r9;
    367		break;
    368	case arg_R10:
    369		rv = &regs->r10;
    370		break;
    371	case arg_R11:
    372		rv = &regs->r11;
    373		break;
    374	case arg_R12:
    375		rv = &regs->r12;
    376		break;
    377	case arg_R13:
    378		rv = &regs->r13;
    379		break;
    380	case arg_R14:
    381		rv = &regs->r14;
    382		break;
    383	case arg_R15:
    384		rv = &regs->r15;
    385		break;
    386#endif
    387	default:
    388		printk(KERN_ERR "mmiotrace: Error reg no# %d\n", no);
    389	}
    390
    391	return rv;
    392}
    393
    394unsigned long get_ins_reg_val(unsigned long ins_addr, struct pt_regs *regs)
    395{
    396	unsigned int opcode;
    397	int reg;
    398	unsigned char *p;
    399	struct prefix_bits prf;
    400	int i;
    401
    402	p = (unsigned char *)ins_addr;
    403	p += skip_prefix(p, &prf);
    404	p += get_opcode(p, &opcode);
    405	for (i = 0; i < ARRAY_SIZE(reg_rop); i++)
    406		if (reg_rop[i] == opcode)
    407			goto do_work;
    408
    409	for (i = 0; i < ARRAY_SIZE(reg_wop); i++)
    410		if (reg_wop[i] == opcode)
    411			goto do_work;
    412
    413	printk(KERN_ERR "mmiotrace: Not a register instruction, opcode "
    414							"0x%02x\n", opcode);
    415	goto err;
    416
    417do_work:
    418	/* for STOS, source register is fixed */
    419	if (opcode == 0xAA || opcode == 0xAB) {
    420		reg = arg_AX;
    421	} else {
    422		unsigned char mod_rm = *p;
    423		reg = ((mod_rm >> 3) & 0x7) | (prf.rexr << 3);
    424	}
    425	switch (get_ins_reg_width(ins_addr)) {
    426	case 1:
    427		return *get_reg_w8(reg, prf.rex, regs);
    428
    429	case 2:
    430		return *(unsigned short *)get_reg_w32(reg, regs);
    431
    432	case 4:
    433		return *(unsigned int *)get_reg_w32(reg, regs);
    434
    435#ifdef __amd64__
    436	case 8:
    437		return *(unsigned long *)get_reg_w32(reg, regs);
    438#endif
    439
    440	default:
    441		printk(KERN_ERR "mmiotrace: Error width# %d\n", reg);
    442	}
    443
    444err:
    445	return 0;
    446}
    447
    448unsigned long get_ins_imm_val(unsigned long ins_addr)
    449{
    450	unsigned int opcode;
    451	unsigned char mod_rm;
    452	unsigned char mod;
    453	unsigned char *p;
    454	struct prefix_bits prf;
    455	int i;
    456
    457	p = (unsigned char *)ins_addr;
    458	p += skip_prefix(p, &prf);
    459	p += get_opcode(p, &opcode);
    460	for (i = 0; i < ARRAY_SIZE(imm_wop); i++)
    461		if (imm_wop[i] == opcode)
    462			goto do_work;
    463
    464	printk(KERN_ERR "mmiotrace: Not an immediate instruction, opcode "
    465							"0x%02x\n", opcode);
    466	goto err;
    467
    468do_work:
    469	mod_rm = *p;
    470	mod = mod_rm >> 6;
    471	p++;
    472	switch (mod) {
    473	case 0:
    474		/* if r/m is 5 we have a 32 disp (IA32 Manual 3, Table 2-2)  */
    475		/* AMD64: XXX Check for address size prefix? */
    476		if ((mod_rm & 0x7) == 0x5)
    477			p += 4;
    478		break;
    479
    480	case 1:
    481		p += 1;
    482		break;
    483
    484	case 2:
    485		p += 4;
    486		break;
    487
    488	case 3:
    489	default:
    490		printk(KERN_ERR "mmiotrace: not a memory access instruction "
    491						"at 0x%lx, rm_mod=0x%02x\n",
    492						ins_addr, mod_rm);
    493	}
    494
    495	switch (get_ins_reg_width(ins_addr)) {
    496	case 1:
    497		return *(unsigned char *)p;
    498
    499	case 2:
    500		return *(unsigned short *)p;
    501
    502	case 4:
    503		return *(unsigned int *)p;
    504
    505#ifdef __amd64__
    506	case 8:
    507		return *(unsigned long *)p;
    508#endif
    509
    510	default:
    511		printk(KERN_ERR "mmiotrace: Error: width.\n");
    512	}
    513
    514err:
    515	return 0;
    516}