cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

test-code-patching.c (11085B)


      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
     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 int __init test_code_patching(void)
    351{
    352	pr_info("Running code patching self-tests ...\n");
    353
    354	test_branch_iform();
    355	test_branch_bform();
    356	test_create_function_call();
    357	test_translate_branch();
    358	test_prefixed_patching();
    359
    360	return 0;
    361}
    362late_initcall(test_code_patching);