Skip to content

Commit f30a578

Browse files
chleroympe
authored andcommitted
powerpc/code-patching: Move code patching selftests in its own file
Code patching selftests are half of code-patching.c. As they are guarded by CONFIG_CODE_PATCHING_SELFTESTS, they'd be better in their own file. Also add a missing __init for instr_is_branch_to_addr() Signed-off-by: Christophe Leroy <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/c0c30504f04eb546a48ff77127a8bccd12a3d809.1638446239.git.christophe.leroy@csgroup.eu
1 parent 31acc59 commit f30a578

File tree

3 files changed

+359
-355
lines changed

3 files changed

+359
-355
lines changed

arch/powerpc/lib/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ endif
2121

2222
obj-y += alloc.o code-patching.o feature-fixups.o pmem.o
2323

24+
obj-$(CONFIG_CODE_PATCHING_SELFTEST) += test-code-patching.o
25+
2426
ifndef CONFIG_KASAN
2527
obj-y += string.o memcmp_$(BITS).o
2628
obj-$(CONFIG_PPC32) += strlen_32.o

arch/powerpc/lib/code-patching.c

Lines changed: 0 additions & 355 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,10 @@
33
* Copyright 2008 Michael Ellerman, IBM Corporation.
44
*/
55

6-
#include <linux/kernel.h>
76
#include <linux/kprobes.h>
87
#include <linux/vmalloc.h>
98
#include <linux/init.h>
10-
#include <linux/mm.h>
119
#include <linux/cpuhotplug.h>
12-
#include <linux/slab.h>
1310
#include <linux/uaccess.h>
1411

1512
#include <asm/tlbflush.h>
@@ -354,355 +351,3 @@ int translate_branch(ppc_inst_t *instr, const u32 *dest, const u32 *src)
354351

355352
return 1;
356353
}
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

Comments
 (0)