• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <asm/setup.h>
18 #include <asm/sections.h>
19 
20 
is_init(unsigned int * addr)21 static inline bool is_init(unsigned int *addr)
22 {
23 	return addr >= (unsigned int *)__init_begin && addr < (unsigned int *)__init_end;
24 }
25 
patch_instruction(unsigned int * addr,unsigned int instr)26 int patch_instruction(unsigned int *addr, unsigned int instr)
27 {
28 	int err;
29 
30 	/* Make sure we aren't patching a freed init section */
31 	if (*PTRRELOC(&init_mem_is_free) && is_init(addr)) {
32 		pr_debug("Skipping init section patching addr: 0x%px\n", addr);
33 		return 0;
34 	}
35 
36 	__put_user_size(instr, addr, 4, err);
37 	if (err)
38 		return err;
39 	asm ("dcbst 0, %0; sync; icbi 0,%0; sync; isync" : : "r" (addr));
40 	return 0;
41 }
42 
patch_branch(unsigned int * addr,unsigned long target,int flags)43 int patch_branch(unsigned int *addr, unsigned long target, int flags)
44 {
45 	return patch_instruction(addr, create_branch(addr, target, flags));
46 }
47 
patch_branch_site(s32 * site,unsigned long target,int flags)48 int patch_branch_site(s32 *site, unsigned long target, int flags)
49 {
50 	unsigned int *addr;
51 
52 	addr = (unsigned int *)((unsigned long)site + *site);
53 	return patch_instruction(addr, create_branch(addr, target, flags));
54 }
55 
patch_instruction_site(s32 * site,unsigned int instr)56 int patch_instruction_site(s32 *site, unsigned int instr)
57 {
58 	unsigned int *addr;
59 
60 	addr = (unsigned int *)((unsigned long)site + *site);
61 	return patch_instruction(addr, instr);
62 }
63 
create_branch(const unsigned int * addr,unsigned long target,int flags)64 unsigned int create_branch(const unsigned int *addr,
65 			   unsigned long target, int flags)
66 {
67 	unsigned int instruction;
68 	long offset;
69 
70 	offset = target;
71 	if (! (flags & BRANCH_ABSOLUTE))
72 		offset = offset - (unsigned long)addr;
73 
74 	/* Check we can represent the target in the instruction format */
75 	if (offset < -0x2000000 || offset > 0x1fffffc || offset & 0x3)
76 		return 0;
77 
78 	/* Mask out the flags and target, so they don't step on each other. */
79 	instruction = 0x48000000 | (flags & 0x3) | (offset & 0x03FFFFFC);
80 
81 	return instruction;
82 }
83 
create_cond_branch(const unsigned int * addr,unsigned long target,int flags)84 unsigned int create_cond_branch(const unsigned int *addr,
85 				unsigned long target, int flags)
86 {
87 	unsigned int instruction;
88 	long offset;
89 
90 	offset = target;
91 	if (! (flags & BRANCH_ABSOLUTE))
92 		offset = offset - (unsigned long)addr;
93 
94 	/* Check we can represent the target in the instruction format */
95 	if (offset < -0x8000 || offset > 0x7FFF || offset & 0x3)
96 		return 0;
97 
98 	/* Mask out the flags and target, so they don't step on each other. */
99 	instruction = 0x40000000 | (flags & 0x3FF0003) | (offset & 0xFFFC);
100 
101 	return instruction;
102 }
103 
branch_opcode(unsigned int instr)104 static unsigned int branch_opcode(unsigned int instr)
105 {
106 	return (instr >> 26) & 0x3F;
107 }
108 
instr_is_branch_iform(unsigned int instr)109 static int instr_is_branch_iform(unsigned int instr)
110 {
111 	return branch_opcode(instr) == 18;
112 }
113 
instr_is_branch_bform(unsigned int instr)114 static int instr_is_branch_bform(unsigned int instr)
115 {
116 	return branch_opcode(instr) == 16;
117 }
118 
instr_is_relative_branch(unsigned int instr)119 int instr_is_relative_branch(unsigned int instr)
120 {
121 	if (instr & BRANCH_ABSOLUTE)
122 		return 0;
123 
124 	return instr_is_branch_iform(instr) || instr_is_branch_bform(instr);
125 }
126 
branch_iform_target(const unsigned int * instr)127 static unsigned long branch_iform_target(const unsigned int *instr)
128 {
129 	signed long imm;
130 
131 	imm = *instr & 0x3FFFFFC;
132 
133 	/* If the top bit of the immediate value is set this is negative */
134 	if (imm & 0x2000000)
135 		imm -= 0x4000000;
136 
137 	if ((*instr & BRANCH_ABSOLUTE) == 0)
138 		imm += (unsigned long)instr;
139 
140 	return (unsigned long)imm;
141 }
142 
branch_bform_target(const unsigned int * instr)143 static unsigned long branch_bform_target(const unsigned int *instr)
144 {
145 	signed long imm;
146 
147 	imm = *instr & 0xFFFC;
148 
149 	/* If the top bit of the immediate value is set this is negative */
150 	if (imm & 0x8000)
151 		imm -= 0x10000;
152 
153 	if ((*instr & BRANCH_ABSOLUTE) == 0)
154 		imm += (unsigned long)instr;
155 
156 	return (unsigned long)imm;
157 }
158 
branch_target(const unsigned int * instr)159 unsigned long branch_target(const unsigned int *instr)
160 {
161 	if (instr_is_branch_iform(*instr))
162 		return branch_iform_target(instr);
163 	else if (instr_is_branch_bform(*instr))
164 		return branch_bform_target(instr);
165 
166 	return 0;
167 }
168 
instr_is_branch_to_addr(const unsigned int * instr,unsigned long addr)169 int instr_is_branch_to_addr(const unsigned int *instr, unsigned long addr)
170 {
171 	if (instr_is_branch_iform(*instr) || instr_is_branch_bform(*instr))
172 		return branch_target(instr) == addr;
173 
174 	return 0;
175 }
176 
translate_branch(const unsigned int * dest,const unsigned int * src)177 unsigned int translate_branch(const unsigned int *dest, const unsigned int *src)
178 {
179 	unsigned long target;
180 
181 	target = branch_target(src);
182 
183 	if (instr_is_branch_iform(*src))
184 		return create_branch(dest, target, *src);
185 	else if (instr_is_branch_bform(*src))
186 		return create_cond_branch(dest, target, *src);
187 
188 	return 0;
189 }
190 
191 #ifdef CONFIG_PPC_BOOK3E_64
__patch_exception(int exc,unsigned long addr)192 void __patch_exception(int exc, unsigned long addr)
193 {
194 	extern unsigned int interrupt_base_book3e;
195 	unsigned int *ibase = &interrupt_base_book3e;
196 
197 	/* Our exceptions vectors start with a NOP and -then- a branch
198 	 * to deal with single stepping from userspace which stops on
199 	 * the second instruction. Thus we need to patch the second
200 	 * instruction of the exception, not the first one
201 	 */
202 
203 	patch_branch(ibase + (exc / 4) + 1, addr, 0);
204 }
205 #endif
206 
207 #ifdef CONFIG_CODE_PATCHING_SELFTEST
208 
test_trampoline(void)209 static void __init test_trampoline(void)
210 {
211 	asm ("nop;\n");
212 }
213 
214 #define check(x)	\
215 	if (!(x)) printk("code-patching: test failed at line %d\n", __LINE__);
216 
test_branch_iform(void)217 static void __init test_branch_iform(void)
218 {
219 	unsigned int instr;
220 	unsigned long addr;
221 
222 	addr = (unsigned long)&instr;
223 
224 	/* The simplest case, branch to self, no flags */
225 	check(instr_is_branch_iform(0x48000000));
226 	/* All bits of target set, and flags */
227 	check(instr_is_branch_iform(0x4bffffff));
228 	/* High bit of opcode set, which is wrong */
229 	check(!instr_is_branch_iform(0xcbffffff));
230 	/* Middle bits of opcode set, which is wrong */
231 	check(!instr_is_branch_iform(0x7bffffff));
232 
233 	/* Simplest case, branch to self with link */
234 	check(instr_is_branch_iform(0x48000001));
235 	/* All bits of targets set */
236 	check(instr_is_branch_iform(0x4bfffffd));
237 	/* Some bits of targets set */
238 	check(instr_is_branch_iform(0x4bff00fd));
239 	/* Must be a valid branch to start with */
240 	check(!instr_is_branch_iform(0x7bfffffd));
241 
242 	/* Absolute branch to 0x100 */
243 	instr = 0x48000103;
244 	check(instr_is_branch_to_addr(&instr, 0x100));
245 	/* Absolute branch to 0x420fc */
246 	instr = 0x480420ff;
247 	check(instr_is_branch_to_addr(&instr, 0x420fc));
248 	/* Maximum positive relative branch, + 20MB - 4B */
249 	instr = 0x49fffffc;
250 	check(instr_is_branch_to_addr(&instr, addr + 0x1FFFFFC));
251 	/* Smallest negative relative branch, - 4B */
252 	instr = 0x4bfffffc;
253 	check(instr_is_branch_to_addr(&instr, addr - 4));
254 	/* Largest negative relative branch, - 32 MB */
255 	instr = 0x4a000000;
256 	check(instr_is_branch_to_addr(&instr, addr - 0x2000000));
257 
258 	/* Branch to self, with link */
259 	instr = create_branch(&instr, addr, BRANCH_SET_LINK);
260 	check(instr_is_branch_to_addr(&instr, addr));
261 
262 	/* Branch to self - 0x100, with link */
263 	instr = create_branch(&instr, addr - 0x100, BRANCH_SET_LINK);
264 	check(instr_is_branch_to_addr(&instr, addr - 0x100));
265 
266 	/* Branch to self + 0x100, no link */
267 	instr = create_branch(&instr, addr + 0x100, 0);
268 	check(instr_is_branch_to_addr(&instr, addr + 0x100));
269 
270 	/* Maximum relative negative offset, - 32 MB */
271 	instr = create_branch(&instr, addr - 0x2000000, BRANCH_SET_LINK);
272 	check(instr_is_branch_to_addr(&instr, addr - 0x2000000));
273 
274 	/* Out of range relative negative offset, - 32 MB + 4*/
275 	instr = create_branch(&instr, addr - 0x2000004, BRANCH_SET_LINK);
276 	check(instr == 0);
277 
278 	/* Out of range relative positive offset, + 32 MB */
279 	instr = create_branch(&instr, addr + 0x2000000, BRANCH_SET_LINK);
280 	check(instr == 0);
281 
282 	/* Unaligned target */
283 	instr = create_branch(&instr, addr + 3, BRANCH_SET_LINK);
284 	check(instr == 0);
285 
286 	/* Check flags are masked correctly */
287 	instr = create_branch(&instr, addr, 0xFFFFFFFC);
288 	check(instr_is_branch_to_addr(&instr, addr));
289 	check(instr == 0x48000000);
290 }
291 
test_create_function_call(void)292 static void __init test_create_function_call(void)
293 {
294 	unsigned int *iptr;
295 	unsigned long dest;
296 
297 	/* Check we can create a function call */
298 	iptr = (unsigned int *)ppc_function_entry(test_trampoline);
299 	dest = ppc_function_entry(test_create_function_call);
300 	patch_instruction(iptr, create_branch(iptr, dest, BRANCH_SET_LINK));
301 	check(instr_is_branch_to_addr(iptr, dest));
302 }
303 
test_branch_bform(void)304 static void __init test_branch_bform(void)
305 {
306 	unsigned long addr;
307 	unsigned int *iptr, instr, flags;
308 
309 	iptr = &instr;
310 	addr = (unsigned long)iptr;
311 
312 	/* The simplest case, branch to self, no flags */
313 	check(instr_is_branch_bform(0x40000000));
314 	/* All bits of target set, and flags */
315 	check(instr_is_branch_bform(0x43ffffff));
316 	/* High bit of opcode set, which is wrong */
317 	check(!instr_is_branch_bform(0xc3ffffff));
318 	/* Middle bits of opcode set, which is wrong */
319 	check(!instr_is_branch_bform(0x7bffffff));
320 
321 	/* Absolute conditional branch to 0x100 */
322 	instr = 0x43ff0103;
323 	check(instr_is_branch_to_addr(&instr, 0x100));
324 	/* Absolute conditional branch to 0x20fc */
325 	instr = 0x43ff20ff;
326 	check(instr_is_branch_to_addr(&instr, 0x20fc));
327 	/* Maximum positive relative conditional branch, + 32 KB - 4B */
328 	instr = 0x43ff7ffc;
329 	check(instr_is_branch_to_addr(&instr, addr + 0x7FFC));
330 	/* Smallest negative relative conditional branch, - 4B */
331 	instr = 0x43fffffc;
332 	check(instr_is_branch_to_addr(&instr, addr - 4));
333 	/* Largest negative relative conditional branch, - 32 KB */
334 	instr = 0x43ff8000;
335 	check(instr_is_branch_to_addr(&instr, addr - 0x8000));
336 
337 	/* All condition code bits set & link */
338 	flags = 0x3ff000 | BRANCH_SET_LINK;
339 
340 	/* Branch to self */
341 	instr = create_cond_branch(iptr, addr, flags);
342 	check(instr_is_branch_to_addr(&instr, addr));
343 
344 	/* Branch to self - 0x100 */
345 	instr = create_cond_branch(iptr, addr - 0x100, flags);
346 	check(instr_is_branch_to_addr(&instr, addr - 0x100));
347 
348 	/* Branch to self + 0x100 */
349 	instr = create_cond_branch(iptr, addr + 0x100, flags);
350 	check(instr_is_branch_to_addr(&instr, addr + 0x100));
351 
352 	/* Maximum relative negative offset, - 32 KB */
353 	instr = create_cond_branch(iptr, addr - 0x8000, flags);
354 	check(instr_is_branch_to_addr(&instr, addr - 0x8000));
355 
356 	/* Out of range relative negative offset, - 32 KB + 4*/
357 	instr = create_cond_branch(iptr, addr - 0x8004, flags);
358 	check(instr == 0);
359 
360 	/* Out of range relative positive offset, + 32 KB */
361 	instr = create_cond_branch(iptr, addr + 0x8000, flags);
362 	check(instr == 0);
363 
364 	/* Unaligned target */
365 	instr = create_cond_branch(iptr, addr + 3, flags);
366 	check(instr == 0);
367 
368 	/* Check flags are masked correctly */
369 	instr = create_cond_branch(iptr, addr, 0xFFFFFFFC);
370 	check(instr_is_branch_to_addr(&instr, addr));
371 	check(instr == 0x43FF0000);
372 }
373 
test_translate_branch(void)374 static void __init test_translate_branch(void)
375 {
376 	unsigned long addr;
377 	unsigned int *p, *q;
378 	void *buf;
379 
380 	buf = vmalloc(PAGE_ALIGN(0x2000000 + 1));
381 	check(buf);
382 	if (!buf)
383 		return;
384 
385 	/* Simple case, branch to self moved a little */
386 	p = buf;
387 	addr = (unsigned long)p;
388 	patch_branch(p, addr, 0);
389 	check(instr_is_branch_to_addr(p, addr));
390 	q = p + 1;
391 	patch_instruction(q, translate_branch(q, p));
392 	check(instr_is_branch_to_addr(q, addr));
393 
394 	/* Maximum negative case, move b . to addr + 32 MB */
395 	p = buf;
396 	addr = (unsigned long)p;
397 	patch_branch(p, addr, 0);
398 	q = buf + 0x2000000;
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 	check(*q == 0x4a000000);
403 
404 	/* Maximum positive case, move x to x - 32 MB + 4 */
405 	p = buf + 0x2000000;
406 	addr = (unsigned long)p;
407 	patch_branch(p, addr, 0);
408 	q = buf + 4;
409 	patch_instruction(q, translate_branch(q, p));
410 	check(instr_is_branch_to_addr(p, addr));
411 	check(instr_is_branch_to_addr(q, addr));
412 	check(*q == 0x49fffffc);
413 
414 	/* Jump to x + 16 MB moved to x + 20 MB */
415 	p = buf;
416 	addr = 0x1000000 + (unsigned long)buf;
417 	patch_branch(p, addr, BRANCH_SET_LINK);
418 	q = buf + 0x1400000;
419 	patch_instruction(q, translate_branch(q, p));
420 	check(instr_is_branch_to_addr(p, addr));
421 	check(instr_is_branch_to_addr(q, addr));
422 
423 	/* Jump to x + 16 MB moved to x - 16 MB + 4 */
424 	p = buf + 0x1000000;
425 	addr = 0x2000000 + (unsigned long)buf;
426 	patch_branch(p, addr, 0);
427 	q = buf + 4;
428 	patch_instruction(q, translate_branch(q, p));
429 	check(instr_is_branch_to_addr(p, addr));
430 	check(instr_is_branch_to_addr(q, addr));
431 
432 
433 	/* Conditional branch tests */
434 
435 	/* Simple case, branch to self moved a little */
436 	p = buf;
437 	addr = (unsigned long)p;
438 	patch_instruction(p, create_cond_branch(p, addr, 0));
439 	check(instr_is_branch_to_addr(p, addr));
440 	q = p + 1;
441 	patch_instruction(q, translate_branch(q, p));
442 	check(instr_is_branch_to_addr(q, addr));
443 
444 	/* Maximum negative case, move b . to addr + 32 KB */
445 	p = buf;
446 	addr = (unsigned long)p;
447 	patch_instruction(p, create_cond_branch(p, addr, 0xFFFFFFFC));
448 	q = buf + 0x8000;
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 	check(*q == 0x43ff8000);
453 
454 	/* Maximum positive case, move x to x - 32 KB + 4 */
455 	p = buf + 0x8000;
456 	addr = (unsigned long)p;
457 	patch_instruction(p, create_cond_branch(p, addr, 0xFFFFFFFC));
458 	q = buf + 4;
459 	patch_instruction(q, translate_branch(q, p));
460 	check(instr_is_branch_to_addr(p, addr));
461 	check(instr_is_branch_to_addr(q, addr));
462 	check(*q == 0x43ff7ffc);
463 
464 	/* Jump to x + 12 KB moved to x + 20 KB */
465 	p = buf;
466 	addr = 0x3000 + (unsigned long)buf;
467 	patch_instruction(p, create_cond_branch(p, addr, BRANCH_SET_LINK));
468 	q = buf + 0x5000;
469 	patch_instruction(q, translate_branch(q, p));
470 	check(instr_is_branch_to_addr(p, addr));
471 	check(instr_is_branch_to_addr(q, addr));
472 
473 	/* Jump to x + 8 KB moved to x - 8 KB + 4 */
474 	p = buf + 0x2000;
475 	addr = 0x4000 + (unsigned long)buf;
476 	patch_instruction(p, create_cond_branch(p, addr, 0));
477 	q = buf + 4;
478 	patch_instruction(q, translate_branch(q, p));
479 	check(instr_is_branch_to_addr(p, addr));
480 	check(instr_is_branch_to_addr(q, addr));
481 
482 	/* Free the buffer we were using */
483 	vfree(buf);
484 }
485 
test_code_patching(void)486 static int __init test_code_patching(void)
487 {
488 	printk(KERN_DEBUG "Running code patching self-tests ...\n");
489 
490 	test_branch_iform();
491 	test_branch_bform();
492 	test_create_function_call();
493 	test_translate_branch();
494 
495 	return 0;
496 }
497 late_initcall(test_code_patching);
498 
499 #endif /* CONFIG_CODE_PATCHING_SELFTEST */
500