Commit f8faaffa authored by Jordan Niethe's avatar Jordan Niethe Committed by Michael Ellerman

powerpc: Use a function for reading instructions

Prefixed instructions will mean there are instructions of different
length. As a result dereferencing a pointer to an instruction will not
necessarily give the desired result. Introduce a function for reading
instructions from memory into the instruction data type.
Signed-off-by: default avatarJordan Niethe <jniethe5@gmail.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Reviewed-by: default avatarAlistair Popple <alistair@popple.id.au>
Link: https://lore.kernel.org/r/20200506034050.24806-13-jniethe5@gmail.com
parent 94afd069
...@@ -27,6 +27,11 @@ static inline struct ppc_inst ppc_inst_swab(struct ppc_inst x) ...@@ -27,6 +27,11 @@ static inline struct ppc_inst ppc_inst_swab(struct ppc_inst x)
return ppc_inst(swab32(ppc_inst_val(x))); return ppc_inst(swab32(ppc_inst_val(x)));
} }
static inline struct ppc_inst ppc_inst_read(const struct ppc_inst *ptr)
{
return *ptr;
}
static inline bool ppc_inst_equal(struct ppc_inst x, struct ppc_inst y) static inline bool ppc_inst_equal(struct ppc_inst x, struct ppc_inst y)
{ {
return ppc_inst_val(x) == ppc_inst_val(y); return ppc_inst_val(x) == ppc_inst_val(y);
......
...@@ -106,7 +106,7 @@ kprobe_opcode_t *kprobe_lookup_name(const char *name, unsigned int offset) ...@@ -106,7 +106,7 @@ kprobe_opcode_t *kprobe_lookup_name(const char *name, unsigned int offset)
int arch_prepare_kprobe(struct kprobe *p) int arch_prepare_kprobe(struct kprobe *p)
{ {
int ret = 0; int ret = 0;
struct ppc_inst insn = *(struct ppc_inst *)p->addr; struct ppc_inst insn = ppc_inst_read((struct ppc_inst *)p->addr);
if ((unsigned long)p->addr & 0x03) { if ((unsigned long)p->addr & 0x03) {
printk("Attempt to register kprobe at an unaligned address\n"); printk("Attempt to register kprobe at an unaligned address\n");
...@@ -127,7 +127,7 @@ int arch_prepare_kprobe(struct kprobe *p) ...@@ -127,7 +127,7 @@ int arch_prepare_kprobe(struct kprobe *p)
if (!ret) { if (!ret) {
memcpy(p->ainsn.insn, p->addr, memcpy(p->ainsn.insn, p->addr,
MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
p->opcode = *p->addr; p->opcode = ppc_inst_val(insn);
flush_icache_range((unsigned long)p->ainsn.insn, flush_icache_range((unsigned long)p->ainsn.insn,
(unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t)); (unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t));
} }
...@@ -217,7 +217,7 @@ NOKPROBE_SYMBOL(arch_prepare_kretprobe); ...@@ -217,7 +217,7 @@ NOKPROBE_SYMBOL(arch_prepare_kretprobe);
static int try_to_emulate(struct kprobe *p, struct pt_regs *regs) static int try_to_emulate(struct kprobe *p, struct pt_regs *regs)
{ {
int ret; int ret;
struct ppc_inst insn = *(struct ppc_inst *)p->ainsn.insn; struct ppc_inst insn = ppc_inst_read((struct ppc_inst *)p->ainsn.insn);
/* regs->nip is also adjusted if emulate_step returns 1 */ /* regs->nip is also adjusted if emulate_step returns 1 */
ret = emulate_step(regs, insn); ret = emulate_step(regs, insn);
......
...@@ -378,7 +378,7 @@ static int mce_find_instr_ea_and_phys(struct pt_regs *regs, uint64_t *addr, ...@@ -378,7 +378,7 @@ static int mce_find_instr_ea_and_phys(struct pt_regs *regs, uint64_t *addr,
pfn = addr_to_pfn(regs, regs->nip); pfn = addr_to_pfn(regs, regs->nip);
if (pfn != ULONG_MAX) { if (pfn != ULONG_MAX) {
instr_addr = (pfn << PAGE_SHIFT) + (regs->nip & ~PAGE_MASK); instr_addr = (pfn << PAGE_SHIFT) + (regs->nip & ~PAGE_MASK);
instr = *(struct ppc_inst *)(instr_addr); instr = ppc_inst_read((struct ppc_inst *)instr_addr);
if (!analyse_instr(&op, &tmp, instr)) { if (!analyse_instr(&op, &tmp, instr)) {
pfn = addr_to_pfn(regs, op.ea); pfn = addr_to_pfn(regs, op.ea);
*addr = op.ea; *addr = op.ea;
......
...@@ -100,9 +100,9 @@ static unsigned long can_optimize(struct kprobe *p) ...@@ -100,9 +100,9 @@ static unsigned long can_optimize(struct kprobe *p)
* Ensure that the instruction is not a conditional branch, * Ensure that the instruction is not a conditional branch,
* and that can be emulated. * and that can be emulated.
*/ */
if (!is_conditional_branch(*(struct ppc_inst *)p->ainsn.insn) && if (!is_conditional_branch(ppc_inst_read((struct ppc_inst *)p->ainsn.insn)) &&
analyse_instr(&op, &regs, analyse_instr(&op, &regs,
*(struct ppc_inst *)p->ainsn.insn) == 1) { ppc_inst_read((struct ppc_inst *)p->ainsn.insn)) == 1) {
emulate_update_regs(&regs, &op); emulate_update_regs(&regs, &op);
nip = regs.nip; nip = regs.nip;
} }
......
...@@ -848,7 +848,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func) ...@@ -848,7 +848,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
struct ppc_inst old, new; struct ppc_inst old, new;
int ret; int ret;
old = *(struct ppc_inst *)&ftrace_call; old = ppc_inst_read((struct ppc_inst *)&ftrace_call);
new = ftrace_call_replace(ip, (unsigned long)func, 1); new = ftrace_call_replace(ip, (unsigned long)func, 1);
ret = ftrace_modify_code(ip, old, new); ret = ftrace_modify_code(ip, old, new);
...@@ -856,7 +856,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func) ...@@ -856,7 +856,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
/* Also update the regs callback function */ /* Also update the regs callback function */
if (!ret) { if (!ret) {
ip = (unsigned long)(&ftrace_regs_call); ip = (unsigned long)(&ftrace_regs_call);
old = *(struct ppc_inst *)&ftrace_regs_call; old = ppc_inst_read((struct ppc_inst *)&ftrace_regs_call);
new = ftrace_call_replace(ip, (unsigned long)func, 1); new = ftrace_call_replace(ip, (unsigned long)func, 1);
ret = ftrace_modify_code(ip, old, new); ret = ftrace_modify_code(ip, old, new);
} }
......
...@@ -174,7 +174,7 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) ...@@ -174,7 +174,7 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
* emulate_step() returns 1 if the insn was successfully emulated. * emulate_step() returns 1 if the insn was successfully emulated.
* For all other cases, we need to single-step in hardware. * For all other cases, we need to single-step in hardware.
*/ */
ret = emulate_step(regs, auprobe->insn); ret = emulate_step(regs, ppc_inst_read(&auprobe->insn));
if (ret > 0) if (ret > 0)
return true; return true;
......
...@@ -348,9 +348,9 @@ static unsigned long branch_bform_target(const struct ppc_inst *instr) ...@@ -348,9 +348,9 @@ static unsigned long branch_bform_target(const struct ppc_inst *instr)
unsigned long branch_target(const struct ppc_inst *instr) unsigned long branch_target(const struct ppc_inst *instr)
{ {
if (instr_is_branch_iform(*instr)) if (instr_is_branch_iform(ppc_inst_read(instr)))
return branch_iform_target(instr); return branch_iform_target(instr);
else if (instr_is_branch_bform(*instr)) else if (instr_is_branch_bform(ppc_inst_read(instr)))
return branch_bform_target(instr); return branch_bform_target(instr);
return 0; return 0;
...@@ -358,7 +358,8 @@ unsigned long branch_target(const struct ppc_inst *instr) ...@@ -358,7 +358,8 @@ unsigned long branch_target(const struct ppc_inst *instr)
int instr_is_branch_to_addr(const struct ppc_inst *instr, unsigned long addr) int instr_is_branch_to_addr(const struct ppc_inst *instr, unsigned long addr)
{ {
if (instr_is_branch_iform(*instr) || instr_is_branch_bform(*instr)) if (instr_is_branch_iform(ppc_inst_read(instr)) ||
instr_is_branch_bform(ppc_inst_read(instr)))
return branch_target(instr) == addr; return branch_target(instr) == addr;
return 0; return 0;
...@@ -368,13 +369,14 @@ int translate_branch(struct ppc_inst *instr, const struct ppc_inst *dest, ...@@ -368,13 +369,14 @@ int translate_branch(struct ppc_inst *instr, const struct ppc_inst *dest,
const struct ppc_inst *src) const struct ppc_inst *src)
{ {
unsigned long target; unsigned long target;
target = branch_target(src); target = branch_target(src);
if (instr_is_branch_iform(*src)) if (instr_is_branch_iform(ppc_inst_read(src)))
return create_branch(instr, dest, target, ppc_inst_val(*src)); return create_branch(instr, dest, target,
else if (instr_is_branch_bform(*src)) ppc_inst_val(ppc_inst_read(src)));
return create_cond_branch(instr, dest, target, ppc_inst_val(*src)); else if (instr_is_branch_bform(ppc_inst_read(src)))
return create_cond_branch(instr, dest, target,
ppc_inst_val(ppc_inst_read(src)));
return 1; return 1;
} }
...@@ -598,7 +600,7 @@ static void __init test_translate_branch(void) ...@@ -598,7 +600,7 @@ static void __init test_translate_branch(void)
patch_instruction(q, instr); patch_instruction(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(*q, ppc_inst(0x4a000000))); check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x4a000000)));
/* 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;
...@@ -609,7 +611,7 @@ static void __init test_translate_branch(void) ...@@ -609,7 +611,7 @@ static void __init test_translate_branch(void)
patch_instruction(q, instr); patch_instruction(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(*q, ppc_inst(0x49fffffc))); check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x49fffffc)));
/* Jump to x + 16 MB moved to x + 20 MB */ /* Jump to x + 16 MB moved to x + 20 MB */
p = buf; p = buf;
...@@ -655,7 +657,7 @@ static void __init test_translate_branch(void) ...@@ -655,7 +657,7 @@ static void __init test_translate_branch(void)
patch_instruction(q, instr); patch_instruction(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(*q, ppc_inst(0x43ff8000))); check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x43ff8000)));
/* Maximum positive case, move x to x - 32 KB + 4 */ /* Maximum positive case, move x to x - 32 KB + 4 */
p = buf + 0x8000; p = buf + 0x8000;
...@@ -667,7 +669,7 @@ static void __init test_translate_branch(void) ...@@ -667,7 +669,7 @@ static void __init test_translate_branch(void)
patch_instruction(q, instr); patch_instruction(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(*q, ppc_inst(0x43ff7ffc))); check(ppc_inst_equal(ppc_inst_read(q), ppc_inst(0x43ff7ffc)));
/* Jump to x + 12 KB moved to x + 20 KB */ /* Jump to x + 12 KB moved to x + 20 KB */
p = buf; p = buf;
......
...@@ -48,7 +48,7 @@ static int patch_alt_instruction(struct ppc_inst *src, struct ppc_inst *dest, ...@@ -48,7 +48,7 @@ static int patch_alt_instruction(struct ppc_inst *src, struct ppc_inst *dest,
int err; int err;
struct ppc_inst instr; struct ppc_inst instr;
instr = *src; instr = ppc_inst_read(src);
if (instr_is_relative_branch(*src)) { if (instr_is_relative_branch(*src)) {
struct ppc_inst *target = (struct ppc_inst *)branch_target(src); struct ppc_inst *target = (struct ppc_inst *)branch_target(src);
...@@ -403,7 +403,7 @@ static void do_final_fixups(void) ...@@ -403,7 +403,7 @@ static void do_final_fixups(void)
length = (__end_interrupts - _stext) / sizeof(struct ppc_inst); length = (__end_interrupts - _stext) / sizeof(struct ppc_inst);
while (length--) { while (length--) {
raw_patch_instruction(dest, *src); raw_patch_instruction(dest, ppc_inst_read(src));
src++; src++;
dest++; dest++;
} }
......
...@@ -702,13 +702,13 @@ static int xmon_core(struct pt_regs *regs, int fromipi) ...@@ -702,13 +702,13 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) { if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
bp = at_breakpoint(regs->nip); bp = at_breakpoint(regs->nip);
if (bp != NULL) { if (bp != NULL) {
int stepped = emulate_step(regs, bp->instr[0]); int stepped = emulate_step(regs, ppc_inst_read(bp->instr));
if (stepped == 0) { if (stepped == 0) {
regs->nip = (unsigned long) &bp->instr[0]; regs->nip = (unsigned long) &bp->instr[0];
atomic_inc(&bp->ref_count); atomic_inc(&bp->ref_count);
} else if (stepped < 0) { } else if (stepped < 0) {
printf("Couldn't single-step %s instruction\n", printf("Couldn't single-step %s instruction\n",
(IS_RFID(bp->instr[0])? "rfid": "mtmsrd")); IS_RFID(ppc_inst_read(bp->instr))? "rfid": "mtmsrd");
} }
} }
} }
...@@ -949,7 +949,7 @@ static void remove_bpts(void) ...@@ -949,7 +949,7 @@ static void remove_bpts(void)
if (mread(bp->address, &instr, 4) == 4 if (mread(bp->address, &instr, 4) == 4
&& ppc_inst_equal(instr, ppc_inst(bpinstr)) && ppc_inst_equal(instr, ppc_inst(bpinstr))
&& patch_instruction( && patch_instruction(
(struct ppc_inst *)bp->address, bp->instr[0]) != 0) (struct ppc_inst *)bp->address, ppc_inst_read(bp->instr)) != 0)
printf("Couldn't remove breakpoint at %lx\n", printf("Couldn't remove breakpoint at %lx\n",
bp->address); bp->address);
} }
......
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