Skip to content

Commit

Permalink
arm64: Add LDR (literal) instruction
Browse files Browse the repository at this point in the history
Add LDR (literal) instruction to load data from address relative to PC.
This instruction will be used to implement long jump from bpf prog to
bpf trampoline in the follow-up patch.

The instruction encoding:

    3       2   2     2                                     0        0
    0       7   6     4                                     5        0
+-----+-------+---+-----+-------------------------------------+--------+
| 0 x | 0 1 1 | 0 | 0 0 |                imm19                |   Rt   |
+-----+-------+---+-----+-------------------------------------+--------+

for 32-bit, variant x == 0; for 64-bit, x == 1.

branch_imm_common() is used to check the distance between pc and target
address, since it's reused by this patch and LDR (literal) is not a branch
instruction, rename it to label_imm_common().

Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
Acked-by: Will Deacon <will@kernel.org>
Reviewed-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
  • Loading branch information
Xu Kuohai authored and Kernel Patches Daemon committed Jul 11, 2022
1 parent c5fffaa commit 046426f
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 4 deletions.
3 changes: 3 additions & 0 deletions arch/arm64/include/asm/insn.h
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,9 @@ u32 aarch64_insn_gen_load_store_imm(enum aarch64_insn_register reg,
unsigned int imm,
enum aarch64_insn_size_type size,
enum aarch64_insn_ldst_type type);
u32 aarch64_insn_gen_load_literal(unsigned long pc, unsigned long addr,
enum aarch64_insn_register reg,
bool is64bit);
u32 aarch64_insn_gen_load_store_pair(enum aarch64_insn_register reg1,
enum aarch64_insn_register reg2,
enum aarch64_insn_register base,
Expand Down
30 changes: 26 additions & 4 deletions arch/arm64/lib/insn.c
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ static u32 aarch64_insn_encode_ldst_size(enum aarch64_insn_size_type type,
return insn;
}

static inline long branch_imm_common(unsigned long pc, unsigned long addr,
static inline long label_imm_common(unsigned long pc, unsigned long addr,
long range)
{
long offset;
Expand Down Expand Up @@ -354,7 +354,7 @@ u32 __kprobes aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr,
* ARM64 virtual address arrangement guarantees all kernel and module
* texts are within +/-128M.
*/
offset = branch_imm_common(pc, addr, SZ_128M);
offset = label_imm_common(pc, addr, SZ_128M);
if (offset >= SZ_128M)
return AARCH64_BREAK_FAULT;

Expand Down Expand Up @@ -382,7 +382,7 @@ u32 aarch64_insn_gen_comp_branch_imm(unsigned long pc, unsigned long addr,
u32 insn;
long offset;

offset = branch_imm_common(pc, addr, SZ_1M);
offset = label_imm_common(pc, addr, SZ_1M);
if (offset >= SZ_1M)
return AARCH64_BREAK_FAULT;

Expand Down Expand Up @@ -421,7 +421,7 @@ u32 aarch64_insn_gen_cond_branch_imm(unsigned long pc, unsigned long addr,
u32 insn;
long offset;

offset = branch_imm_common(pc, addr, SZ_1M);
offset = label_imm_common(pc, addr, SZ_1M);

insn = aarch64_insn_get_bcond_value();

Expand Down Expand Up @@ -543,6 +543,28 @@ u32 aarch64_insn_gen_load_store_imm(enum aarch64_insn_register reg,
return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_12, insn, imm);
}

u32 aarch64_insn_gen_load_literal(unsigned long pc, unsigned long addr,
enum aarch64_insn_register reg,
bool is64bit)
{
u32 insn;
long offset;

offset = label_imm_common(pc, addr, SZ_1M);
if (offset >= SZ_1M)
return AARCH64_BREAK_FAULT;

insn = aarch64_insn_get_ldr_lit_value();

if (is64bit)
insn |= BIT(30);

insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT, insn, reg);

return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_19, insn,
offset >> 2);
}

u32 aarch64_insn_gen_load_store_pair(enum aarch64_insn_register reg1,
enum aarch64_insn_register reg2,
enum aarch64_insn_register base,
Expand Down

0 comments on commit 046426f

Please sign in to comment.