Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Simple sanity tests for instruction emulation infrastructure.
4 *
5 * Copyright IBM Corp. 2016
6 */
7
8#define pr_fmt(fmt) "emulate_step_test: " fmt
9
10#include <linux/ptrace.h>
11#include <asm/sstep.h>
12#include <asm/ppc-opcode.h>
13#include <asm/code-patching.h>
14#include <asm/inst.h>
15
16#define IMM_L(i) ((uintptr_t)(i) & 0xffff)
17#define IMM_DS(i) ((uintptr_t)(i) & 0xfffc)
18
19/*
20 * Defined with TEST_ prefix so it does not conflict with other
21 * definitions.
22 */
23#define TEST_LD(r, base, i) ppc_inst(PPC_INST_LD | ___PPC_RT(r) | \
24 ___PPC_RA(base) | IMM_DS(i))
25#define TEST_LWZ(r, base, i) ppc_inst(PPC_INST_LWZ | ___PPC_RT(r) | \
26 ___PPC_RA(base) | IMM_L(i))
27#define TEST_LWZX(t, a, b) ppc_inst(PPC_INST_LWZX | ___PPC_RT(t) | \
28 ___PPC_RA(a) | ___PPC_RB(b))
29#define TEST_STD(r, base, i) ppc_inst(PPC_INST_STD | ___PPC_RS(r) | \
30 ___PPC_RA(base) | IMM_DS(i))
31#define TEST_LDARX(t, a, b, eh) ppc_inst(PPC_INST_LDARX | ___PPC_RT(t) | \
32 ___PPC_RA(a) | ___PPC_RB(b) | \
33 __PPC_EH(eh))
34#define TEST_STDCX(s, a, b) ppc_inst(PPC_INST_STDCX | ___PPC_RS(s) | \
35 ___PPC_RA(a) | ___PPC_RB(b))
36#define TEST_LFSX(t, a, b) ppc_inst(PPC_INST_LFSX | ___PPC_RT(t) | \
37 ___PPC_RA(a) | ___PPC_RB(b))
38#define TEST_STFSX(s, a, b) ppc_inst(PPC_INST_STFSX | ___PPC_RS(s) | \
39 ___PPC_RA(a) | ___PPC_RB(b))
40#define TEST_LFDX(t, a, b) ppc_inst(PPC_INST_LFDX | ___PPC_RT(t) | \
41 ___PPC_RA(a) | ___PPC_RB(b))
42#define TEST_STFDX(s, a, b) ppc_inst(PPC_INST_STFDX | ___PPC_RS(s) | \
43 ___PPC_RA(a) | ___PPC_RB(b))
44#define TEST_LVX(t, a, b) ppc_inst(PPC_INST_LVX | ___PPC_RT(t) | \
45 ___PPC_RA(a) | ___PPC_RB(b))
46#define TEST_STVX(s, a, b) ppc_inst(PPC_INST_STVX | ___PPC_RS(s) | \
47 ___PPC_RA(a) | ___PPC_RB(b))
48#define TEST_LXVD2X(s, a, b) ppc_inst(PPC_INST_LXVD2X | VSX_XX1((s), R##a, R##b))
49#define TEST_STXVD2X(s, a, b) ppc_inst(PPC_INST_STXVD2X | VSX_XX1((s), R##a, R##b))
50#define TEST_ADD(t, a, b) ppc_inst(PPC_INST_ADD | ___PPC_RT(t) | \
51 ___PPC_RA(a) | ___PPC_RB(b))
52#define TEST_ADD_DOT(t, a, b) ppc_inst(PPC_INST_ADD | ___PPC_RT(t) | \
53 ___PPC_RA(a) | ___PPC_RB(b) | 0x1)
54#define TEST_ADDC(t, a, b) ppc_inst(PPC_INST_ADDC | ___PPC_RT(t) | \
55 ___PPC_RA(a) | ___PPC_RB(b))
56#define TEST_ADDC_DOT(t, a, b) ppc_inst(PPC_INST_ADDC | ___PPC_RT(t) | \
57 ___PPC_RA(a) | ___PPC_RB(b) | 0x1)
58
59#define MAX_SUBTESTS 16
60
61#define IGNORE_GPR(n) (0x1UL << (n))
62#define IGNORE_XER (0x1UL << 32)
63#define IGNORE_CCR (0x1UL << 33)
64
65static void __init init_pt_regs(struct pt_regs *regs)
66{
67 static unsigned long msr;
68 static bool msr_cached;
69
70 memset(regs, 0, sizeof(struct pt_regs));
71
72 if (likely(msr_cached)) {
73 regs->msr = msr;
74 return;
75 }
76
77 asm volatile("mfmsr %0" : "=r"(regs->msr));
78
79 regs->msr |= MSR_FP;
80 regs->msr |= MSR_VEC;
81 regs->msr |= MSR_VSX;
82
83 msr = regs->msr;
84 msr_cached = true;
85}
86
87static void __init show_result(char *mnemonic, char *result)
88{
89 pr_info("%-14s : %s\n", mnemonic, result);
90}
91
92static void __init show_result_with_descr(char *mnemonic, char *descr,
93 char *result)
94{
95 pr_info("%-14s : %-50s %s\n", mnemonic, descr, result);
96}
97
98static void __init test_ld(void)
99{
100 struct pt_regs regs;
101 unsigned long a = 0x23;
102 int stepped = -1;
103
104 init_pt_regs(®s);
105 regs.gpr[3] = (unsigned long) &a;
106
107 /* ld r5, 0(r3) */
108 stepped = emulate_step(®s, TEST_LD(5, 3, 0));
109
110 if (stepped == 1 && regs.gpr[5] == a)
111 show_result("ld", "PASS");
112 else
113 show_result("ld", "FAIL");
114}
115
116static void __init test_lwz(void)
117{
118 struct pt_regs regs;
119 unsigned int a = 0x4545;
120 int stepped = -1;
121
122 init_pt_regs(®s);
123 regs.gpr[3] = (unsigned long) &a;
124
125 /* lwz r5, 0(r3) */
126 stepped = emulate_step(®s, TEST_LWZ(5, 3, 0));
127
128 if (stepped == 1 && regs.gpr[5] == a)
129 show_result("lwz", "PASS");
130 else
131 show_result("lwz", "FAIL");
132}
133
134static void __init test_lwzx(void)
135{
136 struct pt_regs regs;
137 unsigned int a[3] = {0x0, 0x0, 0x1234};
138 int stepped = -1;
139
140 init_pt_regs(®s);
141 regs.gpr[3] = (unsigned long) a;
142 regs.gpr[4] = 8;
143 regs.gpr[5] = 0x8765;
144
145 /* lwzx r5, r3, r4 */
146 stepped = emulate_step(®s, TEST_LWZX(5, 3, 4));
147 if (stepped == 1 && regs.gpr[5] == a[2])
148 show_result("lwzx", "PASS");
149 else
150 show_result("lwzx", "FAIL");
151}
152
153static void __init test_std(void)
154{
155 struct pt_regs regs;
156 unsigned long a = 0x1234;
157 int stepped = -1;
158
159 init_pt_regs(®s);
160 regs.gpr[3] = (unsigned long) &a;
161 regs.gpr[5] = 0x5678;
162
163 /* std r5, 0(r3) */
164 stepped = emulate_step(®s, TEST_STD(5, 3, 0));
165 if (stepped == 1 && regs.gpr[5] == a)
166 show_result("std", "PASS");
167 else
168 show_result("std", "FAIL");
169}
170
171static void __init test_ldarx_stdcx(void)
172{
173 struct pt_regs regs;
174 unsigned long a = 0x1234;
175 int stepped = -1;
176 unsigned long cr0_eq = 0x1 << 29; /* eq bit of CR0 */
177
178 init_pt_regs(®s);
179 asm volatile("mfcr %0" : "=r"(regs.ccr));
180
181
182 /*** ldarx ***/
183
184 regs.gpr[3] = (unsigned long) &a;
185 regs.gpr[4] = 0;
186 regs.gpr[5] = 0x5678;
187
188 /* ldarx r5, r3, r4, 0 */
189 stepped = emulate_step(®s, TEST_LDARX(5, 3, 4, 0));
190
191 /*
192 * Don't touch 'a' here. Touching 'a' can do Load/store
193 * of 'a' which result in failure of subsequent stdcx.
194 * Instead, use hardcoded value for comparison.
195 */
196 if (stepped <= 0 || regs.gpr[5] != 0x1234) {
197 show_result("ldarx / stdcx.", "FAIL (ldarx)");
198 return;
199 }
200
201
202 /*** stdcx. ***/
203
204 regs.gpr[5] = 0x9ABC;
205
206 /* stdcx. r5, r3, r4 */
207 stepped = emulate_step(®s, TEST_STDCX(5, 3, 4));
208
209 /*
210 * Two possible scenarios that indicates successful emulation
211 * of stdcx. :
212 * 1. Reservation is active and store is performed. In this
213 * case cr0.eq bit will be set to 1.
214 * 2. Reservation is not active and store is not performed.
215 * In this case cr0.eq bit will be set to 0.
216 */
217 if (stepped == 1 && ((regs.gpr[5] == a && (regs.ccr & cr0_eq))
218 || (regs.gpr[5] != a && !(regs.ccr & cr0_eq))))
219 show_result("ldarx / stdcx.", "PASS");
220 else
221 show_result("ldarx / stdcx.", "FAIL (stdcx.)");
222}
223
224#ifdef CONFIG_PPC_FPU
225static void __init test_lfsx_stfsx(void)
226{
227 struct pt_regs regs;
228 union {
229 float a;
230 int b;
231 } c;
232 int cached_b;
233 int stepped = -1;
234
235 init_pt_regs(®s);
236
237
238 /*** lfsx ***/
239
240 c.a = 123.45;
241 cached_b = c.b;
242
243 regs.gpr[3] = (unsigned long) &c.a;
244 regs.gpr[4] = 0;
245
246 /* lfsx frt10, r3, r4 */
247 stepped = emulate_step(®s, TEST_LFSX(10, 3, 4));
248
249 if (stepped == 1)
250 show_result("lfsx", "PASS");
251 else
252 show_result("lfsx", "FAIL");
253
254
255 /*** stfsx ***/
256
257 c.a = 678.91;
258
259 /* stfsx frs10, r3, r4 */
260 stepped = emulate_step(®s, TEST_STFSX(10, 3, 4));
261
262 if (stepped == 1 && c.b == cached_b)
263 show_result("stfsx", "PASS");
264 else
265 show_result("stfsx", "FAIL");
266}
267
268static void __init test_lfdx_stfdx(void)
269{
270 struct pt_regs regs;
271 union {
272 double a;
273 long b;
274 } c;
275 long cached_b;
276 int stepped = -1;
277
278 init_pt_regs(®s);
279
280
281 /*** lfdx ***/
282
283 c.a = 123456.78;
284 cached_b = c.b;
285
286 regs.gpr[3] = (unsigned long) &c.a;
287 regs.gpr[4] = 0;
288
289 /* lfdx frt10, r3, r4 */
290 stepped = emulate_step(®s, TEST_LFDX(10, 3, 4));
291
292 if (stepped == 1)
293 show_result("lfdx", "PASS");
294 else
295 show_result("lfdx", "FAIL");
296
297
298 /*** stfdx ***/
299
300 c.a = 987654.32;
301
302 /* stfdx frs10, r3, r4 */
303 stepped = emulate_step(®s, TEST_STFDX(10, 3, 4));
304
305 if (stepped == 1 && c.b == cached_b)
306 show_result("stfdx", "PASS");
307 else
308 show_result("stfdx", "FAIL");
309}
310#else
311static void __init test_lfsx_stfsx(void)
312{
313 show_result("lfsx", "SKIP (CONFIG_PPC_FPU is not set)");
314 show_result("stfsx", "SKIP (CONFIG_PPC_FPU is not set)");
315}
316
317static void __init test_lfdx_stfdx(void)
318{
319 show_result("lfdx", "SKIP (CONFIG_PPC_FPU is not set)");
320 show_result("stfdx", "SKIP (CONFIG_PPC_FPU is not set)");
321}
322#endif /* CONFIG_PPC_FPU */
323
324#ifdef CONFIG_ALTIVEC
325static void __init test_lvx_stvx(void)
326{
327 struct pt_regs regs;
328 union {
329 vector128 a;
330 u32 b[4];
331 } c;
332 u32 cached_b[4];
333 int stepped = -1;
334
335 init_pt_regs(®s);
336
337
338 /*** lvx ***/
339
340 cached_b[0] = c.b[0] = 923745;
341 cached_b[1] = c.b[1] = 2139478;
342 cached_b[2] = c.b[2] = 9012;
343 cached_b[3] = c.b[3] = 982134;
344
345 regs.gpr[3] = (unsigned long) &c.a;
346 regs.gpr[4] = 0;
347
348 /* lvx vrt10, r3, r4 */
349 stepped = emulate_step(®s, TEST_LVX(10, 3, 4));
350
351 if (stepped == 1)
352 show_result("lvx", "PASS");
353 else
354 show_result("lvx", "FAIL");
355
356
357 /*** stvx ***/
358
359 c.b[0] = 4987513;
360 c.b[1] = 84313948;
361 c.b[2] = 71;
362 c.b[3] = 498532;
363
364 /* stvx vrs10, r3, r4 */
365 stepped = emulate_step(®s, TEST_STVX(10, 3, 4));
366
367 if (stepped == 1 && cached_b[0] == c.b[0] && cached_b[1] == c.b[1] &&
368 cached_b[2] == c.b[2] && cached_b[3] == c.b[3])
369 show_result("stvx", "PASS");
370 else
371 show_result("stvx", "FAIL");
372}
373#else
374static void __init test_lvx_stvx(void)
375{
376 show_result("lvx", "SKIP (CONFIG_ALTIVEC is not set)");
377 show_result("stvx", "SKIP (CONFIG_ALTIVEC is not set)");
378}
379#endif /* CONFIG_ALTIVEC */
380
381#ifdef CONFIG_VSX
382static void __init test_lxvd2x_stxvd2x(void)
383{
384 struct pt_regs regs;
385 union {
386 vector128 a;
387 u32 b[4];
388 } c;
389 u32 cached_b[4];
390 int stepped = -1;
391
392 init_pt_regs(®s);
393
394
395 /*** lxvd2x ***/
396
397 cached_b[0] = c.b[0] = 18233;
398 cached_b[1] = c.b[1] = 34863571;
399 cached_b[2] = c.b[2] = 834;
400 cached_b[3] = c.b[3] = 6138911;
401
402 regs.gpr[3] = (unsigned long) &c.a;
403 regs.gpr[4] = 0;
404
405 /* lxvd2x vsr39, r3, r4 */
406 stepped = emulate_step(®s, TEST_LXVD2X(39, 3, 4));
407
408 if (stepped == 1 && cpu_has_feature(CPU_FTR_VSX)) {
409 show_result("lxvd2x", "PASS");
410 } else {
411 if (!cpu_has_feature(CPU_FTR_VSX))
412 show_result("lxvd2x", "PASS (!CPU_FTR_VSX)");
413 else
414 show_result("lxvd2x", "FAIL");
415 }
416
417
418 /*** stxvd2x ***/
419
420 c.b[0] = 21379463;
421 c.b[1] = 87;
422 c.b[2] = 374234;
423 c.b[3] = 4;
424
425 /* stxvd2x vsr39, r3, r4 */
426 stepped = emulate_step(®s, TEST_STXVD2X(39, 3, 4));
427
428 if (stepped == 1 && cached_b[0] == c.b[0] && cached_b[1] == c.b[1] &&
429 cached_b[2] == c.b[2] && cached_b[3] == c.b[3] &&
430 cpu_has_feature(CPU_FTR_VSX)) {
431 show_result("stxvd2x", "PASS");
432 } else {
433 if (!cpu_has_feature(CPU_FTR_VSX))
434 show_result("stxvd2x", "PASS (!CPU_FTR_VSX)");
435 else
436 show_result("stxvd2x", "FAIL");
437 }
438}
439#else
440static void __init test_lxvd2x_stxvd2x(void)
441{
442 show_result("lxvd2x", "SKIP (CONFIG_VSX is not set)");
443 show_result("stxvd2x", "SKIP (CONFIG_VSX is not set)");
444}
445#endif /* CONFIG_VSX */
446
447static void __init run_tests_load_store(void)
448{
449 test_ld();
450 test_lwz();
451 test_lwzx();
452 test_std();
453 test_ldarx_stdcx();
454 test_lfsx_stfsx();
455 test_lfdx_stfdx();
456 test_lvx_stvx();
457 test_lxvd2x_stxvd2x();
458}
459
460struct compute_test {
461 char *mnemonic;
462 struct {
463 char *descr;
464 unsigned long flags;
465 struct ppc_inst instr;
466 struct pt_regs regs;
467 } subtests[MAX_SUBTESTS + 1];
468};
469
470static struct compute_test compute_tests[] = {
471 {
472 .mnemonic = "nop",
473 .subtests = {
474 {
475 .descr = "R0 = LONG_MAX",
476 .instr = ppc_inst(PPC_INST_NOP),
477 .regs = {
478 .gpr[0] = LONG_MAX,
479 }
480 }
481 }
482 },
483 {
484 .mnemonic = "add",
485 .subtests = {
486 {
487 .descr = "RA = LONG_MIN, RB = LONG_MIN",
488 .instr = TEST_ADD(20, 21, 22),
489 .regs = {
490 .gpr[21] = LONG_MIN,
491 .gpr[22] = LONG_MIN,
492 }
493 },
494 {
495 .descr = "RA = LONG_MIN, RB = LONG_MAX",
496 .instr = TEST_ADD(20, 21, 22),
497 .regs = {
498 .gpr[21] = LONG_MIN,
499 .gpr[22] = LONG_MAX,
500 }
501 },
502 {
503 .descr = "RA = LONG_MAX, RB = LONG_MAX",
504 .instr = TEST_ADD(20, 21, 22),
505 .regs = {
506 .gpr[21] = LONG_MAX,
507 .gpr[22] = LONG_MAX,
508 }
509 },
510 {
511 .descr = "RA = ULONG_MAX, RB = ULONG_MAX",
512 .instr = TEST_ADD(20, 21, 22),
513 .regs = {
514 .gpr[21] = ULONG_MAX,
515 .gpr[22] = ULONG_MAX,
516 }
517 },
518 {
519 .descr = "RA = ULONG_MAX, RB = 0x1",
520 .instr = TEST_ADD(20, 21, 22),
521 .regs = {
522 .gpr[21] = ULONG_MAX,
523 .gpr[22] = 0x1,
524 }
525 },
526 {
527 .descr = "RA = INT_MIN, RB = INT_MIN",
528 .instr = TEST_ADD(20, 21, 22),
529 .regs = {
530 .gpr[21] = INT_MIN,
531 .gpr[22] = INT_MIN,
532 }
533 },
534 {
535 .descr = "RA = INT_MIN, RB = INT_MAX",
536 .instr = TEST_ADD(20, 21, 22),
537 .regs = {
538 .gpr[21] = INT_MIN,
539 .gpr[22] = INT_MAX,
540 }
541 },
542 {
543 .descr = "RA = INT_MAX, RB = INT_MAX",
544 .instr = TEST_ADD(20, 21, 22),
545 .regs = {
546 .gpr[21] = INT_MAX,
547 .gpr[22] = INT_MAX,
548 }
549 },
550 {
551 .descr = "RA = UINT_MAX, RB = UINT_MAX",
552 .instr = TEST_ADD(20, 21, 22),
553 .regs = {
554 .gpr[21] = UINT_MAX,
555 .gpr[22] = UINT_MAX,
556 }
557 },
558 {
559 .descr = "RA = UINT_MAX, RB = 0x1",
560 .instr = TEST_ADD(20, 21, 22),
561 .regs = {
562 .gpr[21] = UINT_MAX,
563 .gpr[22] = 0x1,
564 }
565 }
566 }
567 },
568 {
569 .mnemonic = "add.",
570 .subtests = {
571 {
572 .descr = "RA = LONG_MIN, RB = LONG_MIN",
573 .flags = IGNORE_CCR,
574 .instr = TEST_ADD_DOT(20, 21, 22),
575 .regs = {
576 .gpr[21] = LONG_MIN,
577 .gpr[22] = LONG_MIN,
578 }
579 },
580 {
581 .descr = "RA = LONG_MIN, RB = LONG_MAX",
582 .instr = TEST_ADD_DOT(20, 21, 22),
583 .regs = {
584 .gpr[21] = LONG_MIN,
585 .gpr[22] = LONG_MAX,
586 }
587 },
588 {
589 .descr = "RA = LONG_MAX, RB = LONG_MAX",
590 .flags = IGNORE_CCR,
591 .instr = TEST_ADD_DOT(20, 21, 22),
592 .regs = {
593 .gpr[21] = LONG_MAX,
594 .gpr[22] = LONG_MAX,
595 }
596 },
597 {
598 .descr = "RA = ULONG_MAX, RB = ULONG_MAX",
599 .instr = TEST_ADD_DOT(20, 21, 22),
600 .regs = {
601 .gpr[21] = ULONG_MAX,
602 .gpr[22] = ULONG_MAX,
603 }
604 },
605 {
606 .descr = "RA = ULONG_MAX, RB = 0x1",
607 .instr = TEST_ADD_DOT(20, 21, 22),
608 .regs = {
609 .gpr[21] = ULONG_MAX,
610 .gpr[22] = 0x1,
611 }
612 },
613 {
614 .descr = "RA = INT_MIN, RB = INT_MIN",
615 .instr = TEST_ADD_DOT(20, 21, 22),
616 .regs = {
617 .gpr[21] = INT_MIN,
618 .gpr[22] = INT_MIN,
619 }
620 },
621 {
622 .descr = "RA = INT_MIN, RB = INT_MAX",
623 .instr = TEST_ADD_DOT(20, 21, 22),
624 .regs = {
625 .gpr[21] = INT_MIN,
626 .gpr[22] = INT_MAX,
627 }
628 },
629 {
630 .descr = "RA = INT_MAX, RB = INT_MAX",
631 .instr = TEST_ADD_DOT(20, 21, 22),
632 .regs = {
633 .gpr[21] = INT_MAX,
634 .gpr[22] = INT_MAX,
635 }
636 },
637 {
638 .descr = "RA = UINT_MAX, RB = UINT_MAX",
639 .instr = TEST_ADD_DOT(20, 21, 22),
640 .regs = {
641 .gpr[21] = UINT_MAX,
642 .gpr[22] = UINT_MAX,
643 }
644 },
645 {
646 .descr = "RA = UINT_MAX, RB = 0x1",
647 .instr = TEST_ADD_DOT(20, 21, 22),
648 .regs = {
649 .gpr[21] = UINT_MAX,
650 .gpr[22] = 0x1,
651 }
652 }
653 }
654 },
655 {
656 .mnemonic = "addc",
657 .subtests = {
658 {
659 .descr = "RA = LONG_MIN, RB = LONG_MIN",
660 .instr = TEST_ADDC(20, 21, 22),
661 .regs = {
662 .gpr[21] = LONG_MIN,
663 .gpr[22] = LONG_MIN,
664 }
665 },
666 {
667 .descr = "RA = LONG_MIN, RB = LONG_MAX",
668 .instr = TEST_ADDC(20, 21, 22),
669 .regs = {
670 .gpr[21] = LONG_MIN,
671 .gpr[22] = LONG_MAX,
672 }
673 },
674 {
675 .descr = "RA = LONG_MAX, RB = LONG_MAX",
676 .instr = TEST_ADDC(20, 21, 22),
677 .regs = {
678 .gpr[21] = LONG_MAX,
679 .gpr[22] = LONG_MAX,
680 }
681 },
682 {
683 .descr = "RA = ULONG_MAX, RB = ULONG_MAX",
684 .instr = TEST_ADDC(20, 21, 22),
685 .regs = {
686 .gpr[21] = ULONG_MAX,
687 .gpr[22] = ULONG_MAX,
688 }
689 },
690 {
691 .descr = "RA = ULONG_MAX, RB = 0x1",
692 .instr = TEST_ADDC(20, 21, 22),
693 .regs = {
694 .gpr[21] = ULONG_MAX,
695 .gpr[22] = 0x1,
696 }
697 },
698 {
699 .descr = "RA = INT_MIN, RB = INT_MIN",
700 .instr = TEST_ADDC(20, 21, 22),
701 .regs = {
702 .gpr[21] = INT_MIN,
703 .gpr[22] = INT_MIN,
704 }
705 },
706 {
707 .descr = "RA = INT_MIN, RB = INT_MAX",
708 .instr = TEST_ADDC(20, 21, 22),
709 .regs = {
710 .gpr[21] = INT_MIN,
711 .gpr[22] = INT_MAX,
712 }
713 },
714 {
715 .descr = "RA = INT_MAX, RB = INT_MAX",
716 .instr = TEST_ADDC(20, 21, 22),
717 .regs = {
718 .gpr[21] = INT_MAX,
719 .gpr[22] = INT_MAX,
720 }
721 },
722 {
723 .descr = "RA = UINT_MAX, RB = UINT_MAX",
724 .instr = TEST_ADDC(20, 21, 22),
725 .regs = {
726 .gpr[21] = UINT_MAX,
727 .gpr[22] = UINT_MAX,
728 }
729 },
730 {
731 .descr = "RA = UINT_MAX, RB = 0x1",
732 .instr = TEST_ADDC(20, 21, 22),
733 .regs = {
734 .gpr[21] = UINT_MAX,
735 .gpr[22] = 0x1,
736 }
737 },
738 {
739 .descr = "RA = LONG_MIN | INT_MIN, RB = LONG_MIN | INT_MIN",
740 .instr = TEST_ADDC(20, 21, 22),
741 .regs = {
742 .gpr[21] = LONG_MIN | (uint)INT_MIN,
743 .gpr[22] = LONG_MIN | (uint)INT_MIN,
744 }
745 }
746 }
747 },
748 {
749 .mnemonic = "addc.",
750 .subtests = {
751 {
752 .descr = "RA = LONG_MIN, RB = LONG_MIN",
753 .flags = IGNORE_CCR,
754 .instr = TEST_ADDC_DOT(20, 21, 22),
755 .regs = {
756 .gpr[21] = LONG_MIN,
757 .gpr[22] = LONG_MIN,
758 }
759 },
760 {
761 .descr = "RA = LONG_MIN, RB = LONG_MAX",
762 .instr = TEST_ADDC_DOT(20, 21, 22),
763 .regs = {
764 .gpr[21] = LONG_MIN,
765 .gpr[22] = LONG_MAX,
766 }
767 },
768 {
769 .descr = "RA = LONG_MAX, RB = LONG_MAX",
770 .flags = IGNORE_CCR,
771 .instr = TEST_ADDC_DOT(20, 21, 22),
772 .regs = {
773 .gpr[21] = LONG_MAX,
774 .gpr[22] = LONG_MAX,
775 }
776 },
777 {
778 .descr = "RA = ULONG_MAX, RB = ULONG_MAX",
779 .instr = TEST_ADDC_DOT(20, 21, 22),
780 .regs = {
781 .gpr[21] = ULONG_MAX,
782 .gpr[22] = ULONG_MAX,
783 }
784 },
785 {
786 .descr = "RA = ULONG_MAX, RB = 0x1",
787 .instr = TEST_ADDC_DOT(20, 21, 22),
788 .regs = {
789 .gpr[21] = ULONG_MAX,
790 .gpr[22] = 0x1,
791 }
792 },
793 {
794 .descr = "RA = INT_MIN, RB = INT_MIN",
795 .instr = TEST_ADDC_DOT(20, 21, 22),
796 .regs = {
797 .gpr[21] = INT_MIN,
798 .gpr[22] = INT_MIN,
799 }
800 },
801 {
802 .descr = "RA = INT_MIN, RB = INT_MAX",
803 .instr = TEST_ADDC_DOT(20, 21, 22),
804 .regs = {
805 .gpr[21] = INT_MIN,
806 .gpr[22] = INT_MAX,
807 }
808 },
809 {
810 .descr = "RA = INT_MAX, RB = INT_MAX",
811 .instr = TEST_ADDC_DOT(20, 21, 22),
812 .regs = {
813 .gpr[21] = INT_MAX,
814 .gpr[22] = INT_MAX,
815 }
816 },
817 {
818 .descr = "RA = UINT_MAX, RB = UINT_MAX",
819 .instr = TEST_ADDC_DOT(20, 21, 22),
820 .regs = {
821 .gpr[21] = UINT_MAX,
822 .gpr[22] = UINT_MAX,
823 }
824 },
825 {
826 .descr = "RA = UINT_MAX, RB = 0x1",
827 .instr = TEST_ADDC_DOT(20, 21, 22),
828 .regs = {
829 .gpr[21] = UINT_MAX,
830 .gpr[22] = 0x1,
831 }
832 },
833 {
834 .descr = "RA = LONG_MIN | INT_MIN, RB = LONG_MIN | INT_MIN",
835 .instr = TEST_ADDC_DOT(20, 21, 22),
836 .regs = {
837 .gpr[21] = LONG_MIN | (uint)INT_MIN,
838 .gpr[22] = LONG_MIN | (uint)INT_MIN,
839 }
840 }
841 }
842 }
843};
844
845static int __init emulate_compute_instr(struct pt_regs *regs,
846 struct ppc_inst instr)
847{
848 struct instruction_op op;
849
850 if (!regs || !ppc_inst_val(instr))
851 return -EINVAL;
852
853 if (analyse_instr(&op, regs, instr) != 1 ||
854 GETTYPE(op.type) != COMPUTE) {
855 pr_info("emulation failed, instruction = 0x%08x\n", ppc_inst_val(instr));
856 return -EFAULT;
857 }
858
859 emulate_update_regs(regs, &op);
860 return 0;
861}
862
863static int __init execute_compute_instr(struct pt_regs *regs,
864 struct ppc_inst instr)
865{
866 extern int exec_instr(struct pt_regs *regs);
867 extern s32 patch__exec_instr;
868
869 if (!regs || !ppc_inst_val(instr))
870 return -EINVAL;
871
872 /* Patch the NOP with the actual instruction */
873 patch_instruction_site(&patch__exec_instr, instr);
874 if (exec_instr(regs)) {
875 pr_info("execution failed, instruction = 0x%08x\n", ppc_inst_val(instr));
876 return -EFAULT;
877 }
878
879 return 0;
880}
881
882#define gpr_mismatch(gprn, exp, got) \
883 pr_info("GPR%u mismatch, exp = 0x%016lx, got = 0x%016lx\n", \
884 gprn, exp, got)
885
886#define reg_mismatch(name, exp, got) \
887 pr_info("%s mismatch, exp = 0x%016lx, got = 0x%016lx\n", \
888 name, exp, got)
889
890static void __init run_tests_compute(void)
891{
892 unsigned long flags;
893 struct compute_test *test;
894 struct pt_regs *regs, exp, got;
895 unsigned int i, j, k;
896 struct ppc_inst instr;
897 bool ignore_gpr, ignore_xer, ignore_ccr, passed;
898
899 for (i = 0; i < ARRAY_SIZE(compute_tests); i++) {
900 test = &compute_tests[i];
901
902 for (j = 0; j < MAX_SUBTESTS && test->subtests[j].descr; j++) {
903 instr = test->subtests[j].instr;
904 flags = test->subtests[j].flags;
905 regs = &test->subtests[j].regs;
906 ignore_xer = flags & IGNORE_XER;
907 ignore_ccr = flags & IGNORE_CCR;
908 passed = true;
909
910 memcpy(&exp, regs, sizeof(struct pt_regs));
911 memcpy(&got, regs, sizeof(struct pt_regs));
912
913 /*
914 * Set a compatible MSR value explicitly to ensure
915 * that XER and CR bits are updated appropriately
916 */
917 exp.msr = MSR_KERNEL;
918 got.msr = MSR_KERNEL;
919
920 if (emulate_compute_instr(&got, instr) ||
921 execute_compute_instr(&exp, instr)) {
922 passed = false;
923 goto print;
924 }
925
926 /* Verify GPR values */
927 for (k = 0; k < 32; k++) {
928 ignore_gpr = flags & IGNORE_GPR(k);
929 if (!ignore_gpr && exp.gpr[k] != got.gpr[k]) {
930 passed = false;
931 gpr_mismatch(k, exp.gpr[k], got.gpr[k]);
932 }
933 }
934
935 /* Verify LR value */
936 if (exp.link != got.link) {
937 passed = false;
938 reg_mismatch("LR", exp.link, got.link);
939 }
940
941 /* Verify XER value */
942 if (!ignore_xer && exp.xer != got.xer) {
943 passed = false;
944 reg_mismatch("XER", exp.xer, got.xer);
945 }
946
947 /* Verify CR value */
948 if (!ignore_ccr && exp.ccr != got.ccr) {
949 passed = false;
950 reg_mismatch("CR", exp.ccr, got.ccr);
951 }
952
953print:
954 show_result_with_descr(test->mnemonic,
955 test->subtests[j].descr,
956 passed ? "PASS" : "FAIL");
957 }
958 }
959}
960
961static int __init test_emulate_step(void)
962{
963 printk(KERN_INFO "Running instruction emulation self-tests ...\n");
964 run_tests_load_store();
965 run_tests_compute();
966
967 return 0;
968}
969late_initcall(test_emulate_step);