15 #include <linux/types.h>
16 #include <linux/kernel.h>
17 #include <linux/string.h>
19 #include <asm/cputable.h>
22 #include <asm/sections.h>
41 return (
unsigned int *)((
unsigned long)fcur + offset);
44 static int patch_alt_instruction(
unsigned int *
src,
unsigned int *
dest,
45 unsigned int *alt_start,
unsigned int *alt_end)
55 if (target < alt_start || target >= alt_end) {
67 static int patch_feature_section(
unsigned long value,
struct fixup_entry *fcur)
72 end = calc_addr(fcur, fcur->
end_off);
76 if ((alt_end - alt_start) > (end - start))
85 for (; src < alt_end; src++, dest++) {
86 if (patch_alt_instruction(src, dest, alt_start, alt_end))
90 for (; dest <
end; dest++)
103 for (; fcur < fend; fcur++) {
104 if (patch_feature_section(value, fcur)) {
106 printk(
"Unable to patch feature section at %p - %p" \
109 calc_addr(fcur, fcur->
end_off),
127 for (; start <
end; start++) {
128 dest = (
void *)start + *start;
135 #if defined(CONFIG_PPC64) && defined(CONFIG_RELOCATABLE)
144 length = (__end_interrupts -
_stext) /
sizeof(
int);
154 #ifdef CONFIG_FTR_FIXUP_SELFTEST
157 if (!(x)) printk("feature-fixups: test failed at line %d\n", __LINE__);
164 return (
unsigned long)p - (
unsigned long)entry;
167 void test_basic_patching(
void)
169 extern unsigned int ftr_fixup_test1;
170 extern unsigned int end_ftr_fixup_test1;
171 extern unsigned int ftr_fixup_test1_orig;
172 extern unsigned int ftr_fixup_test1_expected;
173 int size = &end_ftr_fixup_test1 - &ftr_fixup_test1;
176 fixup.start_off = calc_offset(&
fixup, &ftr_fixup_test1 + 1);
177 fixup.end_off = calc_offset(&
fixup, &ftr_fixup_test1 + 2);
181 check(
memcmp(&ftr_fixup_test1, &ftr_fixup_test1_orig, size) == 0);
184 patch_feature_section(8, &
fixup);
185 check(
memcmp(&ftr_fixup_test1, &ftr_fixup_test1_orig, size) == 0);
188 patch_feature_section(0, &
fixup);
189 check(
memcmp(&ftr_fixup_test1, &ftr_fixup_test1_expected, size) == 0);
192 memcpy(&ftr_fixup_test1, &ftr_fixup_test1_orig, size);
193 check(
memcmp(&ftr_fixup_test1, &ftr_fixup_test1_orig, size) == 0);
194 patch_feature_section(~8, &
fixup);
195 check(
memcmp(&ftr_fixup_test1, &ftr_fixup_test1_expected, size) == 0);
198 static void test_alternative_patching(
void)
200 extern unsigned int ftr_fixup_test2;
201 extern unsigned int end_ftr_fixup_test2;
202 extern unsigned int ftr_fixup_test2_orig;
203 extern unsigned int ftr_fixup_test2_alt;
204 extern unsigned int ftr_fixup_test2_expected;
205 int size = &end_ftr_fixup_test2 - &ftr_fixup_test2;
208 fixup.start_off = calc_offset(&
fixup, &ftr_fixup_test2 + 1);
209 fixup.end_off = calc_offset(&
fixup, &ftr_fixup_test2 + 2);
210 fixup.alt_start_off = calc_offset(&
fixup, &ftr_fixup_test2_alt);
211 fixup.alt_end_off = calc_offset(&
fixup, &ftr_fixup_test2_alt + 1);
214 check(
memcmp(&ftr_fixup_test2, &ftr_fixup_test2_orig, size) == 0);
217 patch_feature_section(0xF, &
fixup);
218 check(
memcmp(&ftr_fixup_test2, &ftr_fixup_test2_orig, size) == 0);
221 patch_feature_section(0, &
fixup);
222 check(
memcmp(&ftr_fixup_test2, &ftr_fixup_test2_expected, size) == 0);
225 memcpy(&ftr_fixup_test2, &ftr_fixup_test2_orig, size);
226 check(
memcmp(&ftr_fixup_test2, &ftr_fixup_test2_orig, size) == 0);
227 patch_feature_section(~0xF, &
fixup);
228 check(
memcmp(&ftr_fixup_test2, &ftr_fixup_test2_expected, size) == 0);
231 static void test_alternative_case_too_big(
void)
233 extern unsigned int ftr_fixup_test3;
234 extern unsigned int end_ftr_fixup_test3;
235 extern unsigned int ftr_fixup_test3_orig;
236 extern unsigned int ftr_fixup_test3_alt;
237 int size = &end_ftr_fixup_test3 - &ftr_fixup_test3;
240 fixup.start_off = calc_offset(&
fixup, &ftr_fixup_test3 + 1);
241 fixup.end_off = calc_offset(&
fixup, &ftr_fixup_test3 + 2);
242 fixup.alt_start_off = calc_offset(&
fixup, &ftr_fixup_test3_alt);
243 fixup.alt_end_off = calc_offset(&
fixup, &ftr_fixup_test3_alt + 2);
246 check(
memcmp(&ftr_fixup_test3, &ftr_fixup_test3_orig, size) == 0);
249 check(patch_feature_section(0xF, &
fixup) == 1);
250 check(
memcmp(&ftr_fixup_test3, &ftr_fixup_test3_orig, size) == 0);
252 check(
memcmp(&ftr_fixup_test3, &ftr_fixup_test3_orig, size) == 0);
253 check(patch_feature_section(~0xF, &
fixup) == 1);
254 check(
memcmp(&ftr_fixup_test3, &ftr_fixup_test3_orig, size) == 0);
257 static void test_alternative_case_too_small(
void)
259 extern unsigned int ftr_fixup_test4;
260 extern unsigned int end_ftr_fixup_test4;
261 extern unsigned int ftr_fixup_test4_orig;
262 extern unsigned int ftr_fixup_test4_alt;
263 extern unsigned int ftr_fixup_test4_expected;
264 int size = &end_ftr_fixup_test4 - &ftr_fixup_test4;
268 flag = 1
UL << ((
sizeof(
unsigned long) - 1) * 8);
270 fixup.start_off = calc_offset(&
fixup, &ftr_fixup_test4 + 1);
271 fixup.end_off = calc_offset(&
fixup, &ftr_fixup_test4 + 5);
272 fixup.alt_start_off = calc_offset(&
fixup, &ftr_fixup_test4_alt);
273 fixup.alt_end_off = calc_offset(&
fixup, &ftr_fixup_test4_alt + 2);
276 check(
memcmp(&ftr_fixup_test4, &ftr_fixup_test4_orig, size) == 0);
280 check(
memcmp(&ftr_fixup_test4, &ftr_fixup_test4_orig, size) == 0);
283 patch_feature_section(0, &
fixup);
284 check(
memcmp(&ftr_fixup_test4, &ftr_fixup_test4_expected, size) == 0);
287 memcpy(&ftr_fixup_test4, &ftr_fixup_test4_orig, size);
288 check(
memcmp(&ftr_fixup_test4, &ftr_fixup_test4_orig, size) == 0);
290 check(
memcmp(&ftr_fixup_test4, &ftr_fixup_test4_expected, size) == 0);
293 static void test_alternative_case_with_branch(
void)
295 extern unsigned int ftr_fixup_test5;
296 extern unsigned int end_ftr_fixup_test5;
297 extern unsigned int ftr_fixup_test5_expected;
298 int size = &end_ftr_fixup_test5 - &ftr_fixup_test5;
300 check(
memcmp(&ftr_fixup_test5, &ftr_fixup_test5_expected, size) == 0);
303 static void test_alternative_case_with_external_branch(
void)
305 extern unsigned int ftr_fixup_test6;
306 extern unsigned int end_ftr_fixup_test6;
307 extern unsigned int ftr_fixup_test6_expected;
308 int size = &end_ftr_fixup_test6 - &ftr_fixup_test6;
310 check(
memcmp(&ftr_fixup_test6, &ftr_fixup_test6_expected, size) == 0);
313 static void test_cpu_macros(
void)
315 extern u8 ftr_fixup_test_FTR_macros;
316 extern u8 ftr_fixup_test_FTR_macros_expected;
317 unsigned long size = &ftr_fixup_test_FTR_macros_expected -
318 &ftr_fixup_test_FTR_macros;
322 &ftr_fixup_test_FTR_macros_expected, size) == 0);
325 static void test_fw_macros(
void)
328 extern u8 ftr_fixup_test_FW_FTR_macros;
329 extern u8 ftr_fixup_test_FW_FTR_macros_expected;
330 unsigned long size = &ftr_fixup_test_FW_FTR_macros_expected -
331 &ftr_fixup_test_FW_FTR_macros;
335 &ftr_fixup_test_FW_FTR_macros_expected, size) == 0);
339 static void test_lwsync_macros(
void)
341 extern u8 lwsync_fixup_test;
342 extern u8 end_lwsync_fixup_test;
343 extern u8 lwsync_fixup_test_expected_LWSYNC;
344 extern u8 lwsync_fixup_test_expected_SYNC;
345 unsigned long size = &end_lwsync_fixup_test -
351 &lwsync_fixup_test_expected_LWSYNC, size) == 0);
354 &lwsync_fixup_test_expected_SYNC, size) == 0);
358 static int __init test_feature_fixups(
void)
362 test_basic_patching();
363 test_alternative_patching();
364 test_alternative_case_too_big();
365 test_alternative_case_too_small();
366 test_alternative_case_with_branch();
367 test_alternative_case_with_external_branch();
370 test_lwsync_macros();