Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/x86/mm/pf_in.c
29266 views
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 ([email protected])
10
*
11
* Bjorn Steinbrink ([email protected]), 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 */
19
static unsigned char prefix_codes[] = {
20
0xF0, 0xF2, 0xF3, 0x2E, 0x36, 0x3E, 0x26, 0x64,
21
0x65, 0x66, 0x67
22
};
23
/* IA32 Manual 3, 3-432*/
24
static unsigned int reg_rop[] = {
25
0x8A, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F
26
};
27
static unsigned int reg_wop[] = { 0x88, 0x89, 0xAA, 0xAB };
28
static unsigned int imm_wop[] = { 0xC6, 0xC7 };
29
/* IA32 Manual 3, 3-432*/
30
static unsigned int rw8[] = { 0x88, 0x8A, 0xC6, 0xAA };
31
static unsigned int rw32[] = {
32
0x89, 0x8B, 0xC7, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F, 0xAB
33
};
34
static unsigned int mw8[] = { 0x88, 0x8A, 0xC6, 0xB60F, 0xBE0F, 0xAA };
35
static unsigned int mw16[] = { 0xB70F, 0xBF0F };
36
static unsigned int mw32[] = { 0x89, 0x8B, 0xC7, 0xAB };
37
static unsigned int mw64[] = {};
38
#else /* not __i386__ */
39
static 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*/
47
static unsigned int reg_rop[] = {
48
0x8A, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F
49
};
50
static unsigned int reg_wop[] = { 0x88, 0x89, 0xAA, 0xAB };
51
static unsigned int imm_wop[] = { 0xC6, 0xC7 };
52
static unsigned int rw8[] = { 0xC6, 0x88, 0x8A, 0xAA };
53
static unsigned int rw32[] = {
54
0xC7, 0x89, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F, 0xAB
55
};
56
/* 8 bit only */
57
static unsigned int mw8[] = { 0xC6, 0x88, 0x8A, 0xB60F, 0xBE0F, 0xAA };
58
/* 16 bit only */
59
static unsigned int mw16[] = { 0xB70F, 0xBF0F };
60
/* 16 or 32 bit */
61
static unsigned int mw32[] = { 0xC7 };
62
/* 16, 32 or 64 bit */
63
static unsigned int mw64[] = { 0x89, 0x8B, 0xAB };
64
#endif /* not __i386__ */
65
66
struct prefix_bits {
67
unsigned shorted:1;
68
unsigned enlarged:1;
69
unsigned rexr:1;
70
unsigned rex:1;
71
};
72
73
static 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
82
restart:
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
103
static 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
127
enum 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
143
exit:
144
return rv;
145
}
146
#undef CHECK_OP_TYPE
147
148
static 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
171
unsigned 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
*/
206
enum {
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
236
static 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
332
static 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
394
unsigned 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
417
do_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
444
err:
445
return 0;
446
}
447
448
unsigned 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
468
do_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
514
err:
515
return 0;
516
}
517
518