powerpc: Don't use 'struct ppc_inst' to reference instruction location
'struct ppc_inst' is an internal representation of an instruction, but in-memory instructions are and will remain a table of 'u32' forever. Replace all 'struct ppc_inst *' used for locating an instruction in memory by 'u32 *'. This removes a lot of undue casts to 'struct ppc_inst *'. It also helps locating ab-use of 'struct ppc_inst' dereference. Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu> [mpe: Fix ppc_inst_next(), use u32 instead of unsigned int] Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/7062722b087228e42cbd896e39bfdf526d6a340a.1621516826.git.christophe.leroy@csgroup.eu
This commit is contained in:
Родитель
e90a21ea80
Коммит
69d4d6e5fd
|
@ -23,13 +23,13 @@
|
||||||
#define BRANCH_ABSOLUTE 0x2
|
#define BRANCH_ABSOLUTE 0x2
|
||||||
|
|
||||||
bool is_offset_in_branch_range(long offset);
|
bool is_offset_in_branch_range(long offset);
|
||||||
int create_branch(struct ppc_inst *instr, const struct ppc_inst *addr,
|
int create_branch(struct ppc_inst *instr, const u32 *addr,
|
||||||
unsigned long target, int flags);
|
unsigned long target, int flags);
|
||||||
int create_cond_branch(struct ppc_inst *instr, const struct ppc_inst *addr,
|
int create_cond_branch(struct ppc_inst *instr, const u32 *addr,
|
||||||
unsigned long target, int flags);
|
unsigned long target, int flags);
|
||||||
int patch_branch(struct ppc_inst *addr, unsigned long target, int flags);
|
int patch_branch(u32 *addr, unsigned long target, int flags);
|
||||||
int patch_instruction(struct ppc_inst *addr, struct ppc_inst instr);
|
int patch_instruction(u32 *addr, struct ppc_inst instr);
|
||||||
int raw_patch_instruction(struct ppc_inst *addr, struct ppc_inst instr);
|
int raw_patch_instruction(u32 *addr, struct ppc_inst instr);
|
||||||
|
|
||||||
static inline unsigned long patch_site_addr(s32 *site)
|
static inline unsigned long patch_site_addr(s32 *site)
|
||||||
{
|
{
|
||||||
|
@ -38,18 +38,18 @@ static inline unsigned long patch_site_addr(s32 *site)
|
||||||
|
|
||||||
static inline int patch_instruction_site(s32 *site, struct ppc_inst instr)
|
static inline int patch_instruction_site(s32 *site, struct ppc_inst instr)
|
||||||
{
|
{
|
||||||
return patch_instruction((struct ppc_inst *)patch_site_addr(site), instr);
|
return patch_instruction((u32 *)patch_site_addr(site), instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int patch_branch_site(s32 *site, unsigned long target, int flags)
|
static inline int patch_branch_site(s32 *site, unsigned long target, int flags)
|
||||||
{
|
{
|
||||||
return patch_branch((struct ppc_inst *)patch_site_addr(site), target, flags);
|
return patch_branch((u32 *)patch_site_addr(site), target, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int modify_instruction(unsigned int *addr, unsigned int clr,
|
static inline int modify_instruction(unsigned int *addr, unsigned int clr,
|
||||||
unsigned int set)
|
unsigned int set)
|
||||||
{
|
{
|
||||||
return patch_instruction((struct ppc_inst *)addr, ppc_inst((*addr & ~clr) | set));
|
return patch_instruction(addr, ppc_inst((*addr & ~clr) | set));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int modify_instruction_site(s32 *site, unsigned int clr, unsigned int set)
|
static inline int modify_instruction_site(s32 *site, unsigned int clr, unsigned int set)
|
||||||
|
@ -59,9 +59,8 @@ static inline int modify_instruction_site(s32 *site, unsigned int clr, unsigned
|
||||||
|
|
||||||
int instr_is_relative_branch(struct ppc_inst instr);
|
int instr_is_relative_branch(struct ppc_inst instr);
|
||||||
int instr_is_relative_link_branch(struct ppc_inst instr);
|
int instr_is_relative_link_branch(struct ppc_inst instr);
|
||||||
unsigned long branch_target(const struct ppc_inst *instr);
|
unsigned long branch_target(const u32 *instr);
|
||||||
int translate_branch(struct ppc_inst *instr, const struct ppc_inst *dest,
|
int translate_branch(struct ppc_inst *instr, const u32 *dest, const u32 *src);
|
||||||
const struct ppc_inst *src);
|
|
||||||
extern bool is_conditional_branch(struct ppc_inst instr);
|
extern bool is_conditional_branch(struct ppc_inst instr);
|
||||||
#ifdef CONFIG_PPC_BOOK3E_64
|
#ifdef CONFIG_PPC_BOOK3E_64
|
||||||
void __patch_exception(int exc, unsigned long addr);
|
void __patch_exception(int exc, unsigned long addr);
|
||||||
|
|
|
@ -80,13 +80,13 @@ static inline struct ppc_inst ppc_inst_swab(struct ppc_inst x)
|
||||||
return ppc_inst_prefix(swab32(ppc_inst_val(x)), swab32(ppc_inst_suffix(x)));
|
return ppc_inst_prefix(swab32(ppc_inst_val(x)), swab32(ppc_inst_suffix(x)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct ppc_inst ppc_inst_read(const struct ppc_inst *ptr)
|
static inline struct ppc_inst ppc_inst_read(const u32 *ptr)
|
||||||
{
|
{
|
||||||
u32 val, suffix;
|
u32 val, suffix;
|
||||||
|
|
||||||
val = *(u32 *)ptr;
|
val = *ptr;
|
||||||
if ((val >> 26) == OP_PREFIX) {
|
if ((val >> 26) == OP_PREFIX) {
|
||||||
suffix = *((u32 *)ptr + 1);
|
suffix = *(ptr + 1);
|
||||||
return ppc_inst_prefix(val, suffix);
|
return ppc_inst_prefix(val, suffix);
|
||||||
} else {
|
} else {
|
||||||
return ppc_inst(val);
|
return ppc_inst(val);
|
||||||
|
@ -114,9 +114,9 @@ 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)
|
static inline struct ppc_inst ppc_inst_read(const u32 *ptr)
|
||||||
{
|
{
|
||||||
return *ptr;
|
return ppc_inst(*ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_PPC64 */
|
#endif /* CONFIG_PPC64 */
|
||||||
|
@ -139,13 +139,13 @@ static inline int ppc_inst_len(struct ppc_inst x)
|
||||||
* Return the address of the next instruction, if the instruction @value was
|
* Return the address of the next instruction, if the instruction @value was
|
||||||
* located at @location.
|
* located at @location.
|
||||||
*/
|
*/
|
||||||
static inline struct ppc_inst *ppc_inst_next(void *location, struct ppc_inst *value)
|
static inline u32 *ppc_inst_next(u32 *location, u32 *value)
|
||||||
{
|
{
|
||||||
struct ppc_inst tmp;
|
struct ppc_inst tmp;
|
||||||
|
|
||||||
tmp = ppc_inst_read(value);
|
tmp = ppc_inst_read(value);
|
||||||
|
|
||||||
return location + ppc_inst_len(tmp);
|
return (void *)location + ppc_inst_len(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned long ppc_inst_as_ulong(struct ppc_inst x)
|
static inline unsigned long ppc_inst_as_ulong(struct ppc_inst x)
|
||||||
|
@ -177,6 +177,6 @@ static inline char *__ppc_inst_as_str(char str[PPC_INST_STR_LEN], struct ppc_ins
|
||||||
__str; \
|
__str; \
|
||||||
})
|
})
|
||||||
|
|
||||||
int copy_inst_from_kernel_nofault(struct ppc_inst *inst, struct ppc_inst *src);
|
int copy_inst_from_kernel_nofault(struct ppc_inst *inst, u32 *src);
|
||||||
|
|
||||||
#endif /* _ASM_POWERPC_INST_H */
|
#endif /* _ASM_POWERPC_INST_H */
|
||||||
|
|
|
@ -24,8 +24,8 @@ typedef ppc_opcode_t uprobe_opcode_t;
|
||||||
|
|
||||||
struct arch_uprobe {
|
struct arch_uprobe {
|
||||||
union {
|
union {
|
||||||
struct ppc_inst insn;
|
u32 insn[2];
|
||||||
struct ppc_inst ixol;
|
u32 ixol[2];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ void __init reserve_kdump_trampoline(void)
|
||||||
|
|
||||||
static void __init create_trampoline(unsigned long addr)
|
static void __init create_trampoline(unsigned long addr)
|
||||||
{
|
{
|
||||||
struct ppc_inst *p = (struct ppc_inst *)addr;
|
u32 *p = (u32 *)addr;
|
||||||
|
|
||||||
/* The maximum range of a single instruction branch, is the current
|
/* The maximum range of a single instruction branch, is the current
|
||||||
* instruction's address + (32 MB - 4) bytes. For the trampoline we
|
* instruction's address + (32 MB - 4) bytes. For the trampoline we
|
||||||
|
@ -46,7 +46,7 @@ static void __init create_trampoline(unsigned long addr)
|
||||||
* two instructions it doesn't require any registers.
|
* two instructions it doesn't require any registers.
|
||||||
*/
|
*/
|
||||||
patch_instruction(p, ppc_inst(PPC_RAW_NOP()));
|
patch_instruction(p, ppc_inst(PPC_RAW_NOP()));
|
||||||
patch_branch((void *)p + 4, addr + PHYSICAL_START, 0);
|
patch_branch(p + 1, addr + PHYSICAL_START, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __init setup_kdump_trampoline(void)
|
void __init setup_kdump_trampoline(void)
|
||||||
|
|
|
@ -38,9 +38,9 @@ static int __init early_init_dt_scan_epapr(unsigned long node,
|
||||||
|
|
||||||
for (i = 0; i < (len / 4); i++) {
|
for (i = 0; i < (len / 4); i++) {
|
||||||
struct ppc_inst inst = ppc_inst(be32_to_cpu(insts[i]));
|
struct ppc_inst inst = ppc_inst(be32_to_cpu(insts[i]));
|
||||||
patch_instruction((struct ppc_inst *)(epapr_hypercall_start + i), inst);
|
patch_instruction(epapr_hypercall_start + i, inst);
|
||||||
#if !defined(CONFIG_64BIT) || defined(CONFIG_PPC_BOOK3E_64)
|
#if !defined(CONFIG_64BIT) || defined(CONFIG_PPC_BOOK3E_64)
|
||||||
patch_instruction((struct ppc_inst *)(epapr_ev_idle_start + i), inst);
|
patch_instruction(epapr_ev_idle_start + i, inst);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
void arch_jump_label_transform(struct jump_entry *entry,
|
void arch_jump_label_transform(struct jump_entry *entry,
|
||||||
enum jump_label_type type)
|
enum jump_label_type type)
|
||||||
{
|
{
|
||||||
struct ppc_inst *addr = (struct ppc_inst *)jump_entry_code(entry);
|
u32 *addr = (u32 *)jump_entry_code(entry);
|
||||||
|
|
||||||
if (type == JUMP_LABEL_JMP)
|
if (type == JUMP_LABEL_JMP)
|
||||||
patch_branch(addr, jump_entry_target(entry), 0);
|
patch_branch(addr, jump_entry_target(entry), 0);
|
||||||
|
|
|
@ -417,11 +417,10 @@ int kgdb_arch_handle_exception(int vector, int signo, int err_code,
|
||||||
|
|
||||||
int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
|
int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
|
||||||
{
|
{
|
||||||
|
u32 instr, *addr = (u32 *)bpt->bpt_addr;
|
||||||
int err;
|
int err;
|
||||||
unsigned int instr;
|
|
||||||
struct ppc_inst *addr = (struct ppc_inst *)bpt->bpt_addr;
|
|
||||||
|
|
||||||
err = get_kernel_nofault(instr, (unsigned *) addr);
|
err = get_kernel_nofault(instr, addr);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -429,7 +428,7 @@ int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
|
||||||
if (err)
|
if (err)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
*(unsigned int *)bpt->saved_instr = instr;
|
*(u32 *)bpt->saved_instr = instr;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -438,7 +437,7 @@ int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
unsigned int instr = *(unsigned int *)bpt->saved_instr;
|
unsigned int instr = *(unsigned int *)bpt->saved_instr;
|
||||||
struct ppc_inst *addr = (struct ppc_inst *)bpt->bpt_addr;
|
u32 *addr = (u32 *)bpt->bpt_addr;
|
||||||
|
|
||||||
err = patch_instruction(addr, ppc_inst(instr));
|
err = patch_instruction(addr, ppc_inst(instr));
|
||||||
if (err)
|
if (err)
|
||||||
|
|
|
@ -107,7 +107,7 @@ int arch_prepare_kprobe(struct kprobe *p)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct kprobe *prev;
|
struct kprobe *prev;
|
||||||
struct ppc_inst insn = ppc_inst_read((struct ppc_inst *)p->addr);
|
struct ppc_inst insn = ppc_inst_read(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");
|
||||||
|
@ -116,15 +116,14 @@ int arch_prepare_kprobe(struct kprobe *p)
|
||||||
printk("Cannot register a kprobe on rfi/rfid or mtmsr[d]\n");
|
printk("Cannot register a kprobe on rfi/rfid or mtmsr[d]\n");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
} else if ((unsigned long)p->addr & ~PAGE_MASK &&
|
} else if ((unsigned long)p->addr & ~PAGE_MASK &&
|
||||||
ppc_inst_prefixed(ppc_inst_read((struct ppc_inst *)(p->addr - 1)))) {
|
ppc_inst_prefixed(ppc_inst_read(p->addr - 1))) {
|
||||||
printk("Cannot register a kprobe on the second word of prefixed instruction\n");
|
printk("Cannot register a kprobe on the second word of prefixed instruction\n");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
prev = get_kprobe(p->addr - 1);
|
prev = get_kprobe(p->addr - 1);
|
||||||
preempt_enable_no_resched();
|
preempt_enable_no_resched();
|
||||||
if (prev &&
|
if (prev && ppc_inst_prefixed(ppc_inst_read(prev->ainsn.insn))) {
|
||||||
ppc_inst_prefixed(ppc_inst_read((struct ppc_inst *)prev->ainsn.insn))) {
|
|
||||||
printk("Cannot register a kprobe on the second word of prefixed instruction\n");
|
printk("Cannot register a kprobe on the second word of prefixed instruction\n");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -138,7 +137,7 @@ int arch_prepare_kprobe(struct kprobe *p)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
patch_instruction((struct ppc_inst *)p->ainsn.insn, insn);
|
patch_instruction(p->ainsn.insn, insn);
|
||||||
p->opcode = ppc_inst_val(insn);
|
p->opcode = ppc_inst_val(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,13 +148,13 @@ NOKPROBE_SYMBOL(arch_prepare_kprobe);
|
||||||
|
|
||||||
void arch_arm_kprobe(struct kprobe *p)
|
void arch_arm_kprobe(struct kprobe *p)
|
||||||
{
|
{
|
||||||
patch_instruction((struct ppc_inst *)p->addr, ppc_inst(BREAKPOINT_INSTRUCTION));
|
patch_instruction(p->addr, ppc_inst(BREAKPOINT_INSTRUCTION));
|
||||||
}
|
}
|
||||||
NOKPROBE_SYMBOL(arch_arm_kprobe);
|
NOKPROBE_SYMBOL(arch_arm_kprobe);
|
||||||
|
|
||||||
void arch_disarm_kprobe(struct kprobe *p)
|
void arch_disarm_kprobe(struct kprobe *p)
|
||||||
{
|
{
|
||||||
patch_instruction((struct ppc_inst *)p->addr, ppc_inst(p->opcode));
|
patch_instruction(p->addr, ppc_inst(p->opcode));
|
||||||
}
|
}
|
||||||
NOKPROBE_SYMBOL(arch_disarm_kprobe);
|
NOKPROBE_SYMBOL(arch_disarm_kprobe);
|
||||||
|
|
||||||
|
@ -228,7 +227,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 = ppc_inst_read((struct ppc_inst *)p->ainsn.insn);
|
struct ppc_inst insn = ppc_inst_read(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);
|
||||||
|
@ -439,7 +438,7 @@ int kprobe_post_handler(struct pt_regs *regs)
|
||||||
if (!cur || user_mode(regs))
|
if (!cur || user_mode(regs))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
len = ppc_inst_len(ppc_inst_read((struct ppc_inst *)cur->ainsn.insn));
|
len = ppc_inst_len(ppc_inst_read(cur->ainsn.insn));
|
||||||
/* make sure we got here for instruction we have a kprobe on */
|
/* make sure we got here for instruction we have a kprobe on */
|
||||||
if (((unsigned long)cur->ainsn.insn + len) != regs->nip)
|
if (((unsigned long)cur->ainsn.insn + len) != regs->nip)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -463,7 +463,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 = ppc_inst_read((struct ppc_inst *)instr_addr);
|
instr = ppc_inst_read((u32 *)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;
|
||||||
|
|
|
@ -89,9 +89,8 @@ 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(ppc_inst_read((struct ppc_inst *)p->ainsn.insn)) &&
|
if (!is_conditional_branch(ppc_inst_read(p->ainsn.insn)) &&
|
||||||
analyse_instr(&op, ®s,
|
analyse_instr(&op, ®s, ppc_inst_read(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;
|
||||||
}
|
}
|
||||||
|
@ -132,12 +131,10 @@ void arch_remove_optimized_kprobe(struct optimized_kprobe *op)
|
||||||
|
|
||||||
static void patch_imm32_load_insns(unsigned long val, int reg, kprobe_opcode_t *addr)
|
static void patch_imm32_load_insns(unsigned long val, int reg, kprobe_opcode_t *addr)
|
||||||
{
|
{
|
||||||
patch_instruction((struct ppc_inst *)addr,
|
patch_instruction(addr, ppc_inst(PPC_RAW_LIS(reg, IMM_H(val))));
|
||||||
ppc_inst(PPC_RAW_LIS(reg, IMM_H(val))));
|
|
||||||
addr++;
|
addr++;
|
||||||
|
|
||||||
patch_instruction((struct ppc_inst *)addr,
|
patch_instruction(addr, ppc_inst(PPC_RAW_ORI(reg, reg, IMM_L(val))));
|
||||||
ppc_inst(PPC_RAW_ORI(reg, reg, IMM_L(val))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -147,31 +144,31 @@ static void patch_imm32_load_insns(unsigned long val, int reg, kprobe_opcode_t *
|
||||||
static void patch_imm64_load_insns(unsigned long long val, int reg, kprobe_opcode_t *addr)
|
static void patch_imm64_load_insns(unsigned long long val, int reg, kprobe_opcode_t *addr)
|
||||||
{
|
{
|
||||||
/* lis reg,(op)@highest */
|
/* lis reg,(op)@highest */
|
||||||
patch_instruction((struct ppc_inst *)addr,
|
patch_instruction(addr,
|
||||||
ppc_inst(PPC_INST_ADDIS | ___PPC_RT(reg) |
|
ppc_inst(PPC_INST_ADDIS | ___PPC_RT(reg) |
|
||||||
((val >> 48) & 0xffff)));
|
((val >> 48) & 0xffff)));
|
||||||
addr++;
|
addr++;
|
||||||
|
|
||||||
/* ori reg,reg,(op)@higher */
|
/* ori reg,reg,(op)@higher */
|
||||||
patch_instruction((struct ppc_inst *)addr,
|
patch_instruction(addr,
|
||||||
ppc_inst(PPC_INST_ORI | ___PPC_RA(reg) |
|
ppc_inst(PPC_INST_ORI | ___PPC_RA(reg) |
|
||||||
___PPC_RS(reg) | ((val >> 32) & 0xffff)));
|
___PPC_RS(reg) | ((val >> 32) & 0xffff)));
|
||||||
addr++;
|
addr++;
|
||||||
|
|
||||||
/* rldicr reg,reg,32,31 */
|
/* rldicr reg,reg,32,31 */
|
||||||
patch_instruction((struct ppc_inst *)addr,
|
patch_instruction(addr,
|
||||||
ppc_inst(PPC_INST_RLDICR | ___PPC_RA(reg) |
|
ppc_inst(PPC_INST_RLDICR | ___PPC_RA(reg) |
|
||||||
___PPC_RS(reg) | __PPC_SH64(32) | __PPC_ME64(31)));
|
___PPC_RS(reg) | __PPC_SH64(32) | __PPC_ME64(31)));
|
||||||
addr++;
|
addr++;
|
||||||
|
|
||||||
/* oris reg,reg,(op)@h */
|
/* oris reg,reg,(op)@h */
|
||||||
patch_instruction((struct ppc_inst *)addr,
|
patch_instruction(addr,
|
||||||
ppc_inst(PPC_INST_ORIS | ___PPC_RA(reg) |
|
ppc_inst(PPC_INST_ORIS | ___PPC_RA(reg) |
|
||||||
___PPC_RS(reg) | ((val >> 16) & 0xffff)));
|
___PPC_RS(reg) | ((val >> 16) & 0xffff)));
|
||||||
addr++;
|
addr++;
|
||||||
|
|
||||||
/* ori reg,reg,(op)@l */
|
/* ori reg,reg,(op)@l */
|
||||||
patch_instruction((struct ppc_inst *)addr,
|
patch_instruction(addr,
|
||||||
ppc_inst(PPC_INST_ORI | ___PPC_RA(reg) |
|
ppc_inst(PPC_INST_ORI | ___PPC_RA(reg) |
|
||||||
___PPC_RS(reg) | (val & 0xffff)));
|
___PPC_RS(reg) | (val & 0xffff)));
|
||||||
}
|
}
|
||||||
|
@ -225,8 +222,7 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *p)
|
||||||
size = (TMPL_END_IDX * sizeof(kprobe_opcode_t)) / sizeof(int);
|
size = (TMPL_END_IDX * sizeof(kprobe_opcode_t)) / sizeof(int);
|
||||||
pr_devel("Copying template to %p, size %lu\n", buff, size);
|
pr_devel("Copying template to %p, size %lu\n", buff, size);
|
||||||
for (i = 0; i < size; i++) {
|
for (i = 0; i < size; i++) {
|
||||||
rc = patch_instruction((struct ppc_inst *)(buff + i),
|
rc = patch_instruction(buff + i, ppc_inst(*(optprobe_template_entry + i)));
|
||||||
ppc_inst(*(optprobe_template_entry + i)));
|
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -247,34 +243,30 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *p)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = create_branch(&branch_op_callback,
|
rc = create_branch(&branch_op_callback, buff + TMPL_CALL_HDLR_IDX,
|
||||||
(struct ppc_inst *)(buff + TMPL_CALL_HDLR_IDX),
|
|
||||||
(unsigned long)op_callback_addr,
|
(unsigned long)op_callback_addr,
|
||||||
BRANCH_SET_LINK);
|
BRANCH_SET_LINK);
|
||||||
|
|
||||||
rc |= create_branch(&branch_emulate_step,
|
rc |= create_branch(&branch_emulate_step, buff + TMPL_EMULATE_IDX,
|
||||||
(struct ppc_inst *)(buff + TMPL_EMULATE_IDX),
|
|
||||||
(unsigned long)emulate_step_addr,
|
(unsigned long)emulate_step_addr,
|
||||||
BRANCH_SET_LINK);
|
BRANCH_SET_LINK);
|
||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
patch_instruction((struct ppc_inst *)(buff + TMPL_CALL_HDLR_IDX),
|
patch_instruction(buff + TMPL_CALL_HDLR_IDX, branch_op_callback);
|
||||||
branch_op_callback);
|
patch_instruction(buff + TMPL_EMULATE_IDX, branch_emulate_step);
|
||||||
patch_instruction((struct ppc_inst *)(buff + TMPL_EMULATE_IDX),
|
|
||||||
branch_emulate_step);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 3. load instruction to be emulated into relevant register, and
|
* 3. load instruction to be emulated into relevant register, and
|
||||||
*/
|
*/
|
||||||
temp = ppc_inst_read((struct ppc_inst *)p->ainsn.insn);
|
temp = ppc_inst_read(p->ainsn.insn);
|
||||||
patch_imm_load_insns(ppc_inst_as_ulong(temp), 4, buff + TMPL_INSN_IDX);
|
patch_imm_load_insns(ppc_inst_as_ulong(temp), 4, buff + TMPL_INSN_IDX);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 4. branch back from trampoline
|
* 4. branch back from trampoline
|
||||||
*/
|
*/
|
||||||
patch_branch((struct ppc_inst *)(buff + TMPL_RET_IDX), (unsigned long)nip, 0);
|
patch_branch(buff + TMPL_RET_IDX, nip, 0);
|
||||||
|
|
||||||
flush_icache_range((unsigned long)buff,
|
flush_icache_range((unsigned long)buff,
|
||||||
(unsigned long)(&buff[TMPL_END_IDX]));
|
(unsigned long)(&buff[TMPL_END_IDX]));
|
||||||
|
@ -317,10 +309,9 @@ void arch_optimize_kprobes(struct list_head *oplist)
|
||||||
*/
|
*/
|
||||||
memcpy(op->optinsn.copied_insn, op->kp.addr,
|
memcpy(op->optinsn.copied_insn, op->kp.addr,
|
||||||
RELATIVEJUMP_SIZE);
|
RELATIVEJUMP_SIZE);
|
||||||
create_branch(&instr,
|
create_branch(&instr, op->kp.addr,
|
||||||
(struct ppc_inst *)op->kp.addr,
|
|
||||||
(unsigned long)op->optinsn.insn, 0);
|
(unsigned long)op->optinsn.insn, 0);
|
||||||
patch_instruction((struct ppc_inst *)op->kp.addr, instr);
|
patch_instruction(op->kp.addr, instr);
|
||||||
list_del_init(&op->list);
|
list_del_init(&op->list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ EXPORT_SYMBOL(DMA_MODE_WRITE);
|
||||||
*/
|
*/
|
||||||
notrace void __init machine_init(u64 dt_ptr)
|
notrace void __init machine_init(u64 dt_ptr)
|
||||||
{
|
{
|
||||||
struct ppc_inst *addr = (struct ppc_inst *)patch_site_addr(&patch__memset_nocache);
|
u32 *addr = (u32 *)patch_site_addr(&patch__memset_nocache);
|
||||||
struct ppc_inst insn;
|
struct ppc_inst insn;
|
||||||
|
|
||||||
/* Configure static keys first, now that we're relocated. */
|
/* Configure static keys first, now that we're relocated. */
|
||||||
|
|
|
@ -49,7 +49,7 @@ ftrace_call_replace(unsigned long ip, unsigned long addr, int link)
|
||||||
addr = ppc_function_entry((void *)addr);
|
addr = ppc_function_entry((void *)addr);
|
||||||
|
|
||||||
/* if (link) set op to 'bl' else 'b' */
|
/* if (link) set op to 'bl' else 'b' */
|
||||||
create_branch(&op, (struct ppc_inst *)ip, addr, link ? 1 : 0);
|
create_branch(&op, (u32 *)ip, addr, link ? 1 : 0);
|
||||||
|
|
||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ ftrace_modify_code(unsigned long ip, struct ppc_inst old, struct ppc_inst new)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* replace the text with the new text */
|
/* replace the text with the new text */
|
||||||
if (patch_instruction((struct ppc_inst *)ip, new))
|
if (patch_instruction((u32 *)ip, new))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -94,7 +94,7 @@ static int test_24bit_addr(unsigned long ip, unsigned long addr)
|
||||||
addr = ppc_function_entry((void *)addr);
|
addr = ppc_function_entry((void *)addr);
|
||||||
|
|
||||||
/* use the create_branch to verify that this offset can be branched */
|
/* use the create_branch to verify that this offset can be branched */
|
||||||
return create_branch(&op, (struct ppc_inst *)ip, addr, 0) == 0;
|
return create_branch(&op, (u32 *)ip, addr, 0) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_bl_op(struct ppc_inst op)
|
static int is_bl_op(struct ppc_inst op)
|
||||||
|
@ -208,7 +208,7 @@ __ftrace_make_nop(struct module *mod,
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_MPROFILE_KERNEL */
|
#endif /* CONFIG_MPROFILE_KERNEL */
|
||||||
|
|
||||||
if (patch_instruction((struct ppc_inst *)ip, pop)) {
|
if (patch_instruction((u32 *)ip, pop)) {
|
||||||
pr_err("Patching NOP failed.\n");
|
pr_err("Patching NOP failed.\n");
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
|
@ -280,7 +280,7 @@ __ftrace_make_nop(struct module *mod,
|
||||||
|
|
||||||
op = ppc_inst(PPC_RAW_NOP());
|
op = ppc_inst(PPC_RAW_NOP());
|
||||||
|
|
||||||
if (patch_instruction((struct ppc_inst *)ip, op))
|
if (patch_instruction((u32 *)ip, op))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -380,7 +380,7 @@ static int setup_mcount_compiler_tramp(unsigned long tramp)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (patch_branch((struct ppc_inst *)tramp, ptr, 0)) {
|
if (patch_branch((u32 *)tramp, ptr, 0)) {
|
||||||
pr_debug("REL24 out of range!\n");
|
pr_debug("REL24 out of range!\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -424,7 +424,7 @@ static int __ftrace_make_nop_kernel(struct dyn_ftrace *rec, unsigned long addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (patch_instruction((struct ppc_inst *)ip, ppc_inst(PPC_RAW_NOP()))) {
|
if (patch_instruction((u32 *)ip, ppc_inst(PPC_RAW_NOP()))) {
|
||||||
pr_err("Patching NOP failed.\n");
|
pr_err("Patching NOP failed.\n");
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
|
@ -589,10 +589,10 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct ppc_inst op;
|
struct ppc_inst op;
|
||||||
unsigned long ip = rec->ip;
|
u32 *ip = (u32 *)rec->ip;
|
||||||
|
|
||||||
/* read where this goes */
|
/* read where this goes */
|
||||||
if (copy_inst_from_kernel_nofault(&op, (void *)ip))
|
if (copy_inst_from_kernel_nofault(&op, ip))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
/* It should be pointing to a nop */
|
/* It should be pointing to a nop */
|
||||||
|
@ -608,8 +608,7 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create the branch to the trampoline */
|
/* create the branch to the trampoline */
|
||||||
err = create_branch(&op, (struct ppc_inst *)ip,
|
err = create_branch(&op, ip, rec->arch.mod->arch.tramp, BRANCH_SET_LINK);
|
||||||
rec->arch.mod->arch.tramp, BRANCH_SET_LINK);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_err("REL24 out of range!\n");
|
pr_err("REL24 out of range!\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -617,7 +616,7 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
|
||||||
|
|
||||||
pr_devel("write to %lx\n", rec->ip);
|
pr_devel("write to %lx\n", rec->ip);
|
||||||
|
|
||||||
if (patch_instruction((struct ppc_inst *)ip, op))
|
if (patch_instruction(ip, op))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -762,7 +761,7 @@ __ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
|
||||||
/* The new target may be within range */
|
/* The new target may be within range */
|
||||||
if (test_24bit_addr(ip, addr)) {
|
if (test_24bit_addr(ip, addr)) {
|
||||||
/* within range */
|
/* within range */
|
||||||
if (patch_branch((struct ppc_inst *)ip, addr, BRANCH_SET_LINK)) {
|
if (patch_branch((u32 *)ip, addr, BRANCH_SET_LINK)) {
|
||||||
pr_err("REL24 out of range!\n");
|
pr_err("REL24 out of range!\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -790,12 +789,12 @@ __ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure branch is within 24 bits */
|
/* Ensure branch is within 24 bits */
|
||||||
if (create_branch(&op, (struct ppc_inst *)ip, tramp, BRANCH_SET_LINK)) {
|
if (create_branch(&op, (u32 *)ip, tramp, BRANCH_SET_LINK)) {
|
||||||
pr_err("Branch out of range\n");
|
pr_err("Branch out of range\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (patch_branch((struct ppc_inst *)ip, tramp, BRANCH_SET_LINK)) {
|
if (patch_branch((u32 *)ip, tramp, BRANCH_SET_LINK)) {
|
||||||
pr_err("REL24 out of range!\n");
|
pr_err("REL24 out of range!\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -851,7 +850,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 = ppc_inst_read((struct ppc_inst *)&ftrace_call);
|
old = ppc_inst_read((u32 *)&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);
|
||||||
|
|
||||||
|
@ -859,7 +858,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 = ppc_inst_read((struct ppc_inst *)&ftrace_regs_call);
|
old = ppc_inst_read((u32 *)&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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (cpu_has_feature(CPU_FTR_ARCH_31) &&
|
if (cpu_has_feature(CPU_FTR_ARCH_31) &&
|
||||||
ppc_inst_prefixed(ppc_inst_read(&auprobe->insn)) &&
|
ppc_inst_prefixed(ppc_inst_read(auprobe->insn)) &&
|
||||||
(addr & 0x3f) == 60) {
|
(addr & 0x3f) == 60) {
|
||||||
pr_info_ratelimited("Cannot register a uprobe on 64 byte unaligned prefixed instruction\n");
|
pr_info_ratelimited("Cannot register a uprobe on 64 byte unaligned prefixed instruction\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -119,7 +119,7 @@ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
|
||||||
* support doesn't exist and have to fix-up the next instruction
|
* support doesn't exist and have to fix-up the next instruction
|
||||||
* to be executed.
|
* to be executed.
|
||||||
*/
|
*/
|
||||||
regs->nip = (unsigned long)ppc_inst_next((void *)utask->vaddr, &auprobe->insn);
|
regs->nip = (unsigned long)ppc_inst_next((void *)utask->vaddr, auprobe->insn);
|
||||||
|
|
||||||
user_disable_single_step(current);
|
user_disable_single_step(current);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -182,7 +182,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, ppc_inst_read(&auprobe->insn));
|
ret = emulate_step(regs, ppc_inst_read(auprobe->insn));
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,7 @@
|
||||||
#include <asm/setup.h>
|
#include <asm/setup.h>
|
||||||
#include <asm/inst.h>
|
#include <asm/inst.h>
|
||||||
|
|
||||||
static int __patch_instruction(struct ppc_inst *exec_addr, struct ppc_inst instr,
|
static int __patch_instruction(u32 *exec_addr, struct ppc_inst instr, u32 *patch_addr)
|
||||||
struct ppc_inst *patch_addr)
|
|
||||||
{
|
{
|
||||||
if (!ppc_inst_prefixed(instr)) {
|
if (!ppc_inst_prefixed(instr)) {
|
||||||
u32 val = ppc_inst_val(instr);
|
u32 val = ppc_inst_val(instr);
|
||||||
|
@ -40,7 +39,7 @@ failed:
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int raw_patch_instruction(struct ppc_inst *addr, struct ppc_inst instr)
|
int raw_patch_instruction(u32 *addr, struct ppc_inst instr)
|
||||||
{
|
{
|
||||||
return __patch_instruction(addr, instr, addr);
|
return __patch_instruction(addr, instr, addr);
|
||||||
}
|
}
|
||||||
|
@ -148,10 +147,10 @@ static inline int unmap_patch_area(unsigned long addr)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_patch_instruction(struct ppc_inst *addr, struct ppc_inst instr)
|
static int do_patch_instruction(u32 *addr, struct ppc_inst instr)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct ppc_inst *patch_addr = NULL;
|
u32 *patch_addr = NULL;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned long text_poke_addr;
|
unsigned long text_poke_addr;
|
||||||
unsigned long kaddr = (unsigned long)addr;
|
unsigned long kaddr = (unsigned long)addr;
|
||||||
|
@ -172,7 +171,7 @@ static int do_patch_instruction(struct ppc_inst *addr, struct ppc_inst instr)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
patch_addr = (struct ppc_inst *)(text_poke_addr + (kaddr & ~PAGE_MASK));
|
patch_addr = (u32 *)(text_poke_addr + (kaddr & ~PAGE_MASK));
|
||||||
|
|
||||||
__patch_instruction(addr, instr, patch_addr);
|
__patch_instruction(addr, instr, patch_addr);
|
||||||
|
|
||||||
|
@ -187,14 +186,14 @@ out:
|
||||||
}
|
}
|
||||||
#else /* !CONFIG_STRICT_KERNEL_RWX */
|
#else /* !CONFIG_STRICT_KERNEL_RWX */
|
||||||
|
|
||||||
static int do_patch_instruction(struct ppc_inst *addr, struct ppc_inst instr)
|
static int do_patch_instruction(u32 *addr, struct ppc_inst instr)
|
||||||
{
|
{
|
||||||
return raw_patch_instruction(addr, instr);
|
return raw_patch_instruction(addr, instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_STRICT_KERNEL_RWX */
|
#endif /* CONFIG_STRICT_KERNEL_RWX */
|
||||||
|
|
||||||
int patch_instruction(struct ppc_inst *addr, struct ppc_inst instr)
|
int patch_instruction(u32 *addr, struct ppc_inst instr)
|
||||||
{
|
{
|
||||||
/* Make sure we aren't patching a freed init section */
|
/* Make sure we aren't patching a freed init section */
|
||||||
if (init_mem_is_free && init_section_contains(addr, 4)) {
|
if (init_mem_is_free && init_section_contains(addr, 4)) {
|
||||||
|
@ -205,7 +204,7 @@ int patch_instruction(struct ppc_inst *addr, struct ppc_inst instr)
|
||||||
}
|
}
|
||||||
NOKPROBE_SYMBOL(patch_instruction);
|
NOKPROBE_SYMBOL(patch_instruction);
|
||||||
|
|
||||||
int patch_branch(struct ppc_inst *addr, unsigned long target, int flags)
|
int patch_branch(u32 *addr, unsigned long target, int flags)
|
||||||
{
|
{
|
||||||
struct ppc_inst instr;
|
struct ppc_inst instr;
|
||||||
|
|
||||||
|
@ -257,8 +256,7 @@ bool is_conditional_branch(struct ppc_inst instr)
|
||||||
}
|
}
|
||||||
NOKPROBE_SYMBOL(is_conditional_branch);
|
NOKPROBE_SYMBOL(is_conditional_branch);
|
||||||
|
|
||||||
int create_branch(struct ppc_inst *instr,
|
int create_branch(struct ppc_inst *instr, const u32 *addr,
|
||||||
const struct ppc_inst *addr,
|
|
||||||
unsigned long target, int flags)
|
unsigned long target, int flags)
|
||||||
{
|
{
|
||||||
long offset;
|
long offset;
|
||||||
|
@ -278,7 +276,7 @@ int create_branch(struct ppc_inst *instr,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_cond_branch(struct ppc_inst *instr, const struct ppc_inst *addr,
|
int create_cond_branch(struct ppc_inst *instr, const u32 *addr,
|
||||||
unsigned long target, int flags)
|
unsigned long target, int flags)
|
||||||
{
|
{
|
||||||
long offset;
|
long offset;
|
||||||
|
@ -325,7 +323,7 @@ int instr_is_relative_link_branch(struct ppc_inst instr)
|
||||||
return instr_is_relative_branch(instr) && (ppc_inst_val(instr) & BRANCH_SET_LINK);
|
return instr_is_relative_branch(instr) && (ppc_inst_val(instr) & BRANCH_SET_LINK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long branch_iform_target(const struct ppc_inst *instr)
|
static unsigned long branch_iform_target(const u32 *instr)
|
||||||
{
|
{
|
||||||
signed long imm;
|
signed long imm;
|
||||||
|
|
||||||
|
@ -341,7 +339,7 @@ static unsigned long branch_iform_target(const struct ppc_inst *instr)
|
||||||
return (unsigned long)imm;
|
return (unsigned long)imm;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long branch_bform_target(const struct ppc_inst *instr)
|
static unsigned long branch_bform_target(const u32 *instr)
|
||||||
{
|
{
|
||||||
signed long imm;
|
signed long imm;
|
||||||
|
|
||||||
|
@ -357,7 +355,7 @@ static unsigned long branch_bform_target(const struct ppc_inst *instr)
|
||||||
return (unsigned long)imm;
|
return (unsigned long)imm;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long branch_target(const struct ppc_inst *instr)
|
unsigned long branch_target(const u32 *instr)
|
||||||
{
|
{
|
||||||
if (instr_is_branch_iform(ppc_inst_read(instr)))
|
if (instr_is_branch_iform(ppc_inst_read(instr)))
|
||||||
return branch_iform_target(instr);
|
return branch_iform_target(instr);
|
||||||
|
@ -367,8 +365,7 @@ unsigned long branch_target(const struct ppc_inst *instr)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int translate_branch(struct ppc_inst *instr, const struct ppc_inst *dest,
|
int translate_branch(struct ppc_inst *instr, const u32 *dest, const u32 *src)
|
||||||
const struct ppc_inst *src)
|
|
||||||
{
|
{
|
||||||
unsigned long target;
|
unsigned long target;
|
||||||
target = branch_target(src);
|
target = branch_target(src);
|
||||||
|
@ -395,13 +392,13 @@ void __patch_exception(int exc, unsigned long addr)
|
||||||
* instruction of the exception, not the first one
|
* instruction of the exception, not the first one
|
||||||
*/
|
*/
|
||||||
|
|
||||||
patch_branch((struct ppc_inst *)(ibase + (exc / 4) + 1), addr, 0);
|
patch_branch(ibase + (exc / 4) + 1, addr, 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_CODE_PATCHING_SELFTEST
|
#ifdef CONFIG_CODE_PATCHING_SELFTEST
|
||||||
|
|
||||||
static int instr_is_branch_to_addr(const struct ppc_inst *instr, unsigned long addr)
|
static int instr_is_branch_to_addr(const u32 *instr, unsigned long addr)
|
||||||
{
|
{
|
||||||
if (instr_is_branch_iform(ppc_inst_read(instr)) ||
|
if (instr_is_branch_iform(ppc_inst_read(instr)) ||
|
||||||
instr_is_branch_bform(ppc_inst_read(instr)))
|
instr_is_branch_bform(ppc_inst_read(instr)))
|
||||||
|
@ -423,7 +420,7 @@ static void __init test_branch_iform(void)
|
||||||
int err;
|
int err;
|
||||||
struct ppc_inst instr;
|
struct ppc_inst instr;
|
||||||
u32 tmp[2];
|
u32 tmp[2];
|
||||||
struct ppc_inst *iptr = (struct ppc_inst *)tmp;
|
u32 *iptr = tmp;
|
||||||
unsigned long addr = (unsigned long)tmp;
|
unsigned long addr = (unsigned long)tmp;
|
||||||
|
|
||||||
/* The simplest case, branch to self, no flags */
|
/* The simplest case, branch to self, no flags */
|
||||||
|
@ -501,12 +498,12 @@ static void __init test_branch_iform(void)
|
||||||
|
|
||||||
static void __init test_create_function_call(void)
|
static void __init test_create_function_call(void)
|
||||||
{
|
{
|
||||||
struct ppc_inst *iptr;
|
u32 *iptr;
|
||||||
unsigned long dest;
|
unsigned long dest;
|
||||||
struct ppc_inst instr;
|
struct ppc_inst instr;
|
||||||
|
|
||||||
/* Check we can create a function call */
|
/* Check we can create a function call */
|
||||||
iptr = (struct ppc_inst *)ppc_function_entry(test_trampoline);
|
iptr = (u32 *)ppc_function_entry(test_trampoline);
|
||||||
dest = ppc_function_entry(test_create_function_call);
|
dest = ppc_function_entry(test_create_function_call);
|
||||||
create_branch(&instr, iptr, dest, BRANCH_SET_LINK);
|
create_branch(&instr, iptr, dest, BRANCH_SET_LINK);
|
||||||
patch_instruction(iptr, instr);
|
patch_instruction(iptr, instr);
|
||||||
|
@ -517,11 +514,11 @@ static void __init test_branch_bform(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
unsigned long addr;
|
unsigned long addr;
|
||||||
struct ppc_inst *iptr, instr;
|
struct ppc_inst instr;
|
||||||
u32 tmp[2];
|
u32 tmp[2];
|
||||||
|
u32 *iptr = tmp;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
|
|
||||||
iptr = (struct ppc_inst *)tmp;
|
|
||||||
addr = (unsigned long)iptr;
|
addr = (unsigned long)iptr;
|
||||||
|
|
||||||
/* The simplest case, branch to self, no flags */
|
/* The simplest case, branch to self, no flags */
|
||||||
|
@ -726,9 +723,9 @@ static void __init test_prefixed_patching(void)
|
||||||
extern unsigned int code_patching_test1_expected[];
|
extern unsigned int code_patching_test1_expected[];
|
||||||
extern unsigned int end_code_patching_test1[];
|
extern unsigned int end_code_patching_test1[];
|
||||||
|
|
||||||
__patch_instruction((struct ppc_inst *)code_patching_test1,
|
__patch_instruction(code_patching_test1,
|
||||||
ppc_inst_prefix(OP_PREFIX << 26, 0x00000000),
|
ppc_inst_prefix(OP_PREFIX << 26, 0x00000000),
|
||||||
(struct ppc_inst *)code_patching_test1);
|
code_patching_test1);
|
||||||
|
|
||||||
check(!memcmp(code_patching_test1,
|
check(!memcmp(code_patching_test1,
|
||||||
code_patching_test1_expected,
|
code_patching_test1_expected,
|
||||||
|
|
|
@ -33,18 +33,17 @@ struct fixup_entry {
|
||||||
long alt_end_off;
|
long alt_end_off;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ppc_inst *calc_addr(struct fixup_entry *fcur, long offset)
|
static u32 *calc_addr(struct fixup_entry *fcur, long offset)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We store the offset to the code as a negative offset from
|
* We store the offset to the code as a negative offset from
|
||||||
* the start of the alt_entry, to support the VDSO. This
|
* the start of the alt_entry, to support the VDSO. This
|
||||||
* routine converts that back into an actual address.
|
* routine converts that back into an actual address.
|
||||||
*/
|
*/
|
||||||
return (struct ppc_inst *)((unsigned long)fcur + offset);
|
return (u32 *)((unsigned long)fcur + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int patch_alt_instruction(struct ppc_inst *src, struct ppc_inst *dest,
|
static int patch_alt_instruction(u32 *src, u32 *dest, u32 *alt_start, u32 *alt_end)
|
||||||
struct ppc_inst *alt_start, struct ppc_inst *alt_end)
|
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct ppc_inst instr;
|
struct ppc_inst instr;
|
||||||
|
@ -52,7 +51,7 @@ static int patch_alt_instruction(struct ppc_inst *src, struct ppc_inst *dest,
|
||||||
instr = ppc_inst_read(src);
|
instr = ppc_inst_read(src);
|
||||||
|
|
||||||
if (instr_is_relative_branch(ppc_inst_read(src))) {
|
if (instr_is_relative_branch(ppc_inst_read(src))) {
|
||||||
struct ppc_inst *target = (struct ppc_inst *)branch_target(src);
|
u32 *target = (u32 *)branch_target(src);
|
||||||
|
|
||||||
/* Branch within the section doesn't need translating */
|
/* Branch within the section doesn't need translating */
|
||||||
if (target < alt_start || target > alt_end) {
|
if (target < alt_start || target > alt_end) {
|
||||||
|
@ -69,7 +68,7 @@ static int patch_alt_instruction(struct ppc_inst *src, struct ppc_inst *dest,
|
||||||
|
|
||||||
static int patch_feature_section(unsigned long value, struct fixup_entry *fcur)
|
static int patch_feature_section(unsigned long value, struct fixup_entry *fcur)
|
||||||
{
|
{
|
||||||
struct ppc_inst *start, *end, *alt_start, *alt_end, *src, *dest, nop;
|
u32 *start, *end, *alt_start, *alt_end, *src, *dest;
|
||||||
|
|
||||||
start = calc_addr(fcur, fcur->start_off);
|
start = calc_addr(fcur, fcur->start_off);
|
||||||
end = calc_addr(fcur, fcur->end_off);
|
end = calc_addr(fcur, fcur->end_off);
|
||||||
|
@ -91,9 +90,8 @@ static int patch_feature_section(unsigned long value, struct fixup_entry *fcur)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
nop = ppc_inst(PPC_RAW_NOP());
|
for (; dest < end; dest++)
|
||||||
for (; dest < end; dest = ppc_inst_next(dest, &nop))
|
raw_patch_instruction(dest, ppc_inst(PPC_RAW_NOP()));
|
||||||
raw_patch_instruction(dest, nop);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -152,14 +150,14 @@ static void do_stf_entry_barrier_fixups(enum stf_barrier_type types)
|
||||||
|
|
||||||
// See comment in do_entry_flush_fixups() RE order of patching
|
// See comment in do_entry_flush_fixups() RE order of patching
|
||||||
if (types & STF_BARRIER_FALLBACK) {
|
if (types & STF_BARRIER_FALLBACK) {
|
||||||
patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
|
patch_instruction(dest, ppc_inst(instrs[0]));
|
||||||
patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
|
patch_instruction(dest + 2, ppc_inst(instrs[2]));
|
||||||
patch_branch((struct ppc_inst *)(dest + 1),
|
patch_branch(dest + 1,
|
||||||
(unsigned long)&stf_barrier_fallback, BRANCH_SET_LINK);
|
(unsigned long)&stf_barrier_fallback, BRANCH_SET_LINK);
|
||||||
} else {
|
} else {
|
||||||
patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1]));
|
patch_instruction(dest + 1, ppc_inst(instrs[1]));
|
||||||
patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
|
patch_instruction(dest + 2, ppc_inst(instrs[2]));
|
||||||
patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
|
patch_instruction(dest, ppc_inst(instrs[0]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,12 +210,12 @@ static void do_stf_exit_barrier_fixups(enum stf_barrier_type types)
|
||||||
|
|
||||||
pr_devel("patching dest %lx\n", (unsigned long)dest);
|
pr_devel("patching dest %lx\n", (unsigned long)dest);
|
||||||
|
|
||||||
patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
|
patch_instruction(dest, ppc_inst(instrs[0]));
|
||||||
patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1]));
|
patch_instruction(dest + 1, ppc_inst(instrs[1]));
|
||||||
patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
|
patch_instruction(dest + 2, ppc_inst(instrs[2]));
|
||||||
patch_instruction((struct ppc_inst *)(dest + 3), ppc_inst(instrs[3]));
|
patch_instruction(dest + 3, ppc_inst(instrs[3]));
|
||||||
patch_instruction((struct ppc_inst *)(dest + 4), ppc_inst(instrs[4]));
|
patch_instruction(dest + 4, ppc_inst(instrs[4]));
|
||||||
patch_instruction((struct ppc_inst *)(dest + 5), ppc_inst(instrs[5]));
|
patch_instruction(dest + 5, ppc_inst(instrs[5]));
|
||||||
}
|
}
|
||||||
printk(KERN_DEBUG "stf-barrier: patched %d exit locations (%s barrier)\n", i,
|
printk(KERN_DEBUG "stf-barrier: patched %d exit locations (%s barrier)\n", i,
|
||||||
(types == STF_BARRIER_NONE) ? "no" :
|
(types == STF_BARRIER_NONE) ? "no" :
|
||||||
|
@ -281,11 +279,11 @@ void do_uaccess_flush_fixups(enum l1d_flush_type types)
|
||||||
|
|
||||||
pr_devel("patching dest %lx\n", (unsigned long)dest);
|
pr_devel("patching dest %lx\n", (unsigned long)dest);
|
||||||
|
|
||||||
patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
|
patch_instruction(dest, ppc_inst(instrs[0]));
|
||||||
|
|
||||||
patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1]));
|
patch_instruction(dest + 1, ppc_inst(instrs[1]));
|
||||||
patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
|
patch_instruction(dest + 2, ppc_inst(instrs[2]));
|
||||||
patch_instruction((struct ppc_inst *)(dest + 3), ppc_inst(instrs[3]));
|
patch_instruction(dest + 3, ppc_inst(instrs[3]));
|
||||||
}
|
}
|
||||||
|
|
||||||
printk(KERN_DEBUG "uaccess-flush: patched %d locations (%s flush)\n", i,
|
printk(KERN_DEBUG "uaccess-flush: patched %d locations (%s flush)\n", i,
|
||||||
|
@ -357,14 +355,14 @@ static int __do_entry_flush_fixups(void *data)
|
||||||
pr_devel("patching dest %lx\n", (unsigned long)dest);
|
pr_devel("patching dest %lx\n", (unsigned long)dest);
|
||||||
|
|
||||||
if (types == L1D_FLUSH_FALLBACK) {
|
if (types == L1D_FLUSH_FALLBACK) {
|
||||||
patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
|
patch_instruction(dest, ppc_inst(instrs[0]));
|
||||||
patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
|
patch_instruction(dest + 2, ppc_inst(instrs[2]));
|
||||||
patch_branch((struct ppc_inst *)(dest + 1),
|
patch_branch(dest + 1,
|
||||||
(unsigned long)&entry_flush_fallback, BRANCH_SET_LINK);
|
(unsigned long)&entry_flush_fallback, BRANCH_SET_LINK);
|
||||||
} else {
|
} else {
|
||||||
patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1]));
|
patch_instruction(dest + 1, ppc_inst(instrs[1]));
|
||||||
patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
|
patch_instruction(dest + 2, ppc_inst(instrs[2]));
|
||||||
patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
|
patch_instruction(dest, ppc_inst(instrs[0]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,14 +374,14 @@ static int __do_entry_flush_fixups(void *data)
|
||||||
pr_devel("patching dest %lx\n", (unsigned long)dest);
|
pr_devel("patching dest %lx\n", (unsigned long)dest);
|
||||||
|
|
||||||
if (types == L1D_FLUSH_FALLBACK) {
|
if (types == L1D_FLUSH_FALLBACK) {
|
||||||
patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
|
patch_instruction(dest, ppc_inst(instrs[0]));
|
||||||
patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
|
patch_instruction(dest + 2, ppc_inst(instrs[2]));
|
||||||
patch_branch((struct ppc_inst *)(dest + 1),
|
patch_branch(dest + 1,
|
||||||
(unsigned long)&scv_entry_flush_fallback, BRANCH_SET_LINK);
|
(unsigned long)&scv_entry_flush_fallback, BRANCH_SET_LINK);
|
||||||
} else {
|
} else {
|
||||||
patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1]));
|
patch_instruction(dest + 1, ppc_inst(instrs[1]));
|
||||||
patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
|
patch_instruction(dest + 2, ppc_inst(instrs[2]));
|
||||||
patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
|
patch_instruction(dest, ppc_inst(instrs[0]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,9 +440,9 @@ void do_rfi_flush_fixups(enum l1d_flush_type types)
|
||||||
|
|
||||||
pr_devel("patching dest %lx\n", (unsigned long)dest);
|
pr_devel("patching dest %lx\n", (unsigned long)dest);
|
||||||
|
|
||||||
patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
|
patch_instruction(dest, ppc_inst(instrs[0]));
|
||||||
patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1]));
|
patch_instruction(dest + 1, ppc_inst(instrs[1]));
|
||||||
patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
|
patch_instruction(dest + 2, ppc_inst(instrs[2]));
|
||||||
}
|
}
|
||||||
|
|
||||||
printk(KERN_DEBUG "rfi-flush: patched %d locations (%s flush)\n", i,
|
printk(KERN_DEBUG "rfi-flush: patched %d locations (%s flush)\n", i,
|
||||||
|
@ -477,7 +475,7 @@ void do_barrier_nospec_fixups_range(bool enable, void *fixup_start, void *fixup_
|
||||||
dest = (void *)start + *start;
|
dest = (void *)start + *start;
|
||||||
|
|
||||||
pr_devel("patching dest %lx\n", (unsigned long)dest);
|
pr_devel("patching dest %lx\n", (unsigned long)dest);
|
||||||
patch_instruction((struct ppc_inst *)dest, ppc_inst(instr));
|
patch_instruction(dest, ppc_inst(instr));
|
||||||
}
|
}
|
||||||
|
|
||||||
printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i);
|
printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i);
|
||||||
|
@ -520,8 +518,8 @@ void do_barrier_nospec_fixups_range(bool enable, void *fixup_start, void *fixup_
|
||||||
dest = (void *)start + *start;
|
dest = (void *)start + *start;
|
||||||
|
|
||||||
pr_devel("patching dest %lx\n", (unsigned long)dest);
|
pr_devel("patching dest %lx\n", (unsigned long)dest);
|
||||||
patch_instruction((struct ppc_inst *)dest, ppc_inst(instr[0]));
|
patch_instruction(dest, ppc_inst(instr[0]));
|
||||||
patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instr[1]));
|
patch_instruction(dest + 1, ppc_inst(instr[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i);
|
printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i);
|
||||||
|
@ -535,7 +533,7 @@ static void patch_btb_flush_section(long *curr)
|
||||||
end = (void *)curr + *(curr + 1);
|
end = (void *)curr + *(curr + 1);
|
||||||
for (; start < end; start++) {
|
for (; start < end; start++) {
|
||||||
pr_devel("patching dest %lx\n", (unsigned long)start);
|
pr_devel("patching dest %lx\n", (unsigned long)start);
|
||||||
patch_instruction((struct ppc_inst *)start, ppc_inst(PPC_RAW_NOP()));
|
patch_instruction(start, ppc_inst(PPC_RAW_NOP()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,7 +552,7 @@ void do_btb_flush_fixups(void)
|
||||||
void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end)
|
void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end)
|
||||||
{
|
{
|
||||||
long *start, *end;
|
long *start, *end;
|
||||||
struct ppc_inst *dest;
|
u32 *dest;
|
||||||
|
|
||||||
if (!(value & CPU_FTR_LWSYNC))
|
if (!(value & CPU_FTR_LWSYNC))
|
||||||
return ;
|
return ;
|
||||||
|
@ -571,13 +569,14 @@ void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end)
|
||||||
static void do_final_fixups(void)
|
static void do_final_fixups(void)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_PPC64) && defined(CONFIG_RELOCATABLE)
|
#if defined(CONFIG_PPC64) && defined(CONFIG_RELOCATABLE)
|
||||||
struct ppc_inst inst, *src, *dest, *end;
|
struct ppc_inst inst;
|
||||||
|
u32 *src, *dest, *end;
|
||||||
|
|
||||||
if (PHYSICAL_START == 0)
|
if (PHYSICAL_START == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
src = (struct ppc_inst *)(KERNELBASE + PHYSICAL_START);
|
src = (u32 *)(KERNELBASE + PHYSICAL_START);
|
||||||
dest = (struct ppc_inst *)KERNELBASE;
|
dest = (u32 *)KERNELBASE;
|
||||||
end = (void *)src + (__end_interrupts - _stext);
|
end = (void *)src + (__end_interrupts - _stext);
|
||||||
|
|
||||||
while (src < end) {
|
while (src < end) {
|
||||||
|
|
|
@ -12,7 +12,7 @@ bool copy_from_kernel_nofault_allowed(const void *unsafe_src, size_t size)
|
||||||
return is_kernel_addr((unsigned long)unsafe_src);
|
return is_kernel_addr((unsigned long)unsafe_src);
|
||||||
}
|
}
|
||||||
|
|
||||||
int copy_inst_from_kernel_nofault(struct ppc_inst *inst, struct ppc_inst *src)
|
int copy_inst_from_kernel_nofault(struct ppc_inst *inst, u32 *src)
|
||||||
{
|
{
|
||||||
unsigned int val, suffix;
|
unsigned int val, suffix;
|
||||||
int err;
|
int err;
|
||||||
|
@ -21,7 +21,7 @@ int copy_inst_from_kernel_nofault(struct ppc_inst *inst, struct ppc_inst *src)
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
if (IS_ENABLED(CONFIG_PPC64) && get_op(val) == OP_PREFIX) {
|
if (IS_ENABLED(CONFIG_PPC64) && get_op(val) == OP_PREFIX) {
|
||||||
err = copy_from_kernel_nofault(&suffix, (void *)src + 4, 4);
|
err = copy_from_kernel_nofault(&suffix, src + 1, sizeof(suffix));
|
||||||
*inst = ppc_inst_prefix(val, suffix);
|
*inst = ppc_inst_prefix(val, suffix);
|
||||||
} else {
|
} else {
|
||||||
*inst = ppc_inst(val);
|
*inst = ppc_inst(val);
|
||||||
|
|
|
@ -460,7 +460,7 @@ static __u64 power_pmu_bhrb_to(u64 addr)
|
||||||
sizeof(instr)))
|
sizeof(instr)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return branch_target((struct ppc_inst *)&instr);
|
return branch_target(&instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Userspace: need copy instruction here then translate it */
|
/* Userspace: need copy instruction here then translate it */
|
||||||
|
@ -468,7 +468,7 @@ static __u64 power_pmu_bhrb_to(u64 addr)
|
||||||
sizeof(instr)))
|
sizeof(instr)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
target = branch_target((struct ppc_inst *)&instr);
|
target = branch_target(&instr);
|
||||||
if ((!target) || (instr & BRANCH_ABSOLUTE))
|
if ((!target) || (instr & BRANCH_ABSOLUTE))
|
||||||
return target;
|
return target;
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ smp_86xx_kick_cpu(int nr)
|
||||||
|
|
||||||
/* Setup fake reset vector to call __secondary_start_mpc86xx. */
|
/* Setup fake reset vector to call __secondary_start_mpc86xx. */
|
||||||
target = (unsigned long) __secondary_start_mpc86xx;
|
target = (unsigned long) __secondary_start_mpc86xx;
|
||||||
patch_branch((struct ppc_inst *)vector, target, BRANCH_SET_LINK);
|
patch_branch(vector, target, BRANCH_SET_LINK);
|
||||||
|
|
||||||
/* Kick that CPU */
|
/* Kick that CPU */
|
||||||
smp_86xx_release_core(nr);
|
smp_86xx_release_core(nr);
|
||||||
|
@ -83,7 +83,7 @@ smp_86xx_kick_cpu(int nr)
|
||||||
mdelay(1);
|
mdelay(1);
|
||||||
|
|
||||||
/* Restore the exception vector */
|
/* Restore the exception vector */
|
||||||
patch_instruction((struct ppc_inst *)vector, ppc_inst(save_vector));
|
patch_instruction(vector, ppc_inst(save_vector));
|
||||||
|
|
||||||
local_irq_restore(flags);
|
local_irq_restore(flags);
|
||||||
|
|
||||||
|
|
|
@ -810,7 +810,7 @@ static int smp_core99_kick_cpu(int nr)
|
||||||
* b __secondary_start_pmac_0 + nr*8
|
* b __secondary_start_pmac_0 + nr*8
|
||||||
*/
|
*/
|
||||||
target = (unsigned long) __secondary_start_pmac_0 + nr * 8;
|
target = (unsigned long) __secondary_start_pmac_0 + nr * 8;
|
||||||
patch_branch((struct ppc_inst *)vector, target, BRANCH_SET_LINK);
|
patch_branch(vector, target, BRANCH_SET_LINK);
|
||||||
|
|
||||||
/* Put some life in our friend */
|
/* Put some life in our friend */
|
||||||
pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0);
|
pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0);
|
||||||
|
@ -823,7 +823,7 @@ static int smp_core99_kick_cpu(int nr)
|
||||||
mdelay(1);
|
mdelay(1);
|
||||||
|
|
||||||
/* Restore our exception vector */
|
/* Restore our exception vector */
|
||||||
patch_instruction((struct ppc_inst *)vector, ppc_inst(save_vector));
|
patch_instruction(vector, ppc_inst(save_vector));
|
||||||
|
|
||||||
local_irq_restore(flags);
|
local_irq_restore(flags);
|
||||||
if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347);
|
if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347);
|
||||||
|
|
|
@ -100,7 +100,7 @@ static long *xmon_fault_jmp[NR_CPUS];
|
||||||
/* Breakpoint stuff */
|
/* Breakpoint stuff */
|
||||||
struct bpt {
|
struct bpt {
|
||||||
unsigned long address;
|
unsigned long address;
|
||||||
struct ppc_inst *instr;
|
u32 *instr;
|
||||||
atomic_t ref_count;
|
atomic_t ref_count;
|
||||||
int enabled;
|
int enabled;
|
||||||
unsigned long pad;
|
unsigned long pad;
|
||||||
|
@ -946,11 +946,11 @@ static void insert_bpts(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
patch_instruction(bp->instr, instr);
|
patch_instruction(bp->instr, instr);
|
||||||
patch_instruction(ppc_inst_next(bp->instr, &instr),
|
patch_instruction(ppc_inst_next(bp->instr, bp->instr),
|
||||||
ppc_inst(bpinstr));
|
ppc_inst(bpinstr));
|
||||||
if (bp->enabled & BP_CIABR)
|
if (bp->enabled & BP_CIABR)
|
||||||
continue;
|
continue;
|
||||||
if (patch_instruction((struct ppc_inst *)bp->address,
|
if (patch_instruction((u32 *)bp->address,
|
||||||
ppc_inst(bpinstr)) != 0) {
|
ppc_inst(bpinstr)) != 0) {
|
||||||
printf("Couldn't write instruction at %lx, "
|
printf("Couldn't write instruction at %lx, "
|
||||||
"disabling breakpoint there\n", bp->address);
|
"disabling breakpoint there\n", bp->address);
|
||||||
|
@ -992,7 +992,7 @@ static void remove_bpts(void)
|
||||||
if (mread_instr(bp->address, &instr)
|
if (mread_instr(bp->address, &instr)
|
||||||
&& ppc_inst_equal(instr, ppc_inst(bpinstr))
|
&& ppc_inst_equal(instr, ppc_inst(bpinstr))
|
||||||
&& patch_instruction(
|
&& patch_instruction(
|
||||||
(struct ppc_inst *)bp->address, ppc_inst_read(bp->instr)) != 0)
|
(u32 *)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);
|
||||||
}
|
}
|
||||||
|
@ -2214,7 +2214,7 @@ mread_instr(unsigned long adrs, struct ppc_inst *instr)
|
||||||
if (setjmp(bus_error_jmp) == 0) {
|
if (setjmp(bus_error_jmp) == 0) {
|
||||||
catch_memory_errors = 1;
|
catch_memory_errors = 1;
|
||||||
sync();
|
sync();
|
||||||
*instr = ppc_inst_read((struct ppc_inst *)adrs);
|
*instr = ppc_inst_read((u32 *)adrs);
|
||||||
sync();
|
sync();
|
||||||
/* wait a little while to see if we get a machine check */
|
/* wait a little while to see if we get a machine check */
|
||||||
__delay(200);
|
__delay(200);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче