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