^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Modifications for ppc64:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2003 Dave Engebretsen <engebret@us.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Copyright 2008 Michael Ellerman, IBM Corporation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/jump_label.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/sched/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/stop_machine.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <asm/cputable.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <asm/code-patching.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <asm/page.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <asm/sections.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <asm/setup.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <asm/security_features.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <asm/firmware.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <asm/inst.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct fixup_entry {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) unsigned long mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) unsigned long value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) long start_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) long end_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) long alt_start_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) long alt_end_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static struct ppc_inst *calc_addr(struct fixup_entry *fcur, long offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * We store the offset to the code as a negative offset from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * the start of the alt_entry, to support the VDSO. This
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * routine converts that back into an actual address.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) return (struct ppc_inst *)((unsigned long)fcur + offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static int patch_alt_instruction(struct ppc_inst *src, struct ppc_inst *dest,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct ppc_inst *alt_start, struct ppc_inst *alt_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct ppc_inst instr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) instr = ppc_inst_read(src);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) if (instr_is_relative_branch(*src)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct ppc_inst *target = (struct ppc_inst *)branch_target(src);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /* Branch within the section doesn't need translating */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) if (target < alt_start || target > alt_end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) err = translate_branch(&instr, dest, src);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) raw_patch_instruction(dest, instr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static int patch_feature_section(unsigned long value, struct fixup_entry *fcur)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct ppc_inst *start, *end, *alt_start, *alt_end, *src, *dest, nop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) start = calc_addr(fcur, fcur->start_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) end = calc_addr(fcur, fcur->end_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) alt_start = calc_addr(fcur, fcur->alt_start_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) alt_end = calc_addr(fcur, fcur->alt_end_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if ((alt_end - alt_start) > (end - start))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if ((value & fcur->mask) == fcur->value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) src = alt_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) dest = start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) for (; src < alt_end; src = ppc_inst_next(src, src),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) dest = ppc_inst_next(dest, dest)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (patch_alt_instruction(src, dest, alt_start, alt_end))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) nop = ppc_inst(PPC_INST_NOP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) for (; dest < end; dest = ppc_inst_next(dest, &nop))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) raw_patch_instruction(dest, nop);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) struct fixup_entry *fcur, *fend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) fcur = fixup_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) fend = fixup_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) for (; fcur < fend; fcur++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (patch_feature_section(value, fcur)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) WARN_ON(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) printk("Unable to patch feature section at %p - %p" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) " with %p - %p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) calc_addr(fcur, fcur->start_off),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) calc_addr(fcur, fcur->end_off),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) calc_addr(fcur, fcur->alt_start_off),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) calc_addr(fcur, fcur->alt_end_off));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) #ifdef CONFIG_PPC_BOOK3S_64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) static void do_stf_entry_barrier_fixups(enum stf_barrier_type types)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) unsigned int instrs[3], *dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) long *start, *end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) start = PTRRELOC(&__start___stf_entry_barrier_fixup),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) end = PTRRELOC(&__stop___stf_entry_barrier_fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) instrs[0] = 0x60000000; /* nop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) instrs[1] = 0x60000000; /* nop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) instrs[2] = 0x60000000; /* nop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) if (types & STF_BARRIER_FALLBACK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) instrs[i++] = 0x7d4802a6; /* mflr r10 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) instrs[i++] = 0x60000000; /* branch patched below */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) instrs[i++] = 0x7d4803a6; /* mtlr r10 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) } else if (types & STF_BARRIER_EIEIO) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) instrs[i++] = 0x7e0006ac; /* eieio + bit 6 hint */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) } else if (types & STF_BARRIER_SYNC_ORI) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) instrs[i++] = 0x7c0004ac; /* hwsync */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) instrs[i++] = 0xe94d0000; /* ld r10,0(r13) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) for (i = 0; start < end; start++, i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) dest = (void *)start + *start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) pr_devel("patching dest %lx\n", (unsigned long)dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (types & STF_BARRIER_FALLBACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) patch_branch((struct ppc_inst *)(dest + 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) (unsigned long)&stf_barrier_fallback,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) BRANCH_SET_LINK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) patch_instruction((struct ppc_inst *)(dest + 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) ppc_inst(instrs[1]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) printk(KERN_DEBUG "stf-barrier: patched %d entry locations (%s barrier)\n", i,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) (types == STF_BARRIER_NONE) ? "no" :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) (types == STF_BARRIER_FALLBACK) ? "fallback" :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) (types == STF_BARRIER_EIEIO) ? "eieio" :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) (types == (STF_BARRIER_SYNC_ORI)) ? "hwsync"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) : "unknown");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static void do_stf_exit_barrier_fixups(enum stf_barrier_type types)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) unsigned int instrs[6], *dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) long *start, *end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) start = PTRRELOC(&__start___stf_exit_barrier_fixup),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) end = PTRRELOC(&__stop___stf_exit_barrier_fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) instrs[0] = 0x60000000; /* nop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) instrs[1] = 0x60000000; /* nop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) instrs[2] = 0x60000000; /* nop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) instrs[3] = 0x60000000; /* nop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) instrs[4] = 0x60000000; /* nop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) instrs[5] = 0x60000000; /* nop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (types & STF_BARRIER_FALLBACK || types & STF_BARRIER_SYNC_ORI) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) if (cpu_has_feature(CPU_FTR_HVMODE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) instrs[i++] = 0x7db14ba6; /* mtspr 0x131, r13 (HSPRG1) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) instrs[i++] = 0x7db04aa6; /* mfspr r13, 0x130 (HSPRG0) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) instrs[i++] = 0x7db243a6; /* mtsprg 2,r13 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) instrs[i++] = 0x7db142a6; /* mfsprg r13,1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) instrs[i++] = 0x7c0004ac; /* hwsync */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) instrs[i++] = 0xe9ad0000; /* ld r13,0(r13) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) if (cpu_has_feature(CPU_FTR_HVMODE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) instrs[i++] = 0x7db14aa6; /* mfspr r13, 0x131 (HSPRG1) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) instrs[i++] = 0x7db242a6; /* mfsprg r13,2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) } else if (types & STF_BARRIER_EIEIO) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) instrs[i++] = 0x7e0006ac; /* eieio + bit 6 hint */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) for (i = 0; start < end; start++, i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) dest = (void *)start + *start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) pr_devel("patching dest %lx\n", (unsigned long)dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) patch_instruction((struct ppc_inst *)(dest + 3), ppc_inst(instrs[3]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) patch_instruction((struct ppc_inst *)(dest + 4), ppc_inst(instrs[4]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) patch_instruction((struct ppc_inst *)(dest + 5), ppc_inst(instrs[5]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) printk(KERN_DEBUG "stf-barrier: patched %d exit locations (%s barrier)\n", i,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) (types == STF_BARRIER_NONE) ? "no" :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) (types == STF_BARRIER_FALLBACK) ? "fallback" :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) (types == STF_BARRIER_EIEIO) ? "eieio" :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) (types == (STF_BARRIER_SYNC_ORI)) ? "hwsync"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) : "unknown");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) static int __do_stf_barrier_fixups(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) enum stf_barrier_type *types = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) do_stf_entry_barrier_fixups(*types);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) do_stf_exit_barrier_fixups(*types);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) void do_stf_barrier_fixups(enum stf_barrier_type types)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) * The call to the fallback entry flush, and the fallback/sync-ori exit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) * flush can not be safely patched in/out while other CPUs are executing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) * them. So call __do_stf_barrier_fixups() on one CPU while all other CPUs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) * spin in the stop machine core with interrupts hard disabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) stop_machine(__do_stf_barrier_fixups, &types, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) void do_uaccess_flush_fixups(enum l1d_flush_type types)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) unsigned int instrs[4], *dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) long *start, *end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) start = PTRRELOC(&__start___uaccess_flush_fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) end = PTRRELOC(&__stop___uaccess_flush_fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) instrs[0] = 0x60000000; /* nop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) instrs[1] = 0x60000000; /* nop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) instrs[2] = 0x60000000; /* nop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) instrs[3] = 0x4e800020; /* blr */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) if (types == L1D_FLUSH_FALLBACK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) instrs[3] = 0x60000000; /* nop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) /* fallthrough to fallback flush */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) if (types & L1D_FLUSH_ORI) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) instrs[i++] = 0x63de0000; /* ori 30,30,0 L1d flush*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) if (types & L1D_FLUSH_MTTRIG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) for (i = 0; start < end; start++, i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) dest = (void *)start + *start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) pr_devel("patching dest %lx\n", (unsigned long)dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) patch_instruction((struct ppc_inst *)(dest + 3), ppc_inst(instrs[3]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) printk(KERN_DEBUG "uaccess-flush: patched %d locations (%s flush)\n", i,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) (types == L1D_FLUSH_NONE) ? "no" :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) (types == L1D_FLUSH_FALLBACK) ? "fallback displacement" :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) (types & L1D_FLUSH_ORI) ? (types & L1D_FLUSH_MTTRIG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) ? "ori+mttrig type"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) : "ori type" :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) (types & L1D_FLUSH_MTTRIG) ? "mttrig type"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) : "unknown");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) static int __do_entry_flush_fixups(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) enum l1d_flush_type types = *(enum l1d_flush_type *)data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) unsigned int instrs[3], *dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) long *start, *end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) instrs[0] = 0x60000000; /* nop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) instrs[1] = 0x60000000; /* nop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) instrs[2] = 0x60000000; /* nop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) if (types == L1D_FLUSH_FALLBACK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) instrs[i++] = 0x7d4802a6; /* mflr r10 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) instrs[i++] = 0x60000000; /* branch patched below */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) instrs[i++] = 0x7d4803a6; /* mtlr r10 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) if (types & L1D_FLUSH_ORI) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) instrs[i++] = 0x63de0000; /* ori 30,30,0 L1d flush*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (types & L1D_FLUSH_MTTRIG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) start = PTRRELOC(&__start___entry_flush_fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) end = PTRRELOC(&__stop___entry_flush_fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) for (i = 0; start < end; start++, i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) dest = (void *)start + *start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) pr_devel("patching dest %lx\n", (unsigned long)dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) if (types == L1D_FLUSH_FALLBACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) patch_branch((struct ppc_inst *)(dest + 1), (unsigned long)&entry_flush_fallback,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) BRANCH_SET_LINK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) start = PTRRELOC(&__start___scv_entry_flush_fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) end = PTRRELOC(&__stop___scv_entry_flush_fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) for (; start < end; start++, i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) dest = (void *)start + *start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) pr_devel("patching dest %lx\n", (unsigned long)dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) if (types == L1D_FLUSH_FALLBACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) patch_branch((struct ppc_inst *)(dest + 1), (unsigned long)&scv_entry_flush_fallback,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) BRANCH_SET_LINK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) printk(KERN_DEBUG "entry-flush: patched %d locations (%s flush)\n", i,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) (types == L1D_FLUSH_NONE) ? "no" :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) (types == L1D_FLUSH_FALLBACK) ? "fallback displacement" :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) (types & L1D_FLUSH_ORI) ? (types & L1D_FLUSH_MTTRIG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) ? "ori+mttrig type"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) : "ori type" :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) (types & L1D_FLUSH_MTTRIG) ? "mttrig type"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) : "unknown");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) void do_entry_flush_fixups(enum l1d_flush_type types)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) * The call to the fallback flush can not be safely patched in/out while
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) * other CPUs are executing it. So call __do_entry_flush_fixups() on one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) * CPU while all other CPUs spin in the stop machine core with interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) * hard disabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) stop_machine(__do_entry_flush_fixups, &types, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) void do_rfi_flush_fixups(enum l1d_flush_type types)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) unsigned int instrs[3], *dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) long *start, *end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) start = PTRRELOC(&__start___rfi_flush_fixup),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) end = PTRRELOC(&__stop___rfi_flush_fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) instrs[0] = 0x60000000; /* nop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) instrs[1] = 0x60000000; /* nop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) instrs[2] = 0x60000000; /* nop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) if (types & L1D_FLUSH_FALLBACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) /* b .+16 to fallback flush */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) instrs[0] = 0x48000010;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) if (types & L1D_FLUSH_ORI) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) instrs[i++] = 0x63de0000; /* ori 30,30,0 L1d flush*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) if (types & L1D_FLUSH_MTTRIG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) for (i = 0; start < end; start++, i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) dest = (void *)start + *start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) pr_devel("patching dest %lx\n", (unsigned long)dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) printk(KERN_DEBUG "rfi-flush: patched %d locations (%s flush)\n", i,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) (types == L1D_FLUSH_NONE) ? "no" :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) (types == L1D_FLUSH_FALLBACK) ? "fallback displacement" :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) (types & L1D_FLUSH_ORI) ? (types & L1D_FLUSH_MTTRIG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) ? "ori+mttrig type"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) : "ori type" :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) (types & L1D_FLUSH_MTTRIG) ? "mttrig type"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) : "unknown");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) void do_barrier_nospec_fixups_range(bool enable, void *fixup_start, void *fixup_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) unsigned int instr, *dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) long *start, *end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) start = fixup_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) end = fixup_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) instr = 0x60000000; /* nop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) if (enable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) pr_info("barrier-nospec: using ORI speculation barrier\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) instr = 0x63ff0000; /* ori 31,31,0 speculation barrier */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) for (i = 0; start < end; start++, i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) dest = (void *)start + *start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) pr_devel("patching dest %lx\n", (unsigned long)dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) patch_instruction((struct ppc_inst *)dest, ppc_inst(instr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) #endif /* CONFIG_PPC_BOOK3S_64 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) #ifdef CONFIG_PPC_BARRIER_NOSPEC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) void do_barrier_nospec_fixups(bool enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) void *start, *end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) start = PTRRELOC(&__start___barrier_nospec_fixup),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) end = PTRRELOC(&__stop___barrier_nospec_fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) do_barrier_nospec_fixups_range(enable, start, end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) #endif /* CONFIG_PPC_BARRIER_NOSPEC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) #ifdef CONFIG_PPC_FSL_BOOK3E
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) void do_barrier_nospec_fixups_range(bool enable, void *fixup_start, void *fixup_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) unsigned int instr[2], *dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) long *start, *end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) start = fixup_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) end = fixup_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) instr[0] = PPC_INST_NOP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) instr[1] = PPC_INST_NOP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) if (enable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) pr_info("barrier-nospec: using isync; sync as speculation barrier\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) instr[0] = PPC_INST_ISYNC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) instr[1] = PPC_INST_SYNC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) for (i = 0; start < end; start++, i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) dest = (void *)start + *start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) pr_devel("patching dest %lx\n", (unsigned long)dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) patch_instruction((struct ppc_inst *)dest, ppc_inst(instr[0]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instr[1]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) static void patch_btb_flush_section(long *curr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) unsigned int *start, *end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) start = (void *)curr + *curr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) end = (void *)curr + *(curr + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) for (; start < end; start++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) pr_devel("patching dest %lx\n", (unsigned long)start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) patch_instruction((struct ppc_inst *)start, ppc_inst(PPC_INST_NOP));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) void do_btb_flush_fixups(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) long *start, *end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) start = PTRRELOC(&__start__btb_flush_fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) end = PTRRELOC(&__stop__btb_flush_fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) for (; start < end; start += 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) patch_btb_flush_section(start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) #endif /* CONFIG_PPC_FSL_BOOK3E */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) long *start, *end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) struct ppc_inst *dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) if (!(value & CPU_FTR_LWSYNC))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) return ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) start = fixup_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) end = fixup_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) for (; start < end; start++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) dest = (void *)start + *start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) raw_patch_instruction(dest, ppc_inst(PPC_INST_LWSYNC));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) static void do_final_fixups(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) #if defined(CONFIG_PPC64) && defined(CONFIG_RELOCATABLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) struct ppc_inst inst, *src, *dest, *end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) if (PHYSICAL_START == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) src = (struct ppc_inst *)(KERNELBASE + PHYSICAL_START);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) dest = (struct ppc_inst *)KERNELBASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) end = (void *)src + (__end_interrupts - _stext);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) while (src < end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) inst = ppc_inst_read(src);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) raw_patch_instruction(dest, inst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) src = ppc_inst_next(src, src);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) dest = ppc_inst_next(dest, dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) static unsigned long __initdata saved_cpu_features;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) static unsigned int __initdata saved_mmu_features;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) #ifdef CONFIG_PPC64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) static unsigned long __initdata saved_firmware_features;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) void __init apply_feature_fixups(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) struct cpu_spec *spec = PTRRELOC(*PTRRELOC(&cur_cpu_spec));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) *PTRRELOC(&saved_cpu_features) = spec->cpu_features;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) *PTRRELOC(&saved_mmu_features) = spec->mmu_features;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) * Apply the CPU-specific and firmware specific fixups to kernel text
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) * (nop out sections not relevant to this CPU or this firmware).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) do_feature_fixups(spec->cpu_features,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) PTRRELOC(&__start___ftr_fixup),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) PTRRELOC(&__stop___ftr_fixup));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) do_feature_fixups(spec->mmu_features,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) PTRRELOC(&__start___mmu_ftr_fixup),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) PTRRELOC(&__stop___mmu_ftr_fixup));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) do_lwsync_fixups(spec->cpu_features,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) PTRRELOC(&__start___lwsync_fixup),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) PTRRELOC(&__stop___lwsync_fixup));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) #ifdef CONFIG_PPC64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) saved_firmware_features = powerpc_firmware_features;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) do_feature_fixups(powerpc_firmware_features,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) do_final_fixups();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) void __init setup_feature_keys(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) * Initialise jump label. This causes all the cpu/mmu_has_feature()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) * checks to take on their correct polarity based on the current set of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) * CPU/MMU features.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) jump_label_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) cpu_feature_keys_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) mmu_feature_keys_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) static int __init check_features(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) WARN(saved_cpu_features != cur_cpu_spec->cpu_features,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) "CPU features changed after feature patching!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) WARN(saved_mmu_features != cur_cpu_spec->mmu_features,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) "MMU features changed after feature patching!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) #ifdef CONFIG_PPC64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) WARN(saved_firmware_features != powerpc_firmware_features,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) "Firmware features changed after feature patching!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) late_initcall(check_features);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) #ifdef CONFIG_FTR_FIXUP_SELFTEST
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) #define check(x) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) if (!(x)) printk("feature-fixups: test failed at line %d\n", __LINE__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) /* This must be after the text it fixes up, vmlinux.lds.S enforces that atm */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) static struct fixup_entry fixup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) static long calc_offset(struct fixup_entry *entry, unsigned int *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) return (unsigned long)p - (unsigned long)entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) static void test_basic_patching(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) extern unsigned int ftr_fixup_test1[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) extern unsigned int end_ftr_fixup_test1[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) extern unsigned int ftr_fixup_test1_orig[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) extern unsigned int ftr_fixup_test1_expected[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) int size = 4 * (end_ftr_fixup_test1 - ftr_fixup_test1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) fixup.value = fixup.mask = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) fixup.start_off = calc_offset(&fixup, ftr_fixup_test1 + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) fixup.end_off = calc_offset(&fixup, ftr_fixup_test1 + 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) fixup.alt_start_off = fixup.alt_end_off = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) /* Sanity check */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) check(memcmp(ftr_fixup_test1, ftr_fixup_test1_orig, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) /* Check we don't patch if the value matches */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) patch_feature_section(8, &fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) check(memcmp(ftr_fixup_test1, ftr_fixup_test1_orig, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) /* Check we do patch if the value doesn't match */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) patch_feature_section(0, &fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) check(memcmp(ftr_fixup_test1, ftr_fixup_test1_expected, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) /* Check we do patch if the mask doesn't match */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) memcpy(ftr_fixup_test1, ftr_fixup_test1_orig, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) check(memcmp(ftr_fixup_test1, ftr_fixup_test1_orig, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) patch_feature_section(~8, &fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) check(memcmp(ftr_fixup_test1, ftr_fixup_test1_expected, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) static void test_alternative_patching(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) extern unsigned int ftr_fixup_test2[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) extern unsigned int end_ftr_fixup_test2[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) extern unsigned int ftr_fixup_test2_orig[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) extern unsigned int ftr_fixup_test2_alt[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) extern unsigned int ftr_fixup_test2_expected[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) int size = 4 * (end_ftr_fixup_test2 - ftr_fixup_test2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) fixup.value = fixup.mask = 0xF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) fixup.start_off = calc_offset(&fixup, ftr_fixup_test2 + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) fixup.end_off = calc_offset(&fixup, ftr_fixup_test2 + 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) fixup.alt_start_off = calc_offset(&fixup, ftr_fixup_test2_alt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) fixup.alt_end_off = calc_offset(&fixup, ftr_fixup_test2_alt + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) /* Sanity check */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) check(memcmp(ftr_fixup_test2, ftr_fixup_test2_orig, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) /* Check we don't patch if the value matches */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) patch_feature_section(0xF, &fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) check(memcmp(ftr_fixup_test2, ftr_fixup_test2_orig, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) /* Check we do patch if the value doesn't match */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) patch_feature_section(0, &fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) check(memcmp(ftr_fixup_test2, ftr_fixup_test2_expected, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) /* Check we do patch if the mask doesn't match */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) memcpy(ftr_fixup_test2, ftr_fixup_test2_orig, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) check(memcmp(ftr_fixup_test2, ftr_fixup_test2_orig, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) patch_feature_section(~0xF, &fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) check(memcmp(ftr_fixup_test2, ftr_fixup_test2_expected, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) static void test_alternative_case_too_big(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) extern unsigned int ftr_fixup_test3[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) extern unsigned int end_ftr_fixup_test3[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) extern unsigned int ftr_fixup_test3_orig[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) extern unsigned int ftr_fixup_test3_alt[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) int size = 4 * (end_ftr_fixup_test3 - ftr_fixup_test3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) fixup.value = fixup.mask = 0xC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) fixup.start_off = calc_offset(&fixup, ftr_fixup_test3 + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) fixup.end_off = calc_offset(&fixup, ftr_fixup_test3 + 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) fixup.alt_start_off = calc_offset(&fixup, ftr_fixup_test3_alt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) fixup.alt_end_off = calc_offset(&fixup, ftr_fixup_test3_alt + 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) /* Sanity check */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) check(memcmp(ftr_fixup_test3, ftr_fixup_test3_orig, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) /* Expect nothing to be patched, and the error returned to us */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) check(patch_feature_section(0xF, &fixup) == 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) check(memcmp(ftr_fixup_test3, ftr_fixup_test3_orig, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) check(patch_feature_section(0, &fixup) == 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) check(memcmp(ftr_fixup_test3, ftr_fixup_test3_orig, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) check(patch_feature_section(~0xF, &fixup) == 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) check(memcmp(ftr_fixup_test3, ftr_fixup_test3_orig, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) static void test_alternative_case_too_small(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) extern unsigned int ftr_fixup_test4[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) extern unsigned int end_ftr_fixup_test4[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) extern unsigned int ftr_fixup_test4_orig[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) extern unsigned int ftr_fixup_test4_alt[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) extern unsigned int ftr_fixup_test4_expected[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) int size = 4 * (end_ftr_fixup_test4 - ftr_fixup_test4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) unsigned long flag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) /* Check a high-bit flag */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) flag = 1UL << ((sizeof(unsigned long) - 1) * 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) fixup.value = fixup.mask = flag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) fixup.start_off = calc_offset(&fixup, ftr_fixup_test4 + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) fixup.end_off = calc_offset(&fixup, ftr_fixup_test4 + 5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) fixup.alt_start_off = calc_offset(&fixup, ftr_fixup_test4_alt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) fixup.alt_end_off = calc_offset(&fixup, ftr_fixup_test4_alt + 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) /* Sanity check */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) check(memcmp(ftr_fixup_test4, ftr_fixup_test4_orig, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) /* Check we don't patch if the value matches */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) patch_feature_section(flag, &fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) check(memcmp(ftr_fixup_test4, ftr_fixup_test4_orig, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) /* Check we do patch if the value doesn't match */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) patch_feature_section(0, &fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) check(memcmp(ftr_fixup_test4, ftr_fixup_test4_expected, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) /* Check we do patch if the mask doesn't match */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) memcpy(ftr_fixup_test4, ftr_fixup_test4_orig, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) check(memcmp(ftr_fixup_test4, ftr_fixup_test4_orig, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) patch_feature_section(~flag, &fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) check(memcmp(ftr_fixup_test4, ftr_fixup_test4_expected, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) static void test_alternative_case_with_branch(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) extern unsigned int ftr_fixup_test5[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) extern unsigned int end_ftr_fixup_test5[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) extern unsigned int ftr_fixup_test5_expected[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) int size = 4 * (end_ftr_fixup_test5 - ftr_fixup_test5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) check(memcmp(ftr_fixup_test5, ftr_fixup_test5_expected, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) static void test_alternative_case_with_external_branch(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) extern unsigned int ftr_fixup_test6[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) extern unsigned int end_ftr_fixup_test6[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) extern unsigned int ftr_fixup_test6_expected[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) int size = 4 * (end_ftr_fixup_test6 - ftr_fixup_test6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) check(memcmp(ftr_fixup_test6, ftr_fixup_test6_expected, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) static void test_alternative_case_with_branch_to_end(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) extern unsigned int ftr_fixup_test7[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) extern unsigned int end_ftr_fixup_test7[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) extern unsigned int ftr_fixup_test7_expected[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) int size = 4 * (end_ftr_fixup_test7 - ftr_fixup_test7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) check(memcmp(ftr_fixup_test7, ftr_fixup_test7_expected, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) static void test_cpu_macros(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) extern u8 ftr_fixup_test_FTR_macros[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) extern u8 ftr_fixup_test_FTR_macros_expected[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) unsigned long size = ftr_fixup_test_FTR_macros_expected -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) ftr_fixup_test_FTR_macros;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) /* The fixups have already been done for us during boot */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) check(memcmp(ftr_fixup_test_FTR_macros,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) ftr_fixup_test_FTR_macros_expected, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) static void test_fw_macros(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) #ifdef CONFIG_PPC64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) extern u8 ftr_fixup_test_FW_FTR_macros[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) extern u8 ftr_fixup_test_FW_FTR_macros_expected[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) unsigned long size = ftr_fixup_test_FW_FTR_macros_expected -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) ftr_fixup_test_FW_FTR_macros;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) /* The fixups have already been done for us during boot */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) check(memcmp(ftr_fixup_test_FW_FTR_macros,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) ftr_fixup_test_FW_FTR_macros_expected, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) static void test_lwsync_macros(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) extern u8 lwsync_fixup_test[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) extern u8 end_lwsync_fixup_test[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) extern u8 lwsync_fixup_test_expected_LWSYNC[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) extern u8 lwsync_fixup_test_expected_SYNC[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) unsigned long size = end_lwsync_fixup_test -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) lwsync_fixup_test;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) /* The fixups have already been done for us during boot */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) if (cur_cpu_spec->cpu_features & CPU_FTR_LWSYNC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) check(memcmp(lwsync_fixup_test,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) lwsync_fixup_test_expected_LWSYNC, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) check(memcmp(lwsync_fixup_test,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) lwsync_fixup_test_expected_SYNC, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) #ifdef CONFIG_PPC64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) static void __init test_prefix_patching(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) extern unsigned int ftr_fixup_prefix1[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) extern unsigned int end_ftr_fixup_prefix1[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) extern unsigned int ftr_fixup_prefix1_orig[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) extern unsigned int ftr_fixup_prefix1_expected[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) int size = sizeof(unsigned int) * (end_ftr_fixup_prefix1 - ftr_fixup_prefix1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) fixup.value = fixup.mask = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) fixup.start_off = calc_offset(&fixup, ftr_fixup_prefix1 + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) fixup.end_off = calc_offset(&fixup, ftr_fixup_prefix1 + 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) fixup.alt_start_off = fixup.alt_end_off = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) /* Sanity check */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) check(memcmp(ftr_fixup_prefix1, ftr_fixup_prefix1_orig, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) patch_feature_section(0, &fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) check(memcmp(ftr_fixup_prefix1, ftr_fixup_prefix1_expected, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) check(memcmp(ftr_fixup_prefix1, ftr_fixup_prefix1_orig, size) != 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) static void __init test_prefix_alt_patching(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) extern unsigned int ftr_fixup_prefix2[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) extern unsigned int end_ftr_fixup_prefix2[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) extern unsigned int ftr_fixup_prefix2_orig[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) extern unsigned int ftr_fixup_prefix2_expected[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) extern unsigned int ftr_fixup_prefix2_alt[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) int size = sizeof(unsigned int) * (end_ftr_fixup_prefix2 - ftr_fixup_prefix2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) fixup.value = fixup.mask = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) fixup.start_off = calc_offset(&fixup, ftr_fixup_prefix2 + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) fixup.end_off = calc_offset(&fixup, ftr_fixup_prefix2 + 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) fixup.alt_start_off = calc_offset(&fixup, ftr_fixup_prefix2_alt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) fixup.alt_end_off = calc_offset(&fixup, ftr_fixup_prefix2_alt + 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) /* Sanity check */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) check(memcmp(ftr_fixup_prefix2, ftr_fixup_prefix2_orig, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) patch_feature_section(0, &fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) check(memcmp(ftr_fixup_prefix2, ftr_fixup_prefix2_expected, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) check(memcmp(ftr_fixup_prefix2, ftr_fixup_prefix2_orig, size) != 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) static void __init test_prefix_word_alt_patching(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) extern unsigned int ftr_fixup_prefix3[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) extern unsigned int end_ftr_fixup_prefix3[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) extern unsigned int ftr_fixup_prefix3_orig[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) extern unsigned int ftr_fixup_prefix3_expected[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) extern unsigned int ftr_fixup_prefix3_alt[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) int size = sizeof(unsigned int) * (end_ftr_fixup_prefix3 - ftr_fixup_prefix3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) fixup.value = fixup.mask = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) fixup.start_off = calc_offset(&fixup, ftr_fixup_prefix3 + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) fixup.end_off = calc_offset(&fixup, ftr_fixup_prefix3 + 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) fixup.alt_start_off = calc_offset(&fixup, ftr_fixup_prefix3_alt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) fixup.alt_end_off = calc_offset(&fixup, ftr_fixup_prefix3_alt + 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) /* Sanity check */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) check(memcmp(ftr_fixup_prefix3, ftr_fixup_prefix3_orig, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) patch_feature_section(0, &fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) check(memcmp(ftr_fixup_prefix3, ftr_fixup_prefix3_expected, size) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) patch_feature_section(0, &fixup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) check(memcmp(ftr_fixup_prefix3, ftr_fixup_prefix3_orig, size) != 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) static inline void test_prefix_patching(void) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) static inline void test_prefix_alt_patching(void) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) static inline void test_prefix_word_alt_patching(void) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) #endif /* CONFIG_PPC64 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) static int __init test_feature_fixups(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) printk(KERN_DEBUG "Running feature fixup self-tests ...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) test_basic_patching();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) test_alternative_patching();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) test_alternative_case_too_big();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) test_alternative_case_too_small();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) test_alternative_case_with_branch();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) test_alternative_case_with_external_branch();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) test_alternative_case_with_branch_to_end();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) test_cpu_macros();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) test_fw_macros();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) test_lwsync_macros();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) test_prefix_patching();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) test_prefix_alt_patching();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) test_prefix_word_alt_patching();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) late_initcall(test_feature_fixups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) #endif /* CONFIG_FTR_FIXUP_SELFTEST */