Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.17.
  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/text-patching.h>
 10
 11static 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
 20static 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
 30static 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
111static 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
125static 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
203static 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
336static 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
350static 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
441static 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
481static 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}
495late_initcall(test_code_patching);