xref: /openbmc/linux/lib/test_static_keys.c (revision a8fe58ce)
1 /*
2  * Kernel module for testing static keys.
3  *
4  * Copyright 2015 Akamai Technologies Inc. All Rights Reserved
5  *
6  * Authors:
7  *      Jason Baron       <jbaron@akamai.com>
8  *
9  * This software is licensed under the terms of the GNU General Public
10  * License version 2, as published by the Free Software Foundation, and
11  * may be copied, distributed, and modified under those terms.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  */
18 
19 #include <linux/module.h>
20 #include <linux/jump_label.h>
21 
22 /* old keys */
23 struct static_key old_true_key	= STATIC_KEY_INIT_TRUE;
24 struct static_key old_false_key	= STATIC_KEY_INIT_FALSE;
25 
26 /* new api */
27 DEFINE_STATIC_KEY_TRUE(true_key);
28 DEFINE_STATIC_KEY_FALSE(false_key);
29 
30 /* external */
31 extern struct static_key base_old_true_key;
32 extern struct static_key base_inv_old_true_key;
33 extern struct static_key base_old_false_key;
34 extern struct static_key base_inv_old_false_key;
35 
36 /* new api */
37 extern struct static_key_true base_true_key;
38 extern struct static_key_true base_inv_true_key;
39 extern struct static_key_false base_false_key;
40 extern struct static_key_false base_inv_false_key;
41 
42 
43 struct test_key {
44 	bool			init_state;
45 	struct static_key	*key;
46 	bool			(*test_key)(void);
47 };
48 
49 #define test_key_func(key, branch) \
50 	({bool func(void) { return branch(key); } func;	})
51 
52 static void invert_key(struct static_key *key)
53 {
54 	if (static_key_enabled(key))
55 		static_key_disable(key);
56 	else
57 		static_key_enable(key);
58 }
59 
60 static void invert_keys(struct test_key *keys, int size)
61 {
62 	struct static_key *previous = NULL;
63 	int i;
64 
65 	for (i = 0; i < size; i++) {
66 		if (previous != keys[i].key) {
67 			invert_key(keys[i].key);
68 			previous = keys[i].key;
69 		}
70 	}
71 }
72 
73 static int verify_keys(struct test_key *keys, int size, bool invert)
74 {
75 	int i;
76 	bool ret, init;
77 
78 	for (i = 0; i < size; i++) {
79 		ret = static_key_enabled(keys[i].key);
80 		init = keys[i].init_state;
81 		if (ret != (invert ? !init : init))
82 			return -EINVAL;
83 		ret = keys[i].test_key();
84 		if (static_key_enabled(keys[i].key)) {
85 			if (!ret)
86 				return -EINVAL;
87 		} else {
88 			if (ret)
89 				return -EINVAL;
90 		}
91 	}
92 	return 0;
93 }
94 
95 static int __init test_static_key_init(void)
96 {
97 	int ret;
98 	int size;
99 
100 	struct test_key static_key_tests[] = {
101 		/* internal keys - old keys */
102 		{
103 			.init_state	= true,
104 			.key		= &old_true_key,
105 			.test_key	= test_key_func(&old_true_key, static_key_true),
106 		},
107 		{
108 			.init_state	= false,
109 			.key		= &old_false_key,
110 			.test_key	= test_key_func(&old_false_key, static_key_false),
111 		},
112 		/* internal keys - new keys */
113 		{
114 			.init_state	= true,
115 			.key		= &true_key.key,
116 			.test_key	= test_key_func(&true_key, static_branch_likely),
117 		},
118 		{
119 			.init_state	= true,
120 			.key		= &true_key.key,
121 			.test_key	= test_key_func(&true_key, static_branch_unlikely),
122 		},
123 		{
124 			.init_state	= false,
125 			.key		= &false_key.key,
126 			.test_key	= test_key_func(&false_key, static_branch_likely),
127 		},
128 		{
129 			.init_state	= false,
130 			.key		= &false_key.key,
131 			.test_key	= test_key_func(&false_key, static_branch_unlikely),
132 		},
133 		/* external keys - old keys */
134 		{
135 			.init_state	= true,
136 			.key		= &base_old_true_key,
137 			.test_key	= test_key_func(&base_old_true_key, static_key_true),
138 		},
139 		{
140 			.init_state	= false,
141 			.key		= &base_inv_old_true_key,
142 			.test_key	= test_key_func(&base_inv_old_true_key, static_key_true),
143 		},
144 		{
145 			.init_state	= false,
146 			.key		= &base_old_false_key,
147 			.test_key	= test_key_func(&base_old_false_key, static_key_false),
148 		},
149 		{
150 			.init_state	= true,
151 			.key		= &base_inv_old_false_key,
152 			.test_key	= test_key_func(&base_inv_old_false_key, static_key_false),
153 		},
154 		/* external keys - new keys */
155 		{
156 			.init_state	= true,
157 			.key		= &base_true_key.key,
158 			.test_key	= test_key_func(&base_true_key, static_branch_likely),
159 		},
160 		{
161 			.init_state	= true,
162 			.key		= &base_true_key.key,
163 			.test_key	= test_key_func(&base_true_key, static_branch_unlikely),
164 		},
165 		{
166 			.init_state	= false,
167 			.key		= &base_inv_true_key.key,
168 			.test_key	= test_key_func(&base_inv_true_key, static_branch_likely),
169 		},
170 		{
171 			.init_state	= false,
172 			.key		= &base_inv_true_key.key,
173 			.test_key	= test_key_func(&base_inv_true_key, static_branch_unlikely),
174 		},
175 		{
176 			.init_state	= false,
177 			.key		= &base_false_key.key,
178 			.test_key	= test_key_func(&base_false_key, static_branch_likely),
179 		},
180 		{
181 			.init_state	= false,
182 			.key		= &base_false_key.key,
183 			.test_key	= test_key_func(&base_false_key, static_branch_unlikely),
184 		},
185 		{
186 			.init_state	= true,
187 			.key		= &base_inv_false_key.key,
188 			.test_key	= test_key_func(&base_inv_false_key, static_branch_likely),
189 		},
190 		{
191 			.init_state	= true,
192 			.key		= &base_inv_false_key.key,
193 			.test_key	= test_key_func(&base_inv_false_key, static_branch_unlikely),
194 		},
195 	};
196 
197 	size = ARRAY_SIZE(static_key_tests);
198 
199 	ret = verify_keys(static_key_tests, size, false);
200 	if (ret)
201 		goto out;
202 
203 	invert_keys(static_key_tests, size);
204 	ret = verify_keys(static_key_tests, size, true);
205 	if (ret)
206 		goto out;
207 
208 	invert_keys(static_key_tests, size);
209 	ret = verify_keys(static_key_tests, size, false);
210 	if (ret)
211 		goto out;
212 	return 0;
213 out:
214 	return ret;
215 }
216 
217 static void __exit test_static_key_exit(void)
218 {
219 }
220 
221 module_init(test_static_key_init);
222 module_exit(test_static_key_exit);
223 
224 MODULE_AUTHOR("Jason Baron <jbaron@akamai.com>");
225 MODULE_LICENSE("GPL");
226