Merge branch 'for-2.6.27' of git://linux-nfs.org/~bfields/linux
[pandora-kernel.git] / arch / powerpc / lib / code-patching.c
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 */