forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
74 lines
1.7 KiB
74 lines
1.7 KiB
// SPDX-License-Identifier: GPL-2.0-only |
|
/* |
|
* alternative runtime patching |
|
* inspired by the ARM64 and x86 version |
|
* |
|
* Copyright (C) 2021 Sifive. |
|
*/ |
|
|
|
#include <linux/init.h> |
|
#include <linux/cpu.h> |
|
#include <linux/uaccess.h> |
|
#include <asm/alternative.h> |
|
#include <asm/sections.h> |
|
#include <asm/vendorid_list.h> |
|
#include <asm/sbi.h> |
|
#include <asm/csr.h> |
|
|
|
static struct cpu_manufacturer_info_t { |
|
unsigned long vendor_id; |
|
unsigned long arch_id; |
|
unsigned long imp_id; |
|
} cpu_mfr_info; |
|
|
|
static void (*vendor_patch_func)(struct alt_entry *begin, struct alt_entry *end, |
|
unsigned long archid, unsigned long impid); |
|
|
|
static inline void __init riscv_fill_cpu_mfr_info(void) |
|
{ |
|
#ifdef CONFIG_RISCV_M_MODE |
|
cpu_mfr_info.vendor_id = csr_read(CSR_MVENDORID); |
|
cpu_mfr_info.arch_id = csr_read(CSR_MARCHID); |
|
cpu_mfr_info.imp_id = csr_read(CSR_MIMPID); |
|
#else |
|
cpu_mfr_info.vendor_id = sbi_get_mvendorid(); |
|
cpu_mfr_info.arch_id = sbi_get_marchid(); |
|
cpu_mfr_info.imp_id = sbi_get_mimpid(); |
|
#endif |
|
} |
|
|
|
static void __init init_alternative(void) |
|
{ |
|
riscv_fill_cpu_mfr_info(); |
|
|
|
switch (cpu_mfr_info.vendor_id) { |
|
#ifdef CONFIG_ERRATA_SIFIVE |
|
case SIFIVE_VENDOR_ID: |
|
vendor_patch_func = sifive_errata_patch_func; |
|
break; |
|
#endif |
|
default: |
|
vendor_patch_func = NULL; |
|
} |
|
} |
|
|
|
/* |
|
* This is called very early in the boot process (directly after we run |
|
* a feature detect on the boot CPU). No need to worry about other CPUs |
|
* here. |
|
*/ |
|
void __init apply_boot_alternatives(void) |
|
{ |
|
/* If called on non-boot cpu things could go wrong */ |
|
WARN_ON(smp_processor_id() != 0); |
|
|
|
init_alternative(); |
|
|
|
if (!vendor_patch_func) |
|
return; |
|
|
|
vendor_patch_func((struct alt_entry *)__alt_start, |
|
(struct alt_entry *)__alt_end, |
|
cpu_mfr_info.arch_id, cpu_mfr_info.imp_id); |
|
} |
|
|
|
|