18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Kernel module for testing static keys. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2015 Akamai Technologies Inc. All Rights Reserved 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: 88c2ecf20Sopenharmony_ci * Jason Baron <jbaron@akamai.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/jump_label.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* old keys */ 158c2ecf20Sopenharmony_cistruct static_key old_true_key = STATIC_KEY_INIT_TRUE; 168c2ecf20Sopenharmony_cistruct static_key old_false_key = STATIC_KEY_INIT_FALSE; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* new api */ 198c2ecf20Sopenharmony_ciDEFINE_STATIC_KEY_TRUE(true_key); 208c2ecf20Sopenharmony_ciDEFINE_STATIC_KEY_FALSE(false_key); 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* external */ 238c2ecf20Sopenharmony_ciextern struct static_key base_old_true_key; 248c2ecf20Sopenharmony_ciextern struct static_key base_inv_old_true_key; 258c2ecf20Sopenharmony_ciextern struct static_key base_old_false_key; 268c2ecf20Sopenharmony_ciextern struct static_key base_inv_old_false_key; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* new api */ 298c2ecf20Sopenharmony_ciextern struct static_key_true base_true_key; 308c2ecf20Sopenharmony_ciextern struct static_key_true base_inv_true_key; 318c2ecf20Sopenharmony_ciextern struct static_key_false base_false_key; 328c2ecf20Sopenharmony_ciextern struct static_key_false base_inv_false_key; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistruct test_key { 368c2ecf20Sopenharmony_ci bool init_state; 378c2ecf20Sopenharmony_ci struct static_key *key; 388c2ecf20Sopenharmony_ci bool (*test_key)(void); 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define test_key_func(key, branch) \ 428c2ecf20Sopenharmony_cistatic bool key ## _ ## branch(void) \ 438c2ecf20Sopenharmony_ci{ \ 448c2ecf20Sopenharmony_ci return branch(&key); \ 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic void invert_key(struct static_key *key) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci if (static_key_enabled(key)) 508c2ecf20Sopenharmony_ci static_key_disable(key); 518c2ecf20Sopenharmony_ci else 528c2ecf20Sopenharmony_ci static_key_enable(key); 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic void invert_keys(struct test_key *keys, int size) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci struct static_key *previous = NULL; 588c2ecf20Sopenharmony_ci int i; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) { 618c2ecf20Sopenharmony_ci if (previous != keys[i].key) { 628c2ecf20Sopenharmony_ci invert_key(keys[i].key); 638c2ecf20Sopenharmony_ci previous = keys[i].key; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic int verify_keys(struct test_key *keys, int size, bool invert) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci int i; 718c2ecf20Sopenharmony_ci bool ret, init; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) { 748c2ecf20Sopenharmony_ci ret = static_key_enabled(keys[i].key); 758c2ecf20Sopenharmony_ci init = keys[i].init_state; 768c2ecf20Sopenharmony_ci if (ret != (invert ? !init : init)) 778c2ecf20Sopenharmony_ci return -EINVAL; 788c2ecf20Sopenharmony_ci ret = keys[i].test_key(); 798c2ecf20Sopenharmony_ci if (static_key_enabled(keys[i].key)) { 808c2ecf20Sopenharmony_ci if (!ret) 818c2ecf20Sopenharmony_ci return -EINVAL; 828c2ecf20Sopenharmony_ci } else { 838c2ecf20Sopenharmony_ci if (ret) 848c2ecf20Sopenharmony_ci return -EINVAL; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci return 0; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_citest_key_func(old_true_key, static_key_true) 918c2ecf20Sopenharmony_citest_key_func(old_false_key, static_key_false) 928c2ecf20Sopenharmony_citest_key_func(true_key, static_branch_likely) 938c2ecf20Sopenharmony_citest_key_func(true_key, static_branch_unlikely) 948c2ecf20Sopenharmony_citest_key_func(false_key, static_branch_likely) 958c2ecf20Sopenharmony_citest_key_func(false_key, static_branch_unlikely) 968c2ecf20Sopenharmony_citest_key_func(base_old_true_key, static_key_true) 978c2ecf20Sopenharmony_citest_key_func(base_inv_old_true_key, static_key_true) 988c2ecf20Sopenharmony_citest_key_func(base_old_false_key, static_key_false) 998c2ecf20Sopenharmony_citest_key_func(base_inv_old_false_key, static_key_false) 1008c2ecf20Sopenharmony_citest_key_func(base_true_key, static_branch_likely) 1018c2ecf20Sopenharmony_citest_key_func(base_true_key, static_branch_unlikely) 1028c2ecf20Sopenharmony_citest_key_func(base_inv_true_key, static_branch_likely) 1038c2ecf20Sopenharmony_citest_key_func(base_inv_true_key, static_branch_unlikely) 1048c2ecf20Sopenharmony_citest_key_func(base_false_key, static_branch_likely) 1058c2ecf20Sopenharmony_citest_key_func(base_false_key, static_branch_unlikely) 1068c2ecf20Sopenharmony_citest_key_func(base_inv_false_key, static_branch_likely) 1078c2ecf20Sopenharmony_citest_key_func(base_inv_false_key, static_branch_unlikely) 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic int __init test_static_key_init(void) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci int ret; 1128c2ecf20Sopenharmony_ci int size; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci struct test_key static_key_tests[] = { 1158c2ecf20Sopenharmony_ci /* internal keys - old keys */ 1168c2ecf20Sopenharmony_ci { 1178c2ecf20Sopenharmony_ci .init_state = true, 1188c2ecf20Sopenharmony_ci .key = &old_true_key, 1198c2ecf20Sopenharmony_ci .test_key = &old_true_key_static_key_true, 1208c2ecf20Sopenharmony_ci }, 1218c2ecf20Sopenharmony_ci { 1228c2ecf20Sopenharmony_ci .init_state = false, 1238c2ecf20Sopenharmony_ci .key = &old_false_key, 1248c2ecf20Sopenharmony_ci .test_key = &old_false_key_static_key_false, 1258c2ecf20Sopenharmony_ci }, 1268c2ecf20Sopenharmony_ci /* internal keys - new keys */ 1278c2ecf20Sopenharmony_ci { 1288c2ecf20Sopenharmony_ci .init_state = true, 1298c2ecf20Sopenharmony_ci .key = &true_key.key, 1308c2ecf20Sopenharmony_ci .test_key = &true_key_static_branch_likely, 1318c2ecf20Sopenharmony_ci }, 1328c2ecf20Sopenharmony_ci { 1338c2ecf20Sopenharmony_ci .init_state = true, 1348c2ecf20Sopenharmony_ci .key = &true_key.key, 1358c2ecf20Sopenharmony_ci .test_key = &true_key_static_branch_unlikely, 1368c2ecf20Sopenharmony_ci }, 1378c2ecf20Sopenharmony_ci { 1388c2ecf20Sopenharmony_ci .init_state = false, 1398c2ecf20Sopenharmony_ci .key = &false_key.key, 1408c2ecf20Sopenharmony_ci .test_key = &false_key_static_branch_likely, 1418c2ecf20Sopenharmony_ci }, 1428c2ecf20Sopenharmony_ci { 1438c2ecf20Sopenharmony_ci .init_state = false, 1448c2ecf20Sopenharmony_ci .key = &false_key.key, 1458c2ecf20Sopenharmony_ci .test_key = &false_key_static_branch_unlikely, 1468c2ecf20Sopenharmony_ci }, 1478c2ecf20Sopenharmony_ci /* external keys - old keys */ 1488c2ecf20Sopenharmony_ci { 1498c2ecf20Sopenharmony_ci .init_state = true, 1508c2ecf20Sopenharmony_ci .key = &base_old_true_key, 1518c2ecf20Sopenharmony_ci .test_key = &base_old_true_key_static_key_true, 1528c2ecf20Sopenharmony_ci }, 1538c2ecf20Sopenharmony_ci { 1548c2ecf20Sopenharmony_ci .init_state = false, 1558c2ecf20Sopenharmony_ci .key = &base_inv_old_true_key, 1568c2ecf20Sopenharmony_ci .test_key = &base_inv_old_true_key_static_key_true, 1578c2ecf20Sopenharmony_ci }, 1588c2ecf20Sopenharmony_ci { 1598c2ecf20Sopenharmony_ci .init_state = false, 1608c2ecf20Sopenharmony_ci .key = &base_old_false_key, 1618c2ecf20Sopenharmony_ci .test_key = &base_old_false_key_static_key_false, 1628c2ecf20Sopenharmony_ci }, 1638c2ecf20Sopenharmony_ci { 1648c2ecf20Sopenharmony_ci .init_state = true, 1658c2ecf20Sopenharmony_ci .key = &base_inv_old_false_key, 1668c2ecf20Sopenharmony_ci .test_key = &base_inv_old_false_key_static_key_false, 1678c2ecf20Sopenharmony_ci }, 1688c2ecf20Sopenharmony_ci /* external keys - new keys */ 1698c2ecf20Sopenharmony_ci { 1708c2ecf20Sopenharmony_ci .init_state = true, 1718c2ecf20Sopenharmony_ci .key = &base_true_key.key, 1728c2ecf20Sopenharmony_ci .test_key = &base_true_key_static_branch_likely, 1738c2ecf20Sopenharmony_ci }, 1748c2ecf20Sopenharmony_ci { 1758c2ecf20Sopenharmony_ci .init_state = true, 1768c2ecf20Sopenharmony_ci .key = &base_true_key.key, 1778c2ecf20Sopenharmony_ci .test_key = &base_true_key_static_branch_unlikely, 1788c2ecf20Sopenharmony_ci }, 1798c2ecf20Sopenharmony_ci { 1808c2ecf20Sopenharmony_ci .init_state = false, 1818c2ecf20Sopenharmony_ci .key = &base_inv_true_key.key, 1828c2ecf20Sopenharmony_ci .test_key = &base_inv_true_key_static_branch_likely, 1838c2ecf20Sopenharmony_ci }, 1848c2ecf20Sopenharmony_ci { 1858c2ecf20Sopenharmony_ci .init_state = false, 1868c2ecf20Sopenharmony_ci .key = &base_inv_true_key.key, 1878c2ecf20Sopenharmony_ci .test_key = &base_inv_true_key_static_branch_unlikely, 1888c2ecf20Sopenharmony_ci }, 1898c2ecf20Sopenharmony_ci { 1908c2ecf20Sopenharmony_ci .init_state = false, 1918c2ecf20Sopenharmony_ci .key = &base_false_key.key, 1928c2ecf20Sopenharmony_ci .test_key = &base_false_key_static_branch_likely, 1938c2ecf20Sopenharmony_ci }, 1948c2ecf20Sopenharmony_ci { 1958c2ecf20Sopenharmony_ci .init_state = false, 1968c2ecf20Sopenharmony_ci .key = &base_false_key.key, 1978c2ecf20Sopenharmony_ci .test_key = &base_false_key_static_branch_unlikely, 1988c2ecf20Sopenharmony_ci }, 1998c2ecf20Sopenharmony_ci { 2008c2ecf20Sopenharmony_ci .init_state = true, 2018c2ecf20Sopenharmony_ci .key = &base_inv_false_key.key, 2028c2ecf20Sopenharmony_ci .test_key = &base_inv_false_key_static_branch_likely, 2038c2ecf20Sopenharmony_ci }, 2048c2ecf20Sopenharmony_ci { 2058c2ecf20Sopenharmony_ci .init_state = true, 2068c2ecf20Sopenharmony_ci .key = &base_inv_false_key.key, 2078c2ecf20Sopenharmony_ci .test_key = &base_inv_false_key_static_branch_unlikely, 2088c2ecf20Sopenharmony_ci }, 2098c2ecf20Sopenharmony_ci }; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci size = ARRAY_SIZE(static_key_tests); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci ret = verify_keys(static_key_tests, size, false); 2148c2ecf20Sopenharmony_ci if (ret) 2158c2ecf20Sopenharmony_ci goto out; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci invert_keys(static_key_tests, size); 2188c2ecf20Sopenharmony_ci ret = verify_keys(static_key_tests, size, true); 2198c2ecf20Sopenharmony_ci if (ret) 2208c2ecf20Sopenharmony_ci goto out; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci invert_keys(static_key_tests, size); 2238c2ecf20Sopenharmony_ci ret = verify_keys(static_key_tests, size, false); 2248c2ecf20Sopenharmony_ci if (ret) 2258c2ecf20Sopenharmony_ci goto out; 2268c2ecf20Sopenharmony_ci return 0; 2278c2ecf20Sopenharmony_ciout: 2288c2ecf20Sopenharmony_ci return ret; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic void __exit test_static_key_exit(void) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cimodule_init(test_static_key_init); 2368c2ecf20Sopenharmony_cimodule_exit(test_static_key_exit); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jason Baron <jbaron@akamai.com>"); 2398c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 240