Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 101717
b: refs/heads/master
c: 411781a
h: refs/heads/master
i:
  101715: 49b8dd5
v: v3
  • Loading branch information
Michael Ellerman authored and Paul Mackerras committed Jul 1, 2008
1 parent 7d760b5 commit 6086e0c
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 07630a37beefe8e4401c602f04e3e5bcbba50b31
refs/heads/master: 411781a290b0d0a31fd73826b3ee110f1e3cc3b6
107 changes: 107 additions & 0 deletions trunk/arch/powerpc/lib/code-patching.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,110 @@ unsigned int create_branch(const unsigned int *addr,

return instruction;
}

unsigned int create_cond_branch(const unsigned int *addr,
unsigned long target, int flags)
{
unsigned int instruction;
long offset;

offset = target;
if (! (flags & BRANCH_ABSOLUTE))
offset = offset - (unsigned long)addr;

/* Check we can represent the target in the instruction format */
if (offset < -0x8000 || offset > 0x7FFF || offset & 0x3)
return 0;

/* Mask out the flags and target, so they don't step on each other. */
instruction = 0x40000000 | (flags & 0x3FF0003) | (offset & 0xFFFC);

return instruction;
}

static unsigned int branch_opcode(unsigned int instr)
{
return (instr >> 26) & 0x3F;
}

static int instr_is_branch_iform(unsigned int instr)
{
return branch_opcode(instr) == 18;
}

static int instr_is_branch_bform(unsigned int instr)
{
return branch_opcode(instr) == 16;
}

int instr_is_relative_branch(unsigned int instr)
{
if (instr & BRANCH_ABSOLUTE)
return 0;

return instr_is_branch_iform(instr) || instr_is_branch_bform(instr);
}

static unsigned long branch_iform_target(const unsigned int *instr)
{
signed long imm;

imm = *instr & 0x3FFFFFC;

/* If the top bit of the immediate value is set this is negative */
if (imm & 0x2000000)
imm -= 0x4000000;

if ((*instr & BRANCH_ABSOLUTE) == 0)
imm += (unsigned long)instr;

return (unsigned long)imm;
}

static unsigned long branch_bform_target(const unsigned int *instr)
{
signed long imm;

imm = *instr & 0xFFFC;

/* If the top bit of the immediate value is set this is negative */
if (imm & 0x8000)
imm -= 0x10000;

if ((*instr & BRANCH_ABSOLUTE) == 0)
imm += (unsigned long)instr;

return (unsigned long)imm;
}

unsigned long branch_target(const unsigned int *instr)
{
if (instr_is_branch_iform(*instr))
return branch_iform_target(instr);
else if (instr_is_branch_bform(*instr))
return branch_bform_target(instr);

return 0;
}

int instr_is_branch_to_addr(const unsigned int *instr, unsigned long addr)
{
if (instr_is_branch_iform(*instr) || instr_is_branch_bform(*instr))
return branch_target(instr) == addr;

return 0;
}

unsigned int translate_branch(const unsigned int *dest, const unsigned int *src)
{
unsigned long target;

target = branch_target(src);

if (instr_is_branch_iform(*src))
return create_branch(dest, target, *src);
else if (instr_is_branch_bform(*src))
return create_cond_branch(dest, target, *src);

return 0;
}
8 changes: 8 additions & 0 deletions trunk/include/asm-powerpc/code-patching.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,17 @@

unsigned int create_branch(const unsigned int *addr,
unsigned long target, int flags);
unsigned int create_cond_branch(const unsigned int *addr,
unsigned long target, int flags);
void patch_branch(unsigned int *addr, unsigned long target, int flags);
void patch_instruction(unsigned int *addr, unsigned int instr);

int instr_is_relative_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);
unsigned int translate_branch(const unsigned int *dest,
const unsigned int *src);

static inline unsigned long ppc_function_entry(void *func)
{
#ifdef CONFIG_PPC64
Expand Down

0 comments on commit 6086e0c

Please sign in to comment.