[PATCH 2/3] arm64: insn: Add tests for aarch64_insn_gen_logical_immediate()
James Morse
james.morse at arm.com
Thu Jan 27 08:21:26 PST 2022
Aarch64 has instructions to generate reasonably complicated 32 or 64
bit masks from only 13 bits of information.
aarch64_insn_gen_logical_immediate() has to created the immediate
encoding by spotting the patterns in the 32 or 64 bit immediate.
Despite attempts to validate or model this code, or use it as-is outside
the kernel tree, bugs still exist.
Add a self test module that tests this code in place against a golden
set of values.
Signed-off-by: James Morse <james.morse at arm.com>
---
arch/arm64/Kconfig.debug | 3 +
arch/arm64/Makefile | 2 +
arch/arm64/lib/Makefile | 2 +
arch/arm64/lib/insn.c | 3 +
arch/arm64/lib/test_insn.c | 90 ++++++++++++++++++++++
tools/testing/selftests/arm64/Makefile | 2 +-
tools/testing/selftests/arm64/lib/Makefile | 6 ++
tools/testing/selftests/arm64/lib/config | 1 +
tools/testing/selftests/arm64/lib/insn.sh | 5 ++
9 files changed, 113 insertions(+), 1 deletion(-)
create mode 100644 arch/arm64/lib/test_insn.c
create mode 100644 tools/testing/selftests/arm64/lib/Makefile
create mode 100644 tools/testing/selftests/arm64/lib/config
create mode 100755 tools/testing/selftests/arm64/lib/insn.sh
diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug
index 265c4461031f..10df6056db3e 100644
--- a/arch/arm64/Kconfig.debug
+++ b/arch/arm64/Kconfig.debug
@@ -20,4 +20,7 @@ config ARM64_RELOC_TEST
depends on m
tristate "Relocation testing module"
+config TEST_INSN
+ tristate "Test functions located in the aarch64 instruction encoder at runtime"
+
source "drivers/hwtracing/coresight/Kconfig"
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index 0bd590605416..4930a2b077b8 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -176,7 +176,9 @@ vdso_install:
archprepare:
$(Q)$(MAKE) $(build)=arch/arm64/tools kapi
+#ifdef CONFIG_TEST_INSN
$(Q)$(MAKE) $(build)=arch/arm64/tools tests
+#endif
ifeq ($(CONFIG_ARM64_ERRATUM_843419),y)
ifneq ($(CONFIG_ARM64_LD_HAS_FIX_ERRATUM_843419),y)
@echo "warning: ld does not support --fix-cortex-a53-843419; kernel may be susceptible to erratum" >&2
diff --git a/arch/arm64/lib/Makefile b/arch/arm64/lib/Makefile
index 29490be2546b..d180945ecc22 100644
--- a/arch/arm64/lib/Makefile
+++ b/arch/arm64/lib/Makefile
@@ -22,3 +22,5 @@ obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
obj-$(CONFIG_ARM64_MTE) += mte.o
obj-$(CONFIG_KASAN_SW_TAGS) += kasan_sw_tags.o
+
+obj-$(CONFIG_TEST_INSN) += test_insn.o
diff --git a/arch/arm64/lib/insn.c b/arch/arm64/lib/insn.c
index fccfe363e567..8888e407032f 100644
--- a/arch/arm64/lib/insn.c
+++ b/arch/arm64/lib/insn.c
@@ -193,6 +193,7 @@ u64 aarch64_insn_decode_immediate(enum aarch64_insn_imm_type type, u32 insn)
return (insn >> shift) & mask;
}
+EXPORT_SYMBOL_GPL(aarch64_insn_decode_immediate);
u32 __kprobes aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type,
u32 insn, u64 imm)
@@ -256,6 +257,7 @@ u32 aarch64_insn_decode_register(enum aarch64_insn_register_type type,
return (insn >> shift) & GENMASK(4, 0);
}
+EXPORT_SYMBOL_GPL(aarch64_insn_decode_register);
static u32 aarch64_insn_encode_register(enum aarch64_insn_register_type type,
u32 insn,
@@ -1424,6 +1426,7 @@ u32 aarch64_insn_gen_logical_immediate(enum aarch64_insn_logic_type type,
insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, Rn);
return aarch64_encode_immediate(imm, variant, insn);
}
+EXPORT_SYMBOL_GPL(aarch64_insn_gen_logical_immediate);
u32 aarch64_insn_gen_extr(enum aarch64_insn_variant variant,
enum aarch64_insn_register Rm,
diff --git a/arch/arm64/lib/test_insn.c b/arch/arm64/lib/test_insn.c
new file mode 100644
index 000000000000..41466f61c6c0
--- /dev/null
+++ b/arch/arm64/lib/test_insn.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Test cases for the aarch64 insn encoder.
+ *
+ * Copyright (C) 2021 ARM Limited.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/printk.h>
+
+#include <asm/debug-monitors.h>
+#include <asm/insn.h>
+
+#include "../../../tools/testing/selftests/kselftest_module.h"
+
+struct bitmask_test_case {
+ /* input */
+ u64 imm;
+
+ /* expected output */
+ u64 n, immr, imms;
+};
+struct bitmask_test_case aarch64_logic_imm_test[] = {
+#include <asm/test_logic_imm_generated.h>
+};
+
+KSTM_MODULE_GLOBALS();
+
+static void __init test_logic_imm(void)
+{
+ int i;
+ u8 rd, rn;
+ u32 insn;
+
+ for (i = 0; i < ARRAY_SIZE(aarch64_logic_imm_test); i++) {
+ total_tests++;
+
+ rd = i % 30;
+ rn = (i + 1) % 30;
+
+ insn = aarch64_insn_gen_logical_immediate(AARCH64_INSN_LOGIC_AND,
+ AARCH64_INSN_VARIANT_64BIT,
+ rn, rd, aarch64_logic_imm_test[i].imm);
+
+ if (!aarch64_insn_is_and_imm(insn) ||
+ rd != aarch64_insn_decode_register(AARCH64_INSN_REGTYPE_RD, insn) ||
+ rn != aarch64_insn_decode_register(AARCH64_INSN_REGTYPE_RN, insn) ||
+ aarch64_logic_imm_test[i].imms != aarch64_insn_decode_immediate(AARCH64_INSN_IMM_S, insn) ||
+ aarch64_logic_imm_test[i].immr != aarch64_insn_decode_immediate(AARCH64_INSN_IMM_R, insn) ||
+ aarch64_logic_imm_test[i].n != aarch64_insn_decode_immediate(AARCH64_INSN_IMM_N, insn)) {
+ failed_tests++;
+ pr_warn_once("[%s:%u] Failed to encode immediate 0x%llx (got insn 0x%x))\n",
+ __FILE__, __LINE__, aarch64_logic_imm_test[i].imm, insn);
+ continue;
+ }
+ }
+}
+
+static void __init do_test_bad_logic_imm(u64 imm, enum aarch64_insn_variant var)
+{
+ u32 insn;
+
+ total_tests++;
+ insn = aarch64_insn_gen_logical_immediate(AARCH64_INSN_LOGIC_AND,
+ var, 0, 0, imm);
+ if (insn != AARCH64_BREAK_FAULT)
+ failed_tests++;
+}
+
+static void __init test_bad_logic_imm(void)
+{
+ do_test_bad_logic_imm(0, AARCH64_INSN_VARIANT_64BIT);
+ do_test_bad_logic_imm(0x1234, AARCH64_INSN_VARIANT_64BIT);
+ do_test_bad_logic_imm(0xffffffffffffffff, AARCH64_INSN_VARIANT_64BIT);
+ do_test_bad_logic_imm((1ULL<<32), AARCH64_INSN_VARIANT_32BIT);
+}
+
+static void __init selftest(void)
+{
+ test_logic_imm();
+ test_bad_logic_imm();
+}
+
+KSTM_MODULE_LOADERS(test_insn);
+MODULE_AUTHOR("James Morse <james.morse at arm.com>");
+MODULE_LICENSE("GPL");
diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
index 1e8d9a8f59df..2c59e7d40524 100644
--- a/tools/testing/selftests/arm64/Makefile
+++ b/tools/testing/selftests/arm64/Makefile
@@ -4,7 +4,7 @@
ARCH ?= $(shell uname -m 2>/dev/null || echo not)
ifneq (,$(filter $(ARCH),aarch64 arm64))
-ARM64_SUBTARGETS ?= tags signal pauth fp mte bti abi
+ARM64_SUBTARGETS ?= tags signal pauth fp mte bti abi lib
else
ARM64_SUBTARGETS :=
endif
diff --git a/tools/testing/selftests/arm64/lib/Makefile b/tools/testing/selftests/arm64/lib/Makefile
new file mode 100644
index 000000000000..5ed92a5135ce
--- /dev/null
+++ b/tools/testing/selftests/arm64/lib/Makefile
@@ -0,0 +1,6 @@
+# Copyright (C) 2022 ARM Limited
+# Makefile for arm64/lib/ function selftests
+
+TEST_PROGS := insn.sh
+
+include ../../lib.mk
diff --git a/tools/testing/selftests/arm64/lib/config b/tools/testing/selftests/arm64/lib/config
new file mode 100644
index 000000000000..cb982478782b
--- /dev/null
+++ b/tools/testing/selftests/arm64/lib/config
@@ -0,0 +1 @@
+CONFIG_TEST_INSN=m
diff --git a/tools/testing/selftests/arm64/lib/insn.sh b/tools/testing/selftests/arm64/lib/insn.sh
new file mode 100755
index 000000000000..3d893b1a0069
--- /dev/null
+++ b/tools/testing/selftests/arm64/lib/insn.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# Tests the aarch64 instruction generation infrastructure using test_insn
+# kernel module.
+$(dirname $0)/../../kselftest/module.sh "insn" test_insn
--
2.30.2
More information about the linux-arm-kernel
mailing list