1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * alternative runtime patching 4 * inspired by the ARM64 and x86 version 5 * 6 * Copyright (C) 2021 Sifive. 7 */ 8 9 #include <linux/init.h> 10 #include <linux/cpu.h> 11 #include <linux/uaccess.h> 12 #include <asm/alternative.h> 13 #include <asm/sections.h> 14 #include <asm/vendorid_list.h> 15 #include <asm/sbi.h> 16 #include <asm/csr.h> 17 18 static struct cpu_manufacturer_info_t { 19 unsigned long vendor_id; 20 unsigned long arch_id; 21 unsigned long imp_id; 22 } cpu_mfr_info; 23 24 static void (*vendor_patch_func)(struct alt_entry *begin, struct alt_entry *end, 25 unsigned long archid, unsigned long impid); 26 riscv_fill_cpu_mfr_info(void)27static inline void __init riscv_fill_cpu_mfr_info(void) 28 { 29 #ifdef CONFIG_RISCV_M_MODE 30 cpu_mfr_info.vendor_id = csr_read(CSR_MVENDORID); 31 cpu_mfr_info.arch_id = csr_read(CSR_MARCHID); 32 cpu_mfr_info.imp_id = csr_read(CSR_MIMPID); 33 #else 34 cpu_mfr_info.vendor_id = sbi_get_mvendorid(); 35 cpu_mfr_info.arch_id = sbi_get_marchid(); 36 cpu_mfr_info.imp_id = sbi_get_mimpid(); 37 #endif 38 } 39 init_alternative(void)40static void __init init_alternative(void) 41 { 42 riscv_fill_cpu_mfr_info(); 43 44 switch (cpu_mfr_info.vendor_id) { 45 #ifdef CONFIG_ERRATA_SIFIVE 46 case SIFIVE_VENDOR_ID: 47 vendor_patch_func = sifive_errata_patch_func; 48 break; 49 #endif 50 default: 51 vendor_patch_func = NULL; 52 } 53 } 54 55 /* 56 * This is called very early in the boot process (directly after we run 57 * a feature detect on the boot CPU). No need to worry about other CPUs 58 * here. 59 */ apply_boot_alternatives(void)60void __init apply_boot_alternatives(void) 61 { 62 /* If called on non-boot cpu things could go wrong */ 63 WARN_ON(smp_processor_id() != 0); 64 65 init_alternative(); 66 67 if (!vendor_patch_func) 68 return; 69 70 vendor_patch_func((struct alt_entry *)__alt_start, 71 (struct alt_entry *)__alt_end, 72 cpu_mfr_info.arch_id, cpu_mfr_info.imp_id); 73 } 74 75