1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright 2008 Michael Ellerman, IBM Corporation.
4 */
5
6 #include <linux/vmalloc.h>
7 #include <linux/init.h>
8
9 #include <asm/code-patching.h>
10
instr_is_branch_to_addr(const u32 * instr,unsigned long addr)11 static int __init instr_is_branch_to_addr(const u32 *instr, unsigned long addr)
12 {
13 if (instr_is_branch_iform(ppc_inst_read(instr)) ||
14 instr_is_branch_bform(ppc_inst_read(instr)))
15 return branch_target(instr) == addr;
16
17 return 0;
18 }
19
test_trampoline(void)20 static void __init test_trampoline(void)
21 {
22 asm ("nop;nop;\n");
23 }
24
25 #define check(x) do { \
26 if (!(x)) \
27 pr_err("code-patching: test failed at line %d\n", __LINE__); \
28 } while (0)
29
test_branch_iform(void)30 static void __init test_branch_iform(void)
31 {
32 int err;
33 ppc_inst_t instr;
34 u32 tmp[2];
35 u32 *iptr = tmp;
36 unsigned long addr = (unsigned long)tmp;
37
38 /* The simplest case, branch to self, no flags */
39 check(instr_is_branch_iform(ppc_inst(0x48000000)));
40 /* All bits of target set, and flags */
41 check(instr_is_branch_iform(ppc_inst(0x4bffffff)));
42 /* High bit of opcode set, which is wrong */
43 check(!instr_is_branch_iform(ppc_inst(0xcbffffff)));
44 /* Middle bits of opcode set, which is wrong */
45 check(!instr_is_branch_iform(ppc_inst(0x7bffffff)));
46
47 /* Simplest case, branch to self with link */
48 check(instr_is_branch_iform(ppc_inst(0x48000001)));
49 /* All bits of targets set */
50 check(instr_is_branch_iform(ppc_inst(0x4bfffffd)));
51 /* Some bits of targets set */
52 check(instr_is_branch_iform(ppc_inst(0x4bff00fd)));
53 /* Must be a valid branch to start with */
54 check(!instr_is_branch_iform(ppc_inst(0x7bfffffd)));
55
56 /* Absolute branch to 0x100 */
57 ppc_inst_write(iptr, ppc_inst(0x48000103));
58 check(instr_is_branch_to_addr(iptr, 0x100));
59 /* Absolute branch to 0x420fc */
60 ppc_inst_write(iptr, ppc_inst(0x480420ff));
61 check(instr_is_branch_to_addr(iptr, 0x420fc));
62 /* Maximum positive relative branch, + 20MB - 4B */
63 ppc_inst_write(iptr, ppc_inst(0x49fffffc));
64 check(instr_is_branch_to_addr(iptr, addr + 0x1FFFFFC));
65 /* Smallest negative relative branch, - 4B */
66 ppc_inst_write(iptr, ppc_inst(0x4bfffffc));
67 check(instr_is_branch_to_addr(iptr, addr - 4));
68 /* Largest negative relative branch, - 32 MB */
69 ppc_inst_write(iptr, ppc_inst(0x4a000000));
70 check(instr_is_branch_to_addr(iptr, addr - 0x2000000));
71
72 /* Branch to self, with link */
73 err = create_branch(&instr, iptr, addr, BRANCH_SET_LINK);
74 ppc_inst_write(iptr, instr);
75 check(instr_is_branch_to_addr(iptr, addr));
76
77 /* Branch to self - 0x100, with link */
78 err = create_branch(&instr, iptr, addr - 0x100, BRANCH_SET_LINK);
79 ppc_inst_write(iptr, instr);
80 check(instr_is_branch_to_addr(iptr, addr - 0x100));
81
82 /* Branch to self + 0x100, no link */
83 err = create_branch(&instr, iptr, addr + 0x100, 0);
84 ppc_inst_write(iptr, instr);
85 check(instr_is_branch_to_addr(iptr, addr + 0x100));
86
87 /* Maximum relative negative offset, - 32 MB */
88 err = create_branch(&instr, iptr, addr - 0x2000000, BRANCH_SET_LINK);
89 ppc_inst_write(iptr, instr);
90 check(instr_is_branch_to_addr(iptr, addr - 0x2000000));
91
92 /* Out of range relative negative offset, - 32 MB + 4*/
93 err = create_branch(&instr, iptr, addr - 0x2000004, BRANCH_SET_LINK);
94 check(err);
95
96 /* Out of range relative positive offset, + 32 MB */
97 err = create_branch(&instr, iptr, addr + 0x2000000, BRANCH_SET_LINK);
98 check(err);
99
100 /* Unaligned target */
101 err = create_branch(&instr, iptr, addr + 3, BRANCH_SET_LINK);
102 check(err);
103
104 /* Check flags are masked correctly */
105 err = create_branch(&instr, iptr, addr, 0xFFFFFFFC);
106 ppc_inst_write(iptr, instr);
107 check(instr_is_branch_to_addr(iptr, addr));
108 check(ppc_inst_equal(instr, ppc_inst(0x48000000)));
109 }
110
test_create_function_call(void)111 static void __init test_create_function_call(void)
112 {
113 u32 *iptr;
114 unsigned long dest;
115 ppc_inst_t instr;
116
117 /* Check we can create a function call */
118 iptr = (u32 *)ppc_function_entry(test_trampoline);
119 dest = ppc_function_entry(test_create_function_call);
120 create_branch(&instr, iptr, dest, BRANCH_SET_LINK);
121 patch_instruction(iptr, instr);
122 check(instr_is_branch_to_addr(iptr, dest));
123 }
124
test_branch_bform(void)125 static void __init test_branch_bform(void)
126 {
127 int err;
128 unsigned long addr;
129 ppc_inst_t instr;
130 u32 tmp[2];
131 u32 *iptr = tmp;
132 unsigned int flags;
133
134 addr = (unsigned long)iptr;
135
136 /* The simplest case, branch to self, no flags */
137 check(instr_is_branch_bform(ppc_inst(0x40000000)));
138 /* All bits of target set, and flags */
139 check(instr_is_branch_bform(ppc_inst(0x43ffffff)));
140 /* High bit of opcode set, which is wrong */
141 check(!instr_is_branch_bform(ppc_inst(0xc3ffffff)));
142 /* Middle bits of opcode set, which is wrong */
143 check(!instr_is_branch_bform(ppc_inst(0x7bffffff)));
144
145 /* Absolute conditional branch to 0x100 */
146 ppc_inst_write(iptr, ppc_inst(0x43ff0103));
147 check(instr_is_branch_to_addr(iptr, 0x100));
148 /* Absolute conditional branch to 0x20fc */
149 ppc_inst_write(iptr, ppc_inst(0x43ff20ff));
150 check(instr_is_branch_to_addr(iptr, 0x20fc));
151 /* Maximum positive relative conditional branch, + 32 KB - 4B */
152 ppc_inst_write(iptr, ppc_inst(0x43ff7ffc));
153 check(instr_is_branch_to_addr(iptr, addr + 0x7FFC));
154 /* Smallest negative relative conditional branch, - 4B */
155 ppc_inst_write(iptr, ppc_inst(0x43fffffc));
156 check(instr_is_branch_to_addr(iptr, addr - 4));
157 /* Largest negative relative conditional branch, - 32 KB */
158 ppc_inst_write(iptr, ppc_inst(0x43ff8000));
159 check(instr_is_branch_to_addr(iptr, addr - 0x8000));
160
161 /* All condition code bits set & link */
162 flags = 0x3ff000 | BRANCH_SET_LINK;
163
164 /* Branch to self */
165 err = create_cond_branch(&instr, iptr, addr, flags);
166 ppc_inst_write(iptr, instr);
167 check(instr_is_branch_to_addr(iptr, addr));
168
169 /* Branch to self - 0x100 */
170 err = create_cond_branch(&instr, iptr, addr - 0x100, flags);
171 ppc_inst_write(iptr, instr);
172 check(instr_is_branch_to_addr(iptr, addr - 0x100));
173
174 /* Branch to self + 0x100 */
175 err = create_cond_branch(&instr, iptr, addr + 0x100, flags);
176 ppc_inst_write(iptr, instr);
177 check(instr_is_branch_to_addr(iptr, addr + 0x100));
178
179 /* Maximum relative negative offset, - 32 KB */
180 err = create_cond_branch(&instr, iptr, addr - 0x8000, flags);
181 ppc_inst_write(iptr, instr);
182 check(instr_is_branch_to_addr(iptr, addr - 0x8000));
183
184 /* Out of range relative negative offset, - 32 KB + 4*/
185 err = create_cond_branch(&instr, iptr, addr - 0x8004, flags);
186 check(err);
187
188 /* Out of range relative positive offset, + 32 KB */
189 err = create_cond_branch(&instr, iptr, addr + 0x8000, flags);
190 check(err);
191
192 /* Unaligned target */
193 err = create_cond_branch(&instr, iptr, addr + 3, flags);
194 check(err);
195
196 /* Check flags are masked correctly */
197 err = create_cond_branch(&instr, iptr, addr, 0xFFFFFFFC);
198 ppc_inst_write(iptr, instr);
199 check(instr_is_branch_to_addr(iptr, addr));
200 check(ppc_inst_equal(instr, ppc_inst(0x43FF0000)));
201 }
202
test_translate_branch(void)203 static void __init test_translate_branch(void)
204 {
205 unsigned long addr;
206 void *p, *q;
207 ppc_inst_t instr;
208 void *buf;
209
210 buf = vmalloc(PAGE_ALIGN(0x2000000 + 1));
211 check(buf);
212 if (!buf)
213 return;
214
215 /* Simple case, branch to self moved a little */
216 p = buf;
217 addr = (unsigned long)p;
218 create_branch(&instr, p, addr, 0);
219 ppc_inst_write(p, instr);
220 check(instr_is_branch_to_addr(p, addr));
221 q = p + 4;
222 translate_branch(&instr, q, p);
223 ppc_inst_write(q, instr);
224 check(instr_is_branch_to_addr(q, addr));
225
226 /* Maximum negative case, move b . to addr + 32 MB */
227 p = buf;
228 addr = (unsigned long)p;
229 create_branch(&instr, p, addr, 0);
230 ppc_inst_write(p, instr);
231 q = buf + 0x2000000;
232 translate_branch(&instr, q, p);
233 ppc_inst_write(q, instr);
234 check(instr_is_branch_to_addr(p, addr));
235 check(instr_is_branch_to_addr(q, addr));
236 check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x4a000000)));
237
238 /* Maximum positive case, move x to x - 32 MB + 4 */
239 p = buf + 0x2000000;
240 addr = (unsigned long)p;
241 create_branch(&instr, p, addr, 0);
242 ppc_inst_write(p, instr);
243 q = buf + 4;
244 translate_branch(&instr, q, p);
245 ppc_inst_write(q, instr);
246 check(instr_is_branch_to_addr(p, addr));
247 check(instr_is_branch_to_addr(q, addr));
248 check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x49fffffc)));
249
250 /* Jump to x + 16 MB moved to x + 20 MB */
251 p = buf;
252 addr = 0x1000000 + (unsigned long)buf;
253 create_branch(&instr, p, addr, BRANCH_SET_LINK);
254 ppc_inst_write(p, instr);
255 q = buf + 0x1400000;
256 translate_branch(&instr, q, p);
257 ppc_inst_write(q, instr);
258 check(instr_is_branch_to_addr(p, addr));
259 check(instr_is_branch_to_addr(q, addr));
260
261 /* Jump to x + 16 MB moved to x - 16 MB + 4 */
262 p = buf + 0x1000000;
263 addr = 0x2000000 + (unsigned long)buf;
264 create_branch(&instr, p, addr, 0);
265 ppc_inst_write(p, instr);
266 q = buf + 4;
267 translate_branch(&instr, q, p);
268 ppc_inst_write(q, instr);
269 check(instr_is_branch_to_addr(p, addr));
270 check(instr_is_branch_to_addr(q, addr));
271
272
273 /* Conditional branch tests */
274
275 /* Simple case, branch to self moved a little */
276 p = buf;
277 addr = (unsigned long)p;
278 create_cond_branch(&instr, p, addr, 0);
279 ppc_inst_write(p, instr);
280 check(instr_is_branch_to_addr(p, addr));
281 q = buf + 4;
282 translate_branch(&instr, q, p);
283 ppc_inst_write(q, instr);
284 check(instr_is_branch_to_addr(q, addr));
285
286 /* Maximum negative case, move b . to addr + 32 KB */
287 p = buf;
288 addr = (unsigned long)p;
289 create_cond_branch(&instr, p, addr, 0xFFFFFFFC);
290 ppc_inst_write(p, instr);
291 q = buf + 0x8000;
292 translate_branch(&instr, q, p);
293 ppc_inst_write(q, instr);
294 check(instr_is_branch_to_addr(p, addr));
295 check(instr_is_branch_to_addr(q, addr));
296 check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x43ff8000)));
297
298 /* Maximum positive case, move x to x - 32 KB + 4 */
299 p = buf + 0x8000;
300 addr = (unsigned long)p;
301 create_cond_branch(&instr, p, addr, 0xFFFFFFFC);
302 ppc_inst_write(p, instr);
303 q = buf + 4;
304 translate_branch(&instr, q, p);
305 ppc_inst_write(q, instr);
306 check(instr_is_branch_to_addr(p, addr));
307 check(instr_is_branch_to_addr(q, addr));
308 check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x43ff7ffc)));
309
310 /* Jump to x + 12 KB moved to x + 20 KB */
311 p = buf;
312 addr = 0x3000 + (unsigned long)buf;
313 create_cond_branch(&instr, p, addr, BRANCH_SET_LINK);
314 ppc_inst_write(p, instr);
315 q = buf + 0x5000;
316 translate_branch(&instr, q, p);
317 ppc_inst_write(q, instr);
318 check(instr_is_branch_to_addr(p, addr));
319 check(instr_is_branch_to_addr(q, addr));
320
321 /* Jump to x + 8 KB moved to x - 8 KB + 4 */
322 p = buf + 0x2000;
323 addr = 0x4000 + (unsigned long)buf;
324 create_cond_branch(&instr, p, addr, 0);
325 ppc_inst_write(p, instr);
326 q = buf + 4;
327 translate_branch(&instr, q, p);
328 ppc_inst_write(q, instr);
329 check(instr_is_branch_to_addr(p, addr));
330 check(instr_is_branch_to_addr(q, addr));
331
332 /* Free the buffer we were using */
333 vfree(buf);
334 }
335
test_prefixed_patching(void)336 static void __init test_prefixed_patching(void)
337 {
338 u32 *iptr = (u32 *)ppc_function_entry(test_trampoline);
339 u32 expected[2] = {OP_PREFIX << 26, 0};
340 ppc_inst_t inst = ppc_inst_prefix(OP_PREFIX << 26, 0);
341
342 if (!IS_ENABLED(CONFIG_PPC64))
343 return;
344
345 patch_instruction(iptr, inst);
346
347 check(!memcmp(iptr, expected, sizeof(expected)));
348 }
349
test_multi_instruction_patching(void)350 static void __init test_multi_instruction_patching(void)
351 {
352 u32 code[32];
353 void *buf;
354 u32 *addr32;
355 u64 *addr64;
356 ppc_inst_t inst64 = ppc_inst_prefix(OP_PREFIX << 26 | 3UL << 24, PPC_RAW_TRAP());
357 u32 inst32 = PPC_RAW_NOP();
358
359 buf = vzalloc(PAGE_SIZE * 8);
360 check(buf);
361 if (!buf)
362 return;
363
364 /* Test single page 32-bit repeated instruction */
365 addr32 = buf + PAGE_SIZE;
366 check(!patch_instructions(addr32 + 1, &inst32, 12, true));
367
368 check(addr32[0] == 0);
369 check(addr32[1] == inst32);
370 check(addr32[2] == inst32);
371 check(addr32[3] == inst32);
372 check(addr32[4] == 0);
373
374 /* Test single page 64-bit repeated instruction */
375 if (IS_ENABLED(CONFIG_PPC64)) {
376 check(ppc_inst_prefixed(inst64));
377
378 addr64 = buf + PAGE_SIZE * 2;
379 ppc_inst_write(code, inst64);
380 check(!patch_instructions((u32 *)(addr64 + 1), code, 24, true));
381
382 check(addr64[0] == 0);
383 check(ppc_inst_equal(ppc_inst_read((u32 *)&addr64[1]), inst64));
384 check(ppc_inst_equal(ppc_inst_read((u32 *)&addr64[2]), inst64));
385 check(ppc_inst_equal(ppc_inst_read((u32 *)&addr64[3]), inst64));
386 check(addr64[4] == 0);
387 }
388
389 /* Test single page memcpy */
390 addr32 = buf + PAGE_SIZE * 3;
391
392 for (int i = 0; i < ARRAY_SIZE(code); i++)
393 code[i] = i + 1;
394
395 check(!patch_instructions(addr32 + 1, code, sizeof(code), false));
396
397 check(addr32[0] == 0);
398 check(!memcmp(&addr32[1], code, sizeof(code)));
399 check(addr32[ARRAY_SIZE(code) + 1] == 0);
400
401 /* Test multipage 32-bit repeated instruction */
402 addr32 = buf + PAGE_SIZE * 4 - 8;
403 check(!patch_instructions(addr32 + 1, &inst32, 12, true));
404
405 check(addr32[0] == 0);
406 check(addr32[1] == inst32);
407 check(addr32[2] == inst32);
408 check(addr32[3] == inst32);
409 check(addr32[4] == 0);
410
411 /* Test multipage 64-bit repeated instruction */
412 if (IS_ENABLED(CONFIG_PPC64)) {
413 check(ppc_inst_prefixed(inst64));
414
415 addr64 = buf + PAGE_SIZE * 5 - 8;
416 ppc_inst_write(code, inst64);
417 check(!patch_instructions((u32 *)(addr64 + 1), code, 24, true));
418
419 check(addr64[0] == 0);
420 check(ppc_inst_equal(ppc_inst_read((u32 *)&addr64[1]), inst64));
421 check(ppc_inst_equal(ppc_inst_read((u32 *)&addr64[2]), inst64));
422 check(ppc_inst_equal(ppc_inst_read((u32 *)&addr64[3]), inst64));
423 check(addr64[4] == 0);
424 }
425
426 /* Test multipage memcpy */
427 addr32 = buf + PAGE_SIZE * 6 - 12;
428
429 for (int i = 0; i < ARRAY_SIZE(code); i++)
430 code[i] = i + 1;
431
432 check(!patch_instructions(addr32 + 1, code, sizeof(code), false));
433
434 check(addr32[0] == 0);
435 check(!memcmp(&addr32[1], code, sizeof(code)));
436 check(addr32[ARRAY_SIZE(code) + 1] == 0);
437
438 vfree(buf);
439 }
440
test_data_patching(void)441 static void __init test_data_patching(void)
442 {
443 void *buf;
444 u32 *addr32;
445
446 buf = vzalloc(PAGE_SIZE);
447 check(buf);
448 if (!buf)
449 return;
450
451 addr32 = buf + 128;
452
453 addr32[1] = 0xA0A1A2A3;
454 addr32[2] = 0xB0B1B2B3;
455
456 check(!patch_uint(&addr32[1], 0xC0C1C2C3));
457
458 check(addr32[0] == 0);
459 check(addr32[1] == 0xC0C1C2C3);
460 check(addr32[2] == 0xB0B1B2B3);
461 check(addr32[3] == 0);
462
463 /* Unaligned patch_ulong() should fail */
464 if (IS_ENABLED(CONFIG_PPC64))
465 check(patch_ulong(&addr32[1], 0xD0D1D2D3) == -EINVAL);
466
467 check(!patch_ulong(&addr32[2], 0xD0D1D2D3));
468
469 check(addr32[0] == 0);
470 check(addr32[1] == 0xC0C1C2C3);
471 check(*(unsigned long *)(&addr32[2]) == 0xD0D1D2D3);
472
473 if (!IS_ENABLED(CONFIG_PPC64))
474 check(addr32[3] == 0);
475
476 check(addr32[4] == 0);
477
478 vfree(buf);
479 }
480
test_code_patching(void)481 static int __init test_code_patching(void)
482 {
483 pr_info("Running code patching self-tests ...\n");
484
485 test_branch_iform();
486 test_branch_bform();
487 test_create_function_call();
488 test_translate_branch();
489 test_prefixed_patching();
490 test_multi_instruction_patching();
491 test_data_patching();
492
493 return 0;
494 }
495 late_initcall(test_code_patching);
496