Commit 309a0a60 authored by Christophe Leroy's avatar Christophe Leroy Committed by Michael Ellerman

powerpc/code-patching: Replace patch_instruction() by ppc_inst_write() 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: default avatarChristophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/7cf5335cc07ca9b6f8cdaa20ca9887fce4df3bea.1638446239.git.christophe.leroy@csgroup.eu
parent f30a578d
...@@ -131,6 +131,14 @@ static inline unsigned long ppc_inst_as_ulong(ppc_inst_t x) ...@@ -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); 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") #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) static inline char *__ppc_inst_as_str(char str[PPC_INST_STR_LEN], ppc_inst_t x)
......
...@@ -54,39 +54,39 @@ static void __init test_branch_iform(void) ...@@ -54,39 +54,39 @@ static void __init test_branch_iform(void)
check(!instr_is_branch_iform(ppc_inst(0x7bfffffd))); check(!instr_is_branch_iform(ppc_inst(0x7bfffffd)));
/* Absolute branch to 0x100 */ /* 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)); check(instr_is_branch_to_addr(iptr, 0x100));
/* Absolute branch to 0x420fc */ /* 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)); check(instr_is_branch_to_addr(iptr, 0x420fc));
/* Maximum positive relative branch, + 20MB - 4B */ /* 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)); check(instr_is_branch_to_addr(iptr, addr + 0x1FFFFFC));
/* Smallest negative relative branch, - 4B */ /* 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)); check(instr_is_branch_to_addr(iptr, addr - 4));
/* Largest negative relative branch, - 32 MB */ /* 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)); check(instr_is_branch_to_addr(iptr, addr - 0x2000000));
/* Branch to self, with link */ /* Branch to self, with link */
err = create_branch(&instr, iptr, addr, BRANCH_SET_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)); check(instr_is_branch_to_addr(iptr, addr));
/* Branch to self - 0x100, with link */ /* Branch to self - 0x100, with link */
err = create_branch(&instr, iptr, addr - 0x100, BRANCH_SET_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)); check(instr_is_branch_to_addr(iptr, addr - 0x100));
/* Branch to self + 0x100, no link */ /* Branch to self + 0x100, no link */
err = create_branch(&instr, iptr, addr + 0x100, 0); 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)); check(instr_is_branch_to_addr(iptr, addr + 0x100));
/* Maximum relative negative offset, - 32 MB */ /* Maximum relative negative offset, - 32 MB */
err = create_branch(&instr, iptr, addr - 0x2000000, BRANCH_SET_LINK); 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)); check(instr_is_branch_to_addr(iptr, addr - 0x2000000));
/* Out of range relative negative offset, - 32 MB + 4*/ /* Out of range relative negative offset, - 32 MB + 4*/
...@@ -103,7 +103,7 @@ static void __init test_branch_iform(void) ...@@ -103,7 +103,7 @@ static void __init test_branch_iform(void)
/* Check flags are masked correctly */ /* Check flags are masked correctly */
err = create_branch(&instr, iptr, addr, 0xFFFFFFFC); 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(instr_is_branch_to_addr(iptr, addr));
check(ppc_inst_equal(instr, ppc_inst(0x48000000))); check(ppc_inst_equal(instr, ppc_inst(0x48000000)));
} }
...@@ -143,19 +143,19 @@ static void __init test_branch_bform(void) ...@@ -143,19 +143,19 @@ static void __init test_branch_bform(void)
check(!instr_is_branch_bform(ppc_inst(0x7bffffff))); check(!instr_is_branch_bform(ppc_inst(0x7bffffff)));
/* Absolute conditional branch to 0x100 */ /* 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)); check(instr_is_branch_to_addr(iptr, 0x100));
/* Absolute conditional branch to 0x20fc */ /* 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)); check(instr_is_branch_to_addr(iptr, 0x20fc));
/* Maximum positive relative conditional branch, + 32 KB - 4B */ /* 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)); check(instr_is_branch_to_addr(iptr, addr + 0x7FFC));
/* Smallest negative relative conditional branch, - 4B */ /* 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)); check(instr_is_branch_to_addr(iptr, addr - 4));
/* Largest negative relative conditional branch, - 32 KB */ /* 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)); check(instr_is_branch_to_addr(iptr, addr - 0x8000));
/* All condition code bits set & link */ /* All condition code bits set & link */
...@@ -163,22 +163,22 @@ static void __init test_branch_bform(void) ...@@ -163,22 +163,22 @@ static void __init test_branch_bform(void)
/* Branch to self */ /* Branch to self */
err = create_cond_branch(&instr, iptr, addr, flags); 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)); check(instr_is_branch_to_addr(iptr, addr));
/* Branch to self - 0x100 */ /* Branch to self - 0x100 */
err = create_cond_branch(&instr, iptr, addr - 0x100, flags); 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)); check(instr_is_branch_to_addr(iptr, addr - 0x100));
/* Branch to self + 0x100 */ /* Branch to self + 0x100 */
err = create_cond_branch(&instr, iptr, addr + 0x100, flags); 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)); check(instr_is_branch_to_addr(iptr, addr + 0x100));
/* Maximum relative negative offset, - 32 KB */ /* Maximum relative negative offset, - 32 KB */
err = create_cond_branch(&instr, iptr, addr - 0x8000, flags); 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)); check(instr_is_branch_to_addr(iptr, addr - 0x8000));
/* Out of range relative negative offset, - 32 KB + 4*/ /* Out of range relative negative offset, - 32 KB + 4*/
...@@ -195,7 +195,7 @@ static void __init test_branch_bform(void) ...@@ -195,7 +195,7 @@ static void __init test_branch_bform(void)
/* Check flags are masked correctly */ /* Check flags are masked correctly */
err = create_cond_branch(&instr, iptr, addr, 0xFFFFFFFC); 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(instr_is_branch_to_addr(iptr, addr));
check(ppc_inst_equal(instr, ppc_inst(0x43FF0000))); check(ppc_inst_equal(instr, ppc_inst(0x43FF0000)));
} }
...@@ -215,20 +215,22 @@ static void __init test_translate_branch(void) ...@@ -215,20 +215,22 @@ static void __init test_translate_branch(void)
/* Simple case, branch to self moved a little */ /* Simple case, branch to self moved a little */
p = buf; p = buf;
addr = (unsigned long)p; 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)); check(instr_is_branch_to_addr(p, addr));
q = p + 4; q = p + 4;
translate_branch(&instr, q, p); translate_branch(&instr, q, p);
patch_instruction(q, instr); ppc_inst_write(q, instr);
check(instr_is_branch_to_addr(q, addr)); check(instr_is_branch_to_addr(q, addr));
/* Maximum negative case, move b . to addr + 32 MB */ /* Maximum negative case, move b . to addr + 32 MB */
p = buf; p = buf;
addr = (unsigned long)p; addr = (unsigned long)p;
patch_branch(p, addr, 0); create_branch(&instr, p, addr, 0);
ppc_inst_write(p, instr);
q = buf + 0x2000000; q = buf + 0x2000000;
translate_branch(&instr, q, p); 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(p, addr));
check(instr_is_branch_to_addr(q, addr)); check(instr_is_branch_to_addr(q, addr));
check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x4a000000))); check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x4a000000)));
...@@ -236,10 +238,11 @@ static void __init test_translate_branch(void) ...@@ -236,10 +238,11 @@ static void __init test_translate_branch(void)
/* Maximum positive case, move x to x - 32 MB + 4 */ /* Maximum positive case, move x to x - 32 MB + 4 */
p = buf + 0x2000000; p = buf + 0x2000000;
addr = (unsigned long)p; addr = (unsigned long)p;
patch_branch(p, addr, 0); create_branch(&instr, p, addr, 0);
ppc_inst_write(p, instr);
q = buf + 4; q = buf + 4;
translate_branch(&instr, q, p); 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(p, addr));
check(instr_is_branch_to_addr(q, addr)); check(instr_is_branch_to_addr(q, addr));
check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x49fffffc))); check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x49fffffc)));
...@@ -247,20 +250,22 @@ static void __init test_translate_branch(void) ...@@ -247,20 +250,22 @@ static void __init test_translate_branch(void)
/* Jump to x + 16 MB moved to x + 20 MB */ /* Jump to x + 16 MB moved to x + 20 MB */
p = buf; p = buf;
addr = 0x1000000 + (unsigned long)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; q = buf + 0x1400000;
translate_branch(&instr, q, p); 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(p, addr));
check(instr_is_branch_to_addr(q, addr)); check(instr_is_branch_to_addr(q, addr));
/* Jump to x + 16 MB moved to x - 16 MB + 4 */ /* Jump to x + 16 MB moved to x - 16 MB + 4 */
p = buf + 0x1000000; p = buf + 0x1000000;
addr = 0x2000000 + (unsigned long)buf; addr = 0x2000000 + (unsigned long)buf;
patch_branch(p, addr, 0); create_branch(&instr, p, addr, 0);
ppc_inst_write(p, instr);
q = buf + 4; q = buf + 4;
translate_branch(&instr, q, p); 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(p, addr));
check(instr_is_branch_to_addr(q, addr)); check(instr_is_branch_to_addr(q, addr));
...@@ -271,21 +276,21 @@ static void __init test_translate_branch(void) ...@@ -271,21 +276,21 @@ static void __init test_translate_branch(void)
p = buf; p = buf;
addr = (unsigned long)p; addr = (unsigned long)p;
create_cond_branch(&instr, p, addr, 0); create_cond_branch(&instr, p, addr, 0);
patch_instruction(p, instr); ppc_inst_write(p, instr);
check(instr_is_branch_to_addr(p, addr)); check(instr_is_branch_to_addr(p, addr));
q = buf + 4; q = buf + 4;
translate_branch(&instr, q, p); translate_branch(&instr, q, p);
patch_instruction(q, instr); ppc_inst_write(q, instr);
check(instr_is_branch_to_addr(q, addr)); check(instr_is_branch_to_addr(q, addr));
/* Maximum negative case, move b . to addr + 32 KB */ /* Maximum negative case, move b . to addr + 32 KB */
p = buf; p = buf;
addr = (unsigned long)p; addr = (unsigned long)p;
create_cond_branch(&instr, p, addr, 0xFFFFFFFC); create_cond_branch(&instr, p, addr, 0xFFFFFFFC);
patch_instruction(p, instr); ppc_inst_write(p, instr);
q = buf + 0x8000; q = buf + 0x8000;
translate_branch(&instr, q, p); 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(p, addr));
check(instr_is_branch_to_addr(q, addr)); check(instr_is_branch_to_addr(q, addr));
check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x43ff8000))); check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x43ff8000)));
...@@ -294,10 +299,10 @@ static void __init test_translate_branch(void) ...@@ -294,10 +299,10 @@ static void __init test_translate_branch(void)
p = buf + 0x8000; p = buf + 0x8000;
addr = (unsigned long)p; addr = (unsigned long)p;
create_cond_branch(&instr, p, addr, 0xFFFFFFFC); create_cond_branch(&instr, p, addr, 0xFFFFFFFC);
patch_instruction(p, instr); ppc_inst_write(p, instr);
q = buf + 4; q = buf + 4;
translate_branch(&instr, q, p); 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(p, addr));
check(instr_is_branch_to_addr(q, addr)); check(instr_is_branch_to_addr(q, addr));
check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x43ff7ffc))); check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x43ff7ffc)));
...@@ -306,10 +311,10 @@ static void __init test_translate_branch(void) ...@@ -306,10 +311,10 @@ static void __init test_translate_branch(void)
p = buf; p = buf;
addr = 0x3000 + (unsigned long)buf; addr = 0x3000 + (unsigned long)buf;
create_cond_branch(&instr, p, addr, BRANCH_SET_LINK); create_cond_branch(&instr, p, addr, BRANCH_SET_LINK);
patch_instruction(p, instr); ppc_inst_write(p, instr);
q = buf + 0x5000; q = buf + 0x5000;
translate_branch(&instr, q, p); 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(p, addr));
check(instr_is_branch_to_addr(q, addr)); check(instr_is_branch_to_addr(q, addr));
...@@ -317,10 +322,10 @@ static void __init test_translate_branch(void) ...@@ -317,10 +322,10 @@ static void __init test_translate_branch(void)
p = buf + 0x2000; p = buf + 0x2000;
addr = 0x4000 + (unsigned long)buf; addr = 0x4000 + (unsigned long)buf;
create_cond_branch(&instr, p, addr, 0); create_cond_branch(&instr, p, addr, 0);
patch_instruction(p, instr); ppc_inst_write(p, instr);
q = buf + 4; q = buf + 4;
translate_branch(&instr, q, p); 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(p, addr));
check(instr_is_branch_to_addr(q, addr)); check(instr_is_branch_to_addr(q, addr));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment