tests: provide a word-at-a-time test implementation

Message ID 20231009120455.173862-1-svens@linux.ibm.com
State New
Headers
Series tests: provide a word-at-a-time test implementation |

Commit Message

Sven Schnelle Oct. 9, 2023, 12:04 p.m. UTC
  Add some basic tests to test the correctness of has_zero() and
find_zero().

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
---
 lib/Kconfig.debug         | 11 +++++++
 lib/Makefile              |  1 +
 lib/test_word-at-a-time.c | 62 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 74 insertions(+)
 create mode 100644 lib/test_word-at-a-time.c
  

Comments

Kees Cook Oct. 9, 2023, 4:49 p.m. UTC | #1
On Mon, Oct 09, 2023 at 02:04:55PM +0200, Sven Schnelle wrote:
> Add some basic tests to test the correctness of has_zero() and
> find_zero().
> 
> Signed-off-by: Sven Schnelle <svens@linux.ibm.com>

Yay tests! :)

Reviewed-by: Kees Cook <keescook@chromium.org>
  

Patch

diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index fa307f93fa2e..f7a4df3054ac 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2791,6 +2791,17 @@  config SIPHASH_KUNIT_TEST
 	  This is intended to help people writing architecture-specific
 	  optimized versions.  If unsure, say N.
 
+config WORDATATIME_KUNIT_TEST
+	tristate "KUnit test word-at-a-time implementation at runtime" if !KUNIT_ALL_TESTS
+	depends on KUNIT
+	default KUNIT_ALL_TESTS
+	help
+	  Enable this option to test the kernel's word-at-a-time (<asm/word-at-a-time.h>)
+	  functions on boot (or module load).
+
+	  This is intended to help people writing architecture-specific
+	  optimized versions.  If unsure, say N.
+
 config TEST_UDELAY
 	tristate "udelay test driver"
 	help
diff --git a/lib/Makefile b/lib/Makefile
index 740109b6e2c8..b3bc6a698896 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -402,6 +402,7 @@  obj-$(CONFIG_FORTIFY_KUNIT_TEST) += fortify_kunit.o
 obj-$(CONFIG_STRCAT_KUNIT_TEST) += strcat_kunit.o
 obj-$(CONFIG_STRSCPY_KUNIT_TEST) += strscpy_kunit.o
 obj-$(CONFIG_SIPHASH_KUNIT_TEST) += siphash_kunit.o
+obj-$(CONFIG_WORDATATIME_KUNIT_TEST) += test_word-at-a-time.o
 
 obj-$(CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED) += devmem_is_allowed.o
 
diff --git a/lib/test_word-at-a-time.c b/lib/test_word-at-a-time.c
new file mode 100644
index 000000000000..574303a4f913
--- /dev/null
+++ b/lib/test_word-at-a-time.c
@@ -0,0 +1,62 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <kunit/test.h>
+#include <asm/word-at-a-time.h>
+
+static void test_wordatatime_has_zero(struct kunit *test)
+{
+	const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
+	unsigned long val, data;
+
+	val = -1UL;
+	KUNIT_ASSERT_FALSE(test, has_zero(val, &data, &constants));
+
+	for (int i = 0; i < BITS_PER_LONG; i += 8) {
+		val = ~(0xffUL << i);
+		KUNIT_ASSERT_TRUE(test, has_zero(val, &data, &constants));
+	}
+
+	for (int i = 0; i < BITS_PER_LONG; i++) {
+		val = ~(0x1UL << i);
+		KUNIT_ASSERT_FALSE(test, has_zero(val, &data, &constants));
+	}
+
+	for (int i = 0; i < BITS_PER_LONG; i++) {
+		val = 0x1UL << i;
+		KUNIT_ASSERT_TRUE(test, has_zero(val, &data, &constants));
+	}
+}
+
+static void test_wordatatime_find_zero(struct kunit *test)
+{
+	const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
+	unsigned long val, data;
+
+	for (int i = 0; i < BITS_PER_LONG; i += 8) {
+		val = ~(0xffUL << i);
+		KUNIT_ASSERT_TRUE(test, has_zero(val, &data, &constants));
+		data = prep_zero_mask(val, data, &constants);
+		data = create_zero_mask(data);
+#ifdef CONFIG_CPU_BIG_ENDIAN
+		KUNIT_ASSERT_EQ(test, find_zero(data), (BITS_PER_LONG / 8 - 1) - (i / 8));
+#else
+		KUNIT_ASSERT_EQ(test, find_zero(data), i / 8);
+#endif
+	}
+}
+static struct kunit_case wordatatime_test_cases[] = {
+	KUNIT_CASE(test_wordatatime_has_zero),
+	KUNIT_CASE(test_wordatatime_find_zero),
+	{}
+};
+
+static struct kunit_suite wordatatime_test_suite = {
+	.name = "wordatatime_test",
+	.test_cases = wordatatime_test_cases,
+};
+
+kunit_test_suites(&wordatatime_test_suite);
+MODULE_LICENSE("GPL");