mirror of https://gitee.com/openkylin/linux.git
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: Jordan Niethe <jniethe5@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Reviewed-by: Alistair Popple <alistair@popple.id.au> Link: https://lore.kernel.org/r/20200506034050.24806-13-jniethe5@gmail.com
This commit is contained in:
parent
94afd069d9
commit
f8faaffaa7
|
@ -27,6 +27,11 @@ static inline struct ppc_inst ppc_inst_swab(struct ppc_inst 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)
|
||||
{
|
||||
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)
|
|||
int arch_prepare_kprobe(struct kprobe *p)
|
||||
{
|
||||
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) {
|
||||
printk("Attempt to register kprobe at an unaligned address\n");
|
||||
|
@ -127,7 +127,7 @@ int arch_prepare_kprobe(struct kprobe *p)
|
|||
if (!ret) {
|
||||
memcpy(p->ainsn.insn, p->addr,
|
||||
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,
|
||||
(unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t));
|
||||
}
|
||||
|
@ -217,7 +217,7 @@ NOKPROBE_SYMBOL(arch_prepare_kretprobe);
|
|||
static int try_to_emulate(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
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 */
|
||||
ret = emulate_step(regs, insn);
|
||||
|
|
|
@ -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);
|
||||
if (pfn != ULONG_MAX) {
|
||||
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)) {
|
||||
pfn = addr_to_pfn(regs, op.ea);
|
||||
*addr = op.ea;
|
||||
|
|
|
@ -100,9 +100,9 @@ static unsigned long can_optimize(struct kprobe *p)
|
|||
* Ensure that the instruction is not a conditional branch,
|
||||
* 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, ®s,
|
||||
*(struct ppc_inst *)p->ainsn.insn) == 1) {
|
||||
ppc_inst_read((struct ppc_inst *)p->ainsn.insn)) == 1) {
|
||||
emulate_update_regs(®s, &op);
|
||||
nip = regs.nip;
|
||||
}
|
||||
|
|
|
@ -848,7 +848,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
|
|||
struct ppc_inst old, new;
|
||||
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);
|
||||
ret = ftrace_modify_code(ip, old, new);
|
||||
|
||||
|
@ -856,7 +856,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
|
|||
/* Also update the regs callback function */
|
||||
if (!ret) {
|
||||
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);
|
||||
ret = ftrace_modify_code(ip, old, new);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
* 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)
|
||||
return true;
|
||||
|
||||
|
|
|
@ -348,9 +348,9 @@ static unsigned long branch_bform_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);
|
||||
else if (instr_is_branch_bform(*instr))
|
||||
else if (instr_is_branch_bform(ppc_inst_read(instr)))
|
||||
return branch_bform_target(instr);
|
||||
|
||||
return 0;
|
||||
|
@ -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)
|
||||
{
|
||||
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 0;
|
||||
|
@ -368,13 +369,14 @@ int translate_branch(struct ppc_inst *instr, const struct ppc_inst *dest,
|
|||
const struct ppc_inst *src)
|
||||
{
|
||||
unsigned long target;
|
||||
|
||||
target = branch_target(src);
|
||||
|
||||
if (instr_is_branch_iform(*src))
|
||||
return create_branch(instr, dest, target, ppc_inst_val(*src));
|
||||
else if (instr_is_branch_bform(*src))
|
||||
return create_cond_branch(instr, dest, target, ppc_inst_val(*src));
|
||||
if (instr_is_branch_iform(ppc_inst_read(src)))
|
||||
return create_branch(instr, dest, target,
|
||||
ppc_inst_val(ppc_inst_read(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;
|
||||
}
|
||||
|
@ -598,7 +600,7 @@ static void __init test_translate_branch(void)
|
|||
patch_instruction(q, instr);
|
||||
check(instr_is_branch_to_addr(p, 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 */
|
||||
p = buf + 0x2000000;
|
||||
|
@ -609,7 +611,7 @@ static void __init test_translate_branch(void)
|
|||
patch_instruction(q, instr);
|
||||
check(instr_is_branch_to_addr(p, 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 */
|
||||
p = buf;
|
||||
|
@ -655,7 +657,7 @@ static void __init test_translate_branch(void)
|
|||
patch_instruction(q, instr);
|
||||
check(instr_is_branch_to_addr(p, 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 */
|
||||
p = buf + 0x8000;
|
||||
|
@ -667,7 +669,7 @@ static void __init test_translate_branch(void)
|
|||
patch_instruction(q, instr);
|
||||
check(instr_is_branch_to_addr(p, 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 */
|
||||
p = buf;
|
||||
|
|
|
@ -48,7 +48,7 @@ static int patch_alt_instruction(struct ppc_inst *src, struct ppc_inst *dest,
|
|||
int err;
|
||||
struct ppc_inst instr;
|
||||
|
||||
instr = *src;
|
||||
instr = ppc_inst_read(src);
|
||||
|
||||
if (instr_is_relative_branch(*src)) {
|
||||
struct ppc_inst *target = (struct ppc_inst *)branch_target(src);
|
||||
|
@ -403,7 +403,7 @@ static void do_final_fixups(void)
|
|||
length = (__end_interrupts - _stext) / sizeof(struct ppc_inst);
|
||||
|
||||
while (length--) {
|
||||
raw_patch_instruction(dest, *src);
|
||||
raw_patch_instruction(dest, ppc_inst_read(src));
|
||||
src++;
|
||||
dest++;
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
bp = at_breakpoint(regs->nip);
|
||||
if (bp != NULL) {
|
||||
int stepped = emulate_step(regs, bp->instr[0]);
|
||||
int stepped = emulate_step(regs, ppc_inst_read(bp->instr));
|
||||
if (stepped == 0) {
|
||||
regs->nip = (unsigned long) &bp->instr[0];
|
||||
atomic_inc(&bp->ref_count);
|
||||
} else if (stepped < 0) {
|
||||
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)
|
|||
if (mread(bp->address, &instr, 4) == 4
|
||||
&& ppc_inst_equal(instr, ppc_inst(bpinstr))
|
||||
&& 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",
|
||||
bp->address);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue