Files
banban/ql-config/soc_platform/preboot_boot2/sys/patchlib/patchlib.c
T

119 lines
3.2 KiB
C

/*
* Offset = 0xD8010
*
* 00 0D 80 10
* Bits 31-24 23-16 15-8 7-0
* 0000 0000 0000 1101 1000 0000 0001 0000
*
* Bits 31-25 24 23 22 21-12 11-2 10
* 0000000 0 0 0 0011011000 0000000100 00
* S I1 I2 H L
*
* J1 = ~I1 ^ S = 1
* J2 = ~I2 ^ S = 1
* https://web.eecs.umich.edu/~prabal/teaching/eecs373-f10/readings/ARMv7-M_ARM.pdf
* A.6.7.18
*/
#include <assert.h>
/*---------------------------------------------------------------------------*/
#define FIXED2_BL 0x3
#define FIXED2_B 0x2
/*---------------------------------------------------------------------------*/
typedef union {
struct {
unsigned last1 : 1;
unsigned imm11l : 11;
unsigned imm10h : 10;
unsigned i2 : 1;
unsigned i1 : 1;
unsigned s : 1;
unsigned msb7 : 7;
} o;
int v;
} bl_offset_t;
typedef union {
struct {
unsigned imm11l : 11;
unsigned j2 : 1;
unsigned fixed1 : 1;
unsigned j1 : 1;
unsigned fixed2 : 2;
unsigned imm10h : 10;
unsigned s : 1;
unsigned msb5 : 5;
} i;
unsigned v;
} bl_instruction_t;
/*---------------------------------------------------------------------------*/
/*
* Provide the address shown in the disassembler for the instruction to
* calculate for. When the code executes this will be PC.
* Provide the address of the function (branch traget / btarget) the code
* should branch to.
* The return value will be an encode instruction ready to be an instruction
* that can be patched into an ARM binary with a hex editor.
* Why would you use this?
* If you want to branch to a different function with the same (or at least
* comptabile) signature, you can replace the branch instruction and
* alter the code. This particular instruction is a little trickier than
* direct branch instructions.
*/
static unsigned
bl_encode_common(unsigned pc, unsigned target, unsigned fixed2)
{
bl_offset_t offset;
bl_instruction_t final_instr;
pc += 4; /* Due to arm pipeline */
pc &= 0xfffffffe; /* 2 byte alignment */
offset.v = target - pc;
assert(offset.v < 16 * 1024 * 1024 && offset.v > -16 * 1024 * 1024);
final_instr.v = 0;
/* bits 27-31 = 0b11110 */
final_instr.i.msb5 = 0x1e;
/* bit 26 = S */
final_instr.i.s = offset.o.s;
/* imm10h, bits 16-25 */
final_instr.i.imm10h = offset.o.imm10h;
/* static */
final_instr.i.fixed2 = fixed2;
/* j1 */
final_instr.i.j1 = (offset.o.i1 ^ 0x1) ^ offset.o.s;
/* static */
final_instr.i.fixed1 = 0x1;
/* j2 */
final_instr.i.j2 = (offset.o.i2 ^ 0x1) ^ offset.o.s;
/* imm11l */
final_instr.i.imm11l = offset.o.imm11l;
unsigned v = final_instr.v;
v = v >> 16 | v << 16;
return v;
}
/*---------------------------------------------------------------------------*/
unsigned
bl_encode(unsigned pc, unsigned target)
{
return bl_encode_common(pc, target, FIXED2_BL);
}
/*---------------------------------------------------------------------------*/
unsigned
b_encode(unsigned pc, unsigned target)
{
return bl_encode_common(pc, target, FIXED2_B);
}
/*---------------------------------------------------------------------------*/