Message ID | 20220511192921.2223629-4-heiko@sntech.de (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | riscv: support for Svpbmt and D1 memory types | expand |
Looks good:
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Guo Ren <guoren@kernel.org> On Thu, May 12, 2022 at 3:29 AM Heiko Stuebner <heiko@sntech.de> wrote: > > This allows alternatives to also be applied when loading modules > and follows the implementation of other architectures (e.g. arm64). > > Signed-off-by: Heiko Stuebner <heiko@sntech.de> > Reviewed-by: Philipp Tomsich <philipp.tomsich@vrull.eu> > --- > arch/riscv/errata/sifive/errata.c | 14 +++++++++----- > arch/riscv/include/asm/alternative.h | 3 +++ > arch/riscv/kernel/alternative.c | 18 +++++++++++++---- > arch/riscv/kernel/module.c | 29 ++++++++++++++++++++++++++++ > 4 files changed, 55 insertions(+), 9 deletions(-) > > diff --git a/arch/riscv/errata/sifive/errata.c b/arch/riscv/errata/sifive/errata.c > index 4fe03ac41fd7..3e39587a49dc 100644 > --- a/arch/riscv/errata/sifive/errata.c > +++ b/arch/riscv/errata/sifive/errata.c > @@ -4,6 +4,7 @@ > */ > > #include <linux/kernel.h> > +#include <linux/module.h> > #include <linux/string.h> > #include <linux/bug.h> > #include <asm/patch.h> > @@ -54,7 +55,8 @@ static struct errata_info_t errata_list[ERRATA_SIFIVE_NUMBER] = { > }, > }; > > -static u32 __init sifive_errata_probe(unsigned long archid, unsigned long impid) > +static u32 __init_or_module sifive_errata_probe(unsigned long archid, > + unsigned long impid) > { > int idx; > u32 cpu_req_errata = 0; > @@ -66,7 +68,7 @@ static u32 __init sifive_errata_probe(unsigned long archid, unsigned long impid) > return cpu_req_errata; > } > > -static void __init warn_miss_errata(u32 miss_errata) > +static void __init_or_module warn_miss_errata(u32 miss_errata) > { > int i; > > @@ -79,9 +81,11 @@ static void __init warn_miss_errata(u32 miss_errata) > pr_warn("----------------------------------------------------------------\n"); > } > > -void __init sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, > - unsigned long archid, unsigned long impid, > - unsigned int stage) > +void __init_or_module sifive_errata_patch_func(struct alt_entry *begin, > + struct alt_entry *end, > + unsigned long archid, > + unsigned long impid, > + unsigned int stage) > { > struct alt_entry *alt; > u32 cpu_req_errata = sifive_errata_probe(archid, impid); > diff --git a/arch/riscv/include/asm/alternative.h b/arch/riscv/include/asm/alternative.h > index 0ff550667e94..0859529ff08e 100644 > --- a/arch/riscv/include/asm/alternative.h > +++ b/arch/riscv/include/asm/alternative.h > @@ -20,8 +20,10 @@ > #include <asm/hwcap.h> > > #define RISCV_ALTERNATIVES_BOOT 0 /* alternatives applied during regular boot */ > +#define RISCV_ALTERNATIVES_MODULE 1 /* alternatives applied during module-init */ > > void __init apply_boot_alternatives(void); > +void apply_module_alternatives(void *start, size_t length); > > struct alt_entry { > void *old_ptr; /* address of original instruciton or data */ > @@ -43,6 +45,7 @@ void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, > #else /* CONFIG_RISCV_ALTERNATIVE */ > > static inline void apply_boot_alternatives(void) { } > +static inline void apply_module_alternatives(void *start, size_t length) { } > > #endif /* CONFIG_RISCV_ALTERNATIVE */ > > diff --git a/arch/riscv/kernel/alternative.c b/arch/riscv/kernel/alternative.c > index 02db62f55bac..223770b3945c 100644 > --- a/arch/riscv/kernel/alternative.c > +++ b/arch/riscv/kernel/alternative.c > @@ -7,6 +7,7 @@ > */ > > #include <linux/init.h> > +#include <linux/module.h> > #include <linux/cpu.h> > #include <linux/uaccess.h> > #include <asm/alternative.h> > @@ -23,7 +24,7 @@ static struct cpu_manufacturer_info_t { > > static void (*vendor_patch_func)(struct alt_entry *begin, struct alt_entry *end, > unsigned long archid, unsigned long impid, > - unsigned int stage) __initdata; > + unsigned int stage) __initdata_or_module; > > static inline void __init riscv_fill_cpu_mfr_info(void) > { > @@ -58,9 +59,9 @@ static void __init init_alternative(void) > * a feature detect on the boot CPU). No need to worry about other CPUs > * here. > */ > -static void __init _apply_alternatives(struct alt_entry *begin, > - struct alt_entry *end, > - unsigned int stage) > +static void __init_or_module _apply_alternatives(struct alt_entry *begin, > + struct alt_entry *end, > + unsigned int stage) > { > if (!vendor_patch_func) > return; > @@ -81,3 +82,12 @@ void __init apply_boot_alternatives(void) > (struct alt_entry *)__alt_end, > RISCV_ALTERNATIVES_BOOT); > } > + > +#ifdef CONFIG_MODULES > +void apply_module_alternatives(void *start, size_t length) > +{ > + _apply_alternatives((struct alt_entry *)start, > + (struct alt_entry *)(start + length), > + RISCV_ALTERNATIVES_MODULE); > +} > +#endif > diff --git a/arch/riscv/kernel/module.c b/arch/riscv/kernel/module.c > index c29cef90d1dd..91fe16bfaa07 100644 > --- a/arch/riscv/kernel/module.c > +++ b/arch/riscv/kernel/module.c > @@ -11,6 +11,7 @@ > #include <linux/vmalloc.h> > #include <linux/sizes.h> > #include <linux/pgtable.h> > +#include <asm/alternative.h> > #include <asm/sections.h> > > /* > @@ -427,3 +428,31 @@ void *module_alloc(unsigned long size) > __builtin_return_address(0)); > } > #endif > + > +static const Elf_Shdr *find_section(const Elf_Ehdr *hdr, > + const Elf_Shdr *sechdrs, > + const char *name) > +{ > + const Elf_Shdr *s, *se; > + const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; > + > + for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) { > + if (strcmp(name, secstrs + s->sh_name) == 0) > + return s; > + } > + > + return NULL; > +} > + > +int module_finalize(const Elf_Ehdr *hdr, > + const Elf_Shdr *sechdrs, > + struct module *me) > +{ > + const Elf_Shdr *s; > + > + s = find_section(hdr, sechdrs, ".alternative"); > + if (s) > + apply_module_alternatives((void *)s->sh_addr, s->sh_size); > + > + return 0; > +} > -- > 2.35.1 >
diff --git a/arch/riscv/errata/sifive/errata.c b/arch/riscv/errata/sifive/errata.c index 4fe03ac41fd7..3e39587a49dc 100644 --- a/arch/riscv/errata/sifive/errata.c +++ b/arch/riscv/errata/sifive/errata.c @@ -4,6 +4,7 @@ */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/string.h> #include <linux/bug.h> #include <asm/patch.h> @@ -54,7 +55,8 @@ static struct errata_info_t errata_list[ERRATA_SIFIVE_NUMBER] = { }, }; -static u32 __init sifive_errata_probe(unsigned long archid, unsigned long impid) +static u32 __init_or_module sifive_errata_probe(unsigned long archid, + unsigned long impid) { int idx; u32 cpu_req_errata = 0; @@ -66,7 +68,7 @@ static u32 __init sifive_errata_probe(unsigned long archid, unsigned long impid) return cpu_req_errata; } -static void __init warn_miss_errata(u32 miss_errata) +static void __init_or_module warn_miss_errata(u32 miss_errata) { int i; @@ -79,9 +81,11 @@ static void __init warn_miss_errata(u32 miss_errata) pr_warn("----------------------------------------------------------------\n"); } -void __init sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, - unsigned long archid, unsigned long impid, - unsigned int stage) +void __init_or_module sifive_errata_patch_func(struct alt_entry *begin, + struct alt_entry *end, + unsigned long archid, + unsigned long impid, + unsigned int stage) { struct alt_entry *alt; u32 cpu_req_errata = sifive_errata_probe(archid, impid); diff --git a/arch/riscv/include/asm/alternative.h b/arch/riscv/include/asm/alternative.h index 0ff550667e94..0859529ff08e 100644 --- a/arch/riscv/include/asm/alternative.h +++ b/arch/riscv/include/asm/alternative.h @@ -20,8 +20,10 @@ #include <asm/hwcap.h> #define RISCV_ALTERNATIVES_BOOT 0 /* alternatives applied during regular boot */ +#define RISCV_ALTERNATIVES_MODULE 1 /* alternatives applied during module-init */ void __init apply_boot_alternatives(void); +void apply_module_alternatives(void *start, size_t length); struct alt_entry { void *old_ptr; /* address of original instruciton or data */ @@ -43,6 +45,7 @@ void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, #else /* CONFIG_RISCV_ALTERNATIVE */ static inline void apply_boot_alternatives(void) { } +static inline void apply_module_alternatives(void *start, size_t length) { } #endif /* CONFIG_RISCV_ALTERNATIVE */ diff --git a/arch/riscv/kernel/alternative.c b/arch/riscv/kernel/alternative.c index 02db62f55bac..223770b3945c 100644 --- a/arch/riscv/kernel/alternative.c +++ b/arch/riscv/kernel/alternative.c @@ -7,6 +7,7 @@ */ #include <linux/init.h> +#include <linux/module.h> #include <linux/cpu.h> #include <linux/uaccess.h> #include <asm/alternative.h> @@ -23,7 +24,7 @@ static struct cpu_manufacturer_info_t { static void (*vendor_patch_func)(struct alt_entry *begin, struct alt_entry *end, unsigned long archid, unsigned long impid, - unsigned int stage) __initdata; + unsigned int stage) __initdata_or_module; static inline void __init riscv_fill_cpu_mfr_info(void) { @@ -58,9 +59,9 @@ static void __init init_alternative(void) * a feature detect on the boot CPU). No need to worry about other CPUs * here. */ -static void __init _apply_alternatives(struct alt_entry *begin, - struct alt_entry *end, - unsigned int stage) +static void __init_or_module _apply_alternatives(struct alt_entry *begin, + struct alt_entry *end, + unsigned int stage) { if (!vendor_patch_func) return; @@ -81,3 +82,12 @@ void __init apply_boot_alternatives(void) (struct alt_entry *)__alt_end, RISCV_ALTERNATIVES_BOOT); } + +#ifdef CONFIG_MODULES +void apply_module_alternatives(void *start, size_t length) +{ + _apply_alternatives((struct alt_entry *)start, + (struct alt_entry *)(start + length), + RISCV_ALTERNATIVES_MODULE); +} +#endif diff --git a/arch/riscv/kernel/module.c b/arch/riscv/kernel/module.c index c29cef90d1dd..91fe16bfaa07 100644 --- a/arch/riscv/kernel/module.c +++ b/arch/riscv/kernel/module.c @@ -11,6 +11,7 @@ #include <linux/vmalloc.h> #include <linux/sizes.h> #include <linux/pgtable.h> +#include <asm/alternative.h> #include <asm/sections.h> /* @@ -427,3 +428,31 @@ void *module_alloc(unsigned long size) __builtin_return_address(0)); } #endif + +static const Elf_Shdr *find_section(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + const char *name) +{ + const Elf_Shdr *s, *se; + const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + + for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) { + if (strcmp(name, secstrs + s->sh_name) == 0) + return s; + } + + return NULL; +} + +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *me) +{ + const Elf_Shdr *s; + + s = find_section(hdr, sechdrs, ".alternative"); + if (s) + apply_module_alternatives((void *)s->sh_addr, s->sh_size); + + return 0; +}