arm64: insn: Add encoders for LDRSB/LDRSH/LDRSW
authorXu Kuohai <xukuohai@huawei.com>
Tue, 15 Aug 2023 15:41:52 +0000 (11:41 -0400)
committerDaniel Borkmann <daniel@iogearbox.net>
Fri, 18 Aug 2023 13:45:34 +0000 (15:45 +0200)
To support BPF sign-extend load instructions, add encoders for
LDRSB/LDRSH/LDRSW.

LDRSB/LDRSH/LDRSW (immediate) is encoded as follows:

     3     2 2   2   2                       1         0         0
     0     7 6   4   2                       0         5         0
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | sz|1 1 1|0|0 1|opc|        imm12          |    Rn   |    Rt   |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

LDRSB/LDRSH/LDRSW (register) is encoded as follows:

     3     2 2   2   2 2         1     1 1   1         0         0
     0     7 6   4   2 1         6     3 2   0         5         0
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | sz|1 1 1|0|0 0|opc|1|    Rm   | opt |S|1 0|    Rn   |    Rt   |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

where:

   - sz
     indicates whether 8-bit, 16-bit or 32-bit data is to be loaded

   - opc
     opc[1] (bit 23) is always 1 and opc[0] == 1 indicates regsize
     is 32-bit. Since BPF signed load instructions always exend the
     sign bit to bit 63 regardless of whether it loads an 8-bit,
     16-bit or 32-bit data. So only 64-bit register size is required.
     That is, it's sufficient to set field opc fixed to 0x2.

   - opt
     Indicates whether to sign extend the offset register Rm and the
     effective bits of Rm. We set opt to 0x7 (SXTX) since we'll use
     Rm as a sgined 64-bit value in BPF.

   - S
     Optional only when opt field is 0x3 (LSL)

In short, the above fields are encoded to the values listed below.

                   sz   opc  opt   S
LDRSB (immediate)  0x0  0x2  na    na
LDRSH (immediate)  0x1  0x2  na    na
LDRSW (immediate)  0x2  0x2  na    na
LDRSB (register)   0x0  0x2  0x7   0
LDRSH (register)   0x1  0x2  0x7   0
LDRSW (register)   0x2  0x2  0x7   0

Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Tested-by: Florent Revest <revest@chromium.org>
Acked-by: Florent Revest <revest@chromium.org>
Link: https://lore.kernel.org/bpf/20230815154158.717901-2-xukuohai@huaweicloud.com
arch/arm64/include/asm/insn.h
arch/arm64/lib/insn.c

index 139a88e..db1aeac 100644 (file)
@@ -186,6 +186,8 @@ enum aarch64_insn_ldst_type {
        AARCH64_INSN_LDST_LOAD_ACQ_EX,
        AARCH64_INSN_LDST_STORE_EX,
        AARCH64_INSN_LDST_STORE_REL_EX,
+       AARCH64_INSN_LDST_SIGNED_LOAD_IMM_OFFSET,
+       AARCH64_INSN_LDST_SIGNED_LOAD_REG_OFFSET,
 };
 
 enum aarch64_insn_adsb_type {
@@ -324,6 +326,7 @@ __AARCH64_INSN_FUNCS(prfm,  0x3FC00000, 0x39800000)
 __AARCH64_INSN_FUNCS(prfm_lit, 0xFF000000, 0xD8000000)
 __AARCH64_INSN_FUNCS(store_imm,        0x3FC00000, 0x39000000)
 __AARCH64_INSN_FUNCS(load_imm, 0x3FC00000, 0x39400000)
+__AARCH64_INSN_FUNCS(signed_load_imm, 0X3FC00000, 0x39800000)
 __AARCH64_INSN_FUNCS(store_pre,        0x3FE00C00, 0x38000C00)
 __AARCH64_INSN_FUNCS(load_pre, 0x3FE00C00, 0x38400C00)
 __AARCH64_INSN_FUNCS(store_post,       0x3FE00C00, 0x38000400)
@@ -337,6 +340,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(signed_ldr_reg, 0X3FE0FC00, 0x38A0E800)
 __AARCH64_INSN_FUNCS(ldr_imm,  0x3FC00000, 0x39400000)
 __AARCH64_INSN_FUNCS(ldr_lit,  0xBF000000, 0x18000000)
 __AARCH64_INSN_FUNCS(ldrsw_lit,        0xFF000000, 0x98000000)
index 924934c..a635ab8 100644 (file)
@@ -385,6 +385,9 @@ u32 aarch64_insn_gen_load_store_reg(enum aarch64_insn_register reg,
        case AARCH64_INSN_LDST_LOAD_REG_OFFSET:
                insn = aarch64_insn_get_ldr_reg_value();
                break;
+       case AARCH64_INSN_LDST_SIGNED_LOAD_REG_OFFSET:
+               insn = aarch64_insn_get_signed_ldr_reg_value();
+               break;
        case AARCH64_INSN_LDST_STORE_REG_OFFSET:
                insn = aarch64_insn_get_str_reg_value();
                break;
@@ -430,6 +433,9 @@ u32 aarch64_insn_gen_load_store_imm(enum aarch64_insn_register reg,
        case AARCH64_INSN_LDST_LOAD_IMM_OFFSET:
                insn = aarch64_insn_get_ldr_imm_value();
                break;
+       case AARCH64_INSN_LDST_SIGNED_LOAD_IMM_OFFSET:
+               insn = aarch64_insn_get_signed_load_imm_value();
+               break;
        case AARCH64_INSN_LDST_STORE_IMM_OFFSET:
                insn = aarch64_insn_get_str_imm_value();
                break;