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