aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm64/include/asm/insn.h30
-rw-r--r--arch/arm64/kernel/insn.c106
-rw-r--r--arch/arm64/net/bpf_jit.h19
-rw-r--r--arch/arm64/net/bpf_jit_comp.c16
-rw-r--r--lib/test_bpf.c105
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
85enum aarch64_insn_register { 86enum 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
193enum aarch64_insn_adsb_type { 196enum 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
246enum aarch64_insn_prfm_type {
247 AARCH64_INSN_PRFM_TYPE_PLD,
248 AARCH64_INSN_PRFM_TYPE_PLI,
249 AARCH64_INSN_PRFM_TYPE_PST,
250};
251
252enum aarch64_insn_prfm_target {
253 AARCH64_INSN_PRFM_TARGET_L1,
254 AARCH64_INSN_PRFM_TARGET_L2,
255 AARCH64_INSN_PRFM_TARGET_L3,
256};
257
258enum 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) \
244static __always_inline bool aarch64_insn_is_##abbr(u32 code) \ 264static __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);
381u32 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);
360u32 aarch64_insn_gen_add_sub_imm(enum aarch64_insn_register dst, 386u32 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);
426u32 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);
400s32 aarch64_get_branch_offset(u32 insn); 430s32 aarch64_get_branch_offset(u32 insn);
401u32 aarch64_set_branch_offset(u32 insn, s32 offset); 431u32 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
761u32 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
796static 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
849u32 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