As it is always called with an explicit movewide type, we can
check for its validity at compile time and remove the runtime error print.
The other error prints cannot be verified at compile time, but should not
occur in practice and will still lead to a fault BRK, so remove them.
This makes `aarch64_insn_gen_movewide()` safe for inlining
and usage from patching callbacks, as both
`aarch64_insn_encode_register()` and `aarch64_insn_encode_immediate()`
have been made safe in previous commits.
Signed-off-by: Ada Couprie Diaz <ada.coupriediaz@arm.com>
---
arch/arm64/include/asm/insn.h | 58 ++++++++++++++++++++++++++++++++---
arch/arm64/lib/insn.c | 56 ---------------------------------
2 files changed, 54 insertions(+), 60 deletions(-)
diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
index 5f5f6a125b4e..5a25e311717f 100644
--- a/arch/arm64/include/asm/insn.h
+++ b/arch/arm64/include/asm/insn.h
@@ -624,6 +624,8 @@ static __always_inline bool aarch64_get_imm_shift_mask(
#define ADR_IMM_LOSHIFT 29
#define ADR_IMM_HISHIFT 5
+#define AARCH64_INSN_SF_BIT BIT(31)
+
enum aarch64_insn_encoding_class aarch64_get_insn_class(u32 insn);
u64 aarch64_insn_decode_immediate(enum aarch64_insn_imm_type type, u32 insn);
@@ -796,10 +798,58 @@ u32 aarch64_insn_gen_bitfield(enum aarch64_insn_register dst,
int immr, int imms,
enum aarch64_insn_variant variant,
enum aarch64_insn_bitfield_type type);
-u32 aarch64_insn_gen_movewide(enum aarch64_insn_register dst,
- int imm, int shift,
- enum aarch64_insn_variant variant,
- enum aarch64_insn_movewide_type type);
+
+static __always_inline u32 aarch64_insn_gen_movewide(
+ enum aarch64_insn_register dst,
+ int imm, int shift,
+ enum aarch64_insn_variant variant,
+ enum aarch64_insn_movewide_type type)
+{
+ compiletime_assert(type >= AARCH64_INSN_MOVEWIDE_ZERO &&
+ type <= AARCH64_INSN_MOVEWIDE_INVERSE, "unknown movewide encoding");
+ u32 insn;
+
+ switch (type) {
+ case AARCH64_INSN_MOVEWIDE_ZERO:
+ insn = aarch64_insn_get_movz_value();
+ break;
+ case AARCH64_INSN_MOVEWIDE_KEEP:
+ insn = aarch64_insn_get_movk_value();
+ break;
+ case AARCH64_INSN_MOVEWIDE_INVERSE:
+ insn = aarch64_insn_get_movn_value();
+ break;
+ default:
+ return AARCH64_BREAK_FAULT;
+ }
+
+ if (imm & ~(SZ_64K - 1)) {
+ return AARCH64_BREAK_FAULT;
+ }
+
+ switch (variant) {
+ case AARCH64_INSN_VARIANT_32BIT:
+ if (shift != 0 && shift != 16) {
+ return AARCH64_BREAK_FAULT;
+ }
+ break;
+ case AARCH64_INSN_VARIANT_64BIT:
+ insn |= AARCH64_INSN_SF_BIT;
+ if (shift != 0 && shift != 16 && shift != 32 && shift != 48) {
+ return AARCH64_BREAK_FAULT;
+ }
+ break;
+ default:
+ return AARCH64_BREAK_FAULT;
+ }
+
+ insn |= (shift >> 4) << 21;
+
+ insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst);
+
+ return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_16, insn, imm);
+}
+
u32 aarch64_insn_gen_add_sub_shifted_reg(enum aarch64_insn_register dst,
enum aarch64_insn_register src,
enum aarch64_insn_register reg,
diff --git a/arch/arm64/lib/insn.c b/arch/arm64/lib/insn.c
index d77aef7f84f1..7530d51f9b2a 100644
--- a/arch/arm64/lib/insn.c
+++ b/arch/arm64/lib/insn.c
@@ -16,7 +16,6 @@
#include <asm/insn.h>
#include <asm/kprobes.h>
-#define AARCH64_INSN_SF_BIT BIT(31)
#define AARCH64_INSN_N_BIT BIT(22)
#define AARCH64_INSN_LSL_12 BIT(22)
@@ -702,61 +701,6 @@ u32 aarch64_insn_gen_bitfield(enum aarch64_insn_register dst,
return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_S, insn, imms);
}
-u32 aarch64_insn_gen_movewide(enum aarch64_insn_register dst,
- int imm, int shift,
- enum aarch64_insn_variant variant,
- enum aarch64_insn_movewide_type type)
-{
- u32 insn;
-
- switch (type) {
- case AARCH64_INSN_MOVEWIDE_ZERO:
- insn = aarch64_insn_get_movz_value();
- break;
- case AARCH64_INSN_MOVEWIDE_KEEP:
- insn = aarch64_insn_get_movk_value();
- break;
- case AARCH64_INSN_MOVEWIDE_INVERSE:
- insn = aarch64_insn_get_movn_value();
- break;
- default:
- pr_err("%s: unknown movewide encoding %d\n", __func__, type);
- return AARCH64_BREAK_FAULT;
- }
-
- if (imm & ~(SZ_64K - 1)) {
- pr_err("%s: invalid immediate encoding %d\n", __func__, imm);
- return AARCH64_BREAK_FAULT;
- }
-
- switch (variant) {
- case AARCH64_INSN_VARIANT_32BIT:
- if (shift != 0 && shift != 16) {
- pr_err("%s: invalid shift encoding %d\n", __func__,
- shift);
- return AARCH64_BREAK_FAULT;
- }
- break;
- case AARCH64_INSN_VARIANT_64BIT:
- insn |= AARCH64_INSN_SF_BIT;
- if (shift != 0 && shift != 16 && shift != 32 && shift != 48) {
- pr_err("%s: invalid shift encoding %d\n", __func__,
- shift);
- return AARCH64_BREAK_FAULT;
- }
- break;
- default:
- pr_err("%s: unknown variant encoding %d\n", __func__, variant);
- return AARCH64_BREAK_FAULT;
- }
-
- insn |= (shift >> 4) << 21;
-
- insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst);
-
- return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_16, insn, imm);
-}
-
u32 aarch64_insn_gen_add_sub_shifted_reg(enum aarch64_insn_register dst,
enum aarch64_insn_register src,
enum aarch64_insn_register reg,
--
2.43.0