riscv: implement module alternatives

A patch from »svpbmt and t-head memory types« in state Mainline for linux-kernel

From: Heiko Stuebner <heiko@...> Date: Thu, 9 Dec 2021 18:04:40 +0100

Commit-Message

This allows alternatives to also be applied when loading modules and follows somewhat closely to the arm64 variant of this. Signed-off-by: Heiko Stuebner <heiko@...>

Patch-Comment

arch/riscv/include/asm/alternative.h | 3 ++- arch/riscv/kernel/alternative.c | 20 +++++++++++++++---- arch/riscv/kernel/module.c | 29 ++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 5 deletions(-)

Statistics

  • 47 lines added
  • 5 lines removed

Changes

--------------------- arch/riscv/include/asm/alternative.h ---------------------
index bee2eb579252..973892e61c07 100644
@@ -18,8 +18,10 @@
#include <asm/hwcap.h>
#define RISCV_ALTERNATIVES_BOOT 0
+#define RISCV_ALTERNATIVES_MODULE 1
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 */
@@ -37,6 +39,5 @@ struct errata_checkfunc_id {
void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
unsigned long archid, unsigned long impid,
unsigned int stage);
-
#endif
#endif
----------------------- arch/riscv/kernel/alternative.c ------------------------
index 416e7a380ee4..8ad76b290c59 100644
@@ -58,13 +58,14 @@ 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(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;
- vendor_patch_func((struct alt_entry *)__alt_start,
- (struct alt_entry *)__alt_end,
+ vendor_patch_func(begin, end,
cpu_mfr_info.arch_id, cpu_mfr_info.imp_id,
stage);
}
@@ -76,5 +77,16 @@ void __init apply_boot_alternatives(void)
init_alternative();
- _apply_alternatives(RISCV_ALTERNATIVES_BOOT);
+ _apply_alternatives((struct alt_entry *)__alt_start,
+ (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
-------------------------- arch/riscv/kernel/module.c --------------------------
index 68a9e3d1fe16..a778abd5b8b9 100644
@@ -11,6 +11,7 @@
#include <linux/vmalloc.h>
#include <linux/sizes.h>
#include <linux/pgtable.h>
+#include <asm/alternative.h>
#include <asm/sections.h>
static int apply_r_riscv_32_rela(struct module *me, u32 *location, Elf_Addr v)
@@ -416,3 +417,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;
+}
 
 

Recent Patches

About Us

Sed lacus. Donec lectus. Nullam pretium nibh ut turpis. Nam bibendum. In nulla tortor, elementum vel, tempor at, varius non, purus. Mauris vitae nisl nec metus placerat consectetuer.

Read More...