1 // SPDX-License-Identifier: GPL-2.0-only
3 * alternative runtime patching
4 * inspired by the ARM64 and x86 version
6 * Copyright (C) 2021 Sifive.
9 #include <linux/init.h>
10 #include <linux/module.h>
11 #include <linux/cpu.h>
12 #include <linux/uaccess.h>
13 #include <asm/alternative.h>
14 #include <asm/sections.h>
15 #include <asm/vendorid_list.h>
19 struct cpu_manufacturer_info_t {
20 unsigned long vendor_id;
21 unsigned long arch_id;
23 void (*patch_func)(struct alt_entry *begin, struct alt_entry *end,
24 unsigned long archid, unsigned long impid,
28 static void __init_or_module riscv_fill_cpu_mfr_info(struct cpu_manufacturer_info_t *cpu_mfr_info)
30 #ifdef CONFIG_RISCV_M_MODE
31 cpu_mfr_info->vendor_id = csr_read(CSR_MVENDORID);
32 cpu_mfr_info->arch_id = csr_read(CSR_MARCHID);
33 cpu_mfr_info->imp_id = csr_read(CSR_MIMPID);
35 cpu_mfr_info->vendor_id = sbi_get_mvendorid();
36 cpu_mfr_info->arch_id = sbi_get_marchid();
37 cpu_mfr_info->imp_id = sbi_get_mimpid();
40 switch (cpu_mfr_info->vendor_id) {
41 #ifdef CONFIG_ERRATA_SIFIVE
42 case SIFIVE_VENDOR_ID:
43 cpu_mfr_info->patch_func = sifive_errata_patch_func;
46 #ifdef CONFIG_ERRATA_THEAD
48 cpu_mfr_info->patch_func = thead_errata_patch_func;
52 cpu_mfr_info->patch_func = NULL;
57 * This is called very early in the boot process (directly after we run
58 * a feature detect on the boot CPU). No need to worry about other CPUs
61 static void __init_or_module _apply_alternatives(struct alt_entry *begin,
62 struct alt_entry *end,
65 struct cpu_manufacturer_info_t cpu_mfr_info;
67 riscv_fill_cpu_mfr_info(&cpu_mfr_info);
69 riscv_cpufeature_patch_func(begin, end, stage);
71 if (!cpu_mfr_info.patch_func)
74 cpu_mfr_info.patch_func(begin, end,
80 void __init apply_boot_alternatives(void)
82 /* If called on non-boot cpu things could go wrong */
83 WARN_ON(smp_processor_id() != 0);
85 _apply_alternatives((struct alt_entry *)__alt_start,
86 (struct alt_entry *)__alt_end,
87 RISCV_ALTERNATIVES_BOOT);
91 * apply_early_boot_alternatives() is called from setup_vm() with MMU-off.
93 * Following requirements should be honoured for it to work correctly:
94 * 1) It should use PC-relative addressing for accessing kernel symbols.
95 * To achieve this we always use GCC cmodel=medany.
96 * 2) The compiler instrumentation for FTRACE will not work for setup_vm()
97 * so disable compiler instrumentation when FTRACE is enabled.
99 * Currently, the above requirements are honoured by using custom CFLAGS
100 * for alternative.o in kernel/Makefile.
102 void __init apply_early_boot_alternatives(void)
104 #ifdef CONFIG_RISCV_ALTERNATIVE_EARLY
105 _apply_alternatives((struct alt_entry *)__alt_start,
106 (struct alt_entry *)__alt_end,
107 RISCV_ALTERNATIVES_EARLY_BOOT);
111 #ifdef CONFIG_MODULES
112 void apply_module_alternatives(void *start, size_t length)
114 _apply_alternatives((struct alt_entry *)start,
115 (struct alt_entry *)(start + length),
116 RISCV_ALTERNATIVES_MODULE);