Commit ebfa50df authored by Anju T's avatar Anju T Committed by Michael Ellerman

powerpc: Add helper to check if offset is within relative branch range

To permit the use of relative branch instruction in powerpc, the target
address has to be relatively nearby, since the address is specified in an
immediate field (24 bit filed) in the instruction opcode itself. Here
nearby refers to 32MB on either side of the current instruction.

This patch verifies whether the target address is within +/- 32MB
range or not.
Signed-off-by: default avatarNaveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Signed-off-by: default avatarAnju T Sudhakar <anju@linux.vnet.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent c233f597
......@@ -22,6 +22,7 @@
#define BRANCH_SET_LINK 0x1
#define BRANCH_ABSOLUTE 0x2
bool is_offset_in_branch_range(long offset);
unsigned int create_branch(const unsigned int *addr,
unsigned long target, int flags);
unsigned int create_cond_branch(const unsigned int *addr,
......
......@@ -32,6 +32,28 @@ int patch_branch(unsigned int *addr, unsigned long target, int flags)
return patch_instruction(addr, create_branch(addr, target, flags));
}
bool is_offset_in_branch_range(long offset)
{
/*
* Powerpc branch instruction is :
*
* 0 6 30 31
* +---------+----------------+---+---+
* | opcode | LI |AA |LK |
* +---------+----------------+---+---+
* Where AA = 0 and LK = 0
*
* LI is a signed 24 bits integer. The real branch offset is computed
* by: imm32 = SignExtend(LI:'0b00', 32);
*
* So the maximum forward branch should be:
* (0x007fffff << 2) = 0x01fffffc = 0x1fffffc
* The maximum backward branch should be:
* (0xff800000 << 2) = 0xfe000000 = -0x2000000
*/
return (offset >= -0x2000000 && offset <= 0x1fffffc && !(offset & 0x3));
}
unsigned int create_branch(const unsigned int *addr,
unsigned long target, int flags)
{
......@@ -43,7 +65,7 @@ unsigned int create_branch(const unsigned int *addr,
offset = offset - (unsigned long)addr;
/* Check we can represent the target in the instruction format */
if (offset < -0x2000000 || offset > 0x1fffffc || offset & 0x3)
if (!is_offset_in_branch_range(offset))
return 0;
/* Mask out the flags and target, so they don't step on each other. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment