diff options
author | Zi Shen Lim <zlim.lnx@gmail.com> | 2014-08-27 00:15:28 -0400 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2014-09-08 09:39:20 -0400 |
commit | 27f95ba59b34509dc8afa2f89ad51c044df9d7c7 (patch) | |
tree | 219c0e3152d4a5e3ccd323bb50f339948ff94876 /arch | |
parent | 6481063989283f7cbeb0b6c38506ba4dd319f93a (diff) |
arm64: introduce aarch64_insn_gen_data3()
Introduce function to generate data-processing (3 source) instructions.
Signed-off-by: Zi Shen Lim <zlim.lnx@gmail.com>
Acked-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm64/include/asm/insn.h | 14 | ||||
-rw-r--r-- | arch/arm64/kernel/insn.c | 42 |
2 files changed, 56 insertions, 0 deletions
diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h index 367245fab9b7..36e8465cdf71 100644 --- a/arch/arm64/include/asm/insn.h +++ b/arch/arm64/include/asm/insn.h | |||
@@ -79,6 +79,7 @@ enum aarch64_insn_register_type { | |||
79 | AARCH64_INSN_REGTYPE_RT2, | 79 | AARCH64_INSN_REGTYPE_RT2, |
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 | }; | 83 | }; |
83 | 84 | ||
84 | enum aarch64_insn_register { | 85 | enum aarch64_insn_register { |
@@ -200,6 +201,11 @@ enum aarch64_insn_data2_type { | |||
200 | AARCH64_INSN_DATA2_RORV, | 201 | AARCH64_INSN_DATA2_RORV, |
201 | }; | 202 | }; |
202 | 203 | ||
204 | enum aarch64_insn_data3_type { | ||
205 | AARCH64_INSN_DATA3_MADD, | ||
206 | AARCH64_INSN_DATA3_MSUB, | ||
207 | }; | ||
208 | |||
203 | #define __AARCH64_INSN_FUNCS(abbr, mask, val) \ | 209 | #define __AARCH64_INSN_FUNCS(abbr, mask, val) \ |
204 | static __always_inline bool aarch64_insn_is_##abbr(u32 code) \ | 210 | static __always_inline bool aarch64_insn_is_##abbr(u32 code) \ |
205 | { return (code & (mask)) == (val); } \ | 211 | { return (code & (mask)) == (val); } \ |
@@ -226,6 +232,8 @@ __AARCH64_INSN_FUNCS(add, 0x7F200000, 0x0B000000) | |||
226 | __AARCH64_INSN_FUNCS(adds, 0x7F200000, 0x2B000000) | 232 | __AARCH64_INSN_FUNCS(adds, 0x7F200000, 0x2B000000) |
227 | __AARCH64_INSN_FUNCS(sub, 0x7F200000, 0x4B000000) | 233 | __AARCH64_INSN_FUNCS(sub, 0x7F200000, 0x4B000000) |
228 | __AARCH64_INSN_FUNCS(subs, 0x7F200000, 0x6B000000) | 234 | __AARCH64_INSN_FUNCS(subs, 0x7F200000, 0x6B000000) |
235 | __AARCH64_INSN_FUNCS(madd, 0x7FE08000, 0x1B000000) | ||
236 | __AARCH64_INSN_FUNCS(msub, 0x7FE08000, 0x1B008000) | ||
229 | __AARCH64_INSN_FUNCS(udiv, 0x7FE0FC00, 0x1AC00800) | 237 | __AARCH64_INSN_FUNCS(udiv, 0x7FE0FC00, 0x1AC00800) |
230 | __AARCH64_INSN_FUNCS(sdiv, 0x7FE0FC00, 0x1AC00C00) | 238 | __AARCH64_INSN_FUNCS(sdiv, 0x7FE0FC00, 0x1AC00C00) |
231 | __AARCH64_INSN_FUNCS(lslv, 0x7FE0FC00, 0x1AC02000) | 239 | __AARCH64_INSN_FUNCS(lslv, 0x7FE0FC00, 0x1AC02000) |
@@ -309,6 +317,12 @@ u32 aarch64_insn_gen_data2(enum aarch64_insn_register dst, | |||
309 | enum aarch64_insn_register reg, | 317 | enum aarch64_insn_register reg, |
310 | enum aarch64_insn_variant variant, | 318 | enum aarch64_insn_variant variant, |
311 | enum aarch64_insn_data2_type type); | 319 | enum aarch64_insn_data2_type type); |
320 | u32 aarch64_insn_gen_data3(enum aarch64_insn_register dst, | ||
321 | enum aarch64_insn_register src, | ||
322 | enum aarch64_insn_register reg1, | ||
323 | enum aarch64_insn_register reg2, | ||
324 | enum aarch64_insn_variant variant, | ||
325 | enum aarch64_insn_data3_type type); | ||
312 | 326 | ||
313 | bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn); | 327 | bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn); |
314 | 328 | ||
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c index c054164c677b..f73a4bfbb946 100644 --- a/arch/arm64/kernel/insn.c +++ b/arch/arm64/kernel/insn.c | |||
@@ -302,6 +302,7 @@ static u32 aarch64_insn_encode_register(enum aarch64_insn_register_type type, | |||
302 | shift = 5; | 302 | shift = 5; |
303 | break; | 303 | break; |
304 | case AARCH64_INSN_REGTYPE_RT2: | 304 | case AARCH64_INSN_REGTYPE_RT2: |
305 | case AARCH64_INSN_REGTYPE_RA: | ||
305 | shift = 10; | 306 | shift = 10; |
306 | break; | 307 | break; |
307 | case AARCH64_INSN_REGTYPE_RM: | 308 | case AARCH64_INSN_REGTYPE_RM: |
@@ -832,3 +833,44 @@ u32 aarch64_insn_gen_data2(enum aarch64_insn_register dst, | |||
832 | 833 | ||
833 | return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RM, insn, reg); | 834 | return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RM, insn, reg); |
834 | } | 835 | } |
836 | |||
837 | u32 aarch64_insn_gen_data3(enum aarch64_insn_register dst, | ||
838 | enum aarch64_insn_register src, | ||
839 | enum aarch64_insn_register reg1, | ||
840 | enum aarch64_insn_register reg2, | ||
841 | enum aarch64_insn_variant variant, | ||
842 | enum aarch64_insn_data3_type type) | ||
843 | { | ||
844 | u32 insn; | ||
845 | |||
846 | switch (type) { | ||
847 | case AARCH64_INSN_DATA3_MADD: | ||
848 | insn = aarch64_insn_get_madd_value(); | ||
849 | break; | ||
850 | case AARCH64_INSN_DATA3_MSUB: | ||
851 | insn = aarch64_insn_get_msub_value(); | ||
852 | break; | ||
853 | default: | ||
854 | BUG_ON(1); | ||
855 | } | ||
856 | |||
857 | switch (variant) { | ||
858 | case AARCH64_INSN_VARIANT_32BIT: | ||
859 | break; | ||
860 | case AARCH64_INSN_VARIANT_64BIT: | ||
861 | insn |= AARCH64_INSN_SF_BIT; | ||
862 | break; | ||
863 | default: | ||
864 | BUG_ON(1); | ||
865 | } | ||
866 | |||
867 | insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst); | ||
868 | |||
869 | insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RA, insn, src); | ||
870 | |||
871 | insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, | ||
872 | reg1); | ||
873 | |||
874 | return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RM, insn, | ||
875 | reg2); | ||
876 | } | ||