18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci#include <linux/module.h>
38c2ecf20Sopenharmony_ci#include <linux/printk.h>
48c2ecf20Sopenharmony_ci#include <linux/slab.h>
58c2ecf20Sopenharmony_ci#include <linux/string.h>
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_cistatic __init int memset16_selftest(void)
88c2ecf20Sopenharmony_ci{
98c2ecf20Sopenharmony_ci	unsigned i, j, k;
108c2ecf20Sopenharmony_ci	u16 v, *p;
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci	p = kmalloc(256 * 2 * 2, GFP_KERNEL);
138c2ecf20Sopenharmony_ci	if (!p)
148c2ecf20Sopenharmony_ci		return -1;
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci	for (i = 0; i < 256; i++) {
178c2ecf20Sopenharmony_ci		for (j = 0; j < 256; j++) {
188c2ecf20Sopenharmony_ci			memset(p, 0xa1, 256 * 2 * sizeof(v));
198c2ecf20Sopenharmony_ci			memset16(p + i, 0xb1b2, j);
208c2ecf20Sopenharmony_ci			for (k = 0; k < 512; k++) {
218c2ecf20Sopenharmony_ci				v = p[k];
228c2ecf20Sopenharmony_ci				if (k < i) {
238c2ecf20Sopenharmony_ci					if (v != 0xa1a1)
248c2ecf20Sopenharmony_ci						goto fail;
258c2ecf20Sopenharmony_ci				} else if (k < i + j) {
268c2ecf20Sopenharmony_ci					if (v != 0xb1b2)
278c2ecf20Sopenharmony_ci						goto fail;
288c2ecf20Sopenharmony_ci				} else {
298c2ecf20Sopenharmony_ci					if (v != 0xa1a1)
308c2ecf20Sopenharmony_ci						goto fail;
318c2ecf20Sopenharmony_ci				}
328c2ecf20Sopenharmony_ci			}
338c2ecf20Sopenharmony_ci		}
348c2ecf20Sopenharmony_ci	}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cifail:
378c2ecf20Sopenharmony_ci	kfree(p);
388c2ecf20Sopenharmony_ci	if (i < 256)
398c2ecf20Sopenharmony_ci		return (i << 24) | (j << 16) | k | 0x8000;
408c2ecf20Sopenharmony_ci	return 0;
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic __init int memset32_selftest(void)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	unsigned i, j, k;
468c2ecf20Sopenharmony_ci	u32 v, *p;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	p = kmalloc(256 * 2 * 4, GFP_KERNEL);
498c2ecf20Sopenharmony_ci	if (!p)
508c2ecf20Sopenharmony_ci		return -1;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	for (i = 0; i < 256; i++) {
538c2ecf20Sopenharmony_ci		for (j = 0; j < 256; j++) {
548c2ecf20Sopenharmony_ci			memset(p, 0xa1, 256 * 2 * sizeof(v));
558c2ecf20Sopenharmony_ci			memset32(p + i, 0xb1b2b3b4, j);
568c2ecf20Sopenharmony_ci			for (k = 0; k < 512; k++) {
578c2ecf20Sopenharmony_ci				v = p[k];
588c2ecf20Sopenharmony_ci				if (k < i) {
598c2ecf20Sopenharmony_ci					if (v != 0xa1a1a1a1)
608c2ecf20Sopenharmony_ci						goto fail;
618c2ecf20Sopenharmony_ci				} else if (k < i + j) {
628c2ecf20Sopenharmony_ci					if (v != 0xb1b2b3b4)
638c2ecf20Sopenharmony_ci						goto fail;
648c2ecf20Sopenharmony_ci				} else {
658c2ecf20Sopenharmony_ci					if (v != 0xa1a1a1a1)
668c2ecf20Sopenharmony_ci						goto fail;
678c2ecf20Sopenharmony_ci				}
688c2ecf20Sopenharmony_ci			}
698c2ecf20Sopenharmony_ci		}
708c2ecf20Sopenharmony_ci	}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cifail:
738c2ecf20Sopenharmony_ci	kfree(p);
748c2ecf20Sopenharmony_ci	if (i < 256)
758c2ecf20Sopenharmony_ci		return (i << 24) | (j << 16) | k | 0x8000;
768c2ecf20Sopenharmony_ci	return 0;
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic __init int memset64_selftest(void)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	unsigned i, j, k;
828c2ecf20Sopenharmony_ci	u64 v, *p;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	p = kmalloc(256 * 2 * 8, GFP_KERNEL);
858c2ecf20Sopenharmony_ci	if (!p)
868c2ecf20Sopenharmony_ci		return -1;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	for (i = 0; i < 256; i++) {
898c2ecf20Sopenharmony_ci		for (j = 0; j < 256; j++) {
908c2ecf20Sopenharmony_ci			memset(p, 0xa1, 256 * 2 * sizeof(v));
918c2ecf20Sopenharmony_ci			memset64(p + i, 0xb1b2b3b4b5b6b7b8ULL, j);
928c2ecf20Sopenharmony_ci			for (k = 0; k < 512; k++) {
938c2ecf20Sopenharmony_ci				v = p[k];
948c2ecf20Sopenharmony_ci				if (k < i) {
958c2ecf20Sopenharmony_ci					if (v != 0xa1a1a1a1a1a1a1a1ULL)
968c2ecf20Sopenharmony_ci						goto fail;
978c2ecf20Sopenharmony_ci				} else if (k < i + j) {
988c2ecf20Sopenharmony_ci					if (v != 0xb1b2b3b4b5b6b7b8ULL)
998c2ecf20Sopenharmony_ci						goto fail;
1008c2ecf20Sopenharmony_ci				} else {
1018c2ecf20Sopenharmony_ci					if (v != 0xa1a1a1a1a1a1a1a1ULL)
1028c2ecf20Sopenharmony_ci						goto fail;
1038c2ecf20Sopenharmony_ci				}
1048c2ecf20Sopenharmony_ci			}
1058c2ecf20Sopenharmony_ci		}
1068c2ecf20Sopenharmony_ci	}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cifail:
1098c2ecf20Sopenharmony_ci	kfree(p);
1108c2ecf20Sopenharmony_ci	if (i < 256)
1118c2ecf20Sopenharmony_ci		return (i << 24) | (j << 16) | k | 0x8000;
1128c2ecf20Sopenharmony_ci	return 0;
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic __init int strchr_selftest(void)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	const char *test_string = "abcdefghijkl";
1188c2ecf20Sopenharmony_ci	const char *empty_string = "";
1198c2ecf20Sopenharmony_ci	char *result;
1208c2ecf20Sopenharmony_ci	int i;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	for (i = 0; i < strlen(test_string) + 1; i++) {
1238c2ecf20Sopenharmony_ci		result = strchr(test_string, test_string[i]);
1248c2ecf20Sopenharmony_ci		if (result - test_string != i)
1258c2ecf20Sopenharmony_ci			return i + 'a';
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	result = strchr(empty_string, '\0');
1298c2ecf20Sopenharmony_ci	if (result != empty_string)
1308c2ecf20Sopenharmony_ci		return 0x101;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	result = strchr(empty_string, 'a');
1338c2ecf20Sopenharmony_ci	if (result)
1348c2ecf20Sopenharmony_ci		return 0x102;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	result = strchr(test_string, 'z');
1378c2ecf20Sopenharmony_ci	if (result)
1388c2ecf20Sopenharmony_ci		return 0x103;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	return 0;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic __init int strnchr_selftest(void)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	const char *test_string = "abcdefghijkl";
1468c2ecf20Sopenharmony_ci	const char *empty_string = "";
1478c2ecf20Sopenharmony_ci	char *result;
1488c2ecf20Sopenharmony_ci	int i, j;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	for (i = 0; i < strlen(test_string) + 1; i++) {
1518c2ecf20Sopenharmony_ci		for (j = 0; j < strlen(test_string) + 2; j++) {
1528c2ecf20Sopenharmony_ci			result = strnchr(test_string, j, test_string[i]);
1538c2ecf20Sopenharmony_ci			if (j <= i) {
1548c2ecf20Sopenharmony_ci				if (!result)
1558c2ecf20Sopenharmony_ci					continue;
1568c2ecf20Sopenharmony_ci				return ((i + 'a') << 8) | j;
1578c2ecf20Sopenharmony_ci			}
1588c2ecf20Sopenharmony_ci			if (result - test_string != i)
1598c2ecf20Sopenharmony_ci				return ((i + 'a') << 8) | j;
1608c2ecf20Sopenharmony_ci		}
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	result = strnchr(empty_string, 0, '\0');
1648c2ecf20Sopenharmony_ci	if (result)
1658c2ecf20Sopenharmony_ci		return 0x10001;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	result = strnchr(empty_string, 1, '\0');
1688c2ecf20Sopenharmony_ci	if (result != empty_string)
1698c2ecf20Sopenharmony_ci		return 0x10002;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	result = strnchr(empty_string, 1, 'a');
1728c2ecf20Sopenharmony_ci	if (result)
1738c2ecf20Sopenharmony_ci		return 0x10003;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	result = strnchr(NULL, 0, '\0');
1768c2ecf20Sopenharmony_ci	if (result)
1778c2ecf20Sopenharmony_ci		return 0x10004;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	return 0;
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic __init int string_selftest_init(void)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	int test, subtest;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	test = 1;
1878c2ecf20Sopenharmony_ci	subtest = memset16_selftest();
1888c2ecf20Sopenharmony_ci	if (subtest)
1898c2ecf20Sopenharmony_ci		goto fail;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	test = 2;
1928c2ecf20Sopenharmony_ci	subtest = memset32_selftest();
1938c2ecf20Sopenharmony_ci	if (subtest)
1948c2ecf20Sopenharmony_ci		goto fail;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	test = 3;
1978c2ecf20Sopenharmony_ci	subtest = memset64_selftest();
1988c2ecf20Sopenharmony_ci	if (subtest)
1998c2ecf20Sopenharmony_ci		goto fail;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	test = 4;
2028c2ecf20Sopenharmony_ci	subtest = strchr_selftest();
2038c2ecf20Sopenharmony_ci	if (subtest)
2048c2ecf20Sopenharmony_ci		goto fail;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	test = 5;
2078c2ecf20Sopenharmony_ci	subtest = strnchr_selftest();
2088c2ecf20Sopenharmony_ci	if (subtest)
2098c2ecf20Sopenharmony_ci		goto fail;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	pr_info("String selftests succeeded\n");
2128c2ecf20Sopenharmony_ci	return 0;
2138c2ecf20Sopenharmony_cifail:
2148c2ecf20Sopenharmony_ci	pr_crit("String selftest failure %d.%08x\n", test, subtest);
2158c2ecf20Sopenharmony_ci	return 0;
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_cimodule_init(string_selftest_init);
2198c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
220