1 /* 2 * Copyright 2008 Michael Ellerman, IBM Corporation. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 */ 9 10 #include <linux/kernel.h> 11 #include <linux/vmalloc.h> 12 #include <linux/init.h> 13 #include <asm/page.h> 14 #include <asm/code-patching.h> 15 16 17 void patch_instruction(unsigned int *addr, unsigned int instr) 18 { 19 *addr = instr; 20 asm ("dcbst 0, %0; sync; icbi 0,%0; sync; isync" : : "r" (addr)); 21 } 22 23 void patch_branch(unsigned int *addr, unsigned long target, int flags) 24 { 25 patch_instruction(addr, create_branch(addr, target, flags)); 26 } 27 28 unsigned int create_branch(const unsigned int *addr, 29 unsigned long target, int flags) 30 { 31 unsigned int instruction; 32 long offset; 33 34 offset = target; 35 if (! (flags & BRANCH_ABSOLUTE)) 36 offset = offset - (unsigned long)addr; 37 38 /* Check we can represent the target in the instruction format */ 39 if (offset < -0x2000000 || offset > 0x1fffffc || offset & 0x3) 40 return 0; 41 42 /* Mask out the flags and target, so they don't step on each other. */ 43 instruction = 0x48000000 | (flags & 0x3) | (offset & 0x03FFFFFC); 44 45 return instruction; 46 } 47 48 unsigned int create_cond_branch(const unsigned int *addr, 49 unsigned long target, int flags) 50 { 51 unsigned int instruction; 52 long offset; 53 54 offset = target; 55 if (! (flags & BRANCH_ABSOLUTE)) 56 offset = offset - (unsigned long)addr; 57 58 /* Check we can represent the target in the instruction format */ 59 if (offset < -0x8000 || offset > 0x7FFF || offset & 0x3) 60 return 0; 61 62 /* Mask out the flags and target, so they don't step on each other. */ 63 instruction = 0x40000000 | (flags & 0x3FF0003) | (offset & 0xFFFC); 64 65 return instruction; 66 } 67 68 static unsigned int branch_opcode(unsigned int instr) 69 { 70 return (instr >> 26) & 0x3F; 71 } 72 73 static int instr_is_branch_iform(unsigned int instr) 74 { 75 return branch_opcode(instr) == 18; 76 } 77 78 static int instr_is_branch_bform(unsigned int instr) 79 { 80 return branch_opcode(instr) == 16; 81 } 82 83 int instr_is_relative_branch(unsigned int instr) 84 { 85 if (instr & BRANCH_ABSOLUTE) 86 return 0; 87 88 return instr_is_branch_iform(instr) || instr_is_branch_bform(instr); 89 } 90 91 static unsigned long branch_iform_target(const unsigned int *instr) 92 { 93 signed long imm; 94 95 imm = *instr & 0x3FFFFFC; 96 97 /* If the top bit of the immediate value is set this is negative */ 98 if (imm & 0x2000000) 99 imm -= 0x4000000; 100 101 if ((*instr & BRANCH_ABSOLUTE) == 0) 102 imm += (unsigned long)instr; 103 104 return (unsigned long)imm; 105 } 106 107 static unsigned long branch_bform_target(const unsigned int *instr) 108 { 109 signed long imm; 110 111 imm = *instr & 0xFFFC; 112 113 /* If the top bit of the immediate value is set this is negative */ 114 if (imm & 0x8000) 115 imm -= 0x10000; 116 117 if ((*instr & BRANCH_ABSOLUTE) == 0) 118 imm += (unsigned long)instr; 119 120 return (unsigned long)imm; 121 } 122 123 unsigned long branch_target(const unsigned int *instr) 124 { 125 if (instr_is_branch_iform(*instr)) 126 return branch_iform_target(instr); 127 else if (instr_is_branch_bform(*instr)) 128 return branch_bform_target(instr); 129 130 return 0; 131 } 132 133 int instr_is_branch_to_addr(const unsigned int *instr, unsigned long addr) 134 { 135 if (instr_is_branch_iform(*instr) || instr_is_branch_bform(*instr)) 136 return branch_target(instr) == addr; 137 138 return 0; 139 } 140 141 unsigned int translate_branch(const unsigned int *dest, const unsigned int *src) 142 { 143 unsigned long target; 144 145 target = branch_target(src); 146 147 if (instr_is_branch_iform(*src)) 148 return create_branch(dest, target, *src); 149 else if (instr_is_branch_bform(*src)) 150 return create_cond_branch(dest, target, *src); 151 152 return 0; 153 } 154 155 156 #ifdef CONFIG_CODE_PATCHING_SELFTEST 157 158 static void __init test_trampoline(void) 159 { 160 asm ("nop;\n"); 161 } 162 163 #define check(x) \ 164 if (!(x)) printk("code-patching: test failed at line %d\n", __LINE__); 165 166 static void __init test_branch_iform(void) 167 { 168 unsigned int instr; 169 unsigned long addr; 170 171 addr = (unsigned long)&instr; 172 173 /* The simplest case, branch to self, no flags */ 174 check(instr_is_branch_iform(0x48000000)); 175 /* All bits of target set, and flags */ 176 check(instr_is_branch_iform(0x4bffffff)); 177 /* High bit of opcode set, which is wrong */ 178 check(!instr_is_branch_iform(0xcbffffff)); 179 /* Middle bits of opcode set, which is wrong */ 180 check(!instr_is_branch_iform(0x7bffffff)); 181 182 /* Simplest case, branch to self with link */ 183 check(instr_is_branch_iform(0x48000001)); 184 /* All bits of targets set */ 185 check(instr_is_branch_iform(0x4bfffffd)); 186 /* Some bits of targets set */ 187 check(instr_is_branch_iform(0x4bff00fd)); 188 /* Must be a valid branch to start with */ 189 check(!instr_is_branch_iform(0x7bfffffd)); 190 191 /* Absolute branch to 0x100 */ 192 instr = 0x48000103; 193 check(instr_is_branch_to_addr(&instr, 0x100)); 194 /* Absolute branch to 0x420fc */ 195 instr = 0x480420ff; 196 check(instr_is_branch_to_addr(&instr, 0x420fc)); 197 /* Maximum positive relative branch, + 20MB - 4B */ 198 instr = 0x49fffffc; 199 check(instr_is_branch_to_addr(&instr, addr + 0x1FFFFFC)); 200 /* Smallest negative relative branch, - 4B */ 201 instr = 0x4bfffffc; 202 check(instr_is_branch_to_addr(&instr, addr - 4)); 203 /* Largest negative relative branch, - 32 MB */ 204 instr = 0x4a000000; 205 check(instr_is_branch_to_addr(&instr, addr - 0x2000000)); 206 207 /* Branch to self, with link */ 208 instr = create_branch(&instr, addr, BRANCH_SET_LINK); 209 check(instr_is_branch_to_addr(&instr, addr)); 210 211 /* Branch to self - 0x100, with link */ 212 instr = create_branch(&instr, addr - 0x100, BRANCH_SET_LINK); 213 check(instr_is_branch_to_addr(&instr, addr - 0x100)); 214 215 /* Branch to self + 0x100, no link */ 216 instr = create_branch(&instr, addr + 0x100, 0); 217 check(instr_is_branch_to_addr(&instr, addr + 0x100)); 218 219 /* Maximum relative negative offset, - 32 MB */ 220 instr = create_branch(&instr, addr - 0x2000000, BRANCH_SET_LINK); 221 check(instr_is_branch_to_addr(&instr, addr - 0x2000000)); 222 223 /* Out of range relative negative offset, - 32 MB + 4*/ 224 instr = create_branch(&instr, addr - 0x2000004, BRANCH_SET_LINK); 225 check(instr == 0); 226 227 /* Out of range relative positive offset, + 32 MB */ 228 instr = create_branch(&instr, addr + 0x2000000, BRANCH_SET_LINK); 229 check(instr == 0); 230 231 /* Unaligned target */ 232 instr = create_branch(&instr, addr + 3, BRANCH_SET_LINK); 233 check(instr == 0); 234 235 /* Check flags are masked correctly */ 236 instr = create_branch(&instr, addr, 0xFFFFFFFC); 237 check(instr_is_branch_to_addr(&instr, addr)); 238 check(instr == 0x48000000); 239 } 240 241 static void __init test_create_function_call(void) 242 { 243 unsigned int *iptr; 244 unsigned long dest; 245 246 /* Check we can create a function call */ 247 iptr = (unsigned int *)ppc_function_entry(test_trampoline); 248 dest = ppc_function_entry(test_create_function_call); 249 patch_instruction(iptr, create_branch(iptr, dest, BRANCH_SET_LINK)); 250 check(instr_is_branch_to_addr(iptr, dest)); 251 } 252 253 static void __init test_branch_bform(void) 254 { 255 unsigned long addr; 256 unsigned int *iptr, instr, flags; 257 258 iptr = &instr; 259 addr = (unsigned long)iptr; 260 261 /* The simplest case, branch to self, no flags */ 262 check(instr_is_branch_bform(0x40000000)); 263 /* All bits of target set, and flags */ 264 check(instr_is_branch_bform(0x43ffffff)); 265 /* High bit of opcode set, which is wrong */ 266 check(!instr_is_branch_bform(0xc3ffffff)); 267 /* Middle bits of opcode set, which is wrong */ 268 check(!instr_is_branch_bform(0x7bffffff)); 269 270 /* Absolute conditional branch to 0x100 */ 271 instr = 0x43ff0103; 272 check(instr_is_branch_to_addr(&instr, 0x100)); 273 /* Absolute conditional branch to 0x20fc */ 274 instr = 0x43ff20ff; 275 check(instr_is_branch_to_addr(&instr, 0x20fc)); 276 /* Maximum positive relative conditional branch, + 32 KB - 4B */ 277 instr = 0x43ff7ffc; 278 check(instr_is_branch_to_addr(&instr, addr + 0x7FFC)); 279 /* Smallest negative relative conditional branch, - 4B */ 280 instr = 0x43fffffc; 281 check(instr_is_branch_to_addr(&instr, addr - 4)); 282 /* Largest negative relative conditional branch, - 32 KB */ 283 instr = 0x43ff8000; 284 check(instr_is_branch_to_addr(&instr, addr - 0x8000)); 285 286 /* All condition code bits set & link */ 287 flags = 0x3ff000 | BRANCH_SET_LINK; 288 289 /* Branch to self */ 290 instr = create_cond_branch(iptr, addr, flags); 291 check(instr_is_branch_to_addr(&instr, addr)); 292 293 /* Branch to self - 0x100 */ 294 instr = create_cond_branch(iptr, addr - 0x100, flags); 295 check(instr_is_branch_to_addr(&instr, addr - 0x100)); 296 297 /* Branch to self + 0x100 */ 298 instr = create_cond_branch(iptr, addr + 0x100, flags); 299 check(instr_is_branch_to_addr(&instr, addr + 0x100)); 300 301 /* Maximum relative negative offset, - 32 KB */ 302 instr = create_cond_branch(iptr, addr - 0x8000, flags); 303 check(instr_is_branch_to_addr(&instr, addr - 0x8000)); 304 305 /* Out of range relative negative offset, - 32 KB + 4*/ 306 instr = create_cond_branch(iptr, addr - 0x8004, flags); 307 check(instr == 0); 308 309 /* Out of range relative positive offset, + 32 KB */ 310 instr = create_cond_branch(iptr, addr + 0x8000, flags); 311 check(instr == 0); 312 313 /* Unaligned target */ 314 instr = create_cond_branch(iptr, addr + 3, flags); 315 check(instr == 0); 316 317 /* Check flags are masked correctly */ 318 instr = create_cond_branch(iptr, addr, 0xFFFFFFFC); 319 check(instr_is_branch_to_addr(&instr, addr)); 320 check(instr == 0x43FF0000); 321 } 322 323 static void __init test_translate_branch(void) 324 { 325 unsigned long addr; 326 unsigned int *p, *q; 327 void *buf; 328 329 buf = vmalloc(PAGE_ALIGN(0x2000000 + 1)); 330 check(buf); 331 if (!buf) 332 return; 333 334 /* Simple case, branch to self moved a little */ 335 p = buf; 336 addr = (unsigned long)p; 337 patch_branch(p, addr, 0); 338 check(instr_is_branch_to_addr(p, addr)); 339 q = p + 1; 340 patch_instruction(q, translate_branch(q, p)); 341 check(instr_is_branch_to_addr(q, addr)); 342 343 /* Maximum negative case, move b . to addr + 32 MB */ 344 p = buf; 345 addr = (unsigned long)p; 346 patch_branch(p, addr, 0); 347 q = buf + 0x2000000; 348 patch_instruction(q, translate_branch(q, p)); 349 check(instr_is_branch_to_addr(p, addr)); 350 check(instr_is_branch_to_addr(q, addr)); 351 check(*q == 0x4a000000); 352 353 /* Maximum positive case, move x to x - 32 MB + 4 */ 354 p = buf + 0x2000000; 355 addr = (unsigned long)p; 356 patch_branch(p, addr, 0); 357 q = buf + 4; 358 patch_instruction(q, translate_branch(q, p)); 359 check(instr_is_branch_to_addr(p, addr)); 360 check(instr_is_branch_to_addr(q, addr)); 361 check(*q == 0x49fffffc); 362 363 /* Jump to x + 16 MB moved to x + 20 MB */ 364 p = buf; 365 addr = 0x1000000 + (unsigned long)buf; 366 patch_branch(p, addr, BRANCH_SET_LINK); 367 q = buf + 0x1400000; 368 patch_instruction(q, translate_branch(q, p)); 369 check(instr_is_branch_to_addr(p, addr)); 370 check(instr_is_branch_to_addr(q, addr)); 371 372 /* Jump to x + 16 MB moved to x - 16 MB + 4 */ 373 p = buf + 0x1000000; 374 addr = 0x2000000 + (unsigned long)buf; 375 patch_branch(p, addr, 0); 376 q = buf + 4; 377 patch_instruction(q, translate_branch(q, p)); 378 check(instr_is_branch_to_addr(p, addr)); 379 check(instr_is_branch_to_addr(q, addr)); 380 381 382 /* Conditional branch tests */ 383 384 /* Simple case, branch to self moved a little */ 385 p = buf; 386 addr = (unsigned long)p; 387 patch_instruction(p, create_cond_branch(p, addr, 0)); 388 check(instr_is_branch_to_addr(p, addr)); 389 q = p + 1; 390 patch_instruction(q, translate_branch(q, p)); 391 check(instr_is_branch_to_addr(q, addr)); 392 393 /* Maximum negative case, move b . to addr + 32 KB */ 394 p = buf; 395 addr = (unsigned long)p; 396 patch_instruction(p, create_cond_branch(p, addr, 0xFFFFFFFC)); 397 q = buf + 0x8000; 398 patch_instruction(q, translate_branch(q, p)); 399 check(instr_is_branch_to_addr(p, addr)); 400 check(instr_is_branch_to_addr(q, addr)); 401 check(*q == 0x43ff8000); 402 403 /* Maximum positive case, move x to x - 32 KB + 4 */ 404 p = buf + 0x8000; 405 addr = (unsigned long)p; 406 patch_instruction(p, create_cond_branch(p, addr, 0xFFFFFFFC)); 407 q = buf + 4; 408 patch_instruction(q, translate_branch(q, p)); 409 check(instr_is_branch_to_addr(p, addr)); 410 check(instr_is_branch_to_addr(q, addr)); 411 check(*q == 0x43ff7ffc); 412 413 /* Jump to x + 12 KB moved to x + 20 KB */ 414 p = buf; 415 addr = 0x3000 + (unsigned long)buf; 416 patch_instruction(p, create_cond_branch(p, addr, BRANCH_SET_LINK)); 417 q = buf + 0x5000; 418 patch_instruction(q, translate_branch(q, p)); 419 check(instr_is_branch_to_addr(p, addr)); 420 check(instr_is_branch_to_addr(q, addr)); 421 422 /* Jump to x + 8 KB moved to x - 8 KB + 4 */ 423 p = buf + 0x2000; 424 addr = 0x4000 + (unsigned long)buf; 425 patch_instruction(p, create_cond_branch(p, addr, 0)); 426 q = buf + 4; 427 patch_instruction(q, translate_branch(q, p)); 428 check(instr_is_branch_to_addr(p, addr)); 429 check(instr_is_branch_to_addr(q, addr)); 430 431 /* Free the buffer we were using */ 432 vfree(buf); 433 } 434 435 static int __init test_code_patching(void) 436 { 437 printk(KERN_DEBUG "Running code patching self-tests ...\n"); 438 439 test_branch_iform(); 440 test_branch_bform(); 441 test_create_function_call(); 442 test_translate_branch(); 443 444 return 0; 445 } 446 late_initcall(test_code_patching); 447 448 #endif /* CONFIG_CODE_PATCHING_SELFTEST */ 449