|
3 | 3 | * Copyright 2008 Michael Ellerman, IBM Corporation.
|
4 | 4 | */
|
5 | 5 |
|
6 |
| -#include <linux/kernel.h> |
7 | 6 | #include <linux/kprobes.h>
|
8 | 7 | #include <linux/vmalloc.h>
|
9 | 8 | #include <linux/init.h>
|
10 |
| -#include <linux/mm.h> |
11 | 9 | #include <linux/cpuhotplug.h>
|
12 |
| -#include <linux/slab.h> |
13 | 10 | #include <linux/uaccess.h>
|
14 | 11 |
|
15 | 12 | #include <asm/tlbflush.h>
|
@@ -354,355 +351,3 @@ int translate_branch(ppc_inst_t *instr, const u32 *dest, const u32 *src)
|
354 | 351 |
|
355 | 352 | return 1;
|
356 | 353 | }
|
357 |
| - |
358 |
| -#ifdef CONFIG_CODE_PATCHING_SELFTEST |
359 |
| - |
360 |
| -static int __init instr_is_branch_to_addr(const u32 *instr, unsigned long addr) |
361 |
| -{ |
362 |
| - if (instr_is_branch_iform(ppc_inst_read(instr)) || |
363 |
| - instr_is_branch_bform(ppc_inst_read(instr))) |
364 |
| - return branch_target(instr) == addr; |
365 |
| - |
366 |
| - return 0; |
367 |
| -} |
368 |
| - |
369 |
| -static void __init test_trampoline(void) |
370 |
| -{ |
371 |
| - asm ("nop;nop;\n"); |
372 |
| -} |
373 |
| - |
374 |
| -#define check(x) do { \ |
375 |
| - if (!(x)) \ |
376 |
| - pr_err("code-patching: test failed at line %d\n", __LINE__); \ |
377 |
| -} while (0) |
378 |
| - |
379 |
| -static void __init test_branch_iform(void) |
380 |
| -{ |
381 |
| - int err; |
382 |
| - ppc_inst_t instr; |
383 |
| - u32 tmp[2]; |
384 |
| - u32 *iptr = tmp; |
385 |
| - unsigned long addr = (unsigned long)tmp; |
386 |
| - |
387 |
| - /* The simplest case, branch to self, no flags */ |
388 |
| - check(instr_is_branch_iform(ppc_inst(0x48000000))); |
389 |
| - /* All bits of target set, and flags */ |
390 |
| - check(instr_is_branch_iform(ppc_inst(0x4bffffff))); |
391 |
| - /* High bit of opcode set, which is wrong */ |
392 |
| - check(!instr_is_branch_iform(ppc_inst(0xcbffffff))); |
393 |
| - /* Middle bits of opcode set, which is wrong */ |
394 |
| - check(!instr_is_branch_iform(ppc_inst(0x7bffffff))); |
395 |
| - |
396 |
| - /* Simplest case, branch to self with link */ |
397 |
| - check(instr_is_branch_iform(ppc_inst(0x48000001))); |
398 |
| - /* All bits of targets set */ |
399 |
| - check(instr_is_branch_iform(ppc_inst(0x4bfffffd))); |
400 |
| - /* Some bits of targets set */ |
401 |
| - check(instr_is_branch_iform(ppc_inst(0x4bff00fd))); |
402 |
| - /* Must be a valid branch to start with */ |
403 |
| - check(!instr_is_branch_iform(ppc_inst(0x7bfffffd))); |
404 |
| - |
405 |
| - /* Absolute branch to 0x100 */ |
406 |
| - patch_instruction(iptr, ppc_inst(0x48000103)); |
407 |
| - check(instr_is_branch_to_addr(iptr, 0x100)); |
408 |
| - /* Absolute branch to 0x420fc */ |
409 |
| - patch_instruction(iptr, ppc_inst(0x480420ff)); |
410 |
| - check(instr_is_branch_to_addr(iptr, 0x420fc)); |
411 |
| - /* Maximum positive relative branch, + 20MB - 4B */ |
412 |
| - patch_instruction(iptr, ppc_inst(0x49fffffc)); |
413 |
| - check(instr_is_branch_to_addr(iptr, addr + 0x1FFFFFC)); |
414 |
| - /* Smallest negative relative branch, - 4B */ |
415 |
| - patch_instruction(iptr, ppc_inst(0x4bfffffc)); |
416 |
| - check(instr_is_branch_to_addr(iptr, addr - 4)); |
417 |
| - /* Largest negative relative branch, - 32 MB */ |
418 |
| - patch_instruction(iptr, ppc_inst(0x4a000000)); |
419 |
| - check(instr_is_branch_to_addr(iptr, addr - 0x2000000)); |
420 |
| - |
421 |
| - /* Branch to self, with link */ |
422 |
| - err = create_branch(&instr, iptr, addr, BRANCH_SET_LINK); |
423 |
| - patch_instruction(iptr, instr); |
424 |
| - check(instr_is_branch_to_addr(iptr, addr)); |
425 |
| - |
426 |
| - /* Branch to self - 0x100, with link */ |
427 |
| - err = create_branch(&instr, iptr, addr - 0x100, BRANCH_SET_LINK); |
428 |
| - patch_instruction(iptr, instr); |
429 |
| - check(instr_is_branch_to_addr(iptr, addr - 0x100)); |
430 |
| - |
431 |
| - /* Branch to self + 0x100, no link */ |
432 |
| - err = create_branch(&instr, iptr, addr + 0x100, 0); |
433 |
| - patch_instruction(iptr, instr); |
434 |
| - check(instr_is_branch_to_addr(iptr, addr + 0x100)); |
435 |
| - |
436 |
| - /* Maximum relative negative offset, - 32 MB */ |
437 |
| - err = create_branch(&instr, iptr, addr - 0x2000000, BRANCH_SET_LINK); |
438 |
| - patch_instruction(iptr, instr); |
439 |
| - check(instr_is_branch_to_addr(iptr, addr - 0x2000000)); |
440 |
| - |
441 |
| - /* Out of range relative negative offset, - 32 MB + 4*/ |
442 |
| - err = create_branch(&instr, iptr, addr - 0x2000004, BRANCH_SET_LINK); |
443 |
| - check(err); |
444 |
| - |
445 |
| - /* Out of range relative positive offset, + 32 MB */ |
446 |
| - err = create_branch(&instr, iptr, addr + 0x2000000, BRANCH_SET_LINK); |
447 |
| - check(err); |
448 |
| - |
449 |
| - /* Unaligned target */ |
450 |
| - err = create_branch(&instr, iptr, addr + 3, BRANCH_SET_LINK); |
451 |
| - check(err); |
452 |
| - |
453 |
| - /* Check flags are masked correctly */ |
454 |
| - err = create_branch(&instr, iptr, addr, 0xFFFFFFFC); |
455 |
| - patch_instruction(iptr, instr); |
456 |
| - check(instr_is_branch_to_addr(iptr, addr)); |
457 |
| - check(ppc_inst_equal(instr, ppc_inst(0x48000000))); |
458 |
| -} |
459 |
| - |
460 |
| -static void __init test_create_function_call(void) |
461 |
| -{ |
462 |
| - u32 *iptr; |
463 |
| - unsigned long dest; |
464 |
| - ppc_inst_t instr; |
465 |
| - |
466 |
| - /* Check we can create a function call */ |
467 |
| - iptr = (u32 *)ppc_function_entry(test_trampoline); |
468 |
| - dest = ppc_function_entry(test_create_function_call); |
469 |
| - create_branch(&instr, iptr, dest, BRANCH_SET_LINK); |
470 |
| - patch_instruction(iptr, instr); |
471 |
| - check(instr_is_branch_to_addr(iptr, dest)); |
472 |
| -} |
473 |
| - |
474 |
| -static void __init test_branch_bform(void) |
475 |
| -{ |
476 |
| - int err; |
477 |
| - unsigned long addr; |
478 |
| - ppc_inst_t instr; |
479 |
| - u32 tmp[2]; |
480 |
| - u32 *iptr = tmp; |
481 |
| - unsigned int flags; |
482 |
| - |
483 |
| - addr = (unsigned long)iptr; |
484 |
| - |
485 |
| - /* The simplest case, branch to self, no flags */ |
486 |
| - check(instr_is_branch_bform(ppc_inst(0x40000000))); |
487 |
| - /* All bits of target set, and flags */ |
488 |
| - check(instr_is_branch_bform(ppc_inst(0x43ffffff))); |
489 |
| - /* High bit of opcode set, which is wrong */ |
490 |
| - check(!instr_is_branch_bform(ppc_inst(0xc3ffffff))); |
491 |
| - /* Middle bits of opcode set, which is wrong */ |
492 |
| - check(!instr_is_branch_bform(ppc_inst(0x7bffffff))); |
493 |
| - |
494 |
| - /* Absolute conditional branch to 0x100 */ |
495 |
| - patch_instruction(iptr, ppc_inst(0x43ff0103)); |
496 |
| - check(instr_is_branch_to_addr(iptr, 0x100)); |
497 |
| - /* Absolute conditional branch to 0x20fc */ |
498 |
| - patch_instruction(iptr, ppc_inst(0x43ff20ff)); |
499 |
| - check(instr_is_branch_to_addr(iptr, 0x20fc)); |
500 |
| - /* Maximum positive relative conditional branch, + 32 KB - 4B */ |
501 |
| - patch_instruction(iptr, ppc_inst(0x43ff7ffc)); |
502 |
| - check(instr_is_branch_to_addr(iptr, addr + 0x7FFC)); |
503 |
| - /* Smallest negative relative conditional branch, - 4B */ |
504 |
| - patch_instruction(iptr, ppc_inst(0x43fffffc)); |
505 |
| - check(instr_is_branch_to_addr(iptr, addr - 4)); |
506 |
| - /* Largest negative relative conditional branch, - 32 KB */ |
507 |
| - patch_instruction(iptr, ppc_inst(0x43ff8000)); |
508 |
| - check(instr_is_branch_to_addr(iptr, addr - 0x8000)); |
509 |
| - |
510 |
| - /* All condition code bits set & link */ |
511 |
| - flags = 0x3ff000 | BRANCH_SET_LINK; |
512 |
| - |
513 |
| - /* Branch to self */ |
514 |
| - err = create_cond_branch(&instr, iptr, addr, flags); |
515 |
| - patch_instruction(iptr, instr); |
516 |
| - check(instr_is_branch_to_addr(iptr, addr)); |
517 |
| - |
518 |
| - /* Branch to self - 0x100 */ |
519 |
| - err = create_cond_branch(&instr, iptr, addr - 0x100, flags); |
520 |
| - patch_instruction(iptr, instr); |
521 |
| - check(instr_is_branch_to_addr(iptr, addr - 0x100)); |
522 |
| - |
523 |
| - /* Branch to self + 0x100 */ |
524 |
| - err = create_cond_branch(&instr, iptr, addr + 0x100, flags); |
525 |
| - patch_instruction(iptr, instr); |
526 |
| - check(instr_is_branch_to_addr(iptr, addr + 0x100)); |
527 |
| - |
528 |
| - /* Maximum relative negative offset, - 32 KB */ |
529 |
| - err = create_cond_branch(&instr, iptr, addr - 0x8000, flags); |
530 |
| - patch_instruction(iptr, instr); |
531 |
| - check(instr_is_branch_to_addr(iptr, addr - 0x8000)); |
532 |
| - |
533 |
| - /* Out of range relative negative offset, - 32 KB + 4*/ |
534 |
| - err = create_cond_branch(&instr, iptr, addr - 0x8004, flags); |
535 |
| - check(err); |
536 |
| - |
537 |
| - /* Out of range relative positive offset, + 32 KB */ |
538 |
| - err = create_cond_branch(&instr, iptr, addr + 0x8000, flags); |
539 |
| - check(err); |
540 |
| - |
541 |
| - /* Unaligned target */ |
542 |
| - err = create_cond_branch(&instr, iptr, addr + 3, flags); |
543 |
| - check(err); |
544 |
| - |
545 |
| - /* Check flags are masked correctly */ |
546 |
| - err = create_cond_branch(&instr, iptr, addr, 0xFFFFFFFC); |
547 |
| - patch_instruction(iptr, instr); |
548 |
| - check(instr_is_branch_to_addr(iptr, addr)); |
549 |
| - check(ppc_inst_equal(instr, ppc_inst(0x43FF0000))); |
550 |
| -} |
551 |
| - |
552 |
| -static void __init test_translate_branch(void) |
553 |
| -{ |
554 |
| - unsigned long addr; |
555 |
| - void *p, *q; |
556 |
| - ppc_inst_t instr; |
557 |
| - void *buf; |
558 |
| - |
559 |
| - buf = vmalloc(PAGE_ALIGN(0x2000000 + 1)); |
560 |
| - check(buf); |
561 |
| - if (!buf) |
562 |
| - return; |
563 |
| - |
564 |
| - /* Simple case, branch to self moved a little */ |
565 |
| - p = buf; |
566 |
| - addr = (unsigned long)p; |
567 |
| - patch_branch(p, addr, 0); |
568 |
| - check(instr_is_branch_to_addr(p, addr)); |
569 |
| - q = p + 4; |
570 |
| - translate_branch(&instr, q, p); |
571 |
| - patch_instruction(q, instr); |
572 |
| - check(instr_is_branch_to_addr(q, addr)); |
573 |
| - |
574 |
| - /* Maximum negative case, move b . to addr + 32 MB */ |
575 |
| - p = buf; |
576 |
| - addr = (unsigned long)p; |
577 |
| - patch_branch(p, addr, 0); |
578 |
| - q = buf + 0x2000000; |
579 |
| - translate_branch(&instr, q, p); |
580 |
| - patch_instruction(q, instr); |
581 |
| - check(instr_is_branch_to_addr(p, addr)); |
582 |
| - check(instr_is_branch_to_addr(q, addr)); |
583 |
| - check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x4a000000))); |
584 |
| - |
585 |
| - /* Maximum positive case, move x to x - 32 MB + 4 */ |
586 |
| - p = buf + 0x2000000; |
587 |
| - addr = (unsigned long)p; |
588 |
| - patch_branch(p, addr, 0); |
589 |
| - q = buf + 4; |
590 |
| - translate_branch(&instr, q, p); |
591 |
| - patch_instruction(q, instr); |
592 |
| - check(instr_is_branch_to_addr(p, addr)); |
593 |
| - check(instr_is_branch_to_addr(q, addr)); |
594 |
| - check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x49fffffc))); |
595 |
| - |
596 |
| - /* Jump to x + 16 MB moved to x + 20 MB */ |
597 |
| - p = buf; |
598 |
| - addr = 0x1000000 + (unsigned long)buf; |
599 |
| - patch_branch(p, addr, BRANCH_SET_LINK); |
600 |
| - q = buf + 0x1400000; |
601 |
| - translate_branch(&instr, q, p); |
602 |
| - patch_instruction(q, instr); |
603 |
| - check(instr_is_branch_to_addr(p, addr)); |
604 |
| - check(instr_is_branch_to_addr(q, addr)); |
605 |
| - |
606 |
| - /* Jump to x + 16 MB moved to x - 16 MB + 4 */ |
607 |
| - p = buf + 0x1000000; |
608 |
| - addr = 0x2000000 + (unsigned long)buf; |
609 |
| - patch_branch(p, addr, 0); |
610 |
| - q = buf + 4; |
611 |
| - translate_branch(&instr, q, p); |
612 |
| - patch_instruction(q, instr); |
613 |
| - check(instr_is_branch_to_addr(p, addr)); |
614 |
| - check(instr_is_branch_to_addr(q, addr)); |
615 |
| - |
616 |
| - |
617 |
| - /* Conditional branch tests */ |
618 |
| - |
619 |
| - /* Simple case, branch to self moved a little */ |
620 |
| - p = buf; |
621 |
| - addr = (unsigned long)p; |
622 |
| - create_cond_branch(&instr, p, addr, 0); |
623 |
| - patch_instruction(p, instr); |
624 |
| - check(instr_is_branch_to_addr(p, addr)); |
625 |
| - q = buf + 4; |
626 |
| - translate_branch(&instr, q, p); |
627 |
| - patch_instruction(q, instr); |
628 |
| - check(instr_is_branch_to_addr(q, addr)); |
629 |
| - |
630 |
| - /* Maximum negative case, move b . to addr + 32 KB */ |
631 |
| - p = buf; |
632 |
| - addr = (unsigned long)p; |
633 |
| - create_cond_branch(&instr, p, addr, 0xFFFFFFFC); |
634 |
| - patch_instruction(p, instr); |
635 |
| - q = buf + 0x8000; |
636 |
| - translate_branch(&instr, q, p); |
637 |
| - patch_instruction(q, instr); |
638 |
| - check(instr_is_branch_to_addr(p, addr)); |
639 |
| - check(instr_is_branch_to_addr(q, addr)); |
640 |
| - check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x43ff8000))); |
641 |
| - |
642 |
| - /* Maximum positive case, move x to x - 32 KB + 4 */ |
643 |
| - p = buf + 0x8000; |
644 |
| - addr = (unsigned long)p; |
645 |
| - create_cond_branch(&instr, p, addr, 0xFFFFFFFC); |
646 |
| - patch_instruction(p, instr); |
647 |
| - q = buf + 4; |
648 |
| - translate_branch(&instr, q, p); |
649 |
| - patch_instruction(q, instr); |
650 |
| - check(instr_is_branch_to_addr(p, addr)); |
651 |
| - check(instr_is_branch_to_addr(q, addr)); |
652 |
| - check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x43ff7ffc))); |
653 |
| - |
654 |
| - /* Jump to x + 12 KB moved to x + 20 KB */ |
655 |
| - p = buf; |
656 |
| - addr = 0x3000 + (unsigned long)buf; |
657 |
| - create_cond_branch(&instr, p, addr, BRANCH_SET_LINK); |
658 |
| - patch_instruction(p, instr); |
659 |
| - q = buf + 0x5000; |
660 |
| - translate_branch(&instr, q, p); |
661 |
| - patch_instruction(q, instr); |
662 |
| - check(instr_is_branch_to_addr(p, addr)); |
663 |
| - check(instr_is_branch_to_addr(q, addr)); |
664 |
| - |
665 |
| - /* Jump to x + 8 KB moved to x - 8 KB + 4 */ |
666 |
| - p = buf + 0x2000; |
667 |
| - addr = 0x4000 + (unsigned long)buf; |
668 |
| - create_cond_branch(&instr, p, addr, 0); |
669 |
| - patch_instruction(p, instr); |
670 |
| - q = buf + 4; |
671 |
| - translate_branch(&instr, q, p); |
672 |
| - patch_instruction(q, instr); |
673 |
| - check(instr_is_branch_to_addr(p, addr)); |
674 |
| - check(instr_is_branch_to_addr(q, addr)); |
675 |
| - |
676 |
| - /* Free the buffer we were using */ |
677 |
| - vfree(buf); |
678 |
| -} |
679 |
| - |
680 |
| -static void __init test_prefixed_patching(void) |
681 |
| -{ |
682 |
| - u32 *iptr = (u32 *)ppc_function_entry(test_trampoline); |
683 |
| - u32 expected[2] = {OP_PREFIX << 26, 0}; |
684 |
| - ppc_inst_t inst = ppc_inst_prefix(OP_PREFIX << 26, 0); |
685 |
| - |
686 |
| - if (!IS_ENABLED(CONFIG_PPC64)) |
687 |
| - return; |
688 |
| - |
689 |
| - patch_instruction(iptr, inst); |
690 |
| - |
691 |
| - check(!memcmp(iptr, expected, sizeof(expected))); |
692 |
| -} |
693 |
| - |
694 |
| -static int __init test_code_patching(void) |
695 |
| -{ |
696 |
| - pr_info("Running code patching self-tests ...\n"); |
697 |
| - |
698 |
| - test_branch_iform(); |
699 |
| - test_branch_bform(); |
700 |
| - test_create_function_call(); |
701 |
| - test_translate_branch(); |
702 |
| - test_prefixed_patching(); |
703 |
| - |
704 |
| - return 0; |
705 |
| -} |
706 |
| -late_initcall(test_code_patching); |
707 |
| - |
708 |
| -#endif /* CONFIG_CODE_PATCHING_SELFTEST */ |
0 commit comments