cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

alternative.c (3369B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *    Alternative live-patching for parisc.
      4 *    Copyright (C) 2018 Helge Deller <deller@gmx.de>
      5 *
      6 */
      7
      8#include <asm/processor.h>
      9#include <asm/sections.h>
     10#include <asm/alternative.h>
     11#include <asm/cacheflush.h>
     12
     13#include <linux/module.h>
     14
     15static int no_alternatives;
     16static int __init setup_no_alternatives(char *str)
     17{
     18	no_alternatives = 1;
     19	return 1;
     20}
     21__setup("no-alternatives", setup_no_alternatives);
     22
     23void __init_or_module apply_alternatives(struct alt_instr *start,
     24		 struct alt_instr *end, const char *module_name)
     25{
     26	struct alt_instr *entry;
     27	int index = 0, applied = 0;
     28	int num_cpus = num_online_cpus();
     29	u32 cond_check;
     30
     31	cond_check = ALT_COND_ALWAYS |
     32		((num_cpus == 1) ? ALT_COND_NO_SMP : 0) |
     33		((cache_info.dc_size == 0) ? ALT_COND_NO_DCACHE : 0) |
     34		((cache_info.ic_size == 0) ? ALT_COND_NO_ICACHE : 0) |
     35		(running_on_qemu ? ALT_COND_RUN_ON_QEMU : 0) |
     36		((split_tlb == 0) ? ALT_COND_NO_SPLIT_TLB : 0) |
     37		/*
     38		 * If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit
     39		 * set (bit #61, big endian), we have to flush and sync every
     40		 * time IO-PDIR is changed in Ike/Astro.
     41		 */
     42		(((boot_cpu_data.cpu_type > pcxw_) &&
     43		  ((boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC) == 0))
     44			? ALT_COND_NO_IOC_FDC : 0);
     45
     46	for (entry = start; entry < end; entry++, index++) {
     47
     48		u32 *from, cond, replacement;
     49		s32 len;
     50
     51		from = (u32 *)((ulong)&entry->orig_offset + entry->orig_offset);
     52		len = entry->len;
     53		cond = entry->cond;
     54		replacement = entry->replacement;
     55
     56		WARN_ON(!cond);
     57
     58		if ((cond & ALT_COND_ALWAYS) == 0 && no_alternatives)
     59			continue;
     60
     61		pr_debug("Check %d: Cond 0x%x, Replace %02d instructions @ 0x%px with 0x%08x\n",
     62			index, cond, len, from, replacement);
     63
     64		/* Bounce out if none of the conditions are true. */
     65		if ((cond & cond_check) == 0)
     66			continue;
     67
     68		/* Want to replace pdtlb by a pdtlb,l instruction? */
     69		if (replacement == INSN_PxTLB) {
     70			replacement = *from;
     71			if (boot_cpu_data.cpu_type >= pcxu) /* >= pa2.0 ? */
     72				replacement |= (1 << 10); /* set el bit */
     73		}
     74
     75		/*
     76		 * Replace instruction with NOPs?
     77		 * For long distance insert a branch instruction instead.
     78		 */
     79		if (replacement == INSN_NOP && len > 1)
     80			replacement = 0xe8000002 + (len-2)*8; /* "b,n .+8" */
     81
     82		pr_debug("ALTERNATIVE %3d: Cond %2x, Replace %2d instructions to 0x%08x @ 0x%px (%pS)\n",
     83			index, cond, len, replacement, from, from);
     84
     85		if (len < 0) {
     86			/* Replace multiple instruction by new code */
     87			u32 *source;
     88			len = -len;
     89			source = (u32 *)((ulong)&entry->replacement + entry->replacement);
     90			memcpy(from, source, 4 * len);
     91		} else {
     92			/* Replace by one instruction */
     93			*from = replacement;
     94		}
     95		applied++;
     96	}
     97
     98	pr_info("%s%salternatives: applied %d out of %d patches\n",
     99		module_name ? : "", module_name ? " " : "",
    100		applied, index);
    101}
    102
    103
    104void __init apply_alternatives_all(void)
    105{
    106	set_kernel_text_rw(1);
    107
    108	apply_alternatives((struct alt_instr *) &__alt_instructions,
    109		(struct alt_instr *) &__alt_instructions_end, NULL);
    110
    111	if (cache_info.dc_size == 0 && cache_info.ic_size == 0) {
    112		pr_info("alternatives: optimizing cache-flushes.\n");
    113		static_branch_disable(&parisc_has_cache);
    114	}
    115	if (cache_info.dc_size == 0)
    116		static_branch_disable(&parisc_has_dcache);
    117	if (cache_info.ic_size == 0)
    118		static_branch_disable(&parisc_has_icache);
    119
    120	set_kernel_text_rw(0);
    121}