#define BRANCH_ABSOLUTE 0x2
bool is_offset_in_branch_range(long offset);
-int create_branch(unsigned int *instr, const unsigned int *addr,
+int create_branch(struct ppc_inst *instr, const struct ppc_inst *addr,
unsigned long target, int flags);
-int create_cond_branch(unsigned int *instr, const unsigned int *addr,
+int create_cond_branch(struct ppc_inst *instr, const struct ppc_inst *addr,
unsigned long target, int flags);
-int patch_branch(unsigned int *addr, unsigned long target, int flags);
-int patch_instruction(unsigned int *addr, unsigned int instr);
-int raw_patch_instruction(unsigned int *addr, unsigned int instr);
+int patch_branch(struct ppc_inst *addr, unsigned long target, int flags);
+int patch_instruction(struct ppc_inst *addr, struct ppc_inst instr);
+int raw_patch_instruction(struct ppc_inst *addr, struct ppc_inst instr);
static inline unsigned long patch_site_addr(s32 *site)
{
return (unsigned long)site + *site;
}
-static inline int patch_instruction_site(s32 *site, unsigned int instr)
+static inline int patch_instruction_site(s32 *site, struct ppc_inst instr)
{
- return patch_instruction((unsigned int *)patch_site_addr(site), instr);
+ return patch_instruction((struct ppc_inst *)patch_site_addr(site), instr);
}
static inline int patch_branch_site(s32 *site, unsigned long target, int flags)
{
- return patch_branch((unsigned int *)patch_site_addr(site), target, flags);
+ return patch_branch((struct ppc_inst *)patch_site_addr(site), target, flags);
}
static inline int modify_instruction(unsigned int *addr, unsigned int clr,
unsigned int set)
{
- return patch_instruction(addr, ppc_inst((*addr & ~clr) | set));
+ return patch_instruction((struct ppc_inst *)addr, ppc_inst((*addr & ~clr) | set));
}
static inline int modify_instruction_site(s32 *site, unsigned int clr, unsigned int set)
return modify_instruction((unsigned int *)patch_site_addr(site), clr, set);
}
-int instr_is_relative_branch(unsigned int instr);
-int instr_is_relative_link_branch(unsigned int instr);
-int instr_is_branch_to_addr(const unsigned int *instr, unsigned long addr);
-unsigned long branch_target(const unsigned int *instr);
-int translate_branch(unsigned int *instr, const unsigned int *dest,
- const unsigned int *src);
-extern bool is_conditional_branch(unsigned int instr);
+int instr_is_relative_branch(struct ppc_inst instr);
+int instr_is_relative_link_branch(struct ppc_inst instr);
+int instr_is_branch_to_addr(const struct ppc_inst *instr, unsigned long addr);
+unsigned long branch_target(const struct ppc_inst *instr);
+int translate_branch(struct ppc_inst *instr, const struct ppc_inst *dest,
+ const struct ppc_inst *src);
+extern bool is_conditional_branch(struct ppc_inst instr);
#ifdef CONFIG_PPC_BOOK3E_64
void __patch_exception(int exc, unsigned long addr);
#define patch_exception(exc, name) do { \
* Instruction data type for POWER
*/
-#define ppc_inst(x) (x)
+struct ppc_inst {
+ u32 val;
+} __packed;
-static inline u32 ppc_inst_val(u32 x)
+#define ppc_inst(x) ((struct ppc_inst){ .val = x })
+
+static inline u32 ppc_inst_val(struct ppc_inst x)
{
- return x;
+ return x.val;
}
-static inline int ppc_inst_primary_opcode(u32 x)
+static inline int ppc_inst_primary_opcode(struct ppc_inst x)
{
return ppc_inst_val(x) >> 26;
}
-static inline u32 ppc_inst_swab(u32 x)
+static inline struct ppc_inst ppc_inst_swab(struct ppc_inst x)
{
return ppc_inst(swab32(ppc_inst_val(x)));
}
-static inline bool ppc_inst_equal(u32 x, u32 y)
+static inline bool ppc_inst_equal(struct ppc_inst x, struct ppc_inst y)
{
- return x == y;
+ return ppc_inst_val(x) == ppc_inst_val(y);
}
#endif /* _ASM_POWERPC_INST_H */
/*
* Copyright (C) 2004 Paul Mackerras <paulus@au.ibm.com>, IBM
*/
+#include <asm/inst.h>
struct pt_regs;
* otherwise.
*/
extern int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
- unsigned int instr);
+ struct ppc_inst instr);
/*
* Emulate an instruction that can be executed just by updating
* 0 if it could not be emulated, or -1 for an instruction that
* should not be emulated (rfid, mtmsrd clearing MSR_RI, etc.).
*/
-extern int emulate_step(struct pt_regs *regs, unsigned int instr);
+extern int emulate_step(struct pt_regs *regs, struct ppc_inst instr);
/*
* Emulate a load or store instruction by reading/writing the
#include <linux/notifier.h>
#include <asm/probes.h>
+#include <asm/inst.h>
typedef ppc_opcode_t uprobe_opcode_t;
struct arch_uprobe {
union {
- u32 insn;
- u32 ixol;
+ struct ppc_inst insn;
+ struct ppc_inst ixol;
};
};
* so we don't need the address swizzling.
*/
static int emulate_spe(struct pt_regs *regs, unsigned int reg,
- unsigned int instr)
+ struct ppc_inst ppc_instr)
{
int ret;
union {
} data, temp;
unsigned char __user *p, *addr;
unsigned long *evr = ¤t->thread.evr[reg];
- unsigned int nb, flags;
+ unsigned int nb, flags, instr;
+ instr = ppc_inst_val(ppc_instr);
instr = (instr >> 1) & 0x1f;
/* DAR has the operand effective address */
int fix_alignment(struct pt_regs *regs)
{
- unsigned int instr;
+ struct ppc_inst instr;
struct instruction_op op;
int r, type;
*/
CHECK_FULL_REGS(regs);
- if (unlikely(__get_user(instr, (unsigned int __user *)regs->nip)))
+ if (unlikely(__get_user(instr.val, (unsigned int __user *)regs->nip)))
return -EFAULT;
if ((regs->msr & MSR_LE) != (MSR_KERNEL & MSR_LE)) {
/* We don't handle PPC little-endian any more... */
static void __init create_trampoline(unsigned long addr)
{
- unsigned int *p = (unsigned int *)addr;
+ struct ppc_inst *p = (struct ppc_inst *)addr;
/* The maximum range of a single instruction branch, is the current
* instruction's address + (32 MB - 4) bytes. For the trampoline we
return -1;
for (i = 0; i < (len / 4); i++) {
- u32 inst = ppc_inst(be32_to_cpu(insts[i]));
- patch_instruction(epapr_hypercall_start + i, inst);
+ struct ppc_inst inst = ppc_inst(be32_to_cpu(insts[i]));
+ patch_instruction((struct ppc_inst *)(epapr_hypercall_start + i), inst);
#if !defined(CONFIG_64BIT) || defined(CONFIG_PPC_BOOK3E_64)
- patch_instruction(epapr_ev_idle_start + i, inst);
+ patch_instruction((struct ppc_inst *)(epapr_ev_idle_start + i), inst);
#endif
}
static bool stepping_handler(struct pt_regs *regs, struct perf_event *bp,
struct arch_hw_breakpoint *info)
{
- unsigned int instr = ppc_inst(0);
+ struct ppc_inst instr = ppc_inst(0);
int ret, type, size;
struct instruction_op op;
unsigned long addr = info->address;
- if (__get_user_inatomic(instr, (unsigned int *)regs->nip))
+ if (__get_user_inatomic(instr.val, (unsigned int *)regs->nip))
goto fail;
ret = analyse_instr(&op, regs, instr);
void arch_jump_label_transform(struct jump_entry *entry,
enum jump_label_type type)
{
- u32 *addr = (u32 *)(unsigned long)entry->code;
+ struct ppc_inst *addr = (struct ppc_inst *)(unsigned long)entry->code;
if (type == JUMP_LABEL_JMP)
patch_branch(addr, entry->target, 0);
{
int err;
unsigned int instr;
- unsigned int *addr = (unsigned int *)bpt->bpt_addr;
+ struct ppc_inst *addr = (struct ppc_inst *)bpt->bpt_addr;
err = probe_kernel_address(addr, instr);
if (err)
{
int err;
unsigned int instr = *(unsigned int *)bpt->saved_instr;
- unsigned int *addr = (unsigned int *)bpt->bpt_addr;
+ struct ppc_inst *addr = (struct ppc_inst *)bpt->bpt_addr;
err = patch_instruction(addr, ppc_inst(instr));
if (err)
int arch_prepare_kprobe(struct kprobe *p)
{
int ret = 0;
- kprobe_opcode_t insn = *p->addr;
+ struct ppc_inst insn = *(struct ppc_inst *)p->addr;
if ((unsigned long)p->addr & 0x03) {
printk("Attempt to register kprobe at an unaligned address\n");
void arch_arm_kprobe(struct kprobe *p)
{
- patch_instruction(p->addr, ppc_inst(BREAKPOINT_INSTRUCTION));
+ patch_instruction((struct ppc_inst *)p->addr, ppc_inst(BREAKPOINT_INSTRUCTION));
}
NOKPROBE_SYMBOL(arch_arm_kprobe);
void arch_disarm_kprobe(struct kprobe *p)
{
- patch_instruction(p->addr, ppc_inst(p->opcode));
+ patch_instruction((struct ppc_inst *)p->addr, ppc_inst(p->opcode));
}
NOKPROBE_SYMBOL(arch_disarm_kprobe);
static int try_to_emulate(struct kprobe *p, struct pt_regs *regs)
{
int ret;
- unsigned int insn = *p->ainsn.insn;
+ struct ppc_inst insn = *(struct ppc_inst *)p->ainsn.insn;
/* regs->nip is also adjusted if emulate_step returns 1 */
ret = emulate_step(regs, insn);
#include <asm/sstep.h>
#include <asm/exception-64s.h>
#include <asm/extable.h>
+#include <asm/inst.h>
/*
* Convert an address related to an mm to a PFN. NOTE: we are in real
* in real-mode is tricky and can lead to recursive
* faults
*/
- int instr;
+ struct ppc_inst instr;
unsigned long pfn, instr_addr;
struct instruction_op op;
struct pt_regs tmp = *regs;
pfn = addr_to_pfn(regs, regs->nip);
if (pfn != ULONG_MAX) {
instr_addr = (pfn << PAGE_SHIFT) + (regs->nip & ~PAGE_MASK);
- instr = *(unsigned int *)(instr_addr);
+ instr = *(struct ppc_inst *)(instr_addr);
if (!analyse_instr(&op, &tmp, instr)) {
pfn = addr_to_pfn(regs, op.ea);
*addr = op.ea;
* Ensure that the instruction is not a conditional branch,
* and that can be emulated.
*/
- if (!is_conditional_branch(*p->ainsn.insn) &&
- analyse_instr(&op, ®s, *p->ainsn.insn) == 1) {
+ if (!is_conditional_branch(*(struct ppc_inst *)p->ainsn.insn) &&
+ analyse_instr(&op, ®s,
+ *(struct ppc_inst *)p->ainsn.insn) == 1) {
emulate_update_regs(®s, &op);
nip = regs.nip;
}
void patch_imm32_load_insns(unsigned int val, kprobe_opcode_t *addr)
{
/* addis r4,0,(insn)@h */
- patch_instruction(addr, ppc_inst(PPC_INST_ADDIS | ___PPC_RT(4) |
- ((val >> 16) & 0xffff)));
+ patch_instruction((struct ppc_inst *)addr,
+ ppc_inst(PPC_INST_ADDIS | ___PPC_RT(4) |
+ ((val >> 16) & 0xffff)));
addr++;
/* ori r4,r4,(insn)@l */
- patch_instruction(addr, ppc_inst(PPC_INST_ORI | ___PPC_RA(4) |
- ___PPC_RS(4) | (val & 0xffff)));
+ patch_instruction((struct ppc_inst *)addr,
+ ppc_inst(PPC_INST_ORI | ___PPC_RA(4) |
+ ___PPC_RS(4) | (val & 0xffff)));
}
/*
void patch_imm64_load_insns(unsigned long val, kprobe_opcode_t *addr)
{
/* lis r3,(op)@highest */
- patch_instruction(addr, ppc_inst(PPC_INST_ADDIS | ___PPC_RT(3) |
- ((val >> 48) & 0xffff)));
+ patch_instruction((struct ppc_inst *)addr,
+ ppc_inst(PPC_INST_ADDIS | ___PPC_RT(3) |
+ ((val >> 48) & 0xffff)));
addr++;
/* ori r3,r3,(op)@higher */
- patch_instruction(addr, ppc_inst(PPC_INST_ORI | ___PPC_RA(3) |
- ___PPC_RS(3) | ((val >> 32) & 0xffff)));
+ patch_instruction((struct ppc_inst *)addr,
+ ppc_inst(PPC_INST_ORI | ___PPC_RA(3) |
+ ___PPC_RS(3) | ((val >> 32) & 0xffff)));
addr++;
/* rldicr r3,r3,32,31 */
- patch_instruction(addr, ppc_inst(PPC_INST_RLDICR | ___PPC_RA(3) |
- ___PPC_RS(3) | __PPC_SH64(32) | __PPC_ME64(31)));
+ patch_instruction((struct ppc_inst *)addr,
+ ppc_inst(PPC_INST_RLDICR | ___PPC_RA(3) |
+ ___PPC_RS(3) | __PPC_SH64(32) | __PPC_ME64(31)));
addr++;
/* oris r3,r3,(op)@h */
- patch_instruction(addr, ppc_inst(PPC_INST_ORIS | ___PPC_RA(3) |
- ___PPC_RS(3) | ((val >> 16) & 0xffff)));
+ patch_instruction((struct ppc_inst *)addr,
+ ppc_inst(PPC_INST_ORIS | ___PPC_RA(3) |
+ ___PPC_RS(3) | ((val >> 16) & 0xffff)));
addr++;
/* ori r3,r3,(op)@l */
- patch_instruction(addr, ppc_inst(PPC_INST_ORI | ___PPC_RA(3) |
- ___PPC_RS(3) | (val & 0xffff)));
+ patch_instruction((struct ppc_inst *)addr,
+ ppc_inst(PPC_INST_ORI | ___PPC_RA(3) |
+ ___PPC_RS(3) | (val & 0xffff)));
}
int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *p)
{
- kprobe_opcode_t *buff, branch_op_callback, branch_emulate_step;
- kprobe_opcode_t *op_callback_addr, *emulate_step_addr;
+ struct ppc_inst branch_op_callback, branch_emulate_step;
+ kprobe_opcode_t *op_callback_addr, *emulate_step_addr, *buff;
long b_offset;
unsigned long nip, size;
int rc, i;
size = (TMPL_END_IDX * sizeof(kprobe_opcode_t)) / sizeof(int);
pr_devel("Copying template to %p, size %lu\n", buff, size);
for (i = 0; i < size; i++) {
- rc = patch_instruction(buff + i,
+ rc = patch_instruction((struct ppc_inst *)(buff + i),
ppc_inst(*(optprobe_template_entry + i)));
if (rc < 0)
goto error;
}
rc = create_branch(&branch_op_callback,
- (unsigned int *)buff + TMPL_CALL_HDLR_IDX,
+ (struct ppc_inst *)(buff + TMPL_CALL_HDLR_IDX),
(unsigned long)op_callback_addr,
BRANCH_SET_LINK);
rc |= create_branch(&branch_emulate_step,
- (unsigned int *)buff + TMPL_EMULATE_IDX,
+ (struct ppc_inst *)(buff + TMPL_EMULATE_IDX),
(unsigned long)emulate_step_addr,
BRANCH_SET_LINK);
if (rc)
goto error;
- patch_instruction(buff + TMPL_CALL_HDLR_IDX, branch_op_callback);
- patch_instruction(buff + TMPL_EMULATE_IDX, branch_emulate_step);
+ patch_instruction((struct ppc_inst *)(buff + TMPL_CALL_HDLR_IDX),
+ branch_op_callback);
+ patch_instruction((struct ppc_inst *)(buff + TMPL_EMULATE_IDX),
+ branch_emulate_step);
/*
* 3. load instruction to be emulated into relevant register, and
/*
* 4. branch back from trampoline
*/
- patch_branch(buff + TMPL_RET_IDX, (unsigned long)nip, 0);
+ patch_branch((struct ppc_inst *)(buff + TMPL_RET_IDX), (unsigned long)nip, 0);
flush_icache_range((unsigned long)buff,
(unsigned long)(&buff[TMPL_END_IDX]));
void arch_optimize_kprobes(struct list_head *oplist)
{
- unsigned int instr;
+ struct ppc_inst instr;
struct optimized_kprobe *op;
struct optimized_kprobe *tmp;
memcpy(op->optinsn.copied_insn, op->kp.addr,
RELATIVEJUMP_SIZE);
create_branch(&instr,
- (unsigned int *)op->kp.addr,
+ (struct ppc_inst *)op->kp.addr,
(unsigned long)op->optinsn.insn, 0);
- patch_instruction(op->kp.addr, instr);
+ patch_instruction((struct ppc_inst *)op->kp.addr, instr);
list_del_init(&op->list);
}
}
*/
notrace void __init machine_init(u64 dt_ptr)
{
- unsigned int *addr = (unsigned int *)patch_site_addr(&patch__memset_nocache);
- unsigned int insn;
+ struct ppc_inst *addr = (struct ppc_inst *)patch_site_addr(&patch__memset_nocache);
+ struct ppc_inst insn;
/* Configure static keys first, now that we're relocated. */
setup_feature_keys();
#define NUM_FTRACE_TRAMPS 8
static unsigned long ftrace_tramps[NUM_FTRACE_TRAMPS];
-static unsigned int
+static struct ppc_inst
ftrace_call_replace(unsigned long ip, unsigned long addr, int link)
{
- unsigned int op;
+ struct ppc_inst op;
addr = ppc_function_entry((void *)addr);
/* if (link) set op to 'bl' else 'b' */
- create_branch(&op, (unsigned int *)ip, addr, link ? 1 : 0);
+ create_branch(&op, (struct ppc_inst *)ip, addr, link ? 1 : 0);
return op;
}
static int
-ftrace_modify_code(unsigned long ip, unsigned int old, unsigned int new)
+ftrace_modify_code(unsigned long ip, struct ppc_inst old, struct ppc_inst new)
{
- unsigned int replaced;
+ struct ppc_inst replaced;
/*
* Note:
}
/* replace the text with the new text */
- if (patch_instruction((unsigned int *)ip, new))
+ if (patch_instruction((struct ppc_inst *)ip, new))
return -EPERM;
return 0;
*/
static int test_24bit_addr(unsigned long ip, unsigned long addr)
{
- unsigned int op;
+ struct ppc_inst op;
addr = ppc_function_entry((void *)addr);
/* use the create_branch to verify that this offset can be branched */
- return create_branch(&op, (unsigned int *)ip, addr, 0) == 0;
+ return create_branch(&op, (struct ppc_inst *)ip, addr, 0) == 0;
}
-static int is_bl_op(unsigned int op)
+static int is_bl_op(struct ppc_inst op)
{
return (ppc_inst_val(op) & 0xfc000003) == 0x48000001;
}
-static int is_b_op(unsigned int op)
+static int is_b_op(struct ppc_inst op)
{
return (ppc_inst_val(op) & 0xfc000003) == 0x48000000;
}
-static unsigned long find_bl_target(unsigned long ip, unsigned int op)
+static unsigned long find_bl_target(unsigned long ip, struct ppc_inst op)
{
int offset;
{
unsigned long entry, ptr, tramp;
unsigned long ip = rec->ip;
- unsigned int op, pop;
+ struct ppc_inst op, pop;
/* read where this goes */
if (probe_kernel_read(&op, (void *)ip, sizeof(int))) {
}
#endif /* CONFIG_MPROFILE_KERNEL */
- if (patch_instruction((unsigned int *)ip, pop)) {
+ if (patch_instruction((struct ppc_inst *)ip, pop)) {
pr_err("Patching NOP failed.\n");
return -EPERM;
}
__ftrace_make_nop(struct module *mod,
struct dyn_ftrace *rec, unsigned long addr)
{
- unsigned int op;
+ struct ppc_inst op;
unsigned int jmp[4];
unsigned long ip = rec->ip;
unsigned long tramp;
op = ppc_inst(PPC_INST_NOP);
- if (patch_instruction((unsigned int *)ip, op))
+ if (patch_instruction((struct ppc_inst *)ip, op))
return -EPERM;
return 0;
static unsigned long find_ftrace_tramp(unsigned long ip)
{
int i;
- unsigned int instr;
+ struct ppc_inst instr;
/*
* We have the compiler generated long_branch tramps at the end
*/
static int setup_mcount_compiler_tramp(unsigned long tramp)
{
- int i, op;
+ int i;
+ struct ppc_inst op;
unsigned long ptr;
- unsigned int instr;
+ struct ppc_inst instr;
static unsigned long ftrace_plt_tramps[NUM_FTRACE_TRAMPS];
/* Is this a known long jump tramp? */
return -1;
}
- if (patch_branch((unsigned int *)tramp, ptr, 0)) {
+ if (patch_branch((struct ppc_inst *)tramp, ptr, 0)) {
pr_debug("REL24 out of range!\n");
return -1;
}
static int __ftrace_make_nop_kernel(struct dyn_ftrace *rec, unsigned long addr)
{
unsigned long tramp, ip = rec->ip;
- unsigned int op;
+ struct ppc_inst op;
/* Read where this goes */
if (probe_kernel_read(&op, (void *)ip, sizeof(int))) {
}
}
- if (patch_instruction((unsigned int *)ip, ppc_inst(PPC_INST_NOP))) {
+ if (patch_instruction((struct ppc_inst *)ip, ppc_inst(PPC_INST_NOP))) {
pr_err("Patching NOP failed.\n");
return -EPERM;
}
struct dyn_ftrace *rec, unsigned long addr)
{
unsigned long ip = rec->ip;
- unsigned int old, new;
+ struct ppc_inst old, new;
/*
* If the calling address is more that 24 bits away,
*/
#ifndef CONFIG_MPROFILE_KERNEL
static int
-expected_nop_sequence(void *ip, unsigned int op0, unsigned int op1)
+expected_nop_sequence(void *ip, struct ppc_inst op0, struct ppc_inst op1)
{
/*
* We expect to see:
}
#else
static int
-expected_nop_sequence(void *ip, unsigned int op0, unsigned int op1)
+expected_nop_sequence(void *ip, struct ppc_inst op0, struct ppc_inst op1)
{
/* look for patched "NOP" on ppc64 with -mprofile-kernel */
if (!ppc_inst_equal(op0, ppc_inst(PPC_INST_NOP)))
static int
__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
{
- unsigned int op[2];
- unsigned int instr;
+ struct ppc_inst op[2];
+ struct ppc_inst instr;
void *ip = (void *)rec->ip;
unsigned long entry, ptr, tramp;
struct module *mod = rec->arch.mod;
__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
{
int err;
- unsigned int op;
+ struct ppc_inst op;
unsigned long ip = rec->ip;
/* read where this goes */
}
/* create the branch to the trampoline */
- err = create_branch(&op, (unsigned int *)ip,
+ err = create_branch(&op, (struct ppc_inst *)ip,
rec->arch.mod->arch.tramp, BRANCH_SET_LINK);
if (err) {
pr_err("REL24 out of range!\n");
pr_devel("write to %lx\n", rec->ip);
- if (patch_instruction((unsigned int *)ip, op))
+ if (patch_instruction((struct ppc_inst *)ip, op))
return -EPERM;
return 0;
static int __ftrace_make_call_kernel(struct dyn_ftrace *rec, unsigned long addr)
{
- unsigned int op;
+ struct ppc_inst op;
void *ip = (void *)rec->ip;
unsigned long tramp, entry, ptr;
int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
{
unsigned long ip = rec->ip;
- unsigned int old, new;
+ struct ppc_inst old, new;
/*
* If the calling address is more that 24 bits away,
__ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
unsigned long addr)
{
- unsigned int op;
+ struct ppc_inst op;
unsigned long ip = rec->ip;
unsigned long entry, ptr, tramp;
struct module *mod = rec->arch.mod;
/* The new target may be within range */
if (test_24bit_addr(ip, addr)) {
/* within range */
- if (patch_branch((unsigned int *)ip, addr, BRANCH_SET_LINK)) {
+ if (patch_branch((struct ppc_inst *)ip, addr, BRANCH_SET_LINK)) {
pr_err("REL24 out of range!\n");
return -EINVAL;
}
}
/* Ensure branch is within 24 bits */
- if (create_branch(&op, (unsigned int *)ip, tramp, BRANCH_SET_LINK)) {
+ if (create_branch(&op, (struct ppc_inst *)ip, tramp, BRANCH_SET_LINK)) {
pr_err("Branch out of range\n");
return -EINVAL;
}
- if (patch_branch((unsigned int *)ip, tramp, BRANCH_SET_LINK)) {
+ if (patch_branch((struct ppc_inst *)ip, tramp, BRANCH_SET_LINK)) {
pr_err("REL24 out of range!\n");
return -EINVAL;
}
unsigned long addr)
{
unsigned long ip = rec->ip;
- unsigned int old, new;
+ struct ppc_inst old, new;
/*
* If the calling address is more that 24 bits away,
int ftrace_update_ftrace_func(ftrace_func_t func)
{
unsigned long ip = (unsigned long)(&ftrace_call);
- unsigned int old, new;
+ struct ppc_inst old, new;
int ret;
- old = *(unsigned int *)&ftrace_call;
+ old = *(struct ppc_inst *)&ftrace_call;
new = ftrace_call_replace(ip, (unsigned long)func, 1);
ret = ftrace_modify_code(ip, old, new);
/* Also update the regs callback function */
if (!ret) {
ip = (unsigned long)(&ftrace_regs_call);
- old = *(unsigned int *)&ftrace_regs_call;
+ old = *(struct ppc_inst *)&ftrace_regs_call;
new = ftrace_call_replace(ip, (unsigned long)func, 1);
ret = ftrace_modify_code(ip, old, new);
}
unsigned long ip = (unsigned long)(&ftrace_graph_call);
unsigned long addr = (unsigned long)(&ftrace_graph_caller);
unsigned long stub = (unsigned long)(&ftrace_graph_stub);
- unsigned int old, new;
+ struct ppc_inst old, new;
old = ftrace_call_replace(ip, stub, 0);
new = ftrace_call_replace(ip, addr, 0);
unsigned long ip = (unsigned long)(&ftrace_graph_call);
unsigned long addr = (unsigned long)(&ftrace_graph_caller);
unsigned long stub = (unsigned long)(&ftrace_graph_stub);
- unsigned int old, new;
+ struct ppc_inst old, new;
old = ftrace_call_replace(ip, addr, 0);
new = ftrace_call_replace(ip, stub, 0);
int emulate_altivec(struct pt_regs *regs)
{
- unsigned int instr, i, word;
+ struct ppc_inst instr;
+ unsigned int i, word;
unsigned int va, vb, vc, vd;
vector128 *vrs;
- if (get_user(instr, (unsigned int __user *) regs->nip))
+ if (get_user(instr.val, (unsigned int __user *)regs->nip))
return -EFAULT;
word = ppc_inst_val(instr);
#include <asm/setup.h>
#include <asm/inst.h>
-static int __patch_instruction(unsigned int *exec_addr, unsigned int instr,
- unsigned int *patch_addr)
+static int __patch_instruction(struct ppc_inst *exec_addr, struct ppc_inst instr,
+ struct ppc_inst *patch_addr)
{
int err = 0;
- __put_user_asm(instr, patch_addr, err, "stw");
+ __put_user_asm(ppc_inst_val(instr), patch_addr, err, "stw");
if (err)
return err;
return 0;
}
-int raw_patch_instruction(unsigned int *addr, unsigned int instr)
+int raw_patch_instruction(struct ppc_inst *addr, struct ppc_inst instr)
{
return __patch_instruction(addr, instr, addr);
}
return 0;
}
-static int do_patch_instruction(unsigned int *addr, unsigned int instr)
+static int do_patch_instruction(struct ppc_inst *addr, struct ppc_inst instr)
{
int err;
- unsigned int *patch_addr = NULL;
+ struct ppc_inst *patch_addr = NULL;
unsigned long flags;
unsigned long text_poke_addr;
unsigned long kaddr = (unsigned long)addr;
goto out;
}
- patch_addr = (unsigned int *)(text_poke_addr) +
- ((kaddr & ~PAGE_MASK) / sizeof(unsigned int));
+ patch_addr = (struct ppc_inst *)(text_poke_addr + (kaddr & ~PAGE_MASK));
__patch_instruction(addr, instr, patch_addr);
}
#else /* !CONFIG_STRICT_KERNEL_RWX */
-static int do_patch_instruction(unsigned int *addr, unsigned int instr)
+static int do_patch_instruction(struct ppc_inst *addr, struct ppc_inst instr)
{
return raw_patch_instruction(addr, instr);
}
#endif /* CONFIG_STRICT_KERNEL_RWX */
-int patch_instruction(unsigned int *addr, unsigned int instr)
+int patch_instruction(struct ppc_inst *addr, struct ppc_inst instr)
{
/* Make sure we aren't patching a freed init section */
if (init_mem_is_free && init_section_contains(addr, 4)) {
}
NOKPROBE_SYMBOL(patch_instruction);
-int patch_branch(unsigned int *addr, unsigned long target, int flags)
+int patch_branch(struct ppc_inst *addr, unsigned long target, int flags)
{
- unsigned int instr;
+ struct ppc_inst instr;
create_branch(&instr, addr, target, flags);
return patch_instruction(addr, instr);
* Helper to check if a given instruction is a conditional branch
* Derived from the conditional checks in analyse_instr()
*/
-bool is_conditional_branch(unsigned int instr)
+bool is_conditional_branch(struct ppc_inst instr)
{
unsigned int opcode = ppc_inst_primary_opcode(instr);
}
NOKPROBE_SYMBOL(is_conditional_branch);
-int create_branch(unsigned int *instr,
- const unsigned int *addr,
+int create_branch(struct ppc_inst *instr,
+ const struct ppc_inst *addr,
unsigned long target, int flags)
{
long offset;
- *instr = 0;
+ *instr = ppc_inst(0);
offset = target;
if (! (flags & BRANCH_ABSOLUTE))
offset = offset - (unsigned long)addr;
return 1;
/* Mask out the flags and target, so they don't step on each other. */
- *instr = 0x48000000 | (flags & 0x3) | (offset & 0x03FFFFFC);
+ *instr = ppc_inst(0x48000000 | (flags & 0x3) | (offset & 0x03FFFFFC));
return 0;
}
-int create_cond_branch(unsigned int *instr, const unsigned int *addr,
+int create_cond_branch(struct ppc_inst *instr, const struct ppc_inst *addr,
unsigned long target, int flags)
{
long offset;
return 1;
/* Mask out the flags and target, so they don't step on each other. */
- *instr = 0x40000000 | (flags & 0x3FF0003) | (offset & 0xFFFC);
+ *instr = ppc_inst(0x40000000 | (flags & 0x3FF0003) | (offset & 0xFFFC));
return 0;
}
-static unsigned int branch_opcode(unsigned int instr)
+static unsigned int branch_opcode(struct ppc_inst instr)
{
return ppc_inst_primary_opcode(instr) & 0x3F;
}
-static int instr_is_branch_iform(unsigned int instr)
+static int instr_is_branch_iform(struct ppc_inst instr)
{
return branch_opcode(instr) == 18;
}
-static int instr_is_branch_bform(unsigned int instr)
+static int instr_is_branch_bform(struct ppc_inst instr)
{
return branch_opcode(instr) == 16;
}
-int instr_is_relative_branch(unsigned int instr)
+int instr_is_relative_branch(struct ppc_inst instr)
{
if (ppc_inst_val(instr) & BRANCH_ABSOLUTE)
return 0;
return instr_is_branch_iform(instr) || instr_is_branch_bform(instr);
}
-int instr_is_relative_link_branch(unsigned int instr)
+int instr_is_relative_link_branch(struct ppc_inst instr)
{
return instr_is_relative_branch(instr) && (ppc_inst_val(instr) & BRANCH_SET_LINK);
}
-static unsigned long branch_iform_target(const unsigned int *instr)
+static unsigned long branch_iform_target(const struct ppc_inst *instr)
{
signed long imm;
return (unsigned long)imm;
}
-static unsigned long branch_bform_target(const unsigned int *instr)
+static unsigned long branch_bform_target(const struct ppc_inst *instr)
{
signed long imm;
return (unsigned long)imm;
}
-unsigned long branch_target(const unsigned int *instr)
+unsigned long branch_target(const struct ppc_inst *instr)
{
if (instr_is_branch_iform(*instr))
return branch_iform_target(instr);
return 0;
}
-int instr_is_branch_to_addr(const unsigned int *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))
return branch_target(instr) == addr;
return 0;
}
-int translate_branch(unsigned int *instr, const unsigned int *dest,
- const unsigned int *src)
+int translate_branch(struct ppc_inst *instr, const struct ppc_inst *dest,
+ const struct ppc_inst *src)
{
unsigned long target;
* instruction of the exception, not the first one
*/
- patch_branch(ibase + (exc / 4) + 1, addr, 0);
+ patch_branch((struct ppc_inst *)(ibase + (exc / 4) + 1), addr, 0);
}
#endif
static void __init test_branch_iform(void)
{
int err;
- unsigned int instr;
+ struct ppc_inst instr;
unsigned long addr;
addr = (unsigned long)&instr;
static void __init test_create_function_call(void)
{
- unsigned int *iptr;
+ struct ppc_inst *iptr;
unsigned long dest;
- unsigned int instr;
+ struct ppc_inst instr;
/* Check we can create a function call */
- iptr = (unsigned int *)ppc_function_entry(test_trampoline);
+ iptr = (struct ppc_inst *)ppc_function_entry(test_trampoline);
dest = ppc_function_entry(test_create_function_call);
create_branch(&instr, iptr, dest, BRANCH_SET_LINK);
patch_instruction(iptr, instr);
{
int err;
unsigned long addr;
- unsigned int *iptr, instr, flags;
+ struct ppc_inst *iptr, instr;
+ unsigned int flags;
iptr = &instr;
addr = (unsigned long)iptr;
static void __init test_translate_branch(void)
{
unsigned long addr;
- unsigned int *p, *q;
- unsigned int instr;
+ struct ppc_inst *p, *q;
+ struct ppc_inst instr;
void *buf;
buf = vmalloc(PAGE_ALIGN(0x2000000 + 1));
long alt_end_off;
};
-static unsigned int *calc_addr(struct fixup_entry *fcur, long offset)
+static struct ppc_inst *calc_addr(struct fixup_entry *fcur, long offset)
{
/*
* We store the offset to the code as a negative offset from
* the start of the alt_entry, to support the VDSO. This
* routine converts that back into an actual address.
*/
- return (unsigned int *)((unsigned long)fcur + offset);
+ return (struct ppc_inst *)((unsigned long)fcur + offset);
}
-static int patch_alt_instruction(unsigned int *src, unsigned int *dest,
- unsigned int *alt_start, unsigned int *alt_end)
+static int patch_alt_instruction(struct ppc_inst *src, struct ppc_inst *dest,
+ struct ppc_inst *alt_start, struct ppc_inst *alt_end)
{
int err;
- unsigned int instr;
+ struct ppc_inst instr;
instr = *src;
if (instr_is_relative_branch(*src)) {
- unsigned int *target = (unsigned int *)branch_target(src);
+ struct ppc_inst *target = (struct ppc_inst *)branch_target(src);
/* Branch within the section doesn't need translating */
if (target < alt_start || target > alt_end) {
static int patch_feature_section(unsigned long value, struct fixup_entry *fcur)
{
- unsigned int *start, *end, *alt_start, *alt_end, *src, *dest;
+ struct ppc_inst *start, *end, *alt_start, *alt_end, *src, *dest;
start = calc_addr(fcur, fcur->start_off);
end = calc_addr(fcur, fcur->end_off);
pr_devel("patching dest %lx\n", (unsigned long)dest);
- patch_instruction(dest, ppc_inst(instrs[0]));
+ patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
if (types & STF_BARRIER_FALLBACK)
- patch_branch(dest + 1, (unsigned long)&stf_barrier_fallback,
+ patch_branch((struct ppc_inst *)(dest + 1),
+ (unsigned long)&stf_barrier_fallback,
BRANCH_SET_LINK);
else
- patch_instruction(dest + 1, ppc_inst(instrs[1]));
+ patch_instruction((struct ppc_inst *)(dest + 1),
+ ppc_inst(instrs[1]));
- patch_instruction(dest + 2, ppc_inst(instrs[2]));
+ patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
}
printk(KERN_DEBUG "stf-barrier: patched %d entry locations (%s barrier)\n", i,
pr_devel("patching dest %lx\n", (unsigned long)dest);
- patch_instruction(dest, ppc_inst(instrs[0]));
- patch_instruction(dest + 1, ppc_inst(instrs[1]));
- patch_instruction(dest + 2, ppc_inst(instrs[2]));
- patch_instruction(dest + 3, ppc_inst(instrs[3]));
- patch_instruction(dest + 4, ppc_inst(instrs[4]));
- patch_instruction(dest + 5, ppc_inst(instrs[5]));
+ patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
+ patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1]));
+ patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
+ patch_instruction((struct ppc_inst *)(dest + 3), ppc_inst(instrs[3]));
+ patch_instruction((struct ppc_inst *)(dest + 4), ppc_inst(instrs[4]));
+ patch_instruction((struct ppc_inst *)(dest + 5), ppc_inst(instrs[5]));
}
printk(KERN_DEBUG "stf-barrier: patched %d exit locations (%s barrier)\n", i,
(types == STF_BARRIER_NONE) ? "no" :
pr_devel("patching dest %lx\n", (unsigned long)dest);
- patch_instruction(dest, ppc_inst(instrs[0]));
- patch_instruction(dest + 1, ppc_inst(instrs[1]));
- patch_instruction(dest + 2, ppc_inst(instrs[2]));
+ patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
+ patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1]));
+ patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
}
printk(KERN_DEBUG "rfi-flush: patched %d locations (%s flush)\n", i,
dest = (void *)start + *start;
pr_devel("patching dest %lx\n", (unsigned long)dest);
- patch_instruction(dest, ppc_inst(instr));
+ patch_instruction((struct ppc_inst *)dest, ppc_inst(instr));
}
printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i);
dest = (void *)start + *start;
pr_devel("patching dest %lx\n", (unsigned long)dest);
- patch_instruction(dest, ppc_inst(instr[0]));
- patch_instruction(dest + 1, ppc_inst(instr[1]));
+ patch_instruction((struct ppc_inst *)dest, ppc_inst(instr[0]));
+ patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instr[1]));
}
printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i);
end = (void *)curr + *(curr + 1);
for (; start < end; start++) {
pr_devel("patching dest %lx\n", (unsigned long)start);
- patch_instruction(start, ppc_inst(PPC_INST_NOP));
+ patch_instruction((struct ppc_inst *)start, ppc_inst(PPC_INST_NOP));
}
}
void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end)
{
long *start, *end;
- unsigned int *dest;
+ struct ppc_inst *dest;
if (!(value & CPU_FTR_LWSYNC))
return ;
static void do_final_fixups(void)
{
#if defined(CONFIG_PPC64) && defined(CONFIG_RELOCATABLE)
- int *src, *dest;
+ struct ppc_inst *src, *dest;
unsigned long length;
if (PHYSICAL_START == 0)
return;
- src = (int *)(KERNELBASE + PHYSICAL_START);
- dest = (int *)KERNELBASE;
- length = (__end_interrupts - _stext) / sizeof(int);
+ src = (struct ppc_inst *)(KERNELBASE + PHYSICAL_START);
+ dest = (struct ppc_inst *)KERNELBASE;
+ length = (__end_interrupts - _stext) / sizeof(struct ppc_inst);
while (length--) {
- raw_patch_instruction(dest, ppc_inst(*src));
+ raw_patch_instruction(dest, *src);
src++;
dest++;
}
* otherwise.
*/
int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
- unsigned int instr)
+ struct ppc_inst instr)
{
unsigned int opcode, ra, rb, rc, rd, spr, u;
unsigned long int imm;
* or -1 if the instruction is one that should not be stepped,
* such as an rfid, or a mtmsrd that would clear MSR_RI.
*/
-int emulate_step(struct pt_regs *regs, unsigned int instr)
+int emulate_step(struct pt_regs *regs, struct ppc_inst instr)
{
struct instruction_op op;
int r, err, type;
struct {
char *descr;
unsigned long flags;
- unsigned int instr;
+ struct ppc_inst instr;
struct pt_regs regs;
} subtests[MAX_SUBTESTS + 1];
};
};
static int __init emulate_compute_instr(struct pt_regs *regs,
- unsigned int instr)
+ struct ppc_inst instr)
{
struct instruction_op op;
}
static int __init execute_compute_instr(struct pt_regs *regs,
- unsigned int instr)
+ struct ppc_inst instr)
{
extern int exec_instr(struct pt_regs *regs);
extern s32 patch__exec_instr;
unsigned long flags;
struct compute_test *test;
struct pt_regs *regs, exp, got;
- unsigned int i, j, k, instr;
+ unsigned int i, j, k;
+ struct ppc_inst instr;
bool ignore_gpr, ignore_xer, ignore_ccr, passed;
for (i = 0; i < ARRAY_SIZE(compute_tests); i++) {
* Check whether the instruction inst is a store using
* an update addressing form which will update r1.
*/
-static bool store_updates_sp(unsigned int inst)
+static bool store_updates_sp(struct ppc_inst inst)
{
/* check for 1 in the rA field */
if (((ppc_inst_val(inst) >> 16) & 0x1f) != 1)
if ((flags & FAULT_FLAG_WRITE) && (flags & FAULT_FLAG_USER) &&
access_ok(nip, sizeof(*nip))) {
- unsigned int inst;
+ struct ppc_inst inst;
if (!probe_user_read(&inst, nip, sizeof(inst)))
return !store_updates_sp(inst);
if (probe_kernel_read(&instr, (void *)addr, sizeof(instr)))
return 0;
- return branch_target(&instr);
+ return branch_target((struct ppc_inst *)&instr);
}
/* Userspace: need copy instruction here then translate it */
if (probe_user_read(&instr, (unsigned int __user *)addr, sizeof(instr)))
return 0;
- target = branch_target(&instr);
+ target = branch_target((struct ppc_inst *)&instr);
if ((!target) || (instr & BRANCH_ABSOLUTE))
return target;
/* Setup fake reset vector to call __secondary_start_mpc86xx. */
target = (unsigned long) __secondary_start_mpc86xx;
- patch_branch(vector, target, BRANCH_SET_LINK);
+ patch_branch((struct ppc_inst *)vector, target, BRANCH_SET_LINK);
/* Kick that CPU */
smp_86xx_release_core(nr);
mdelay(1);
/* Restore the exception vector */
- patch_instruction(vector, ppc_inst(save_vector));
+ patch_instruction((struct ppc_inst *)vector, ppc_inst(save_vector));
local_irq_restore(flags);
* b __secondary_start_pmac_0 + nr*8
*/
target = (unsigned long) __secondary_start_pmac_0 + nr * 8;
- patch_branch(vector, target, BRANCH_SET_LINK);
+ patch_branch((struct ppc_inst *)vector, target, BRANCH_SET_LINK);
/* Put some life in our friend */
pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0);
mdelay(1);
/* Restore our exception vector */
- patch_instruction(vector, ppc_inst(save_vector));
+ patch_instruction((struct ppc_inst *)vector, ppc_inst(save_vector));
local_irq_restore(flags);
if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347);
/* Breakpoint stuff */
struct bpt {
unsigned long address;
- unsigned int *instr;
+ struct ppc_inst *instr;
atomic_t ref_count;
int enabled;
unsigned long pad;
for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
bp->address = a;
- bp->instr = bpt_table + ((bp - bpts) * BPT_WORDS);
- patch_instruction(bp->instr + 1, bpinstr);
+ bp->instr = (void *)(bpt_table + ((bp - bpts) * BPT_WORDS));
+ patch_instruction(bp->instr + 1, ppc_inst(bpinstr));
return bp;
}
}
static void insert_bpts(void)
{
int i;
- unsigned int instr;
+ struct ppc_inst instr;
struct bpt *bp;
bp = bpts;
patch_instruction(bp->instr, instr);
if (bp->enabled & BP_CIABR)
continue;
- if (patch_instruction((unsigned int *)bp->address,
- bpinstr) != 0) {
+ if (patch_instruction((struct ppc_inst *)bp->address,
+ ppc_inst(bpinstr)) != 0) {
printf("Couldn't write instruction at %lx, "
"disabling breakpoint there\n", bp->address);
bp->enabled &= ~BP_TRAP;
{
int i;
struct bpt *bp;
- unsigned instr;
+ struct ppc_inst instr;
bp = bpts;
for (i = 0; i < NBPTS; ++i, ++bp) {
if (mread(bp->address, &instr, 4) == 4
&& ppc_inst_equal(instr, ppc_inst(bpinstr))
&& patch_instruction(
- (unsigned int *)bp->address, bp->instr[0]) != 0)
+ (struct ppc_inst *)bp->address, bp->instr[0]) != 0)
printf("Couldn't remove breakpoint at %lx\n",
bp->address);
}
*/
static int do_step(struct pt_regs *regs)
{
- unsigned int instr;
+ struct ppc_inst instr;
int stepped;
force_enable_xmon();
*/
static long check_bp_loc(unsigned long addr)
{
- unsigned int instr;
+ struct ppc_inst instr;
addr &= ~3;
if (!is_kernel_addr(addr)) {
{
int nr, dotted;
unsigned long first_adr;
- unsigned int inst, last_inst = ppc_inst(0);
+ struct ppc_inst inst, last_inst = ppc_inst(0);
unsigned char val[4];
dotted = 0;
#define NBPTS 256
#ifndef __ASSEMBLY__
-#define BPT_SIZE (sizeof(unsigned int) * 2)
-#define BPT_WORDS (BPT_SIZE / sizeof(unsigned int))
+#include <asm/inst.h>
+#define BPT_SIZE (sizeof(struct ppc_inst) * 2)
+#define BPT_WORDS (BPT_SIZE / sizeof(struct ppc_inst))
extern unsigned int bpt_table[NBPTS * BPT_WORDS];
-
#endif /* __ASSEMBLY__ */
#endif /* XMON_BPTS_H */