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