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:
committed by
Michael Ellerman
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)));
|
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)
|
|||||||
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)
|
|||||||
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);
|
|||||||
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,
|
|||||||
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)
|
|||||||
* 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, ®s,
|
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);
|
emulate_update_regs(®s, &op);
|
||||||
nip = regs.nip;
|
nip = regs.nip;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
|||||||
/* 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)
|
|||||||
* 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)
|
|||||||
|
|
||||||
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)
|
|||||||
|
|
||||||
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,
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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,
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user