blob: c1746df0f88e953c7b404ba0f55f2179882d48b3 [file] [log] [blame]
Michael Ellermanaaddd3e2008-06-24 11:32:21 +10001/*
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>
Michael Ellermanae0dc732008-06-24 11:32:32 +100011#include <linux/vmalloc.h>
12#include <linux/init.h>
Andrea Righi27ac7922008-07-23 21:28:13 -070013#include <linux/mm.h>
Michael Ellermanae0dc732008-06-24 11:32:32 +100014#include <asm/page.h>
Michael Ellermanaaddd3e2008-06-24 11:32:21 +100015#include <asm/code-patching.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080016#include <linux/uaccess.h>
Michael Ellermanaaddd3e2008-06-24 11:32:21 +100017
18
Steven Rostedtb6e37962012-04-26 08:31:18 +000019int patch_instruction(unsigned int *addr, unsigned int instr)
Michael Ellermanaaddd3e2008-06-24 11:32:21 +100020{
Steven Rostedtb6e37962012-04-26 08:31:18 +000021 int err;
22
Benjamin Herrenschmidt636802e2012-09-04 15:08:28 +000023 __put_user_size(instr, addr, 4, err);
Steven Rostedtb6e37962012-04-26 08:31:18 +000024 if (err)
25 return err;
Michael Ellermane7a57272008-06-24 11:32:22 +100026 asm ("dcbst 0, %0; sync; icbi 0,%0; sync; isync" : : "r" (addr));
Steven Rostedtb6e37962012-04-26 08:31:18 +000027 return 0;
Michael Ellermanaaddd3e2008-06-24 11:32:21 +100028}
29
Steven Rostedtb6e37962012-04-26 08:31:18 +000030int patch_branch(unsigned int *addr, unsigned long target, int flags)
Michael Ellermane7a57272008-06-24 11:32:22 +100031{
Steven Rostedtb6e37962012-04-26 08:31:18 +000032 return patch_instruction(addr, create_branch(addr, target, flags));
Michael Ellermane7a57272008-06-24 11:32:22 +100033}
34
35unsigned int create_branch(const unsigned int *addr,
36 unsigned long target, int flags)
Michael Ellermanaaddd3e2008-06-24 11:32:21 +100037{
38 unsigned int instruction;
Michael Ellerman053a8582008-06-24 11:32:24 +100039 long offset;
Michael Ellermanaaddd3e2008-06-24 11:32:21 +100040
Michael Ellerman053a8582008-06-24 11:32:24 +100041 offset = target;
Michael Ellermanaaddd3e2008-06-24 11:32:21 +100042 if (! (flags & BRANCH_ABSOLUTE))
Michael Ellerman053a8582008-06-24 11:32:24 +100043 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;
Michael Ellermanaaddd3e2008-06-24 11:32:21 +100048
49 /* Mask out the flags and target, so they don't step on each other. */
Michael Ellerman053a8582008-06-24 11:32:24 +100050 instruction = 0x48000000 | (flags & 0x3) | (offset & 0x03FFFFFC);
Michael Ellermanaaddd3e2008-06-24 11:32:21 +100051
Michael Ellermane7a57272008-06-24 11:32:22 +100052 return instruction;
Michael Ellermanaaddd3e2008-06-24 11:32:21 +100053}
Michael Ellerman411781a2008-06-24 11:32:29 +100054
55unsigned 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
75static unsigned int branch_opcode(unsigned int instr)
76{
77 return (instr >> 26) & 0x3F;
78}
79
80static int instr_is_branch_iform(unsigned int instr)
81{
82 return branch_opcode(instr) == 18;
83}
84
85static int instr_is_branch_bform(unsigned int instr)
86{
87 return branch_opcode(instr) == 16;
88}
89
90int 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
98static 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
114static 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
130unsigned 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
140int 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
148unsigned 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}
Michael Ellermanae0dc732008-06-24 11:32:32 +1000161
Kevin Hao1e8341a2013-05-12 07:26:22 +0800162#ifdef CONFIG_PPC_BOOK3E_64
163void __patch_exception(int exc, unsigned long addr)
164{
165 extern unsigned int interrupt_base_book3e;
166 unsigned int *ibase = &interrupt_base_book3e;
167
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
172 */
173
174 patch_branch(ibase + (exc / 4) + 1, addr, 0);
175}
176#endif
Michael Ellermanae0dc732008-06-24 11:32:32 +1000177
178#ifdef CONFIG_CODE_PATCHING_SELFTEST
179
180static void __init test_trampoline(void)
181{
182 asm ("nop;\n");
183}
184
185#define check(x) \
186 if (!(x)) printk("code-patching: test failed at line %d\n", __LINE__);
187
188static void __init test_branch_iform(void)
189{
190 unsigned int instr;
191 unsigned long addr;
192
193 addr = (unsigned long)&instr;
194
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));
203
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));
212
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));
228
229 /* Branch to self, with link */
230 instr = create_branch(&instr, addr, BRANCH_SET_LINK);
231 check(instr_is_branch_to_addr(&instr, addr));
232
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));
236
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));
240
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));
244
245 /* Out of range relative negative offset, - 32 MB + 4*/
246 instr = create_branch(&instr, addr - 0x2000004, BRANCH_SET_LINK);
247 check(instr == 0);
248
249 /* Out of range relative positive offset, + 32 MB */
250 instr = create_branch(&instr, addr + 0x2000000, BRANCH_SET_LINK);
251 check(instr == 0);
252
253 /* Unaligned target */
254 instr = create_branch(&instr, addr + 3, BRANCH_SET_LINK);
255 check(instr == 0);
256
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);
261}
262
263static void __init test_create_function_call(void)
264{
265 unsigned int *iptr;
266 unsigned long dest;
267
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));
273}
274
275static void __init test_branch_bform(void)
276{
277 unsigned long addr;
278 unsigned int *iptr, instr, flags;
279
280 iptr = &instr;
281 addr = (unsigned long)iptr;
282
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));
291
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));
307
308 /* All condition code bits set & link */
309 flags = 0x3ff000 | BRANCH_SET_LINK;
310
311 /* Branch to self */
312 instr = create_cond_branch(iptr, addr, flags);
313 check(instr_is_branch_to_addr(&instr, addr));
314
315 /* Branch to self - 0x100 */
316 instr = create_cond_branch(iptr, addr - 0x100, flags);
317 check(instr_is_branch_to_addr(&instr, addr - 0x100));
318
319 /* Branch to self + 0x100 */
320 instr = create_cond_branch(iptr, addr + 0x100, flags);
321 check(instr_is_branch_to_addr(&instr, addr + 0x100));
322
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));
326
327 /* Out of range relative negative offset, - 32 KB + 4*/
328 instr = create_cond_branch(iptr, addr - 0x8004, flags);
329 check(instr == 0);
330
331 /* Out of range relative positive offset, + 32 KB */
332 instr = create_cond_branch(iptr, addr + 0x8000, flags);
333 check(instr == 0);
334
335 /* Unaligned target */
336 instr = create_cond_branch(iptr, addr + 3, flags);
337 check(instr == 0);
338
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);
343}
344
345static void __init test_translate_branch(void)
346{
347 unsigned long addr;
348 unsigned int *p, *q;
349 void *buf;
350
351 buf = vmalloc(PAGE_ALIGN(0x2000000 + 1));
352 check(buf);
353 if (!buf)
354 return;
355
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));
364
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);
374
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);
384
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));
393
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));
402
403
404 /* Conditional branch tests */
405
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));
414
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);
424
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);
434
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));
443
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));
452
453 /* Free the buffer we were using */
454 vfree(buf);
455}
456
457static int __init test_code_patching(void)
458{
459 printk(KERN_DEBUG "Running code patching self-tests ...\n");
460
461 test_branch_iform();
462 test_branch_bform();
463 test_create_function_call();
464 test_translate_branch();
465
466 return 0;
467}
468late_initcall(test_code_patching);
469
470#endif /* CONFIG_CODE_PATCHING_SELFTEST */