Skip to content

Commit

Permalink
powerpc/code-patching: Replace patch_instruction() by ppc_inst_write(…
Browse files Browse the repository at this point in the history
…) in selftests

The purpose of selftests is to check that instructions are
properly formed. Not to check that they properly run.

For that test it uses normal memory, not special test
memory.

In preparation of a future patch enforcing patch_instruction()
to be used only on valid text areas, implement a ppc_inst_write()
instruction which is the complement of ppc_inst_read(). This
new function writes the formated instruction in valid kernel
memory and doesn't bother about icache.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/7cf5335cc07ca9b6f8cdaa20ca9887fce4df3bea.1638446239.git.christophe.leroy@csgroup.eu
  • Loading branch information
Christophe Leroy authored and Michael Ellerman committed Dec 23, 2021
1 parent f30a578 commit 309a0a6
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 40 deletions.
8 changes: 8 additions & 0 deletions arch/powerpc/include/asm/inst.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,14 @@ static inline unsigned long ppc_inst_as_ulong(ppc_inst_t x)
return (u64)ppc_inst_val(x) << 32 | ppc_inst_suffix(x);
}

static inline void ppc_inst_write(u32 *ptr, ppc_inst_t x)
{
if (!ppc_inst_prefixed(x))
*ptr = ppc_inst_val(x);
else
*(u64 *)ptr = ppc_inst_as_ulong(x);
}

#define PPC_INST_STR_LEN sizeof("00000000 00000000")

static inline char *__ppc_inst_as_str(char str[PPC_INST_STR_LEN], ppc_inst_t x)
Expand Down
85 changes: 45 additions & 40 deletions arch/powerpc/lib/test-code-patching.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,39 +54,39 @@ static void __init test_branch_iform(void)
check(!instr_is_branch_iform(ppc_inst(0x7bfffffd)));

/* Absolute branch to 0x100 */
patch_instruction(iptr, ppc_inst(0x48000103));
ppc_inst_write(iptr, ppc_inst(0x48000103));
check(instr_is_branch_to_addr(iptr, 0x100));
/* Absolute branch to 0x420fc */
patch_instruction(iptr, ppc_inst(0x480420ff));
ppc_inst_write(iptr, ppc_inst(0x480420ff));
check(instr_is_branch_to_addr(iptr, 0x420fc));
/* Maximum positive relative branch, + 20MB - 4B */
patch_instruction(iptr, ppc_inst(0x49fffffc));
ppc_inst_write(iptr, ppc_inst(0x49fffffc));
check(instr_is_branch_to_addr(iptr, addr + 0x1FFFFFC));
/* Smallest negative relative branch, - 4B */
patch_instruction(iptr, ppc_inst(0x4bfffffc));
ppc_inst_write(iptr, ppc_inst(0x4bfffffc));
check(instr_is_branch_to_addr(iptr, addr - 4));
/* Largest negative relative branch, - 32 MB */
patch_instruction(iptr, ppc_inst(0x4a000000));
ppc_inst_write(iptr, ppc_inst(0x4a000000));
check(instr_is_branch_to_addr(iptr, addr - 0x2000000));

/* Branch to self, with link */
err = create_branch(&instr, iptr, addr, BRANCH_SET_LINK);
patch_instruction(iptr, instr);
ppc_inst_write(iptr, instr);
check(instr_is_branch_to_addr(iptr, addr));

/* Branch to self - 0x100, with link */
err = create_branch(&instr, iptr, addr - 0x100, BRANCH_SET_LINK);
patch_instruction(iptr, instr);
ppc_inst_write(iptr, instr);
check(instr_is_branch_to_addr(iptr, addr - 0x100));

/* Branch to self + 0x100, no link */
err = create_branch(&instr, iptr, addr + 0x100, 0);
patch_instruction(iptr, instr);
ppc_inst_write(iptr, instr);
check(instr_is_branch_to_addr(iptr, addr + 0x100));

/* Maximum relative negative offset, - 32 MB */
err = create_branch(&instr, iptr, addr - 0x2000000, BRANCH_SET_LINK);
patch_instruction(iptr, instr);
ppc_inst_write(iptr, instr);
check(instr_is_branch_to_addr(iptr, addr - 0x2000000));

/* Out of range relative negative offset, - 32 MB + 4*/
Expand All @@ -103,7 +103,7 @@ static void __init test_branch_iform(void)

/* Check flags are masked correctly */
err = create_branch(&instr, iptr, addr, 0xFFFFFFFC);
patch_instruction(iptr, instr);
ppc_inst_write(iptr, instr);
check(instr_is_branch_to_addr(iptr, addr));
check(ppc_inst_equal(instr, ppc_inst(0x48000000)));
}
Expand Down Expand Up @@ -143,42 +143,42 @@ static void __init test_branch_bform(void)
check(!instr_is_branch_bform(ppc_inst(0x7bffffff)));

/* Absolute conditional branch to 0x100 */
patch_instruction(iptr, ppc_inst(0x43ff0103));
ppc_inst_write(iptr, ppc_inst(0x43ff0103));
check(instr_is_branch_to_addr(iptr, 0x100));
/* Absolute conditional branch to 0x20fc */
patch_instruction(iptr, ppc_inst(0x43ff20ff));
ppc_inst_write(iptr, ppc_inst(0x43ff20ff));
check(instr_is_branch_to_addr(iptr, 0x20fc));
/* Maximum positive relative conditional branch, + 32 KB - 4B */
patch_instruction(iptr, ppc_inst(0x43ff7ffc));
ppc_inst_write(iptr, ppc_inst(0x43ff7ffc));
check(instr_is_branch_to_addr(iptr, addr + 0x7FFC));
/* Smallest negative relative conditional branch, - 4B */
patch_instruction(iptr, ppc_inst(0x43fffffc));
ppc_inst_write(iptr, ppc_inst(0x43fffffc));
check(instr_is_branch_to_addr(iptr, addr - 4));
/* Largest negative relative conditional branch, - 32 KB */
patch_instruction(iptr, ppc_inst(0x43ff8000));
ppc_inst_write(iptr, ppc_inst(0x43ff8000));
check(instr_is_branch_to_addr(iptr, addr - 0x8000));

/* All condition code bits set & link */
flags = 0x3ff000 | BRANCH_SET_LINK;

/* Branch to self */
err = create_cond_branch(&instr, iptr, addr, flags);
patch_instruction(iptr, instr);
ppc_inst_write(iptr, instr);
check(instr_is_branch_to_addr(iptr, addr));

/* Branch to self - 0x100 */
err = create_cond_branch(&instr, iptr, addr - 0x100, flags);
patch_instruction(iptr, instr);
ppc_inst_write(iptr, instr);
check(instr_is_branch_to_addr(iptr, addr - 0x100));

/* Branch to self + 0x100 */
err = create_cond_branch(&instr, iptr, addr + 0x100, flags);
patch_instruction(iptr, instr);
ppc_inst_write(iptr, instr);
check(instr_is_branch_to_addr(iptr, addr + 0x100));

/* Maximum relative negative offset, - 32 KB */
err = create_cond_branch(&instr, iptr, addr - 0x8000, flags);
patch_instruction(iptr, instr);
ppc_inst_write(iptr, instr);
check(instr_is_branch_to_addr(iptr, addr - 0x8000));

/* Out of range relative negative offset, - 32 KB + 4*/
Expand All @@ -195,7 +195,7 @@ static void __init test_branch_bform(void)

/* Check flags are masked correctly */
err = create_cond_branch(&instr, iptr, addr, 0xFFFFFFFC);
patch_instruction(iptr, instr);
ppc_inst_write(iptr, instr);
check(instr_is_branch_to_addr(iptr, addr));
check(ppc_inst_equal(instr, ppc_inst(0x43FF0000)));
}
Expand All @@ -215,52 +215,57 @@ static void __init test_translate_branch(void)
/* Simple case, branch to self moved a little */
p = buf;
addr = (unsigned long)p;
patch_branch(p, addr, 0);
create_branch(&instr, p, addr, 0);
ppc_inst_write(p, instr);
check(instr_is_branch_to_addr(p, addr));
q = p + 4;
translate_branch(&instr, q, p);
patch_instruction(q, instr);
ppc_inst_write(q, instr);
check(instr_is_branch_to_addr(q, addr));

/* Maximum negative case, move b . to addr + 32 MB */
p = buf;
addr = (unsigned long)p;
patch_branch(p, addr, 0);
create_branch(&instr, p, addr, 0);
ppc_inst_write(p, instr);
q = buf + 0x2000000;
translate_branch(&instr, q, p);
patch_instruction(q, instr);
ppc_inst_write(q, instr);
check(instr_is_branch_to_addr(p, addr));
check(instr_is_branch_to_addr(q, addr));
check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x4a000000)));

/* Maximum positive case, move x to x - 32 MB + 4 */
p = buf + 0x2000000;
addr = (unsigned long)p;
patch_branch(p, addr, 0);
create_branch(&instr, p, addr, 0);
ppc_inst_write(p, instr);
q = buf + 4;
translate_branch(&instr, q, p);
patch_instruction(q, instr);
ppc_inst_write(q, instr);
check(instr_is_branch_to_addr(p, addr));
check(instr_is_branch_to_addr(q, addr));
check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x49fffffc)));

/* Jump to x + 16 MB moved to x + 20 MB */
p = buf;
addr = 0x1000000 + (unsigned long)buf;
patch_branch(p, addr, BRANCH_SET_LINK);
create_branch(&instr, p, addr, BRANCH_SET_LINK);
ppc_inst_write(p, instr);
q = buf + 0x1400000;
translate_branch(&instr, q, p);
patch_instruction(q, instr);
ppc_inst_write(q, instr);
check(instr_is_branch_to_addr(p, addr));
check(instr_is_branch_to_addr(q, addr));

/* Jump to x + 16 MB moved to x - 16 MB + 4 */
p = buf + 0x1000000;
addr = 0x2000000 + (unsigned long)buf;
patch_branch(p, addr, 0);
create_branch(&instr, p, addr, 0);
ppc_inst_write(p, instr);
q = buf + 4;
translate_branch(&instr, q, p);
patch_instruction(q, instr);
ppc_inst_write(q, instr);
check(instr_is_branch_to_addr(p, addr));
check(instr_is_branch_to_addr(q, addr));

Expand All @@ -271,21 +276,21 @@ static void __init test_translate_branch(void)
p = buf;
addr = (unsigned long)p;
create_cond_branch(&instr, p, addr, 0);
patch_instruction(p, instr);
ppc_inst_write(p, instr);
check(instr_is_branch_to_addr(p, addr));
q = buf + 4;
translate_branch(&instr, q, p);
patch_instruction(q, instr);
ppc_inst_write(q, instr);
check(instr_is_branch_to_addr(q, addr));

/* Maximum negative case, move b . to addr + 32 KB */
p = buf;
addr = (unsigned long)p;
create_cond_branch(&instr, p, addr, 0xFFFFFFFC);
patch_instruction(p, instr);
ppc_inst_write(p, instr);
q = buf + 0x8000;
translate_branch(&instr, q, p);
patch_instruction(q, instr);
ppc_inst_write(q, instr);
check(instr_is_branch_to_addr(p, addr));
check(instr_is_branch_to_addr(q, addr));
check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x43ff8000)));
Expand All @@ -294,10 +299,10 @@ static void __init test_translate_branch(void)
p = buf + 0x8000;
addr = (unsigned long)p;
create_cond_branch(&instr, p, addr, 0xFFFFFFFC);
patch_instruction(p, instr);
ppc_inst_write(p, instr);
q = buf + 4;
translate_branch(&instr, q, p);
patch_instruction(q, instr);
ppc_inst_write(q, instr);
check(instr_is_branch_to_addr(p, addr));
check(instr_is_branch_to_addr(q, addr));
check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x43ff7ffc)));
Expand All @@ -306,21 +311,21 @@ static void __init test_translate_branch(void)
p = buf;
addr = 0x3000 + (unsigned long)buf;
create_cond_branch(&instr, p, addr, BRANCH_SET_LINK);
patch_instruction(p, instr);
ppc_inst_write(p, instr);
q = buf + 0x5000;
translate_branch(&instr, q, p);
patch_instruction(q, instr);
ppc_inst_write(q, instr);
check(instr_is_branch_to_addr(p, addr));
check(instr_is_branch_to_addr(q, addr));

/* Jump to x + 8 KB moved to x - 8 KB + 4 */
p = buf + 0x2000;
addr = 0x4000 + (unsigned long)buf;
create_cond_branch(&instr, p, addr, 0);
patch_instruction(p, instr);
ppc_inst_write(p, instr);
q = buf + 4;
translate_branch(&instr, q, p);
patch_instruction(q, instr);
ppc_inst_write(q, instr);
check(instr_is_branch_to_addr(p, addr));
check(instr_is_branch_to_addr(q, addr));

Expand Down

0 comments on commit 309a0a6

Please sign in to comment.