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:
Jordan Niethe
2020-05-06 13:40:31 +10:00
committed by Michael Ellerman
parent 217862d9b9
commit 94afd069d9
26 changed files with 237 additions and 214 deletions

View File

@@ -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);