18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Modifications for ppc64: 68c2ecf20Sopenharmony_ci * Copyright (C) 2003 Dave Engebretsen <engebret@us.ibm.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright 2008 Michael Ellerman, IBM Corporation. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/types.h> 128c2ecf20Sopenharmony_ci#include <linux/jump_label.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/string.h> 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci#include <linux/sched/mm.h> 178c2ecf20Sopenharmony_ci#include <linux/stop_machine.h> 188c2ecf20Sopenharmony_ci#include <asm/cputable.h> 198c2ecf20Sopenharmony_ci#include <asm/code-patching.h> 208c2ecf20Sopenharmony_ci#include <asm/page.h> 218c2ecf20Sopenharmony_ci#include <asm/sections.h> 228c2ecf20Sopenharmony_ci#include <asm/setup.h> 238c2ecf20Sopenharmony_ci#include <asm/security_features.h> 248c2ecf20Sopenharmony_ci#include <asm/firmware.h> 258c2ecf20Sopenharmony_ci#include <asm/inst.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistruct fixup_entry { 288c2ecf20Sopenharmony_ci unsigned long mask; 298c2ecf20Sopenharmony_ci unsigned long value; 308c2ecf20Sopenharmony_ci long start_off; 318c2ecf20Sopenharmony_ci long end_off; 328c2ecf20Sopenharmony_ci long alt_start_off; 338c2ecf20Sopenharmony_ci long alt_end_off; 348c2ecf20Sopenharmony_ci}; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic struct ppc_inst *calc_addr(struct fixup_entry *fcur, long offset) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci /* 398c2ecf20Sopenharmony_ci * We store the offset to the code as a negative offset from 408c2ecf20Sopenharmony_ci * the start of the alt_entry, to support the VDSO. This 418c2ecf20Sopenharmony_ci * routine converts that back into an actual address. 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_ci return (struct ppc_inst *)((unsigned long)fcur + offset); 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic int patch_alt_instruction(struct ppc_inst *src, struct ppc_inst *dest, 478c2ecf20Sopenharmony_ci struct ppc_inst *alt_start, struct ppc_inst *alt_end) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci int err; 508c2ecf20Sopenharmony_ci struct ppc_inst instr; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci instr = ppc_inst_read(src); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (instr_is_relative_branch(*src)) { 558c2ecf20Sopenharmony_ci struct ppc_inst *target = (struct ppc_inst *)branch_target(src); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci /* Branch within the section doesn't need translating */ 588c2ecf20Sopenharmony_ci if (target < alt_start || target > alt_end) { 598c2ecf20Sopenharmony_ci err = translate_branch(&instr, dest, src); 608c2ecf20Sopenharmony_ci if (err) 618c2ecf20Sopenharmony_ci return 1; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci raw_patch_instruction(dest, instr); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci return 0; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic int patch_feature_section(unsigned long value, struct fixup_entry *fcur) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci struct ppc_inst *start, *end, *alt_start, *alt_end, *src, *dest, nop; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci start = calc_addr(fcur, fcur->start_off); 758c2ecf20Sopenharmony_ci end = calc_addr(fcur, fcur->end_off); 768c2ecf20Sopenharmony_ci alt_start = calc_addr(fcur, fcur->alt_start_off); 778c2ecf20Sopenharmony_ci alt_end = calc_addr(fcur, fcur->alt_end_off); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if ((alt_end - alt_start) > (end - start)) 808c2ecf20Sopenharmony_ci return 1; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if ((value & fcur->mask) == fcur->value) 838c2ecf20Sopenharmony_ci return 0; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci src = alt_start; 868c2ecf20Sopenharmony_ci dest = start; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci for (; src < alt_end; src = ppc_inst_next(src, src), 898c2ecf20Sopenharmony_ci dest = ppc_inst_next(dest, dest)) { 908c2ecf20Sopenharmony_ci if (patch_alt_instruction(src, dest, alt_start, alt_end)) 918c2ecf20Sopenharmony_ci return 1; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci nop = ppc_inst(PPC_INST_NOP); 958c2ecf20Sopenharmony_ci for (; dest < end; dest = ppc_inst_next(dest, &nop)) 968c2ecf20Sopenharmony_ci raw_patch_instruction(dest, nop); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci return 0; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_civoid do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci struct fixup_entry *fcur, *fend; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci fcur = fixup_start; 1068c2ecf20Sopenharmony_ci fend = fixup_end; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci for (; fcur < fend; fcur++) { 1098c2ecf20Sopenharmony_ci if (patch_feature_section(value, fcur)) { 1108c2ecf20Sopenharmony_ci WARN_ON(1); 1118c2ecf20Sopenharmony_ci printk("Unable to patch feature section at %p - %p" \ 1128c2ecf20Sopenharmony_ci " with %p - %p\n", 1138c2ecf20Sopenharmony_ci calc_addr(fcur, fcur->start_off), 1148c2ecf20Sopenharmony_ci calc_addr(fcur, fcur->end_off), 1158c2ecf20Sopenharmony_ci calc_addr(fcur, fcur->alt_start_off), 1168c2ecf20Sopenharmony_ci calc_addr(fcur, fcur->alt_end_off)); 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64 1228c2ecf20Sopenharmony_cistatic void do_stf_entry_barrier_fixups(enum stf_barrier_type types) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci unsigned int instrs[3], *dest; 1258c2ecf20Sopenharmony_ci long *start, *end; 1268c2ecf20Sopenharmony_ci int i; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci start = PTRRELOC(&__start___stf_entry_barrier_fixup), 1298c2ecf20Sopenharmony_ci end = PTRRELOC(&__stop___stf_entry_barrier_fixup); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci instrs[0] = 0x60000000; /* nop */ 1328c2ecf20Sopenharmony_ci instrs[1] = 0x60000000; /* nop */ 1338c2ecf20Sopenharmony_ci instrs[2] = 0x60000000; /* nop */ 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci i = 0; 1368c2ecf20Sopenharmony_ci if (types & STF_BARRIER_FALLBACK) { 1378c2ecf20Sopenharmony_ci instrs[i++] = 0x7d4802a6; /* mflr r10 */ 1388c2ecf20Sopenharmony_ci instrs[i++] = 0x60000000; /* branch patched below */ 1398c2ecf20Sopenharmony_ci instrs[i++] = 0x7d4803a6; /* mtlr r10 */ 1408c2ecf20Sopenharmony_ci } else if (types & STF_BARRIER_EIEIO) { 1418c2ecf20Sopenharmony_ci instrs[i++] = 0x7e0006ac; /* eieio + bit 6 hint */ 1428c2ecf20Sopenharmony_ci } else if (types & STF_BARRIER_SYNC_ORI) { 1438c2ecf20Sopenharmony_ci instrs[i++] = 0x7c0004ac; /* hwsync */ 1448c2ecf20Sopenharmony_ci instrs[i++] = 0xe94d0000; /* ld r10,0(r13) */ 1458c2ecf20Sopenharmony_ci instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */ 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci for (i = 0; start < end; start++, i++) { 1498c2ecf20Sopenharmony_ci dest = (void *)start + *start; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci pr_devel("patching dest %lx\n", (unsigned long)dest); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0])); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (types & STF_BARRIER_FALLBACK) 1568c2ecf20Sopenharmony_ci patch_branch((struct ppc_inst *)(dest + 1), 1578c2ecf20Sopenharmony_ci (unsigned long)&stf_barrier_fallback, 1588c2ecf20Sopenharmony_ci BRANCH_SET_LINK); 1598c2ecf20Sopenharmony_ci else 1608c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)(dest + 1), 1618c2ecf20Sopenharmony_ci ppc_inst(instrs[1])); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2])); 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci printk(KERN_DEBUG "stf-barrier: patched %d entry locations (%s barrier)\n", i, 1678c2ecf20Sopenharmony_ci (types == STF_BARRIER_NONE) ? "no" : 1688c2ecf20Sopenharmony_ci (types == STF_BARRIER_FALLBACK) ? "fallback" : 1698c2ecf20Sopenharmony_ci (types == STF_BARRIER_EIEIO) ? "eieio" : 1708c2ecf20Sopenharmony_ci (types == (STF_BARRIER_SYNC_ORI)) ? "hwsync" 1718c2ecf20Sopenharmony_ci : "unknown"); 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic void do_stf_exit_barrier_fixups(enum stf_barrier_type types) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci unsigned int instrs[6], *dest; 1778c2ecf20Sopenharmony_ci long *start, *end; 1788c2ecf20Sopenharmony_ci int i; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci start = PTRRELOC(&__start___stf_exit_barrier_fixup), 1818c2ecf20Sopenharmony_ci end = PTRRELOC(&__stop___stf_exit_barrier_fixup); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci instrs[0] = 0x60000000; /* nop */ 1848c2ecf20Sopenharmony_ci instrs[1] = 0x60000000; /* nop */ 1858c2ecf20Sopenharmony_ci instrs[2] = 0x60000000; /* nop */ 1868c2ecf20Sopenharmony_ci instrs[3] = 0x60000000; /* nop */ 1878c2ecf20Sopenharmony_ci instrs[4] = 0x60000000; /* nop */ 1888c2ecf20Sopenharmony_ci instrs[5] = 0x60000000; /* nop */ 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci i = 0; 1918c2ecf20Sopenharmony_ci if (types & STF_BARRIER_FALLBACK || types & STF_BARRIER_SYNC_ORI) { 1928c2ecf20Sopenharmony_ci if (cpu_has_feature(CPU_FTR_HVMODE)) { 1938c2ecf20Sopenharmony_ci instrs[i++] = 0x7db14ba6; /* mtspr 0x131, r13 (HSPRG1) */ 1948c2ecf20Sopenharmony_ci instrs[i++] = 0x7db04aa6; /* mfspr r13, 0x130 (HSPRG0) */ 1958c2ecf20Sopenharmony_ci } else { 1968c2ecf20Sopenharmony_ci instrs[i++] = 0x7db243a6; /* mtsprg 2,r13 */ 1978c2ecf20Sopenharmony_ci instrs[i++] = 0x7db142a6; /* mfsprg r13,1 */ 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci instrs[i++] = 0x7c0004ac; /* hwsync */ 2008c2ecf20Sopenharmony_ci instrs[i++] = 0xe9ad0000; /* ld r13,0(r13) */ 2018c2ecf20Sopenharmony_ci instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */ 2028c2ecf20Sopenharmony_ci if (cpu_has_feature(CPU_FTR_HVMODE)) { 2038c2ecf20Sopenharmony_ci instrs[i++] = 0x7db14aa6; /* mfspr r13, 0x131 (HSPRG1) */ 2048c2ecf20Sopenharmony_ci } else { 2058c2ecf20Sopenharmony_ci instrs[i++] = 0x7db242a6; /* mfsprg r13,2 */ 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci } else if (types & STF_BARRIER_EIEIO) { 2088c2ecf20Sopenharmony_ci instrs[i++] = 0x7e0006ac; /* eieio + bit 6 hint */ 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci for (i = 0; start < end; start++, i++) { 2128c2ecf20Sopenharmony_ci dest = (void *)start + *start; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci pr_devel("patching dest %lx\n", (unsigned long)dest); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0])); 2178c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1])); 2188c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2])); 2198c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)(dest + 3), ppc_inst(instrs[3])); 2208c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)(dest + 4), ppc_inst(instrs[4])); 2218c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)(dest + 5), ppc_inst(instrs[5])); 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci printk(KERN_DEBUG "stf-barrier: patched %d exit locations (%s barrier)\n", i, 2248c2ecf20Sopenharmony_ci (types == STF_BARRIER_NONE) ? "no" : 2258c2ecf20Sopenharmony_ci (types == STF_BARRIER_FALLBACK) ? "fallback" : 2268c2ecf20Sopenharmony_ci (types == STF_BARRIER_EIEIO) ? "eieio" : 2278c2ecf20Sopenharmony_ci (types == (STF_BARRIER_SYNC_ORI)) ? "hwsync" 2288c2ecf20Sopenharmony_ci : "unknown"); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic int __do_stf_barrier_fixups(void *data) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci enum stf_barrier_type *types = data; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci do_stf_entry_barrier_fixups(*types); 2368c2ecf20Sopenharmony_ci do_stf_exit_barrier_fixups(*types); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return 0; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_civoid do_stf_barrier_fixups(enum stf_barrier_type types) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci /* 2448c2ecf20Sopenharmony_ci * The call to the fallback entry flush, and the fallback/sync-ori exit 2458c2ecf20Sopenharmony_ci * flush can not be safely patched in/out while other CPUs are executing 2468c2ecf20Sopenharmony_ci * them. So call __do_stf_barrier_fixups() on one CPU while all other CPUs 2478c2ecf20Sopenharmony_ci * spin in the stop machine core with interrupts hard disabled. 2488c2ecf20Sopenharmony_ci */ 2498c2ecf20Sopenharmony_ci stop_machine(__do_stf_barrier_fixups, &types, NULL); 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_civoid do_uaccess_flush_fixups(enum l1d_flush_type types) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci unsigned int instrs[4], *dest; 2558c2ecf20Sopenharmony_ci long *start, *end; 2568c2ecf20Sopenharmony_ci int i; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci start = PTRRELOC(&__start___uaccess_flush_fixup); 2598c2ecf20Sopenharmony_ci end = PTRRELOC(&__stop___uaccess_flush_fixup); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci instrs[0] = 0x60000000; /* nop */ 2628c2ecf20Sopenharmony_ci instrs[1] = 0x60000000; /* nop */ 2638c2ecf20Sopenharmony_ci instrs[2] = 0x60000000; /* nop */ 2648c2ecf20Sopenharmony_ci instrs[3] = 0x4e800020; /* blr */ 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci i = 0; 2678c2ecf20Sopenharmony_ci if (types == L1D_FLUSH_FALLBACK) { 2688c2ecf20Sopenharmony_ci instrs[3] = 0x60000000; /* nop */ 2698c2ecf20Sopenharmony_ci /* fallthrough to fallback flush */ 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (types & L1D_FLUSH_ORI) { 2738c2ecf20Sopenharmony_ci instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */ 2748c2ecf20Sopenharmony_ci instrs[i++] = 0x63de0000; /* ori 30,30,0 L1d flush*/ 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (types & L1D_FLUSH_MTTRIG) 2788c2ecf20Sopenharmony_ci instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */ 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci for (i = 0; start < end; start++, i++) { 2818c2ecf20Sopenharmony_ci dest = (void *)start + *start; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci pr_devel("patching dest %lx\n", (unsigned long)dest); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0])); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1])); 2888c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2])); 2898c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)(dest + 3), ppc_inst(instrs[3])); 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci printk(KERN_DEBUG "uaccess-flush: patched %d locations (%s flush)\n", i, 2938c2ecf20Sopenharmony_ci (types == L1D_FLUSH_NONE) ? "no" : 2948c2ecf20Sopenharmony_ci (types == L1D_FLUSH_FALLBACK) ? "fallback displacement" : 2958c2ecf20Sopenharmony_ci (types & L1D_FLUSH_ORI) ? (types & L1D_FLUSH_MTTRIG) 2968c2ecf20Sopenharmony_ci ? "ori+mttrig type" 2978c2ecf20Sopenharmony_ci : "ori type" : 2988c2ecf20Sopenharmony_ci (types & L1D_FLUSH_MTTRIG) ? "mttrig type" 2998c2ecf20Sopenharmony_ci : "unknown"); 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic int __do_entry_flush_fixups(void *data) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci enum l1d_flush_type types = *(enum l1d_flush_type *)data; 3058c2ecf20Sopenharmony_ci unsigned int instrs[3], *dest; 3068c2ecf20Sopenharmony_ci long *start, *end; 3078c2ecf20Sopenharmony_ci int i; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci instrs[0] = 0x60000000; /* nop */ 3108c2ecf20Sopenharmony_ci instrs[1] = 0x60000000; /* nop */ 3118c2ecf20Sopenharmony_ci instrs[2] = 0x60000000; /* nop */ 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci i = 0; 3148c2ecf20Sopenharmony_ci if (types == L1D_FLUSH_FALLBACK) { 3158c2ecf20Sopenharmony_ci instrs[i++] = 0x7d4802a6; /* mflr r10 */ 3168c2ecf20Sopenharmony_ci instrs[i++] = 0x60000000; /* branch patched below */ 3178c2ecf20Sopenharmony_ci instrs[i++] = 0x7d4803a6; /* mtlr r10 */ 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (types & L1D_FLUSH_ORI) { 3218c2ecf20Sopenharmony_ci instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */ 3228c2ecf20Sopenharmony_ci instrs[i++] = 0x63de0000; /* ori 30,30,0 L1d flush*/ 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci if (types & L1D_FLUSH_MTTRIG) 3268c2ecf20Sopenharmony_ci instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */ 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci start = PTRRELOC(&__start___entry_flush_fixup); 3298c2ecf20Sopenharmony_ci end = PTRRELOC(&__stop___entry_flush_fixup); 3308c2ecf20Sopenharmony_ci for (i = 0; start < end; start++, i++) { 3318c2ecf20Sopenharmony_ci dest = (void *)start + *start; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci pr_devel("patching dest %lx\n", (unsigned long)dest); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0])); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (types == L1D_FLUSH_FALLBACK) 3388c2ecf20Sopenharmony_ci patch_branch((struct ppc_inst *)(dest + 1), (unsigned long)&entry_flush_fallback, 3398c2ecf20Sopenharmony_ci BRANCH_SET_LINK); 3408c2ecf20Sopenharmony_ci else 3418c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1])); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2])); 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci start = PTRRELOC(&__start___scv_entry_flush_fixup); 3478c2ecf20Sopenharmony_ci end = PTRRELOC(&__stop___scv_entry_flush_fixup); 3488c2ecf20Sopenharmony_ci for (; start < end; start++, i++) { 3498c2ecf20Sopenharmony_ci dest = (void *)start + *start; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci pr_devel("patching dest %lx\n", (unsigned long)dest); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0])); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (types == L1D_FLUSH_FALLBACK) 3568c2ecf20Sopenharmony_ci patch_branch((struct ppc_inst *)(dest + 1), (unsigned long)&scv_entry_flush_fallback, 3578c2ecf20Sopenharmony_ci BRANCH_SET_LINK); 3588c2ecf20Sopenharmony_ci else 3598c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1])); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2])); 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci printk(KERN_DEBUG "entry-flush: patched %d locations (%s flush)\n", i, 3668c2ecf20Sopenharmony_ci (types == L1D_FLUSH_NONE) ? "no" : 3678c2ecf20Sopenharmony_ci (types == L1D_FLUSH_FALLBACK) ? "fallback displacement" : 3688c2ecf20Sopenharmony_ci (types & L1D_FLUSH_ORI) ? (types & L1D_FLUSH_MTTRIG) 3698c2ecf20Sopenharmony_ci ? "ori+mttrig type" 3708c2ecf20Sopenharmony_ci : "ori type" : 3718c2ecf20Sopenharmony_ci (types & L1D_FLUSH_MTTRIG) ? "mttrig type" 3728c2ecf20Sopenharmony_ci : "unknown"); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci return 0; 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_civoid do_entry_flush_fixups(enum l1d_flush_type types) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci /* 3808c2ecf20Sopenharmony_ci * The call to the fallback flush can not be safely patched in/out while 3818c2ecf20Sopenharmony_ci * other CPUs are executing it. So call __do_entry_flush_fixups() on one 3828c2ecf20Sopenharmony_ci * CPU while all other CPUs spin in the stop machine core with interrupts 3838c2ecf20Sopenharmony_ci * hard disabled. 3848c2ecf20Sopenharmony_ci */ 3858c2ecf20Sopenharmony_ci stop_machine(__do_entry_flush_fixups, &types, NULL); 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_civoid do_rfi_flush_fixups(enum l1d_flush_type types) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci unsigned int instrs[3], *dest; 3918c2ecf20Sopenharmony_ci long *start, *end; 3928c2ecf20Sopenharmony_ci int i; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci start = PTRRELOC(&__start___rfi_flush_fixup), 3958c2ecf20Sopenharmony_ci end = PTRRELOC(&__stop___rfi_flush_fixup); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci instrs[0] = 0x60000000; /* nop */ 3988c2ecf20Sopenharmony_ci instrs[1] = 0x60000000; /* nop */ 3998c2ecf20Sopenharmony_ci instrs[2] = 0x60000000; /* nop */ 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci if (types & L1D_FLUSH_FALLBACK) 4028c2ecf20Sopenharmony_ci /* b .+16 to fallback flush */ 4038c2ecf20Sopenharmony_ci instrs[0] = 0x48000010; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci i = 0; 4068c2ecf20Sopenharmony_ci if (types & L1D_FLUSH_ORI) { 4078c2ecf20Sopenharmony_ci instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */ 4088c2ecf20Sopenharmony_ci instrs[i++] = 0x63de0000; /* ori 30,30,0 L1d flush*/ 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (types & L1D_FLUSH_MTTRIG) 4128c2ecf20Sopenharmony_ci instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */ 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci for (i = 0; start < end; start++, i++) { 4158c2ecf20Sopenharmony_ci dest = (void *)start + *start; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci pr_devel("patching dest %lx\n", (unsigned long)dest); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0])); 4208c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1])); 4218c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2])); 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci printk(KERN_DEBUG "rfi-flush: patched %d locations (%s flush)\n", i, 4258c2ecf20Sopenharmony_ci (types == L1D_FLUSH_NONE) ? "no" : 4268c2ecf20Sopenharmony_ci (types == L1D_FLUSH_FALLBACK) ? "fallback displacement" : 4278c2ecf20Sopenharmony_ci (types & L1D_FLUSH_ORI) ? (types & L1D_FLUSH_MTTRIG) 4288c2ecf20Sopenharmony_ci ? "ori+mttrig type" 4298c2ecf20Sopenharmony_ci : "ori type" : 4308c2ecf20Sopenharmony_ci (types & L1D_FLUSH_MTTRIG) ? "mttrig type" 4318c2ecf20Sopenharmony_ci : "unknown"); 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_civoid do_barrier_nospec_fixups_range(bool enable, void *fixup_start, void *fixup_end) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci unsigned int instr, *dest; 4378c2ecf20Sopenharmony_ci long *start, *end; 4388c2ecf20Sopenharmony_ci int i; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci start = fixup_start; 4418c2ecf20Sopenharmony_ci end = fixup_end; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci instr = 0x60000000; /* nop */ 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci if (enable) { 4468c2ecf20Sopenharmony_ci pr_info("barrier-nospec: using ORI speculation barrier\n"); 4478c2ecf20Sopenharmony_ci instr = 0x63ff0000; /* ori 31,31,0 speculation barrier */ 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci for (i = 0; start < end; start++, i++) { 4518c2ecf20Sopenharmony_ci dest = (void *)start + *start; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci pr_devel("patching dest %lx\n", (unsigned long)dest); 4548c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)dest, ppc_inst(instr)); 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i); 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC_BOOK3S_64 */ 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_BARRIER_NOSPEC 4638c2ecf20Sopenharmony_civoid do_barrier_nospec_fixups(bool enable) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci void *start, *end; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci start = PTRRELOC(&__start___barrier_nospec_fixup), 4688c2ecf20Sopenharmony_ci end = PTRRELOC(&__stop___barrier_nospec_fixup); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci do_barrier_nospec_fixups_range(enable, start, end); 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC_BARRIER_NOSPEC */ 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_FSL_BOOK3E 4758c2ecf20Sopenharmony_civoid do_barrier_nospec_fixups_range(bool enable, void *fixup_start, void *fixup_end) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci unsigned int instr[2], *dest; 4788c2ecf20Sopenharmony_ci long *start, *end; 4798c2ecf20Sopenharmony_ci int i; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci start = fixup_start; 4828c2ecf20Sopenharmony_ci end = fixup_end; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci instr[0] = PPC_INST_NOP; 4858c2ecf20Sopenharmony_ci instr[1] = PPC_INST_NOP; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (enable) { 4888c2ecf20Sopenharmony_ci pr_info("barrier-nospec: using isync; sync as speculation barrier\n"); 4898c2ecf20Sopenharmony_ci instr[0] = PPC_INST_ISYNC; 4908c2ecf20Sopenharmony_ci instr[1] = PPC_INST_SYNC; 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci for (i = 0; start < end; start++, i++) { 4948c2ecf20Sopenharmony_ci dest = (void *)start + *start; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci pr_devel("patching dest %lx\n", (unsigned long)dest); 4978c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)dest, ppc_inst(instr[0])); 4988c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instr[1])); 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i); 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic void patch_btb_flush_section(long *curr) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci unsigned int *start, *end; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci start = (void *)curr + *curr; 5098c2ecf20Sopenharmony_ci end = (void *)curr + *(curr + 1); 5108c2ecf20Sopenharmony_ci for (; start < end; start++) { 5118c2ecf20Sopenharmony_ci pr_devel("patching dest %lx\n", (unsigned long)start); 5128c2ecf20Sopenharmony_ci patch_instruction((struct ppc_inst *)start, ppc_inst(PPC_INST_NOP)); 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_civoid do_btb_flush_fixups(void) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci long *start, *end; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci start = PTRRELOC(&__start__btb_flush_fixup); 5218c2ecf20Sopenharmony_ci end = PTRRELOC(&__stop__btb_flush_fixup); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci for (; start < end; start += 2) 5248c2ecf20Sopenharmony_ci patch_btb_flush_section(start); 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC_FSL_BOOK3E */ 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_civoid do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci long *start, *end; 5318c2ecf20Sopenharmony_ci struct ppc_inst *dest; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if (!(value & CPU_FTR_LWSYNC)) 5348c2ecf20Sopenharmony_ci return ; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci start = fixup_start; 5378c2ecf20Sopenharmony_ci end = fixup_end; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci for (; start < end; start++) { 5408c2ecf20Sopenharmony_ci dest = (void *)start + *start; 5418c2ecf20Sopenharmony_ci raw_patch_instruction(dest, ppc_inst(PPC_INST_LWSYNC)); 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cistatic void do_final_fixups(void) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci#if defined(CONFIG_PPC64) && defined(CONFIG_RELOCATABLE) 5488c2ecf20Sopenharmony_ci struct ppc_inst inst, *src, *dest, *end; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci if (PHYSICAL_START == 0) 5518c2ecf20Sopenharmony_ci return; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci src = (struct ppc_inst *)(KERNELBASE + PHYSICAL_START); 5548c2ecf20Sopenharmony_ci dest = (struct ppc_inst *)KERNELBASE; 5558c2ecf20Sopenharmony_ci end = (void *)src + (__end_interrupts - _stext); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci while (src < end) { 5588c2ecf20Sopenharmony_ci inst = ppc_inst_read(src); 5598c2ecf20Sopenharmony_ci raw_patch_instruction(dest, inst); 5608c2ecf20Sopenharmony_ci src = ppc_inst_next(src, src); 5618c2ecf20Sopenharmony_ci dest = ppc_inst_next(dest, dest); 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci#endif 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistatic unsigned long __initdata saved_cpu_features; 5678c2ecf20Sopenharmony_cistatic unsigned int __initdata saved_mmu_features; 5688c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64 5698c2ecf20Sopenharmony_cistatic unsigned long __initdata saved_firmware_features; 5708c2ecf20Sopenharmony_ci#endif 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_civoid __init apply_feature_fixups(void) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci struct cpu_spec *spec = PTRRELOC(*PTRRELOC(&cur_cpu_spec)); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci *PTRRELOC(&saved_cpu_features) = spec->cpu_features; 5778c2ecf20Sopenharmony_ci *PTRRELOC(&saved_mmu_features) = spec->mmu_features; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci /* 5808c2ecf20Sopenharmony_ci * Apply the CPU-specific and firmware specific fixups to kernel text 5818c2ecf20Sopenharmony_ci * (nop out sections not relevant to this CPU or this firmware). 5828c2ecf20Sopenharmony_ci */ 5838c2ecf20Sopenharmony_ci do_feature_fixups(spec->cpu_features, 5848c2ecf20Sopenharmony_ci PTRRELOC(&__start___ftr_fixup), 5858c2ecf20Sopenharmony_ci PTRRELOC(&__stop___ftr_fixup)); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci do_feature_fixups(spec->mmu_features, 5888c2ecf20Sopenharmony_ci PTRRELOC(&__start___mmu_ftr_fixup), 5898c2ecf20Sopenharmony_ci PTRRELOC(&__stop___mmu_ftr_fixup)); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci do_lwsync_fixups(spec->cpu_features, 5928c2ecf20Sopenharmony_ci PTRRELOC(&__start___lwsync_fixup), 5938c2ecf20Sopenharmony_ci PTRRELOC(&__stop___lwsync_fixup)); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64 5968c2ecf20Sopenharmony_ci saved_firmware_features = powerpc_firmware_features; 5978c2ecf20Sopenharmony_ci do_feature_fixups(powerpc_firmware_features, 5988c2ecf20Sopenharmony_ci &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup); 5998c2ecf20Sopenharmony_ci#endif 6008c2ecf20Sopenharmony_ci do_final_fixups(); 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_civoid __init setup_feature_keys(void) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci /* 6068c2ecf20Sopenharmony_ci * Initialise jump label. This causes all the cpu/mmu_has_feature() 6078c2ecf20Sopenharmony_ci * checks to take on their correct polarity based on the current set of 6088c2ecf20Sopenharmony_ci * CPU/MMU features. 6098c2ecf20Sopenharmony_ci */ 6108c2ecf20Sopenharmony_ci jump_label_init(); 6118c2ecf20Sopenharmony_ci cpu_feature_keys_init(); 6128c2ecf20Sopenharmony_ci mmu_feature_keys_init(); 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistatic int __init check_features(void) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci WARN(saved_cpu_features != cur_cpu_spec->cpu_features, 6188c2ecf20Sopenharmony_ci "CPU features changed after feature patching!\n"); 6198c2ecf20Sopenharmony_ci WARN(saved_mmu_features != cur_cpu_spec->mmu_features, 6208c2ecf20Sopenharmony_ci "MMU features changed after feature patching!\n"); 6218c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64 6228c2ecf20Sopenharmony_ci WARN(saved_firmware_features != powerpc_firmware_features, 6238c2ecf20Sopenharmony_ci "Firmware features changed after feature patching!\n"); 6248c2ecf20Sopenharmony_ci#endif 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci return 0; 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_cilate_initcall(check_features); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci#ifdef CONFIG_FTR_FIXUP_SELFTEST 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci#define check(x) \ 6338c2ecf20Sopenharmony_ci if (!(x)) printk("feature-fixups: test failed at line %d\n", __LINE__); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci/* This must be after the text it fixes up, vmlinux.lds.S enforces that atm */ 6368c2ecf20Sopenharmony_cistatic struct fixup_entry fixup; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic long calc_offset(struct fixup_entry *entry, unsigned int *p) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci return (unsigned long)p - (unsigned long)entry; 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic void test_basic_patching(void) 6448c2ecf20Sopenharmony_ci{ 6458c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_test1[]; 6468c2ecf20Sopenharmony_ci extern unsigned int end_ftr_fixup_test1[]; 6478c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_test1_orig[]; 6488c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_test1_expected[]; 6498c2ecf20Sopenharmony_ci int size = 4 * (end_ftr_fixup_test1 - ftr_fixup_test1); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci fixup.value = fixup.mask = 8; 6528c2ecf20Sopenharmony_ci fixup.start_off = calc_offset(&fixup, ftr_fixup_test1 + 1); 6538c2ecf20Sopenharmony_ci fixup.end_off = calc_offset(&fixup, ftr_fixup_test1 + 2); 6548c2ecf20Sopenharmony_ci fixup.alt_start_off = fixup.alt_end_off = 0; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci /* Sanity check */ 6578c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test1, ftr_fixup_test1_orig, size) == 0); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* Check we don't patch if the value matches */ 6608c2ecf20Sopenharmony_ci patch_feature_section(8, &fixup); 6618c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test1, ftr_fixup_test1_orig, size) == 0); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci /* Check we do patch if the value doesn't match */ 6648c2ecf20Sopenharmony_ci patch_feature_section(0, &fixup); 6658c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test1, ftr_fixup_test1_expected, size) == 0); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci /* Check we do patch if the mask doesn't match */ 6688c2ecf20Sopenharmony_ci memcpy(ftr_fixup_test1, ftr_fixup_test1_orig, size); 6698c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test1, ftr_fixup_test1_orig, size) == 0); 6708c2ecf20Sopenharmony_ci patch_feature_section(~8, &fixup); 6718c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test1, ftr_fixup_test1_expected, size) == 0); 6728c2ecf20Sopenharmony_ci} 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_cistatic void test_alternative_patching(void) 6758c2ecf20Sopenharmony_ci{ 6768c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_test2[]; 6778c2ecf20Sopenharmony_ci extern unsigned int end_ftr_fixup_test2[]; 6788c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_test2_orig[]; 6798c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_test2_alt[]; 6808c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_test2_expected[]; 6818c2ecf20Sopenharmony_ci int size = 4 * (end_ftr_fixup_test2 - ftr_fixup_test2); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci fixup.value = fixup.mask = 0xF; 6848c2ecf20Sopenharmony_ci fixup.start_off = calc_offset(&fixup, ftr_fixup_test2 + 1); 6858c2ecf20Sopenharmony_ci fixup.end_off = calc_offset(&fixup, ftr_fixup_test2 + 2); 6868c2ecf20Sopenharmony_ci fixup.alt_start_off = calc_offset(&fixup, ftr_fixup_test2_alt); 6878c2ecf20Sopenharmony_ci fixup.alt_end_off = calc_offset(&fixup, ftr_fixup_test2_alt + 1); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci /* Sanity check */ 6908c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test2, ftr_fixup_test2_orig, size) == 0); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci /* Check we don't patch if the value matches */ 6938c2ecf20Sopenharmony_ci patch_feature_section(0xF, &fixup); 6948c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test2, ftr_fixup_test2_orig, size) == 0); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci /* Check we do patch if the value doesn't match */ 6978c2ecf20Sopenharmony_ci patch_feature_section(0, &fixup); 6988c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test2, ftr_fixup_test2_expected, size) == 0); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci /* Check we do patch if the mask doesn't match */ 7018c2ecf20Sopenharmony_ci memcpy(ftr_fixup_test2, ftr_fixup_test2_orig, size); 7028c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test2, ftr_fixup_test2_orig, size) == 0); 7038c2ecf20Sopenharmony_ci patch_feature_section(~0xF, &fixup); 7048c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test2, ftr_fixup_test2_expected, size) == 0); 7058c2ecf20Sopenharmony_ci} 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_cistatic void test_alternative_case_too_big(void) 7088c2ecf20Sopenharmony_ci{ 7098c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_test3[]; 7108c2ecf20Sopenharmony_ci extern unsigned int end_ftr_fixup_test3[]; 7118c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_test3_orig[]; 7128c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_test3_alt[]; 7138c2ecf20Sopenharmony_ci int size = 4 * (end_ftr_fixup_test3 - ftr_fixup_test3); 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci fixup.value = fixup.mask = 0xC; 7168c2ecf20Sopenharmony_ci fixup.start_off = calc_offset(&fixup, ftr_fixup_test3 + 1); 7178c2ecf20Sopenharmony_ci fixup.end_off = calc_offset(&fixup, ftr_fixup_test3 + 2); 7188c2ecf20Sopenharmony_ci fixup.alt_start_off = calc_offset(&fixup, ftr_fixup_test3_alt); 7198c2ecf20Sopenharmony_ci fixup.alt_end_off = calc_offset(&fixup, ftr_fixup_test3_alt + 2); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci /* Sanity check */ 7228c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test3, ftr_fixup_test3_orig, size) == 0); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci /* Expect nothing to be patched, and the error returned to us */ 7258c2ecf20Sopenharmony_ci check(patch_feature_section(0xF, &fixup) == 1); 7268c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test3, ftr_fixup_test3_orig, size) == 0); 7278c2ecf20Sopenharmony_ci check(patch_feature_section(0, &fixup) == 1); 7288c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test3, ftr_fixup_test3_orig, size) == 0); 7298c2ecf20Sopenharmony_ci check(patch_feature_section(~0xF, &fixup) == 1); 7308c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test3, ftr_fixup_test3_orig, size) == 0); 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_cistatic void test_alternative_case_too_small(void) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_test4[]; 7368c2ecf20Sopenharmony_ci extern unsigned int end_ftr_fixup_test4[]; 7378c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_test4_orig[]; 7388c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_test4_alt[]; 7398c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_test4_expected[]; 7408c2ecf20Sopenharmony_ci int size = 4 * (end_ftr_fixup_test4 - ftr_fixup_test4); 7418c2ecf20Sopenharmony_ci unsigned long flag; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci /* Check a high-bit flag */ 7448c2ecf20Sopenharmony_ci flag = 1UL << ((sizeof(unsigned long) - 1) * 8); 7458c2ecf20Sopenharmony_ci fixup.value = fixup.mask = flag; 7468c2ecf20Sopenharmony_ci fixup.start_off = calc_offset(&fixup, ftr_fixup_test4 + 1); 7478c2ecf20Sopenharmony_ci fixup.end_off = calc_offset(&fixup, ftr_fixup_test4 + 5); 7488c2ecf20Sopenharmony_ci fixup.alt_start_off = calc_offset(&fixup, ftr_fixup_test4_alt); 7498c2ecf20Sopenharmony_ci fixup.alt_end_off = calc_offset(&fixup, ftr_fixup_test4_alt + 2); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* Sanity check */ 7528c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test4, ftr_fixup_test4_orig, size) == 0); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci /* Check we don't patch if the value matches */ 7558c2ecf20Sopenharmony_ci patch_feature_section(flag, &fixup); 7568c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test4, ftr_fixup_test4_orig, size) == 0); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci /* Check we do patch if the value doesn't match */ 7598c2ecf20Sopenharmony_ci patch_feature_section(0, &fixup); 7608c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test4, ftr_fixup_test4_expected, size) == 0); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci /* Check we do patch if the mask doesn't match */ 7638c2ecf20Sopenharmony_ci memcpy(ftr_fixup_test4, ftr_fixup_test4_orig, size); 7648c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test4, ftr_fixup_test4_orig, size) == 0); 7658c2ecf20Sopenharmony_ci patch_feature_section(~flag, &fixup); 7668c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test4, ftr_fixup_test4_expected, size) == 0); 7678c2ecf20Sopenharmony_ci} 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_cistatic void test_alternative_case_with_branch(void) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_test5[]; 7728c2ecf20Sopenharmony_ci extern unsigned int end_ftr_fixup_test5[]; 7738c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_test5_expected[]; 7748c2ecf20Sopenharmony_ci int size = 4 * (end_ftr_fixup_test5 - ftr_fixup_test5); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test5, ftr_fixup_test5_expected, size) == 0); 7778c2ecf20Sopenharmony_ci} 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_cistatic void test_alternative_case_with_external_branch(void) 7808c2ecf20Sopenharmony_ci{ 7818c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_test6[]; 7828c2ecf20Sopenharmony_ci extern unsigned int end_ftr_fixup_test6[]; 7838c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_test6_expected[]; 7848c2ecf20Sopenharmony_ci int size = 4 * (end_ftr_fixup_test6 - ftr_fixup_test6); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test6, ftr_fixup_test6_expected, size) == 0); 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_cistatic void test_alternative_case_with_branch_to_end(void) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_test7[]; 7928c2ecf20Sopenharmony_ci extern unsigned int end_ftr_fixup_test7[]; 7938c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_test7_expected[]; 7948c2ecf20Sopenharmony_ci int size = 4 * (end_ftr_fixup_test7 - ftr_fixup_test7); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test7, ftr_fixup_test7_expected, size) == 0); 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cistatic void test_cpu_macros(void) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci extern u8 ftr_fixup_test_FTR_macros[]; 8028c2ecf20Sopenharmony_ci extern u8 ftr_fixup_test_FTR_macros_expected[]; 8038c2ecf20Sopenharmony_ci unsigned long size = ftr_fixup_test_FTR_macros_expected - 8048c2ecf20Sopenharmony_ci ftr_fixup_test_FTR_macros; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci /* The fixups have already been done for us during boot */ 8078c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test_FTR_macros, 8088c2ecf20Sopenharmony_ci ftr_fixup_test_FTR_macros_expected, size) == 0); 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_cistatic void test_fw_macros(void) 8128c2ecf20Sopenharmony_ci{ 8138c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64 8148c2ecf20Sopenharmony_ci extern u8 ftr_fixup_test_FW_FTR_macros[]; 8158c2ecf20Sopenharmony_ci extern u8 ftr_fixup_test_FW_FTR_macros_expected[]; 8168c2ecf20Sopenharmony_ci unsigned long size = ftr_fixup_test_FW_FTR_macros_expected - 8178c2ecf20Sopenharmony_ci ftr_fixup_test_FW_FTR_macros; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci /* The fixups have already been done for us during boot */ 8208c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_test_FW_FTR_macros, 8218c2ecf20Sopenharmony_ci ftr_fixup_test_FW_FTR_macros_expected, size) == 0); 8228c2ecf20Sopenharmony_ci#endif 8238c2ecf20Sopenharmony_ci} 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_cistatic void test_lwsync_macros(void) 8268c2ecf20Sopenharmony_ci{ 8278c2ecf20Sopenharmony_ci extern u8 lwsync_fixup_test[]; 8288c2ecf20Sopenharmony_ci extern u8 end_lwsync_fixup_test[]; 8298c2ecf20Sopenharmony_ci extern u8 lwsync_fixup_test_expected_LWSYNC[]; 8308c2ecf20Sopenharmony_ci extern u8 lwsync_fixup_test_expected_SYNC[]; 8318c2ecf20Sopenharmony_ci unsigned long size = end_lwsync_fixup_test - 8328c2ecf20Sopenharmony_ci lwsync_fixup_test; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci /* The fixups have already been done for us during boot */ 8358c2ecf20Sopenharmony_ci if (cur_cpu_spec->cpu_features & CPU_FTR_LWSYNC) { 8368c2ecf20Sopenharmony_ci check(memcmp(lwsync_fixup_test, 8378c2ecf20Sopenharmony_ci lwsync_fixup_test_expected_LWSYNC, size) == 0); 8388c2ecf20Sopenharmony_ci } else { 8398c2ecf20Sopenharmony_ci check(memcmp(lwsync_fixup_test, 8408c2ecf20Sopenharmony_ci lwsync_fixup_test_expected_SYNC, size) == 0); 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64 8458c2ecf20Sopenharmony_cistatic void __init test_prefix_patching(void) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_prefix1[]; 8488c2ecf20Sopenharmony_ci extern unsigned int end_ftr_fixup_prefix1[]; 8498c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_prefix1_orig[]; 8508c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_prefix1_expected[]; 8518c2ecf20Sopenharmony_ci int size = sizeof(unsigned int) * (end_ftr_fixup_prefix1 - ftr_fixup_prefix1); 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci fixup.value = fixup.mask = 8; 8548c2ecf20Sopenharmony_ci fixup.start_off = calc_offset(&fixup, ftr_fixup_prefix1 + 1); 8558c2ecf20Sopenharmony_ci fixup.end_off = calc_offset(&fixup, ftr_fixup_prefix1 + 3); 8568c2ecf20Sopenharmony_ci fixup.alt_start_off = fixup.alt_end_off = 0; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci /* Sanity check */ 8598c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_prefix1, ftr_fixup_prefix1_orig, size) == 0); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci patch_feature_section(0, &fixup); 8628c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_prefix1, ftr_fixup_prefix1_expected, size) == 0); 8638c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_prefix1, ftr_fixup_prefix1_orig, size) != 0); 8648c2ecf20Sopenharmony_ci} 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_cistatic void __init test_prefix_alt_patching(void) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_prefix2[]; 8698c2ecf20Sopenharmony_ci extern unsigned int end_ftr_fixup_prefix2[]; 8708c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_prefix2_orig[]; 8718c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_prefix2_expected[]; 8728c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_prefix2_alt[]; 8738c2ecf20Sopenharmony_ci int size = sizeof(unsigned int) * (end_ftr_fixup_prefix2 - ftr_fixup_prefix2); 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci fixup.value = fixup.mask = 8; 8768c2ecf20Sopenharmony_ci fixup.start_off = calc_offset(&fixup, ftr_fixup_prefix2 + 1); 8778c2ecf20Sopenharmony_ci fixup.end_off = calc_offset(&fixup, ftr_fixup_prefix2 + 3); 8788c2ecf20Sopenharmony_ci fixup.alt_start_off = calc_offset(&fixup, ftr_fixup_prefix2_alt); 8798c2ecf20Sopenharmony_ci fixup.alt_end_off = calc_offset(&fixup, ftr_fixup_prefix2_alt + 2); 8808c2ecf20Sopenharmony_ci /* Sanity check */ 8818c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_prefix2, ftr_fixup_prefix2_orig, size) == 0); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci patch_feature_section(0, &fixup); 8848c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_prefix2, ftr_fixup_prefix2_expected, size) == 0); 8858c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_prefix2, ftr_fixup_prefix2_orig, size) != 0); 8868c2ecf20Sopenharmony_ci} 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_cistatic void __init test_prefix_word_alt_patching(void) 8898c2ecf20Sopenharmony_ci{ 8908c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_prefix3[]; 8918c2ecf20Sopenharmony_ci extern unsigned int end_ftr_fixup_prefix3[]; 8928c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_prefix3_orig[]; 8938c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_prefix3_expected[]; 8948c2ecf20Sopenharmony_ci extern unsigned int ftr_fixup_prefix3_alt[]; 8958c2ecf20Sopenharmony_ci int size = sizeof(unsigned int) * (end_ftr_fixup_prefix3 - ftr_fixup_prefix3); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci fixup.value = fixup.mask = 8; 8988c2ecf20Sopenharmony_ci fixup.start_off = calc_offset(&fixup, ftr_fixup_prefix3 + 1); 8998c2ecf20Sopenharmony_ci fixup.end_off = calc_offset(&fixup, ftr_fixup_prefix3 + 4); 9008c2ecf20Sopenharmony_ci fixup.alt_start_off = calc_offset(&fixup, ftr_fixup_prefix3_alt); 9018c2ecf20Sopenharmony_ci fixup.alt_end_off = calc_offset(&fixup, ftr_fixup_prefix3_alt + 3); 9028c2ecf20Sopenharmony_ci /* Sanity check */ 9038c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_prefix3, ftr_fixup_prefix3_orig, size) == 0); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci patch_feature_section(0, &fixup); 9068c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_prefix3, ftr_fixup_prefix3_expected, size) == 0); 9078c2ecf20Sopenharmony_ci patch_feature_section(0, &fixup); 9088c2ecf20Sopenharmony_ci check(memcmp(ftr_fixup_prefix3, ftr_fixup_prefix3_orig, size) != 0); 9098c2ecf20Sopenharmony_ci} 9108c2ecf20Sopenharmony_ci#else 9118c2ecf20Sopenharmony_cistatic inline void test_prefix_patching(void) {} 9128c2ecf20Sopenharmony_cistatic inline void test_prefix_alt_patching(void) {} 9138c2ecf20Sopenharmony_cistatic inline void test_prefix_word_alt_patching(void) {} 9148c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC64 */ 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_cistatic int __init test_feature_fixups(void) 9178c2ecf20Sopenharmony_ci{ 9188c2ecf20Sopenharmony_ci printk(KERN_DEBUG "Running feature fixup self-tests ...\n"); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci test_basic_patching(); 9218c2ecf20Sopenharmony_ci test_alternative_patching(); 9228c2ecf20Sopenharmony_ci test_alternative_case_too_big(); 9238c2ecf20Sopenharmony_ci test_alternative_case_too_small(); 9248c2ecf20Sopenharmony_ci test_alternative_case_with_branch(); 9258c2ecf20Sopenharmony_ci test_alternative_case_with_external_branch(); 9268c2ecf20Sopenharmony_ci test_alternative_case_with_branch_to_end(); 9278c2ecf20Sopenharmony_ci test_cpu_macros(); 9288c2ecf20Sopenharmony_ci test_fw_macros(); 9298c2ecf20Sopenharmony_ci test_lwsync_macros(); 9308c2ecf20Sopenharmony_ci test_prefix_patching(); 9318c2ecf20Sopenharmony_ci test_prefix_alt_patching(); 9328c2ecf20Sopenharmony_ci test_prefix_word_alt_patching(); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci return 0; 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_cilate_initcall(test_feature_fixups); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci#endif /* CONFIG_FTR_FIXUP_SELFTEST */ 939