riscv: implement module alternatives

A patch from »SVPBMT + T-Head memory types next try« 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 | 21 ++++++++++++++++---- arch/riscv/kernel/module.c | 29 ++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 5 deletions(-)

Statistics

  • 48 lines added
  • 5 lines removed

Changes

--------------------- arch/riscv/include/asm/alternative.h ---------------------
index 811bdd8027db..625ad4da830e 100644
@@ -18,8 +18,10 @@
#include <asm/hwcap.h>
#define RISCV_ALTERNATIVES_BOOT 0 /* alternatives applied during regular boot */
+#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..e1849faa2fa1 100644
@@ -7,6 +7,7 @@
*/
#include <linux/init.h>
+#include <linux/module.h>
#include <linux/cpu.h>
#include <linux/uaccess.h>
#include <asm/alternative.h>
@@ -58,13 +59,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 +78,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...