18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Test cases for lib/hexdump.c module. 38c2ecf20Sopenharmony_ci */ 48c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/init.h> 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/random.h> 108c2ecf20Sopenharmony_ci#include <linux/string.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistatic const unsigned char data_b[] = { 138c2ecf20Sopenharmony_ci '\xbe', '\x32', '\xdb', '\x7b', '\x0a', '\x18', '\x93', '\xb2', /* 00 - 07 */ 148c2ecf20Sopenharmony_ci '\x70', '\xba', '\xc4', '\x24', '\x7d', '\x83', '\x34', '\x9b', /* 08 - 0f */ 158c2ecf20Sopenharmony_ci '\xa6', '\x9c', '\x31', '\xad', '\x9c', '\x0f', '\xac', '\xe9', /* 10 - 17 */ 168c2ecf20Sopenharmony_ci '\x4c', '\xd1', '\x19', '\x99', '\x43', '\xb1', '\xaf', '\x0c', /* 18 - 1f */ 178c2ecf20Sopenharmony_ci}; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic const unsigned char data_a[] = ".2.{....p..$}.4...1.....L...C..."; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic const char * const test_data_1[] __initconst = { 228c2ecf20Sopenharmony_ci "be", "32", "db", "7b", "0a", "18", "93", "b2", 238c2ecf20Sopenharmony_ci "70", "ba", "c4", "24", "7d", "83", "34", "9b", 248c2ecf20Sopenharmony_ci "a6", "9c", "31", "ad", "9c", "0f", "ac", "e9", 258c2ecf20Sopenharmony_ci "4c", "d1", "19", "99", "43", "b1", "af", "0c", 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic const char * const test_data_2_le[] __initconst = { 298c2ecf20Sopenharmony_ci "32be", "7bdb", "180a", "b293", 308c2ecf20Sopenharmony_ci "ba70", "24c4", "837d", "9b34", 318c2ecf20Sopenharmony_ci "9ca6", "ad31", "0f9c", "e9ac", 328c2ecf20Sopenharmony_ci "d14c", "9919", "b143", "0caf", 338c2ecf20Sopenharmony_ci}; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic const char * const test_data_2_be[] __initconst = { 368c2ecf20Sopenharmony_ci "be32", "db7b", "0a18", "93b2", 378c2ecf20Sopenharmony_ci "70ba", "c424", "7d83", "349b", 388c2ecf20Sopenharmony_ci "a69c", "31ad", "9c0f", "ace9", 398c2ecf20Sopenharmony_ci "4cd1", "1999", "43b1", "af0c", 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic const char * const test_data_4_le[] __initconst = { 438c2ecf20Sopenharmony_ci "7bdb32be", "b293180a", "24c4ba70", "9b34837d", 448c2ecf20Sopenharmony_ci "ad319ca6", "e9ac0f9c", "9919d14c", "0cafb143", 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic const char * const test_data_4_be[] __initconst = { 488c2ecf20Sopenharmony_ci "be32db7b", "0a1893b2", "70bac424", "7d83349b", 498c2ecf20Sopenharmony_ci "a69c31ad", "9c0face9", "4cd11999", "43b1af0c", 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic const char * const test_data_8_le[] __initconst = { 538c2ecf20Sopenharmony_ci "b293180a7bdb32be", "9b34837d24c4ba70", 548c2ecf20Sopenharmony_ci "e9ac0f9cad319ca6", "0cafb1439919d14c", 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic const char * const test_data_8_be[] __initconst = { 588c2ecf20Sopenharmony_ci "be32db7b0a1893b2", "70bac4247d83349b", 598c2ecf20Sopenharmony_ci "a69c31ad9c0face9", "4cd1199943b1af0c", 608c2ecf20Sopenharmony_ci}; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define FILL_CHAR '#' 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic unsigned total_tests __initdata; 658c2ecf20Sopenharmony_cistatic unsigned failed_tests __initdata; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic void __init test_hexdump_prepare_test(size_t len, int rowsize, 688c2ecf20Sopenharmony_ci int groupsize, char *test, 698c2ecf20Sopenharmony_ci size_t testlen, bool ascii) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci char *p; 728c2ecf20Sopenharmony_ci const char * const *result; 738c2ecf20Sopenharmony_ci size_t l = len; 748c2ecf20Sopenharmony_ci int gs = groupsize, rs = rowsize; 758c2ecf20Sopenharmony_ci unsigned int i; 768c2ecf20Sopenharmony_ci const bool is_be = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (rs != 16 && rs != 32) 798c2ecf20Sopenharmony_ci rs = 16; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (l > rs) 828c2ecf20Sopenharmony_ci l = rs; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (!is_power_of_2(gs) || gs > 8 || (len % gs != 0)) 858c2ecf20Sopenharmony_ci gs = 1; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (gs == 8) 888c2ecf20Sopenharmony_ci result = is_be ? test_data_8_be : test_data_8_le; 898c2ecf20Sopenharmony_ci else if (gs == 4) 908c2ecf20Sopenharmony_ci result = is_be ? test_data_4_be : test_data_4_le; 918c2ecf20Sopenharmony_ci else if (gs == 2) 928c2ecf20Sopenharmony_ci result = is_be ? test_data_2_be : test_data_2_le; 938c2ecf20Sopenharmony_ci else 948c2ecf20Sopenharmony_ci result = test_data_1; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci /* hex dump */ 978c2ecf20Sopenharmony_ci p = test; 988c2ecf20Sopenharmony_ci for (i = 0; i < l / gs; i++) { 998c2ecf20Sopenharmony_ci const char *q = *result++; 1008c2ecf20Sopenharmony_ci size_t amount = strlen(q); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci memcpy(p, q, amount); 1038c2ecf20Sopenharmony_ci p += amount; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci *p++ = ' '; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci if (i) 1088c2ecf20Sopenharmony_ci p--; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* ASCII part */ 1118c2ecf20Sopenharmony_ci if (ascii) { 1128c2ecf20Sopenharmony_ci do { 1138c2ecf20Sopenharmony_ci *p++ = ' '; 1148c2ecf20Sopenharmony_ci } while (p < test + rs * 2 + rs / gs + 1); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci strncpy(p, data_a, l); 1178c2ecf20Sopenharmony_ci p += l; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci *p = '\0'; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci#define TEST_HEXDUMP_BUF_SIZE (32 * 3 + 2 + 32 + 1) 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic void __init test_hexdump(size_t len, int rowsize, int groupsize, 1268c2ecf20Sopenharmony_ci bool ascii) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci char test[TEST_HEXDUMP_BUF_SIZE]; 1298c2ecf20Sopenharmony_ci char real[TEST_HEXDUMP_BUF_SIZE]; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci total_tests++; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci memset(real, FILL_CHAR, sizeof(real)); 1348c2ecf20Sopenharmony_ci hex_dump_to_buffer(data_b, len, rowsize, groupsize, real, sizeof(real), 1358c2ecf20Sopenharmony_ci ascii); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci memset(test, FILL_CHAR, sizeof(test)); 1388c2ecf20Sopenharmony_ci test_hexdump_prepare_test(len, rowsize, groupsize, test, sizeof(test), 1398c2ecf20Sopenharmony_ci ascii); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (memcmp(test, real, TEST_HEXDUMP_BUF_SIZE)) { 1428c2ecf20Sopenharmony_ci pr_err("Len: %zu row: %d group: %d\n", len, rowsize, groupsize); 1438c2ecf20Sopenharmony_ci pr_err("Result: '%s'\n", real); 1448c2ecf20Sopenharmony_ci pr_err("Expect: '%s'\n", test); 1458c2ecf20Sopenharmony_ci failed_tests++; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic void __init test_hexdump_set(int rowsize, bool ascii) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci size_t d = min_t(size_t, sizeof(data_b), rowsize); 1528c2ecf20Sopenharmony_ci size_t len = get_random_int() % d + 1; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci test_hexdump(len, rowsize, 4, ascii); 1558c2ecf20Sopenharmony_ci test_hexdump(len, rowsize, 2, ascii); 1568c2ecf20Sopenharmony_ci test_hexdump(len, rowsize, 8, ascii); 1578c2ecf20Sopenharmony_ci test_hexdump(len, rowsize, 1, ascii); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic void __init test_hexdump_overflow(size_t buflen, size_t len, 1618c2ecf20Sopenharmony_ci int rowsize, int groupsize, 1628c2ecf20Sopenharmony_ci bool ascii) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci char test[TEST_HEXDUMP_BUF_SIZE]; 1658c2ecf20Sopenharmony_ci char buf[TEST_HEXDUMP_BUF_SIZE]; 1668c2ecf20Sopenharmony_ci int rs = rowsize, gs = groupsize; 1678c2ecf20Sopenharmony_ci int ae, he, e, f, r; 1688c2ecf20Sopenharmony_ci bool a; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci total_tests++; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci memset(buf, FILL_CHAR, sizeof(buf)); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci r = hex_dump_to_buffer(data_b, len, rs, gs, buf, buflen, ascii); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci /* 1778c2ecf20Sopenharmony_ci * Caller must provide the data length multiple of groupsize. The 1788c2ecf20Sopenharmony_ci * calculations below are made with that assumption in mind. 1798c2ecf20Sopenharmony_ci */ 1808c2ecf20Sopenharmony_ci ae = rs * 2 /* hex */ + rs / gs /* spaces */ + 1 /* space */ + len /* ascii */; 1818c2ecf20Sopenharmony_ci he = (gs * 2 /* hex */ + 1 /* space */) * len / gs - 1 /* no trailing space */; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (ascii) 1848c2ecf20Sopenharmony_ci e = ae; 1858c2ecf20Sopenharmony_ci else 1868c2ecf20Sopenharmony_ci e = he; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci f = min_t(int, e + 1, buflen); 1898c2ecf20Sopenharmony_ci if (buflen) { 1908c2ecf20Sopenharmony_ci test_hexdump_prepare_test(len, rs, gs, test, sizeof(test), ascii); 1918c2ecf20Sopenharmony_ci test[f - 1] = '\0'; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci memset(test + f, FILL_CHAR, sizeof(test) - f); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci a = r == e && !memcmp(test, buf, TEST_HEXDUMP_BUF_SIZE); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci buf[sizeof(buf) - 1] = '\0'; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (!a) { 2008c2ecf20Sopenharmony_ci pr_err("Len: %zu buflen: %zu strlen: %zu\n", 2018c2ecf20Sopenharmony_ci len, buflen, strnlen(buf, sizeof(buf))); 2028c2ecf20Sopenharmony_ci pr_err("Result: %d '%s'\n", r, buf); 2038c2ecf20Sopenharmony_ci pr_err("Expect: %d '%s'\n", e, test); 2048c2ecf20Sopenharmony_ci failed_tests++; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic void __init test_hexdump_overflow_set(size_t buflen, bool ascii) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci unsigned int i = 0; 2118c2ecf20Sopenharmony_ci int rs = (get_random_int() % 2 + 1) * 16; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci do { 2148c2ecf20Sopenharmony_ci int gs = 1 << i; 2158c2ecf20Sopenharmony_ci size_t len = get_random_int() % rs + gs; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci test_hexdump_overflow(buflen, rounddown(len, gs), rs, gs, ascii); 2188c2ecf20Sopenharmony_ci } while (i++ < 3); 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic int __init test_hexdump_init(void) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci unsigned int i; 2248c2ecf20Sopenharmony_ci int rowsize; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci rowsize = (get_random_int() % 2 + 1) * 16; 2278c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) 2288c2ecf20Sopenharmony_ci test_hexdump_set(rowsize, false); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci rowsize = (get_random_int() % 2 + 1) * 16; 2318c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) 2328c2ecf20Sopenharmony_ci test_hexdump_set(rowsize, true); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci for (i = 0; i <= TEST_HEXDUMP_BUF_SIZE; i++) 2358c2ecf20Sopenharmony_ci test_hexdump_overflow_set(i, false); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci for (i = 0; i <= TEST_HEXDUMP_BUF_SIZE; i++) 2388c2ecf20Sopenharmony_ci test_hexdump_overflow_set(i, true); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (failed_tests == 0) 2418c2ecf20Sopenharmony_ci pr_info("all %u tests passed\n", total_tests); 2428c2ecf20Sopenharmony_ci else 2438c2ecf20Sopenharmony_ci pr_err("failed %u out of %u tests\n", failed_tests, total_tests); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci return failed_tests ? -EINVAL : 0; 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_cimodule_init(test_hexdump_init); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic void __exit test_hexdump_exit(void) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci /* do nothing */ 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_cimodule_exit(test_hexdump_exit); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>"); 2568c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 257