powerpc: Use a datatype for instructions
Currently unsigned ints are used to represent instructions on powerpc. This has worked well as instructions have always been 4 byte words. However, ISA v3.1 introduces some changes to instructions that mean this scheme will no longer work as well. This change is Prefixed Instructions. A prefixed instruction is made up of a word prefix followed by a word suffix to make an 8 byte double word instruction. No matter the endianness of the system the prefix always comes first. Prefixed instructions are only planned for powerpc64. Introduce a ppc_inst type to represent both prefixed and word instructions on powerpc64 while keeping it possible to exclusively have word instructions on powerpc32. Signed-off-by: Jordan Niethe <jniethe5@gmail.com> [mpe: Fix compile error in emulate_spe()] Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/20200506034050.24806-12-jniethe5@gmail.com
This commit is contained in:

committed by
Michael Ellerman

parent
217862d9b9
commit
94afd069d9
@@ -41,23 +41,23 @@
|
||||
#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:
|
||||
@@ -79,7 +79,7 @@ ftrace_modify_code(unsigned long ip, unsigned int old, unsigned int new)
|
||||
}
|
||||
|
||||
/* 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;
|
||||
@@ -90,24 +90,24 @@ ftrace_modify_code(unsigned long ip, unsigned int old, unsigned int new)
|
||||
*/
|
||||
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;
|
||||
|
||||
@@ -127,7 +127,7 @@ __ftrace_make_nop(struct module *mod,
|
||||
{
|
||||
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))) {
|
||||
@@ -208,7 +208,7 @@ __ftrace_make_nop(struct module *mod,
|
||||
}
|
||||
#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;
|
||||
}
|
||||
@@ -221,7 +221,7 @@ static int
|
||||
__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;
|
||||
@@ -280,7 +280,7 @@ __ftrace_make_nop(struct module *mod,
|
||||
|
||||
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;
|
||||
@@ -291,7 +291,7 @@ __ftrace_make_nop(struct module *mod,
|
||||
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
|
||||
@@ -328,9 +328,10 @@ static int add_ftrace_tramp(unsigned long tramp)
|
||||
*/
|
||||
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? */
|
||||
@@ -379,7 +380,7 @@ static int setup_mcount_compiler_tramp(unsigned long 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;
|
||||
}
|
||||
@@ -395,7 +396,7 @@ static int setup_mcount_compiler_tramp(unsigned long tramp)
|
||||
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))) {
|
||||
@@ -423,7 +424,7 @@ static int __ftrace_make_nop_kernel(struct dyn_ftrace *rec, unsigned long addr)
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -435,7 +436,7 @@ int ftrace_make_nop(struct module *mod,
|
||||
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,
|
||||
@@ -488,7 +489,7 @@ int ftrace_make_nop(struct module *mod,
|
||||
*/
|
||||
#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:
|
||||
@@ -506,7 +507,7 @@ expected_nop_sequence(void *ip, unsigned int op0, unsigned int op1)
|
||||
}
|
||||
#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)))
|
||||
@@ -518,8 +519,8 @@ expected_nop_sequence(void *ip, unsigned int op0, unsigned int op1)
|
||||
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;
|
||||
@@ -584,7 +585,7 @@ static int
|
||||
__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 */
|
||||
@@ -604,7 +605,7 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
|
||||
}
|
||||
|
||||
/* 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");
|
||||
@@ -613,7 +614,7 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
|
||||
|
||||
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;
|
||||
@@ -623,7 +624,7 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
|
||||
|
||||
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;
|
||||
|
||||
@@ -671,7 +672,7 @@ static int __ftrace_make_call_kernel(struct dyn_ftrace *rec, unsigned long addr)
|
||||
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,
|
||||
@@ -710,7 +711,7 @@ static int
|
||||
__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;
|
||||
@@ -758,7 +759,7 @@ __ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
|
||||
/* 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;
|
||||
}
|
||||
@@ -786,12 +787,12 @@ __ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
@@ -804,7 +805,7 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
|
||||
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,
|
||||
@@ -844,10 +845,10 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
|
||||
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);
|
||||
|
||||
@@ -855,7 +856,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
|
||||
/* Also update the regs callback function */
|
||||
if (!ret) {
|
||||
ip = (unsigned long)(&ftrace_regs_call);
|
||||
old = *(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);
|
||||
}
|
||||
@@ -929,7 +930,7 @@ int ftrace_enable_ftrace_graph_caller(void)
|
||||
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);
|
||||
@@ -942,7 +943,7 @@ int ftrace_disable_ftrace_graph_caller(void)
|
||||
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);
|
||||
|
Reference in New Issue
Block a user