aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/lib/feature-fixups.c
diff options
context:
space:
mode:
authorMichael Ellerman <michael@ellerman.id.au>2008-06-23 21:33:03 -0400
committerPaul Mackerras <paulus@samba.org>2008-06-30 21:28:30 -0400
commit362e7701fd183d990e0863883461edef61392710 (patch)
treea39d5466e2a6b68dd16187da8fad27ea50fb9851 /arch/powerpc/lib/feature-fixups.c
parent9b1a735de64cc975c31a1642ec55e082ddbdfeaf (diff)
powerpc: Add self-tests of the feature fixup code
This commit adds tests of the feature fixup code, they are run during boot if CONFIG_FTR_FIXUP_SELFTEST=y. Some of the tests manually invoke the patching routines to check their behaviour, and others use the macros and so are patched during the normal patching done during boot. Because we have two sets of macros with different names, we use a macro to generate the test of the macros, very niiiice. Signed-off-by: Michael Ellerman <michael@ellerman.id.au> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/lib/feature-fixups.c')
-rw-r--r--arch/powerpc/lib/feature-fixups.c206
1 files changed, 206 insertions, 0 deletions
diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c
index 174c1eba9ac..48e1ed89052 100644
--- a/arch/powerpc/lib/feature-fixups.c
+++ b/arch/powerpc/lib/feature-fixups.c
@@ -13,6 +13,8 @@
13 */ 13 */
14 14
15#include <linux/kernel.h> 15#include <linux/kernel.h>
16#include <linux/string.h>
17#include <linux/init.h>
16#include <asm/cputable.h> 18#include <asm/cputable.h>
17#include <asm/code-patching.h> 19#include <asm/code-patching.h>
18 20
@@ -107,3 +109,207 @@ void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
107 } 109 }
108 } 110 }
109} 111}
112
113#ifdef CONFIG_FTR_FIXUP_SELFTEST
114
115#define check(x) \
116 if (!(x)) printk("feature-fixups: test failed at line %d\n", __LINE__);
117
118/* This must be after the text it fixes up, vmlinux.lds.S enforces that atm */
119static struct fixup_entry fixup;
120
121static long calc_offset(struct fixup_entry *entry, unsigned int *p)
122{
123 return (unsigned long)p - (unsigned long)entry;
124}
125
126void test_basic_patching(void)
127{
128 extern unsigned int ftr_fixup_test1;
129 extern unsigned int end_ftr_fixup_test1;
130 extern unsigned int ftr_fixup_test1_orig;
131 extern unsigned int ftr_fixup_test1_expected;
132 int size = &end_ftr_fixup_test1 - &ftr_fixup_test1;
133
134 fixup.value = fixup.mask = 8;
135 fixup.start_off = calc_offset(&fixup, &ftr_fixup_test1 + 1);
136 fixup.end_off = calc_offset(&fixup, &ftr_fixup_test1 + 2);
137 fixup.alt_start_off = fixup.alt_end_off = 0;
138
139 /* Sanity check */
140 check(memcmp(&ftr_fixup_test1, &ftr_fixup_test1_orig, size) == 0);
141
142 /* Check we don't patch if the value matches */
143 patch_feature_section(8, &fixup);
144 check(memcmp(&ftr_fixup_test1, &ftr_fixup_test1_orig, size) == 0);
145
146 /* Check we do patch if the value doesn't match */
147 patch_feature_section(0, &fixup);
148 check(memcmp(&ftr_fixup_test1, &ftr_fixup_test1_expected, size) == 0);
149
150 /* Check we do patch if the mask doesn't match */
151 memcpy(&ftr_fixup_test1, &ftr_fixup_test1_orig, size);
152 check(memcmp(&ftr_fixup_test1, &ftr_fixup_test1_orig, size) == 0);
153 patch_feature_section(~8, &fixup);
154 check(memcmp(&ftr_fixup_test1, &ftr_fixup_test1_expected, size) == 0);
155}
156
157static void test_alternative_patching(void)
158{
159 extern unsigned int ftr_fixup_test2;
160 extern unsigned int end_ftr_fixup_test2;
161 extern unsigned int ftr_fixup_test2_orig;
162 extern unsigned int ftr_fixup_test2_alt;
163 extern unsigned int ftr_fixup_test2_expected;
164 int size = &end_ftr_fixup_test2 - &ftr_fixup_test2;
165
166 fixup.value = fixup.mask = 0xF;
167 fixup.start_off = calc_offset(&fixup, &ftr_fixup_test2 + 1);
168 fixup.end_off = calc_offset(&fixup, &ftr_fixup_test2 + 2);
169 fixup.alt_start_off = calc_offset(&fixup, &ftr_fixup_test2_alt);
170 fixup.alt_end_off = calc_offset(&fixup, &ftr_fixup_test2_alt + 1);
171
172 /* Sanity check */
173 check(memcmp(&ftr_fixup_test2, &ftr_fixup_test2_orig, size) == 0);
174
175 /* Check we don't patch if the value matches */
176 patch_feature_section(0xF, &fixup);
177 check(memcmp(&ftr_fixup_test2, &ftr_fixup_test2_orig, size) == 0);
178
179 /* Check we do patch if the value doesn't match */
180 patch_feature_section(0, &fixup);
181 check(memcmp(&ftr_fixup_test2, &ftr_fixup_test2_expected, size) == 0);
182
183 /* Check we do patch if the mask doesn't match */
184 memcpy(&ftr_fixup_test2, &ftr_fixup_test2_orig, size);
185 check(memcmp(&ftr_fixup_test2, &ftr_fixup_test2_orig, size) == 0);
186 patch_feature_section(~0xF, &fixup);
187 check(memcmp(&ftr_fixup_test2, &ftr_fixup_test2_expected, size) == 0);
188}
189
190static void test_alternative_case_too_big(void)
191{
192 extern unsigned int ftr_fixup_test3;
193 extern unsigned int end_ftr_fixup_test3;
194 extern unsigned int ftr_fixup_test3_orig;
195 extern unsigned int ftr_fixup_test3_alt;
196 int size = &end_ftr_fixup_test3 - &ftr_fixup_test3;
197
198 fixup.value = fixup.mask = 0xC;
199 fixup.start_off = calc_offset(&fixup, &ftr_fixup_test3 + 1);
200 fixup.end_off = calc_offset(&fixup, &ftr_fixup_test3 + 2);
201 fixup.alt_start_off = calc_offset(&fixup, &ftr_fixup_test3_alt);
202 fixup.alt_end_off = calc_offset(&fixup, &ftr_fixup_test3_alt + 2);
203
204 /* Sanity check */
205 check(memcmp(&ftr_fixup_test3, &ftr_fixup_test3_orig, size) == 0);
206
207 /* Expect nothing to be patched, and the error returned to us */
208 check(patch_feature_section(0xF, &fixup) == 1);
209 check(memcmp(&ftr_fixup_test3, &ftr_fixup_test3_orig, size) == 0);
210 check(patch_feature_section(0, &fixup) == 1);
211 check(memcmp(&ftr_fixup_test3, &ftr_fixup_test3_orig, size) == 0);
212 check(patch_feature_section(~0xF, &fixup) == 1);
213 check(memcmp(&ftr_fixup_test3, &ftr_fixup_test3_orig, size) == 0);
214}
215
216static void test_alternative_case_too_small(void)
217{
218 extern unsigned int ftr_fixup_test4;
219 extern unsigned int end_ftr_fixup_test4;
220 extern unsigned int ftr_fixup_test4_orig;
221 extern unsigned int ftr_fixup_test4_alt;
222 extern unsigned int ftr_fixup_test4_expected;
223 int size = &end_ftr_fixup_test4 - &ftr_fixup_test4;
224 unsigned long flag;
225
226 /* Check a high-bit flag */
227 flag = 1UL << ((sizeof(unsigned long) - 1) * 8);
228 fixup.value = fixup.mask = flag;
229 fixup.start_off = calc_offset(&fixup, &ftr_fixup_test4 + 1);
230 fixup.end_off = calc_offset(&fixup, &ftr_fixup_test4 + 5);
231 fixup.alt_start_off = calc_offset(&fixup, &ftr_fixup_test4_alt);
232 fixup.alt_end_off = calc_offset(&fixup, &ftr_fixup_test4_alt + 2);
233
234 /* Sanity check */
235 check(memcmp(&ftr_fixup_test4, &ftr_fixup_test4_orig, size) == 0);
236
237 /* Check we don't patch if the value matches */
238 patch_feature_section(flag, &fixup);
239 check(memcmp(&ftr_fixup_test4, &ftr_fixup_test4_orig, size) == 0);
240
241 /* Check we do patch if the value doesn't match */
242 patch_feature_section(0, &fixup);
243 check(memcmp(&ftr_fixup_test4, &ftr_fixup_test4_expected, size) == 0);
244
245 /* Check we do patch if the mask doesn't match */
246 memcpy(&ftr_fixup_test4, &ftr_fixup_test4_orig, size);
247 check(memcmp(&ftr_fixup_test4, &ftr_fixup_test4_orig, size) == 0);
248 patch_feature_section(~flag, &fixup);
249 check(memcmp(&ftr_fixup_test4, &ftr_fixup_test4_expected, size) == 0);
250}
251
252static void test_alternative_case_with_branch(void)
253{
254 extern unsigned int ftr_fixup_test5;
255 extern unsigned int end_ftr_fixup_test5;
256 extern unsigned int ftr_fixup_test5_expected;
257 int size = &end_ftr_fixup_test5 - &ftr_fixup_test5;
258
259 check(memcmp(&ftr_fixup_test5, &ftr_fixup_test5_expected, size) == 0);
260}
261
262static void test_alternative_case_with_external_branch(void)
263{
264 extern unsigned int ftr_fixup_test6;
265 extern unsigned int end_ftr_fixup_test6;
266 extern unsigned int ftr_fixup_test6_expected;
267 int size = &end_ftr_fixup_test6 - &ftr_fixup_test6;
268
269 check(memcmp(&ftr_fixup_test6, &ftr_fixup_test6_expected, size) == 0);
270}
271
272static void test_cpu_macros(void)
273{
274 extern void ftr_fixup_test_FTR_macros;
275 extern void ftr_fixup_test_FTR_macros_expected;
276 unsigned long size = &ftr_fixup_test_FTR_macros_expected -
277 &ftr_fixup_test_FTR_macros;
278
279 /* The fixups have already been done for us during boot */
280 check(memcmp(&ftr_fixup_test_FTR_macros,
281 &ftr_fixup_test_FTR_macros_expected, size) == 0);
282}
283
284static void test_fw_macros(void)
285{
286#ifdef CONFIG_PPC64
287 extern void ftr_fixup_test_FW_FTR_macros;
288 extern void ftr_fixup_test_FW_FTR_macros_expected;
289 unsigned long size = &ftr_fixup_test_FW_FTR_macros_expected -
290 &ftr_fixup_test_FW_FTR_macros;
291
292 /* The fixups have already been done for us during boot */
293 check(memcmp(&ftr_fixup_test_FW_FTR_macros,
294 &ftr_fixup_test_FW_FTR_macros_expected, size) == 0);
295#endif
296}
297
298static int __init test_feature_fixups(void)
299{
300 printk(KERN_DEBUG "Running feature fixup self-tests ...\n");
301
302 test_basic_patching();
303 test_alternative_patching();
304 test_alternative_case_too_big();
305 test_alternative_case_too_small();
306 test_alternative_case_with_branch();
307 test_alternative_case_with_external_branch();
308 test_cpu_macros();
309 test_fw_macros();
310
311 return 0;
312}
313late_initcall(test_feature_fixups);
314
315#endif /* CONFIG_FTR_FIXUP_SELFTEST */