mirror of
https://github.com/torvalds/linux.git
synced 2026-05-21 05:18:45 +02:00
arm64, insn: Add ldr/str with immediate offset
This patch introduces ldr/str with immediate offset support to simplify the JIT implementation of BPF LDX/STX instructions on arm64. Although arm64 ldr/str immediate is available in pre-index, post-index and unsigned offset forms, the unsigned offset form is sufficient for BPF, so this patch only adds this type. Signed-off-by: Xu Kuohai <xukuohai@huawei.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Link: https://lore.kernel.org/bpf/20220321152852.2334294-2-xukuohai@huawei.com
This commit is contained in:
parent
2975dbdc39
commit
30c90f6757
|
|
@ -201,6 +201,8 @@ enum aarch64_insn_size_type {
|
|||
enum aarch64_insn_ldst_type {
|
||||
AARCH64_INSN_LDST_LOAD_REG_OFFSET,
|
||||
AARCH64_INSN_LDST_STORE_REG_OFFSET,
|
||||
AARCH64_INSN_LDST_LOAD_IMM_OFFSET,
|
||||
AARCH64_INSN_LDST_STORE_IMM_OFFSET,
|
||||
AARCH64_INSN_LDST_LOAD_PAIR_PRE_INDEX,
|
||||
AARCH64_INSN_LDST_STORE_PAIR_PRE_INDEX,
|
||||
AARCH64_INSN_LDST_LOAD_PAIR_POST_INDEX,
|
||||
|
|
@ -335,6 +337,7 @@ __AARCH64_INSN_FUNCS(load_pre, 0x3FE00C00, 0x38400C00)
|
|||
__AARCH64_INSN_FUNCS(store_post, 0x3FE00C00, 0x38000400)
|
||||
__AARCH64_INSN_FUNCS(load_post, 0x3FE00C00, 0x38400400)
|
||||
__AARCH64_INSN_FUNCS(str_reg, 0x3FE0EC00, 0x38206800)
|
||||
__AARCH64_INSN_FUNCS(str_imm, 0x3FC00000, 0x39000000)
|
||||
__AARCH64_INSN_FUNCS(ldadd, 0x3F20FC00, 0x38200000)
|
||||
__AARCH64_INSN_FUNCS(ldclr, 0x3F20FC00, 0x38201000)
|
||||
__AARCH64_INSN_FUNCS(ldeor, 0x3F20FC00, 0x38202000)
|
||||
|
|
@ -342,6 +345,7 @@ __AARCH64_INSN_FUNCS(ldset, 0x3F20FC00, 0x38203000)
|
|||
__AARCH64_INSN_FUNCS(swp, 0x3F20FC00, 0x38208000)
|
||||
__AARCH64_INSN_FUNCS(cas, 0x3FA07C00, 0x08A07C00)
|
||||
__AARCH64_INSN_FUNCS(ldr_reg, 0x3FE0EC00, 0x38606800)
|
||||
__AARCH64_INSN_FUNCS(ldr_imm, 0x3FC00000, 0x39400000)
|
||||
__AARCH64_INSN_FUNCS(ldr_lit, 0xBF000000, 0x18000000)
|
||||
__AARCH64_INSN_FUNCS(ldrsw_lit, 0xFF000000, 0x98000000)
|
||||
__AARCH64_INSN_FUNCS(exclusive, 0x3F800000, 0x08000000)
|
||||
|
|
@ -501,6 +505,11 @@ u32 aarch64_insn_gen_load_store_reg(enum aarch64_insn_register reg,
|
|||
enum aarch64_insn_register offset,
|
||||
enum aarch64_insn_size_type size,
|
||||
enum aarch64_insn_ldst_type type);
|
||||
u32 aarch64_insn_gen_load_store_imm(enum aarch64_insn_register reg,
|
||||
enum aarch64_insn_register base,
|
||||
unsigned int imm,
|
||||
enum aarch64_insn_size_type size,
|
||||
enum aarch64_insn_ldst_type type);
|
||||
u32 aarch64_insn_gen_load_store_pair(enum aarch64_insn_register reg1,
|
||||
enum aarch64_insn_register reg2,
|
||||
enum aarch64_insn_register base,
|
||||
|
|
|
|||
|
|
@ -299,29 +299,24 @@ static u32 aarch64_insn_encode_register(enum aarch64_insn_register_type type,
|
|||
return insn;
|
||||
}
|
||||
|
||||
static const u32 aarch64_insn_ldst_size[] = {
|
||||
[AARCH64_INSN_SIZE_8] = 0,
|
||||
[AARCH64_INSN_SIZE_16] = 1,
|
||||
[AARCH64_INSN_SIZE_32] = 2,
|
||||
[AARCH64_INSN_SIZE_64] = 3,
|
||||
};
|
||||
|
||||
static u32 aarch64_insn_encode_ldst_size(enum aarch64_insn_size_type type,
|
||||
u32 insn)
|
||||
{
|
||||
u32 size;
|
||||
|
||||
switch (type) {
|
||||
case AARCH64_INSN_SIZE_8:
|
||||
size = 0;
|
||||
break;
|
||||
case AARCH64_INSN_SIZE_16:
|
||||
size = 1;
|
||||
break;
|
||||
case AARCH64_INSN_SIZE_32:
|
||||
size = 2;
|
||||
break;
|
||||
case AARCH64_INSN_SIZE_64:
|
||||
size = 3;
|
||||
break;
|
||||
default:
|
||||
if (type < AARCH64_INSN_SIZE_8 || type > AARCH64_INSN_SIZE_64) {
|
||||
pr_err("%s: unknown size encoding %d\n", __func__, type);
|
||||
return AARCH64_BREAK_FAULT;
|
||||
}
|
||||
|
||||
size = aarch64_insn_ldst_size[type];
|
||||
insn &= ~GENMASK(31, 30);
|
||||
insn |= size << 30;
|
||||
|
||||
|
|
@ -504,6 +499,50 @@ u32 aarch64_insn_gen_load_store_reg(enum aarch64_insn_register reg,
|
|||
offset);
|
||||
}
|
||||
|
||||
u32 aarch64_insn_gen_load_store_imm(enum aarch64_insn_register reg,
|
||||
enum aarch64_insn_register base,
|
||||
unsigned int imm,
|
||||
enum aarch64_insn_size_type size,
|
||||
enum aarch64_insn_ldst_type type)
|
||||
{
|
||||
u32 insn;
|
||||
u32 shift;
|
||||
|
||||
if (size < AARCH64_INSN_SIZE_8 || size > AARCH64_INSN_SIZE_64) {
|
||||
pr_err("%s: unknown size encoding %d\n", __func__, type);
|
||||
return AARCH64_BREAK_FAULT;
|
||||
}
|
||||
|
||||
shift = aarch64_insn_ldst_size[size];
|
||||
if (imm & ~(BIT(12 + shift) - BIT(shift))) {
|
||||
pr_err("%s: invalid imm: %d\n", __func__, imm);
|
||||
return AARCH64_BREAK_FAULT;
|
||||
}
|
||||
|
||||
imm >>= shift;
|
||||
|
||||
switch (type) {
|
||||
case AARCH64_INSN_LDST_LOAD_IMM_OFFSET:
|
||||
insn = aarch64_insn_get_ldr_imm_value();
|
||||
break;
|
||||
case AARCH64_INSN_LDST_STORE_IMM_OFFSET:
|
||||
insn = aarch64_insn_get_str_imm_value();
|
||||
break;
|
||||
default:
|
||||
pr_err("%s: unknown load/store encoding %d\n", __func__, type);
|
||||
return AARCH64_BREAK_FAULT;
|
||||
}
|
||||
|
||||
insn = aarch64_insn_encode_ldst_size(size, insn);
|
||||
|
||||
insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT, insn, reg);
|
||||
|
||||
insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn,
|
||||
base);
|
||||
|
||||
return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_12, insn, imm);
|
||||
}
|
||||
|
||||
u32 aarch64_insn_gen_load_store_pair(enum aarch64_insn_register reg1,
|
||||
enum aarch64_insn_register reg2,
|
||||
enum aarch64_insn_register base,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user