Skip to content

Commit a8e9101

Browse files
mmindpalmer-dabbelt
authored andcommitted
riscv: implement module alternatives
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> Link: https://lore.kernel.org/r/20220511192921.2223629-4-heiko@sntech.de Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
1 parent d14ca1f commit a8e9101

4 files changed

Lines changed: 55 additions & 9 deletions

File tree

arch/riscv/errata/sifive/errata.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
#include <linux/kernel.h>
7+
#include <linux/module.h>
78
#include <linux/string.h>
89
#include <linux/bug.h>
910
#include <asm/patch.h>
@@ -54,7 +55,8 @@ static struct errata_info_t errata_list[ERRATA_SIFIVE_NUMBER] = {
5455
},
5556
};
5657

57-
static u32 __init sifive_errata_probe(unsigned long archid, unsigned long impid)
58+
static u32 __init_or_module sifive_errata_probe(unsigned long archid,
59+
unsigned long impid)
5860
{
5961
int idx;
6062
u32 cpu_req_errata = 0;
@@ -66,7 +68,7 @@ static u32 __init sifive_errata_probe(unsigned long archid, unsigned long impid)
6668
return cpu_req_errata;
6769
}
6870

69-
static void __init warn_miss_errata(u32 miss_errata)
71+
static void __init_or_module warn_miss_errata(u32 miss_errata)
7072
{
7173
int i;
7274

@@ -79,9 +81,11 @@ static void __init warn_miss_errata(u32 miss_errata)
7981
pr_warn("----------------------------------------------------------------\n");
8082
}
8183

82-
void __init sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
83-
unsigned long archid, unsigned long impid,
84-
unsigned int stage)
84+
void __init_or_module sifive_errata_patch_func(struct alt_entry *begin,
85+
struct alt_entry *end,
86+
unsigned long archid,
87+
unsigned long impid,
88+
unsigned int stage)
8589
{
8690
struct alt_entry *alt;
8791
u32 cpu_req_errata = sifive_errata_probe(archid, impid);

arch/riscv/include/asm/alternative.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
#include <asm/hwcap.h>
2121

2222
#define RISCV_ALTERNATIVES_BOOT 0 /* alternatives applied during regular boot */
23+
#define RISCV_ALTERNATIVES_MODULE 1 /* alternatives applied during module-init */
2324

2425
void __init apply_boot_alternatives(void);
26+
void apply_module_alternatives(void *start, size_t length);
2527

2628
struct alt_entry {
2729
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,
4345
#else /* CONFIG_RISCV_ALTERNATIVE */
4446

4547
static inline void apply_boot_alternatives(void) { }
48+
static inline void apply_module_alternatives(void *start, size_t length) { }
4649

4750
#endif /* CONFIG_RISCV_ALTERNATIVE */
4851

arch/riscv/kernel/alternative.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
#include <linux/init.h>
10+
#include <linux/module.h>
1011
#include <linux/cpu.h>
1112
#include <linux/uaccess.h>
1213
#include <asm/alternative.h>
@@ -23,7 +24,7 @@ static struct cpu_manufacturer_info_t {
2324

2425
static void (*vendor_patch_func)(struct alt_entry *begin, struct alt_entry *end,
2526
unsigned long archid, unsigned long impid,
26-
unsigned int stage) __initdata;
27+
unsigned int stage) __initdata_or_module;
2728

2829
static inline void __init riscv_fill_cpu_mfr_info(void)
2930
{
@@ -58,9 +59,9 @@ static void __init init_alternative(void)
5859
* a feature detect on the boot CPU). No need to worry about other CPUs
5960
* here.
6061
*/
61-
static void __init _apply_alternatives(struct alt_entry *begin,
62-
struct alt_entry *end,
63-
unsigned int stage)
62+
static void __init_or_module _apply_alternatives(struct alt_entry *begin,
63+
struct alt_entry *end,
64+
unsigned int stage)
6465
{
6566
if (!vendor_patch_func)
6667
return;
@@ -81,3 +82,12 @@ void __init apply_boot_alternatives(void)
8182
(struct alt_entry *)__alt_end,
8283
RISCV_ALTERNATIVES_BOOT);
8384
}
85+
86+
#ifdef CONFIG_MODULES
87+
void apply_module_alternatives(void *start, size_t length)
88+
{
89+
_apply_alternatives((struct alt_entry *)start,
90+
(struct alt_entry *)(start + length),
91+
RISCV_ALTERNATIVES_MODULE);
92+
}
93+
#endif

arch/riscv/kernel/module.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/vmalloc.h>
1212
#include <linux/sizes.h>
1313
#include <linux/pgtable.h>
14+
#include <asm/alternative.h>
1415
#include <asm/sections.h>
1516

1617
/*
@@ -427,3 +428,31 @@ void *module_alloc(unsigned long size)
427428
__builtin_return_address(0));
428429
}
429430
#endif
431+
432+
static const Elf_Shdr *find_section(const Elf_Ehdr *hdr,
433+
const Elf_Shdr *sechdrs,
434+
const char *name)
435+
{
436+
const Elf_Shdr *s, *se;
437+
const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
438+
439+
for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) {
440+
if (strcmp(name, secstrs + s->sh_name) == 0)
441+
return s;
442+
}
443+
444+
return NULL;
445+
}
446+
447+
int module_finalize(const Elf_Ehdr *hdr,
448+
const Elf_Shdr *sechdrs,
449+
struct module *me)
450+
{
451+
const Elf_Shdr *s;
452+
453+
s = find_section(hdr, sechdrs, ".alternative");
454+
if (s)
455+
apply_module_alternatives((void *)s->sh_addr, s->sh_size);
456+
457+
return 0;
458+
}

0 commit comments

Comments
 (0)