Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
code-patching.c
Go to the documentation of this file.
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;
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;
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;
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;
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;
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;
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;
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;
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;
424  q = buf + 0x5000;
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;
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 */