diff options
| -rw-r--r-- | arch/arm64/include/asm/insn.h | 30 | ||||
| -rw-r--r-- | arch/arm64/kernel/insn.c | 106 | ||||
| -rw-r--r-- | arch/arm64/net/bpf_jit.h | 19 | ||||
| -rw-r--r-- | arch/arm64/net/bpf_jit_comp.c | 16 | ||||
| -rw-r--r-- | lib/test_bpf.c | 105 |
5 files changed, 271 insertions, 5 deletions
diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h index aecc07e09a18..29cb2ca756f6 100644 --- a/arch/arm64/include/asm/insn.h +++ b/arch/arm64/include/asm/insn.h | |||
| @@ -80,6 +80,7 @@ enum aarch64_insn_register_type { | |||
| 80 | AARCH64_INSN_REGTYPE_RM, | 80 | AARCH64_INSN_REGTYPE_RM, |
| 81 | AARCH64_INSN_REGTYPE_RD, | 81 | AARCH64_INSN_REGTYPE_RD, |
| 82 | AARCH64_INSN_REGTYPE_RA, | 82 | AARCH64_INSN_REGTYPE_RA, |
| 83 | AARCH64_INSN_REGTYPE_RS, | ||
| 83 | }; | 84 | }; |
| 84 | 85 | ||
| 85 | enum aarch64_insn_register { | 86 | enum aarch64_insn_register { |
| @@ -188,6 +189,8 @@ enum aarch64_insn_ldst_type { | |||
| 188 | AARCH64_INSN_LDST_STORE_PAIR_PRE_INDEX, | 189 | AARCH64_INSN_LDST_STORE_PAIR_PRE_INDEX, |
| 189 | AARCH64_INSN_LDST_LOAD_PAIR_POST_INDEX, | 190 | AARCH64_INSN_LDST_LOAD_PAIR_POST_INDEX, |
| 190 | AARCH64_INSN_LDST_STORE_PAIR_POST_INDEX, | 191 | AARCH64_INSN_LDST_STORE_PAIR_POST_INDEX, |
| 192 | AARCH64_INSN_LDST_LOAD_EX, | ||
| 193 | AARCH64_INSN_LDST_STORE_EX, | ||
| 191 | }; | 194 | }; |
| 192 | 195 | ||
| 193 | enum aarch64_insn_adsb_type { | 196 | enum aarch64_insn_adsb_type { |
| @@ -240,6 +243,23 @@ enum aarch64_insn_logic_type { | |||
| 240 | AARCH64_INSN_LOGIC_BIC_SETFLAGS | 243 | AARCH64_INSN_LOGIC_BIC_SETFLAGS |
| 241 | }; | 244 | }; |
| 242 | 245 | ||
| 246 | enum aarch64_insn_prfm_type { | ||
| 247 | AARCH64_INSN_PRFM_TYPE_PLD, | ||
| 248 | AARCH64_INSN_PRFM_TYPE_PLI, | ||
| 249 | AARCH64_INSN_PRFM_TYPE_PST, | ||
| 250 | }; | ||
| 251 | |||
| 252 | enum aarch64_insn_prfm_target { | ||
| 253 | AARCH64_INSN_PRFM_TARGET_L1, | ||
| 254 | AARCH64_INSN_PRFM_TARGET_L2, | ||
| 255 | AARCH64_INSN_PRFM_TARGET_L3, | ||
| 256 | }; | ||
| 257 | |||
| 258 | enum aarch64_insn_prfm_policy { | ||
| 259 | AARCH64_INSN_PRFM_POLICY_KEEP, | ||
| 260 | AARCH64_INSN_PRFM_POLICY_STRM, | ||
| 261 | }; | ||
| 262 | |||
| 243 | #define __AARCH64_INSN_FUNCS(abbr, mask, val) \ | 263 | #define __AARCH64_INSN_FUNCS(abbr, mask, val) \ |
| 244 | static __always_inline bool aarch64_insn_is_##abbr(u32 code) \ | 264 | static __always_inline bool aarch64_insn_is_##abbr(u32 code) \ |
| 245 | { return (code & (mask)) == (val); } \ | 265 | { return (code & (mask)) == (val); } \ |
| @@ -248,6 +268,7 @@ static __always_inline u32 aarch64_insn_get_##abbr##_value(void) \ | |||
| 248 | 268 | ||
| 249 | __AARCH64_INSN_FUNCS(adr, 0x9F000000, 0x10000000) | 269 | __AARCH64_INSN_FUNCS(adr, 0x9F000000, 0x10000000) |
| 250 | __AARCH64_INSN_FUNCS(adrp, 0x9F000000, 0x90000000) | 270 | __AARCH64_INSN_FUNCS(adrp, 0x9F000000, 0x90000000) |
| 271 | __AARCH64_INSN_FUNCS(prfm, 0x3FC00000, 0x39800000) | ||
| 251 | __AARCH64_INSN_FUNCS(prfm_lit, 0xFF000000, 0xD8000000) | 272 | __AARCH64_INSN_FUNCS(prfm_lit, 0xFF000000, 0xD8000000) |
| 252 | __AARCH64_INSN_FUNCS(str_reg, 0x3FE0EC00, 0x38206800) | 273 | __AARCH64_INSN_FUNCS(str_reg, 0x3FE0EC00, 0x38206800) |
| 253 | __AARCH64_INSN_FUNCS(ldr_reg, 0x3FE0EC00, 0x38606800) | 274 | __AARCH64_INSN_FUNCS(ldr_reg, 0x3FE0EC00, 0x38606800) |
| @@ -357,6 +378,11 @@ u32 aarch64_insn_gen_load_store_pair(enum aarch64_insn_register reg1, | |||
| 357 | int offset, | 378 | int offset, |
| 358 | enum aarch64_insn_variant variant, | 379 | enum aarch64_insn_variant variant, |
| 359 | enum aarch64_insn_ldst_type type); | 380 | enum aarch64_insn_ldst_type type); |
| 381 | u32 aarch64_insn_gen_load_store_ex(enum aarch64_insn_register reg, | ||
| 382 | enum aarch64_insn_register base, | ||
| 383 | enum aarch64_insn_register state, | ||
| 384 | enum aarch64_insn_size_type size, | ||
| 385 | enum aarch64_insn_ldst_type type); | ||
| 360 | u32 aarch64_insn_gen_add_sub_imm(enum aarch64_insn_register dst, | 386 | u32 aarch64_insn_gen_add_sub_imm(enum aarch64_insn_register dst, |
| 361 | enum aarch64_insn_register src, | 387 | enum aarch64_insn_register src, |
| 362 | int imm, enum aarch64_insn_variant variant, | 388 | int imm, enum aarch64_insn_variant variant, |
| @@ -397,6 +423,10 @@ u32 aarch64_insn_gen_logical_shifted_reg(enum aarch64_insn_register dst, | |||
| 397 | int shift, | 423 | int shift, |
| 398 | enum aarch64_insn_variant variant, | 424 | enum aarch64_insn_variant variant, |
| 399 | enum aarch64_insn_logic_type type); | 425 | enum aarch64_insn_logic_type type); |
| 426 | u32 aarch64_insn_gen_prefetch(enum aarch64_insn_register base, | ||
| 427 | enum aarch64_insn_prfm_type type, | ||
| 428 | enum aarch64_insn_prfm_target target, | ||
| 429 | enum aarch64_insn_prfm_policy policy); | ||
| 400 | s32 aarch64_get_branch_offset(u32 insn); | 430 | s32 aarch64_get_branch_offset(u32 insn); |
| 401 | u32 aarch64_set_branch_offset(u32 insn, s32 offset); | 431 | u32 aarch64_set_branch_offset(u32 insn, s32 offset); |
| 402 | 432 | ||
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c index 3a63954a8b14..b884a926a632 100644 --- a/arch/arm64/kernel/insn.c +++ b/arch/arm64/kernel/insn.c | |||
| @@ -474,6 +474,7 @@ static u32 aarch64_insn_encode_register(enum aarch64_insn_register_type type, | |||
| 474 | shift = 10; | 474 | shift = 10; |
| 475 | break; | 475 | break; |
| 476 | case AARCH64_INSN_REGTYPE_RM: | 476 | case AARCH64_INSN_REGTYPE_RM: |
| 477 | case AARCH64_INSN_REGTYPE_RS: | ||
| 477 | shift = 16; | 478 | shift = 16; |
| 478 | break; | 479 | break; |
| 479 | default: | 480 | default: |
| @@ -757,6 +758,111 @@ u32 aarch64_insn_gen_load_store_pair(enum aarch64_insn_register reg1, | |||
| 757 | offset >> shift); | 758 | offset >> shift); |
| 758 | } | 759 | } |
| 759 | 760 | ||
| 761 | u32 aarch64_insn_gen_load_store_ex(enum aarch64_insn_register reg, | ||
| 762 | enum aarch64_insn_register base, | ||
| 763 | enum aarch64_insn_register state, | ||
| 764 | enum aarch64_insn_size_type size, | ||
| 765 | enum aarch64_insn_ldst_type type) | ||
| 766 | { | ||
| 767 | u32 insn; | ||
| 768 | |||
| 769 | switch (type) { | ||
| 770 | case AARCH64_INSN_LDST_LOAD_EX: | ||
| 771 | insn = aarch64_insn_get_load_ex_value(); | ||
| 772 | break; | ||
| 773 | case AARCH64_INSN_LDST_STORE_EX: | ||
| 774 | insn = aarch64_insn_get_store_ex_value(); | ||
| 775 | break; | ||
| 776 | default: | ||
| 777 | pr_err("%s: unknown load/store exclusive encoding %d\n", __func__, type); | ||
| 778 | return AARCH64_BREAK_FAULT; | ||
| 779 | } | ||
| 780 | |||
| 781 | insn = aarch64_insn_encode_ldst_size(size, insn); | ||
| 782 | |||
| 783 | insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT, insn, | ||
| 784 | reg); | ||
| 785 | |||
| 786 | insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, | ||
| 787 | base); | ||
| 788 | |||
| 789 | insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT2, insn, | ||
| 790 | AARCH64_INSN_REG_ZR); | ||
| 791 | |||
| 792 | return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RS, insn, | ||
| 793 | state); | ||
| 794 | } | ||
| 795 | |||
| 796 | static u32 aarch64_insn_encode_prfm_imm(enum aarch64_insn_prfm_type type, | ||
| 797 | enum aarch64_insn_prfm_target target, | ||
| 798 | enum aarch64_insn_prfm_policy policy, | ||
| 799 | u32 insn) | ||
| 800 | { | ||
| 801 | u32 imm_type = 0, imm_target = 0, imm_policy = 0; | ||
| 802 | |||
| 803 | switch (type) { | ||
| 804 | case AARCH64_INSN_PRFM_TYPE_PLD: | ||
| 805 | break; | ||
| 806 | case AARCH64_INSN_PRFM_TYPE_PLI: | ||
| 807 | imm_type = BIT(0); | ||
| 808 | break; | ||
| 809 | case AARCH64_INSN_PRFM_TYPE_PST: | ||
| 810 | imm_type = BIT(1); | ||
| 811 | break; | ||
| 812 | default: | ||
| 813 | pr_err("%s: unknown prfm type encoding %d\n", __func__, type); | ||
| 814 | return AARCH64_BREAK_FAULT; | ||
| 815 | } | ||
| 816 | |||
| 817 | switch (target) { | ||
| 818 | case AARCH64_INSN_PRFM_TARGET_L1: | ||
| 819 | break; | ||
| 820 | case AARCH64_INSN_PRFM_TARGET_L2: | ||
| 821 | imm_target = BIT(0); | ||
| 822 | break; | ||
| 823 | case AARCH64_INSN_PRFM_TARGET_L3: | ||
| 824 | imm_target = BIT(1); | ||
| 825 | break; | ||
| 826 | default: | ||
| 827 | pr_err("%s: unknown prfm target encoding %d\n", __func__, target); | ||
| 828 | return AARCH64_BREAK_FAULT; | ||
| 829 | } | ||
| 830 | |||
| 831 | switch (policy) { | ||
| 832 | case AARCH64_INSN_PRFM_POLICY_KEEP: | ||
| 833 | break; | ||
| 834 | case AARCH64_INSN_PRFM_POLICY_STRM: | ||
| 835 | imm_policy = BIT(0); | ||
| 836 | break; | ||
| 837 | default: | ||
| 838 | pr_err("%s: unknown prfm policy encoding %d\n", __func__, policy); | ||
| 839 | return AARCH64_BREAK_FAULT; | ||
| 840 | } | ||
| 841 | |||
| 842 | /* In this case, imm5 is encoded into Rt field. */ | ||
| 843 | insn &= ~GENMASK(4, 0); | ||
| 844 | insn |= imm_policy | (imm_target << 1) | (imm_type << 3); | ||
| 845 | |||
| 846 | return insn; | ||
| 847 | } | ||
| 848 | |||
| 849 | u32 aarch64_insn_gen_prefetch(enum aarch64_insn_register base, | ||
| 850 | enum aarch64_insn_prfm_type type, | ||
| 851 | enum aarch64_insn_prfm_target target, | ||
| 852 | enum aarch64_insn_prfm_policy policy) | ||
| 853 | { | ||
| 854 | u32 insn = aarch64_insn_get_prfm_value(); | ||
| 855 | |||
| 856 | insn = aarch64_insn_encode_ldst_size(AARCH64_INSN_SIZE_64, insn); | ||
| 857 | |||
| 858 | insn = aarch64_insn_encode_prfm_imm(type, target, policy, insn); | ||
| 859 | |||
