Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
[linux/fpc-iii.git] / arch / powerpc / lib / code-patching.c
blobd5edbeb8eb8209e61a9d6524acfa565e3f30782f
1 /*
2 * Copyright 2008 Michael Ellerman, IBM Corporation.
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 */
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>
19 int patch_instruction(unsigned int *addr, unsigned int instr)
21 int err;
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;
30 int patch_branch(unsigned int *addr, unsigned long target, int flags)
32 return patch_instruction(addr, create_branch(addr, target, flags));
35 unsigned int create_branch(const unsigned int *addr,
36 unsigned long target, int flags)
38 unsigned int instruction;
39 long offset;
41 offset = target;
42 if (! (flags & BRANCH_ABSOLUTE))
43 offset = offset - (unsigned long)addr;
45 /* Check we can represent the target in the instruction format */
46 if (offset < -0x2000000 || offset > 0x1fffffc || offset & 0x3)
47 return 0;
49 /* Mask out the flags and target, so they don't step on each other. */
50 instruction = 0x48000000 | (flags & 0x3) | (offset & 0x03FFFFFC);
52 return instruction;
55 unsigned int create_cond_branch(const unsigned int *addr,
56 unsigned long target, int flags)
58 unsigned int instruction;
59 long offset;
61 offset = target;
62 if (! (flags & BRANCH_ABSOLUTE))
63 offset = offset - (unsigned long)addr;
65 /* Check we can represent the target in the instruction format */
66 if (offset < -0x8000 || offset > 0x7FFF || offset & 0x3)
67 return 0;
69 /* Mask out the flags and target, so they don't step on each other. */
70 instruction = 0x40000000 | (flags & 0x3FF0003) | (offset & 0xFFFC);
72 return instruction;
75 static unsigned int branch_opcode(unsigned int instr)
77 return (instr >> 26) & 0x3F;
80 static int instr_is_branch_iform(unsigned int instr)
82 return branch_opcode(instr) == 18;
85 static int instr_is_branch_bform(unsigned int instr)
87 return branch_opcode(instr) == 16;
90 int instr_is_relative_branch(unsigned int instr)
92 if (instr & BRANCH_ABSOLUTE)
93 return 0;
95 return instr_is_branch_iform(instr) || instr_is_branch_bform(instr);
98 static unsigned long branch_iform_target(const unsigned int *instr)
100 signed long imm;
102 imm = *instr & 0x3FFFFFC;
104 /* If the top bit of the immediate value is set this is negative */
105 if (imm & 0x2000000)
106 imm -= 0x4000000;
108 if ((*instr & BRANCH_ABSOLUTE) == 0)
109 imm += (unsigned long)instr;
111 return (unsigned long)imm;
114 static unsigned long branch_bform_target(const unsigned int *instr)
116 signed long imm;
118 imm = *instr & 0xFFFC;
120 /* If the top bit of the immediate value is set this is negative */
121 if (imm & 0x8000)
122 imm -= 0x10000;
124 if ((*instr & BRANCH_ABSOLUTE) == 0)
125 imm += (unsigned long)instr;
127 return (unsigned long)imm;
130 unsigned long branch_target(const unsigned int *instr)
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);
137 return 0;
140 int instr_is_branch_to_addr(const unsigned int *instr, unsigned long addr)
142 if (instr_is_branch_iform(*instr) || instr_is_branch_bform(*instr))
143 return branch_target(instr) == addr;
145 return 0;
148 unsigned int translate_branch(const unsigned int *dest, const unsigned int *src)
150 unsigned long target;
152 target = branch_target(src);
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);
159 return 0;
162 #ifdef CONFIG_PPC_BOOK3E_64
163 void __patch_exception(int exc, unsigned long addr)
165 extern unsigned int interrupt_base_book3e;
166 unsigned int *ibase = &interrupt_base_book3e;
168 /* Our exceptions vectors start with a NOP and -then- a branch
169 * to deal with single stepping from userspace which stops on
170 * the second instruction. Thus we need to patch the second
171 * instruction of the exception, not the first one
174 patch_branch(ibase + (exc / 4) + 1, addr, 0);
176 #endif
178 #ifdef CONFIG_CODE_PATCHING_SELFTEST
180 static void __init test_trampoline(void)
182 asm ("nop;\n");
185 #define check(x) \
186 if (!(x)) printk("code-patching: test failed at line %d\n", __LINE__);
188 static void __init test_branch_iform(void)
190 unsigned int instr;
191 unsigned long addr;
193 addr = (unsigned long)&instr;
195 /* The simplest case, branch to self, no flags */
196 check(instr_is_branch_iform(0x48000000));
197 /* All bits of target set, and flags */
198 check(instr_is_branch_iform(0x4bffffff));
199 /* High bit of opcode set, which is wrong */
200 check(!instr_is_branch_iform(0xcbffffff));
201 /* Middle bits of opcode set, which is wrong */
202 check(!instr_is_branch_iform(0x7bffffff));
204 /* Simplest case, branch to self with link */
205 check(instr_is_branch_iform(0x48000001));
206 /* All bits of targets set */
207 check(instr_is_branch_iform(0x4bfffffd));
208 /* Some bits of targets set */
209 check(instr_is_branch_iform(0x4bff00fd));
210 /* Must be a valid branch to start with */
211 check(!instr_is_branch_iform(0x7bfffffd));
213 /* Absolute branch to 0x100 */
214 instr = 0x48000103;
215 check(instr_is_branch_to_addr(&instr, 0x100));
216 /* Absolute branch to 0x420fc */
217 instr = 0x480420ff;
218 check(instr_is_branch_to_addr(&instr, 0x420fc));
219 /* Maximum positive relative branch, + 20MB - 4B */
220 instr = 0x49fffffc;
221 check(instr_is_branch_to_addr(&instr, addr + 0x1FFFFFC));
222 /* Smallest negative relative branch, - 4B */
223 instr = 0x4bfffffc;
224 check(instr_is_branch_to_addr(&instr, addr - 4));
225 /* Largest negative relative branch, - 32 MB */
226 instr = 0x4a000000;
227 check(instr_is_branch_to_addr(&instr, addr - 0x2000000));
229 /* Branch to self, with link */
230 instr = create_branch(&instr, addr, BRANCH_SET_LINK);
231 check(instr_is_branch_to_addr(&instr, addr));
233 /* Branch to self - 0x100, with link */
234 instr = create_branch(&instr, addr - 0x100, BRANCH_SET_LINK);
235 check(instr_is_branch_to_addr(&instr, addr - 0x100));
237 /* Branch to self + 0x100, no link */
238 instr = create_branch(&instr, addr + 0x100, 0);
239 check(instr_is_branch_to_addr(&instr, addr + 0x100));
241 /* Maximum relative negative offset, - 32 MB */
242 instr = create_branch(&instr, addr - 0x2000000, BRANCH_SET_LINK);
243 check(instr_is_branch_to_addr(&instr, addr - 0x2000000));
245 /* Out of range relative negative offset, - 32 MB + 4*/
246 instr = create_branch(&instr, addr - 0x2000004, BRANCH_SET_LINK);
247 check(instr == 0);
249 /* Out of range relative positive offset, + 32 MB */
250 instr = create_branch(&instr, addr + 0x2000000, BRANCH_SET_LINK);
251 check(instr == 0);
253 /* Unaligned target */
254 instr = create_branch(&instr, addr + 3, BRANCH_SET_LINK);
255 check(instr == 0);
257 /* Check flags are masked correctly */
258 instr = create_branch(&instr, addr, 0xFFFFFFFC);
259 check(instr_is_branch_to_addr(&instr, addr));
260 check(instr == 0x48000000);
263 static void __init test_create_function_call(void)
265 unsigned int *iptr;
266 unsigned long dest;
268 /* Check we can create a function call */
269 iptr = (unsigned int *)ppc_function_entry(test_trampoline);
270 dest = ppc_function_entry(test_create_function_call);
271 patch_instruction(iptr, create_branch(iptr, dest, BRANCH_SET_LINK));
272 check(instr_is_branch_to_addr(iptr, dest));
275 static void __init test_branch_bform(void)
277 unsigned long addr;
278 unsigned int *iptr, instr, flags;
280 iptr = &instr;
281 addr = (unsigned long)iptr;
283 /* The simplest case, branch to self, no flags */
284 check(instr_is_branch_bform(0x40000000));
285 /* All bits of target set, and flags */
286 check(instr_is_branch_bform(0x43ffffff));
287 /* High bit of opcode set, which is wrong */
288 check(!instr_is_branch_bform(0xc3ffffff));
289 /* Middle bits of opcode set, which is wrong */
290 check(!instr_is_branch_bform(0x7bffffff));
292 /* Absolute conditional branch to 0x100 */
293 instr = 0x43ff0103;
294 check(instr_is_branch_to_addr(&instr, 0x100));
295 /* Absolute conditional branch to 0x20fc */
296 instr = 0x43ff20ff;
297 check(instr_is_branch_to_addr(&instr, 0x20fc));
298 /* Maximum positive relative conditional branch, + 32 KB - 4B */
299 instr = 0x43ff7ffc;
300 check(instr_is_branch_to_addr(&instr, addr + 0x7FFC));
301 /* Smallest negative relative conditional branch, - 4B */
302 instr = 0x43fffffc;
303 check(instr_is_branch_to_addr(&instr, addr - 4));
304 /* Largest negative relative conditional branch, - 32 KB */
305 instr = 0x43ff8000;
306 check(instr_is_branch_to_addr(&instr, addr - 0x8000));
308 /* All condition code bits set & link */
309 flags = 0x3ff000 | BRANCH_SET_LINK;
311 /* Branch to self */
312 instr = create_cond_branch(iptr, addr, flags);
313 check(instr_is_branch_to_addr(&instr, addr));
315 /* Branch to self - 0x100 */
316 instr = create_cond_branch(iptr, addr - 0x100, flags);
317 check(instr_is_branch_to_addr(&instr, addr - 0x100));
319 /* Branch to self + 0x100 */
320 instr = create_cond_branch(iptr, addr + 0x100, flags);
321 check(instr_is_branch_to_addr(&instr, addr + 0x100));
323 /* Maximum relative negative offset, - 32 KB */
324 instr = create_cond_branch(iptr, addr - 0x8000, flags);
325 check(instr_is_branch_to_addr(&instr, addr - 0x8000));
327 /* Out of range relative negative offset, - 32 KB + 4*/
328 instr = create_cond_branch(iptr, addr - 0x8004, flags);
329 check(instr == 0);
331 /* Out of range relative positive offset, + 32 KB */
332 instr = create_cond_branch(iptr, addr + 0x8000, flags);
333 check(instr == 0);
335 /* Unaligned target */
336 instr = create_cond_branch(iptr, addr + 3, flags);
337 check(instr == 0);
339 /* Check flags are masked correctly */
340 instr = create_cond_branch(iptr, addr, 0xFFFFFFFC);
341 check(instr_is_branch_to_addr(&instr, addr));
342 check(instr == 0x43FF0000);
345 static void __init test_translate_branch(void)
347 unsigned long addr;
348 unsigned int *p, *q;
349 void *buf;
351 buf = vmalloc(PAGE_ALIGN(0x2000000 + 1));
352 check(buf);
353 if (!buf)
354 return;
356 /* Simple case, branch to self moved a little */
357 p = buf;
358 addr = (unsigned long)p;
359 patch_branch(p, addr, 0);
360 check(instr_is_branch_to_addr(p, addr));
361 q = p + 1;
362 patch_instruction(q, translate_branch(q, p));
363 check(instr_is_branch_to_addr(q, addr));
365 /* Maximum negative case, move b . to addr + 32 MB */
366 p = buf;
367 addr = (unsigned long)p;
368 patch_branch(p, addr, 0);
369 q = buf + 0x2000000;
370 patch_instruction(q, translate_branch(q, p));
371 check(instr_is_branch_to_addr(p, addr));
372 check(instr_is_branch_to_addr(q, addr));
373 check(*q == 0x4a000000);
375 /* Maximum positive case, move x to x - 32 MB + 4 */
376 p = buf + 0x2000000;
377 addr = (unsigned long)p;
378 patch_branch(p, addr, 0);
379 q = buf + 4;
380 patch_instruction(q, translate_branch(q, p));
381 check(instr_is_branch_to_addr(p, addr));
382 check(instr_is_branch_to_addr(q, addr));
383 check(*q == 0x49fffffc);
385 /* Jump to x + 16 MB moved to x + 20 MB */
386 p = buf;
387 addr = 0x1000000 + (unsigned long)buf;
388 patch_branch(p, addr, BRANCH_SET_LINK);
389 q = buf + 0x1400000;
390 patch_instruction(q, translate_branch(q, p));
391 check(instr_is_branch_to_addr(p, addr));
392 check(instr_is_branch_to_addr(q, addr));
394 /* Jump to x + 16 MB moved to x - 16 MB + 4 */
395 p = buf + 0x1000000;
396 addr = 0x2000000 + (unsigned long)buf;
397 patch_branch(p, addr, 0);
398 q = buf + 4;
399 patch_instruction(q, translate_branch(q, p));
400 check(instr_is_branch_to_addr(p, addr));
401 check(instr_is_branch_to_addr(q, addr));
404 /* Conditional branch tests */
406 /* Simple case, branch to self moved a little */
407 p = buf;
408 addr = (unsigned long)p;
409 patch_instruction(p, create_cond_branch(p, addr, 0));
410 check(instr_is_branch_to_addr(p, addr));
411 q = p + 1;
412 patch_instruction(q, translate_branch(q, p));
413 check(instr_is_branch_to_addr(q, addr));
415 /* Maximum negative case, move b . to addr + 32 KB */
416 p = buf;
417 addr = (unsigned long)p;
418 patch_instruction(p, create_cond_branch(p, addr, 0xFFFFFFFC));
419 q = buf + 0x8000;
420 patch_instruction(q, translate_branch(q, p));
421 check(instr_is_branch_to_addr(p, addr));
422 check(instr_is_branch_to_addr(q, addr));
423 check(*q == 0x43ff8000);
425 /* Maximum positive case, move x to x - 32 KB + 4 */
426 p = buf + 0x8000;
427 addr = (unsigned long)p;
428 patch_instruction(p, create_cond_branch(p, addr, 0xFFFFFFFC));
429 q = buf + 4;
430 patch_instruction(q, translate_branch(q, p));
431 check(instr_is_branch_to_addr(p, addr));
432 check(instr_is_branch_to_addr(q, addr));
433 check(*q == 0x43ff7ffc);
435 /* Jump to x + 12 KB moved to x + 20 KB */
436 p = buf;
437 addr = 0x3000 + (unsigned long)buf;
438 patch_instruction(p, create_cond_branch(p, addr, BRANCH_SET_LINK));
439 q = buf + 0x5000;
440 patch_instruction(q, translate_branch(q, p));
441 check(instr_is_branch_to_addr(p, addr));
442 check(instr_is_branch_to_addr(q, addr));
444 /* Jump to x + 8 KB moved to x - 8 KB + 4 */
445 p = buf + 0x2000;
446 addr = 0x4000 + (unsigned long)buf;
447 patch_instruction(p, create_cond_branch(p, addr, 0));
448 q = buf + 4;
449 patch_instruction(q, translate_branch(q, p));
450 check(instr_is_branch_to_addr(p, addr));
451 check(instr_is_branch_to_addr(q, addr));
453 /* Free the buffer we were using */
454 vfree(buf);
457 static int __init test_code_patching(void)
459 printk(KERN_DEBUG "Running code patching self-tests ...\n");
461 test_branch_iform();
462 test_branch_bform();
463 test_create_function_call();
464 test_translate_branch();
466 return 0;
468 late_initcall(test_code_patching);
470 #endif /* CONFIG_CODE_PATCHING_SELFTEST */