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.
10 #include <linux/kernel.h>
11 #include <linux/vmalloc.h>
12 #include <linux/init.h>
15 #include <asm/code-patching.h>
16 #include <asm/uaccess.h>
19 int patch_instruction(unsigned int *addr
, unsigned int instr
)
23 __put_user_size(instr
, addr
, 4, err
);
26 asm ("dcbst 0, %0; sync; icbi 0,%0; sync; isync" : : "r" (addr
));
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
;
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)
49 /* Mask out the flags and target, so they don't step on each other. */
50 instruction
= 0x48000000 | (flags
& 0x3) | (offset
& 0x03FFFFFC);
55 unsigned int create_cond_branch(const unsigned int *addr
,
56 unsigned long target
, int flags
)
58 unsigned int instruction
;
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)
69 /* Mask out the flags and target, so they don't step on each other. */
70 instruction
= 0x40000000 | (flags
& 0x3FF0003) | (offset
& 0xFFFC);
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
)
95 return instr_is_branch_iform(instr
) || instr_is_branch_bform(instr
);
98 static unsigned long branch_iform_target(const unsigned int *instr
)
102 imm
= *instr
& 0x3FFFFFC;
104 /* If the top bit of the immediate value is set this is negative */
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
)
118 imm
= *instr
& 0xFFFC;
120 /* If the top bit of the immediate value is set this is negative */
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
);
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
;
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
);
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);
178 #ifdef CONFIG_CODE_PATCHING_SELFTEST
180 static void __init
test_trampoline(void)
186 if (!(x)) printk("code-patching: test failed at line %d\n", __LINE__);
188 static void __init
test_branch_iform(void)
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 */
215 check(instr_is_branch_to_addr(&instr
, 0x100));
216 /* Absolute branch to 0x420fc */
218 check(instr_is_branch_to_addr(&instr
, 0x420fc));
219 /* Maximum positive relative branch, + 20MB - 4B */
221 check(instr_is_branch_to_addr(&instr
, addr
+ 0x1FFFFFC));
222 /* Smallest negative relative branch, - 4B */
224 check(instr_is_branch_to_addr(&instr
, addr
- 4));
225 /* Largest negative relative branch, - 32 MB */
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
);
249 /* Out of range relative positive offset, + 32 MB */
250 instr
= create_branch(&instr
, addr
+ 0x2000000, BRANCH_SET_LINK
);
253 /* Unaligned target */
254 instr
= create_branch(&instr
, addr
+ 3, BRANCH_SET_LINK
);
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)
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)
278 unsigned int *iptr
, instr
, flags
;
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 */
294 check(instr_is_branch_to_addr(&instr
, 0x100));
295 /* Absolute conditional branch to 0x20fc */
297 check(instr_is_branch_to_addr(&instr
, 0x20fc));
298 /* Maximum positive relative conditional branch, + 32 KB - 4B */
300 check(instr_is_branch_to_addr(&instr
, addr
+ 0x7FFC));
301 /* Smallest negative relative conditional branch, - 4B */
303 check(instr_is_branch_to_addr(&instr
, addr
- 4));
304 /* Largest negative relative conditional branch, - 32 KB */
306 check(instr_is_branch_to_addr(&instr
, addr
- 0x8000));
308 /* All condition code bits set & link */
309 flags
= 0x3ff000 | BRANCH_SET_LINK
;
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
);
331 /* Out of range relative positive offset, + 32 KB */
332 instr
= create_cond_branch(iptr
, addr
+ 0x8000, flags
);
335 /* Unaligned target */
336 instr
= create_cond_branch(iptr
, addr
+ 3, flags
);
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)
351 buf
= vmalloc(PAGE_ALIGN(0x2000000 + 1));
356 /* Simple case, branch to self moved a little */
358 addr
= (unsigned long)p
;
359 patch_branch(p
, addr
, 0);
360 check(instr_is_branch_to_addr(p
, addr
));
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 */
367 addr
= (unsigned long)p
;
368 patch_branch(p
, addr
, 0);
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 */
377 addr
= (unsigned long)p
;
378 patch_branch(p
, addr
, 0);
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 */
387 addr
= 0x1000000 + (unsigned long)buf
;
388 patch_branch(p
, addr
, BRANCH_SET_LINK
);
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 */
396 addr
= 0x2000000 + (unsigned long)buf
;
397 patch_branch(p
, addr
, 0);
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 */
408 addr
= (unsigned long)p
;
409 patch_instruction(p
, create_cond_branch(p
, addr
, 0));
410 check(instr_is_branch_to_addr(p
, addr
));
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 */
417 addr
= (unsigned long)p
;
418 patch_instruction(p
, create_cond_branch(p
, addr
, 0xFFFFFFFC));
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 */
427 addr
= (unsigned long)p
;
428 patch_instruction(p
, create_cond_branch(p
, addr
, 0xFFFFFFFC));
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 */
437 addr
= 0x3000 + (unsigned long)buf
;
438 patch_instruction(p
, create_cond_branch(p
, addr
, BRANCH_SET_LINK
));
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 */
446 addr
= 0x4000 + (unsigned long)buf
;
447 patch_instruction(p
, create_cond_branch(p
, addr
, 0));
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 */
457 static int __init
test_code_patching(void)
459 printk(KERN_DEBUG
"Running code patching self-tests ...\n");
463 test_create_function_call();
464 test_translate_branch();
468 late_initcall(test_code_patching
);
470 #endif /* CONFIG_CODE_PATCHING_SELFTEST */