Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Copyright 2008 Michael Ellerman, IBM Corporation.
0004  */
0005 
0006 #include <linux/vmalloc.h>
0007 #include <linux/init.h>
0008 
0009 #include <asm/code-patching.h>
0010 
0011 static int __init instr_is_branch_to_addr(const u32 *instr, unsigned long addr)
0012 {
0013     if (instr_is_branch_iform(ppc_inst_read(instr)) ||
0014         instr_is_branch_bform(ppc_inst_read(instr)))
0015         return branch_target(instr) == addr;
0016 
0017     return 0;
0018 }
0019 
0020 static void __init test_trampoline(void)
0021 {
0022     asm ("nop;nop;\n");
0023 }
0024 
0025 #define check(x)    do {    \
0026     if (!(x))       \
0027         pr_err("code-patching: test failed at line %d\n", __LINE__); \
0028 } while (0)
0029 
0030 static void __init test_branch_iform(void)
0031 {
0032     int err;
0033     ppc_inst_t instr;
0034     u32 tmp[2];
0035     u32 *iptr = tmp;
0036     unsigned long addr = (unsigned long)tmp;
0037 
0038     /* The simplest case, branch to self, no flags */
0039     check(instr_is_branch_iform(ppc_inst(0x48000000)));
0040     /* All bits of target set, and flags */
0041     check(instr_is_branch_iform(ppc_inst(0x4bffffff)));
0042     /* High bit of opcode set, which is wrong */
0043     check(!instr_is_branch_iform(ppc_inst(0xcbffffff)));
0044     /* Middle bits of opcode set, which is wrong */
0045     check(!instr_is_branch_iform(ppc_inst(0x7bffffff)));
0046 
0047     /* Simplest case, branch to self with link */
0048     check(instr_is_branch_iform(ppc_inst(0x48000001)));
0049     /* All bits of targets set */
0050     check(instr_is_branch_iform(ppc_inst(0x4bfffffd)));
0051     /* Some bits of targets set */
0052     check(instr_is_branch_iform(ppc_inst(0x4bff00fd)));
0053     /* Must be a valid branch to start with */
0054     check(!instr_is_branch_iform(ppc_inst(0x7bfffffd)));
0055 
0056     /* Absolute branch to 0x100 */
0057     ppc_inst_write(iptr, ppc_inst(0x48000103));
0058     check(instr_is_branch_to_addr(iptr, 0x100));
0059     /* Absolute branch to 0x420fc */
0060     ppc_inst_write(iptr, ppc_inst(0x480420ff));
0061     check(instr_is_branch_to_addr(iptr, 0x420fc));
0062     /* Maximum positive relative branch, + 20MB - 4B */
0063     ppc_inst_write(iptr, ppc_inst(0x49fffffc));
0064     check(instr_is_branch_to_addr(iptr, addr + 0x1FFFFFC));
0065     /* Smallest negative relative branch, - 4B */
0066     ppc_inst_write(iptr, ppc_inst(0x4bfffffc));
0067     check(instr_is_branch_to_addr(iptr, addr - 4));
0068     /* Largest negative relative branch, - 32 MB */
0069     ppc_inst_write(iptr, ppc_inst(0x4a000000));
0070     check(instr_is_branch_to_addr(iptr, addr - 0x2000000));
0071 
0072     /* Branch to self, with link */
0073     err = create_branch(&instr, iptr, addr, BRANCH_SET_LINK);
0074     ppc_inst_write(iptr, instr);
0075     check(instr_is_branch_to_addr(iptr, addr));
0076 
0077     /* Branch to self - 0x100, with link */
0078     err = create_branch(&instr, iptr, addr - 0x100, BRANCH_SET_LINK);
0079     ppc_inst_write(iptr, instr);
0080     check(instr_is_branch_to_addr(iptr, addr - 0x100));
0081 
0082     /* Branch to self + 0x100, no link */
0083     err = create_branch(&instr, iptr, addr + 0x100, 0);
0084     ppc_inst_write(iptr, instr);
0085     check(instr_is_branch_to_addr(iptr, addr + 0x100));
0086 
0087     /* Maximum relative negative offset, - 32 MB */
0088     err = create_branch(&instr, iptr, addr - 0x2000000, BRANCH_SET_LINK);
0089     ppc_inst_write(iptr, instr);
0090     check(instr_is_branch_to_addr(iptr, addr - 0x2000000));
0091 
0092     /* Out of range relative negative offset, - 32 MB + 4*/
0093     err = create_branch(&instr, iptr, addr - 0x2000004, BRANCH_SET_LINK);
0094     check(err);
0095 
0096     /* Out of range relative positive offset, + 32 MB */
0097     err = create_branch(&instr, iptr, addr + 0x2000000, BRANCH_SET_LINK);
0098     check(err);
0099 
0100     /* Unaligned target */
0101     err = create_branch(&instr, iptr, addr + 3, BRANCH_SET_LINK);
0102     check(err);
0103 
0104     /* Check flags are masked correctly */
0105     err = create_branch(&instr, iptr, addr, 0xFFFFFFFC);
0106     ppc_inst_write(iptr, instr);
0107     check(instr_is_branch_to_addr(iptr, addr));
0108     check(ppc_inst_equal(instr, ppc_inst(0x48000000)));
0109 }
0110 
0111 static void __init test_create_function_call(void)
0112 {
0113     u32 *iptr;
0114     unsigned long dest;
0115     ppc_inst_t instr;
0116 
0117     /* Check we can create a function call */
0118     iptr = (u32 *)ppc_function_entry(test_trampoline);
0119     dest = ppc_function_entry(test_create_function_call);
0120     create_branch(&instr, iptr, dest, BRANCH_SET_LINK);
0121     patch_instruction(iptr, instr);
0122     check(instr_is_branch_to_addr(iptr, dest));
0123 }
0124 
0125 static void __init test_branch_bform(void)
0126 {
0127     int err;
0128     unsigned long addr;
0129     ppc_inst_t instr;
0130     u32 tmp[2];
0131     u32 *iptr = tmp;
0132     unsigned int flags;
0133 
0134     addr = (unsigned long)iptr;
0135 
0136     /* The simplest case, branch to self, no flags */
0137     check(instr_is_branch_bform(ppc_inst(0x40000000)));
0138     /* All bits of target set, and flags */
0139     check(instr_is_branch_bform(ppc_inst(0x43ffffff)));
0140     /* High bit of opcode set, which is wrong */
0141     check(!instr_is_branch_bform(ppc_inst(0xc3ffffff)));
0142     /* Middle bits of opcode set, which is wrong */
0143     check(!instr_is_branch_bform(ppc_inst(0x7bffffff)));
0144 
0145     /* Absolute conditional branch to 0x100 */
0146     ppc_inst_write(iptr, ppc_inst(0x43ff0103));
0147     check(instr_is_branch_to_addr(iptr, 0x100));
0148     /* Absolute conditional branch to 0x20fc */
0149     ppc_inst_write(iptr, ppc_inst(0x43ff20ff));
0150     check(instr_is_branch_to_addr(iptr, 0x20fc));
0151     /* Maximum positive relative conditional branch, + 32 KB - 4B */
0152     ppc_inst_write(iptr, ppc_inst(0x43ff7ffc));
0153     check(instr_is_branch_to_addr(iptr, addr + 0x7FFC));
0154     /* Smallest negative relative conditional branch, - 4B */
0155     ppc_inst_write(iptr, ppc_inst(0x43fffffc));
0156     check(instr_is_branch_to_addr(iptr, addr - 4));
0157     /* Largest negative relative conditional branch, - 32 KB */
0158     ppc_inst_write(iptr, ppc_inst(0x43ff8000));
0159     check(instr_is_branch_to_addr(iptr, addr - 0x8000));
0160 
0161     /* All condition code bits set & link */
0162     flags = 0x3ff000 | BRANCH_SET_LINK;
0163 
0164     /* Branch to self */
0165     err = create_cond_branch(&instr, iptr, addr, flags);
0166     ppc_inst_write(iptr, instr);
0167     check(instr_is_branch_to_addr(iptr, addr));
0168 
0169     /* Branch to self - 0x100 */
0170     err = create_cond_branch(&instr, iptr, addr - 0x100, flags);
0171     ppc_inst_write(iptr, instr);
0172     check(instr_is_branch_to_addr(iptr, addr - 0x100));
0173 
0174     /* Branch to self + 0x100 */
0175     err = create_cond_branch(&instr, iptr, addr + 0x100, flags);
0176     ppc_inst_write(iptr, instr);
0177     check(instr_is_branch_to_addr(iptr, addr + 0x100));
0178 
0179     /* Maximum relative negative offset, - 32 KB */
0180     err = create_cond_branch(&instr, iptr, addr - 0x8000, flags);
0181     ppc_inst_write(iptr, instr);
0182     check(instr_is_branch_to_addr(iptr, addr - 0x8000));
0183 
0184     /* Out of range relative negative offset, - 32 KB + 4*/
0185     err = create_cond_branch(&instr, iptr, addr - 0x8004, flags);
0186     check(err);
0187 
0188     /* Out of range relative positive offset, + 32 KB */
0189     err = create_cond_branch(&instr, iptr, addr + 0x8000, flags);
0190     check(err);
0191 
0192     /* Unaligned target */
0193     err = create_cond_branch(&instr, iptr, addr + 3, flags);
0194     check(err);
0195 
0196     /* Check flags are masked correctly */
0197     err = create_cond_branch(&instr, iptr, addr, 0xFFFFFFFC);
0198     ppc_inst_write(iptr, instr);
0199     check(instr_is_branch_to_addr(iptr, addr));
0200     check(ppc_inst_equal(instr, ppc_inst(0x43FF0000)));
0201 }
0202 
0203 static void __init test_translate_branch(void)
0204 {
0205     unsigned long addr;
0206     void *p, *q;
0207     ppc_inst_t instr;
0208     void *buf;
0209 
0210     buf = vmalloc(PAGE_ALIGN(0x2000000 + 1));
0211     check(buf);
0212     if (!buf)
0213         return;
0214 
0215     /* Simple case, branch to self moved a little */
0216     p = buf;
0217     addr = (unsigned long)p;
0218     create_branch(&instr, p, addr, 0);
0219     ppc_inst_write(p, instr);
0220     check(instr_is_branch_to_addr(p, addr));
0221     q = p + 4;
0222     translate_branch(&instr, q, p);
0223     ppc_inst_write(q, instr);
0224     check(instr_is_branch_to_addr(q, addr));
0225 
0226     /* Maximum negative case, move b . to addr + 32 MB */
0227     p = buf;
0228     addr = (unsigned long)p;
0229     create_branch(&instr, p, addr, 0);
0230     ppc_inst_write(p, instr);
0231     q = buf + 0x2000000;
0232     translate_branch(&instr, q, p);
0233     ppc_inst_write(q, instr);
0234     check(instr_is_branch_to_addr(p, addr));
0235     check(instr_is_branch_to_addr(q, addr));
0236     check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x4a000000)));
0237 
0238     /* Maximum positive case, move x to x - 32 MB + 4 */
0239     p = buf + 0x2000000;
0240     addr = (unsigned long)p;
0241     create_branch(&instr, p, addr, 0);
0242     ppc_inst_write(p, instr);
0243     q = buf + 4;
0244     translate_branch(&instr, q, p);
0245     ppc_inst_write(q, instr);
0246     check(instr_is_branch_to_addr(p, addr));
0247     check(instr_is_branch_to_addr(q, addr));
0248     check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x49fffffc)));
0249 
0250     /* Jump to x + 16 MB moved to x + 20 MB */
0251     p = buf;
0252     addr = 0x1000000 + (unsigned long)buf;
0253     create_branch(&instr, p, addr, BRANCH_SET_LINK);
0254     ppc_inst_write(p, instr);
0255     q = buf + 0x1400000;
0256     translate_branch(&instr, q, p);
0257     ppc_inst_write(q, instr);
0258     check(instr_is_branch_to_addr(p, addr));
0259     check(instr_is_branch_to_addr(q, addr));
0260 
0261     /* Jump to x + 16 MB moved to x - 16 MB + 4 */
0262     p = buf + 0x1000000;
0263     addr = 0x2000000 + (unsigned long)buf;
0264     create_branch(&instr, p, addr, 0);
0265     ppc_inst_write(p, instr);
0266     q = buf + 4;
0267     translate_branch(&instr, q, p);
0268     ppc_inst_write(q, instr);
0269     check(instr_is_branch_to_addr(p, addr));
0270     check(instr_is_branch_to_addr(q, addr));
0271 
0272 
0273     /* Conditional branch tests */
0274 
0275     /* Simple case, branch to self moved a little */
0276     p = buf;
0277     addr = (unsigned long)p;
0278     create_cond_branch(&instr, p, addr, 0);
0279     ppc_inst_write(p, instr);
0280     check(instr_is_branch_to_addr(p, addr));
0281     q = buf + 4;
0282     translate_branch(&instr, q, p);
0283     ppc_inst_write(q, instr);
0284     check(instr_is_branch_to_addr(q, addr));
0285 
0286     /* Maximum negative case, move b . to addr + 32 KB */
0287     p = buf;
0288     addr = (unsigned long)p;
0289     create_cond_branch(&instr, p, addr, 0xFFFFFFFC);
0290     ppc_inst_write(p, instr);
0291     q = buf + 0x8000;
0292     translate_branch(&instr, q, p);
0293     ppc_inst_write(q, instr);
0294     check(instr_is_branch_to_addr(p, addr));
0295     check(instr_is_branch_to_addr(q, addr));
0296     check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x43ff8000)));
0297 
0298     /* Maximum positive case, move x to x - 32 KB + 4 */
0299     p = buf + 0x8000;
0300     addr = (unsigned long)p;
0301     create_cond_branch(&instr, p, addr, 0xFFFFFFFC);
0302     ppc_inst_write(p, instr);
0303     q = buf + 4;
0304     translate_branch(&instr, q, p);
0305     ppc_inst_write(q, instr);
0306     check(instr_is_branch_to_addr(p, addr));
0307     check(instr_is_branch_to_addr(q, addr));
0308     check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x43ff7ffc)));
0309 
0310     /* Jump to x + 12 KB moved to x + 20 KB */
0311     p = buf;
0312     addr = 0x3000 + (unsigned long)buf;
0313     create_cond_branch(&instr, p, addr, BRANCH_SET_LINK);
0314     ppc_inst_write(p, instr);
0315     q = buf + 0x5000;
0316     translate_branch(&instr, q, p);
0317     ppc_inst_write(q, instr);
0318     check(instr_is_branch_to_addr(p, addr));
0319     check(instr_is_branch_to_addr(q, addr));
0320 
0321     /* Jump to x + 8 KB moved to x - 8 KB + 4 */
0322     p = buf + 0x2000;
0323     addr = 0x4000 + (unsigned long)buf;
0324     create_cond_branch(&instr, p, addr, 0);
0325     ppc_inst_write(p, instr);
0326     q = buf + 4;
0327     translate_branch(&instr, q, p);
0328     ppc_inst_write(q, instr);
0329     check(instr_is_branch_to_addr(p, addr));
0330     check(instr_is_branch_to_addr(q, addr));
0331 
0332     /* Free the buffer we were using */
0333     vfree(buf);
0334 }
0335 
0336 static void __init test_prefixed_patching(void)
0337 {
0338     u32 *iptr = (u32 *)ppc_function_entry(test_trampoline);
0339     u32 expected[2] = {OP_PREFIX << 26, 0};
0340     ppc_inst_t inst = ppc_inst_prefix(OP_PREFIX << 26, 0);
0341 
0342     if (!IS_ENABLED(CONFIG_PPC64))
0343         return;
0344 
0345     patch_instruction(iptr, inst);
0346 
0347     check(!memcmp(iptr, expected, sizeof(expected)));
0348 }
0349 
0350 static int __init test_code_patching(void)
0351 {
0352     pr_info("Running code patching self-tests ...\n");
0353 
0354     test_branch_iform();
0355     test_branch_bform();
0356     test_create_function_call();
0357     test_translate_branch();
0358     test_prefixed_patching();
0359 
0360     return 0;
0361 }
0362 late_initcall(test_code_patching);