riscv: implement module alternatives

A patch from »riscv: support for svpbmt and D1 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 the implementation of other architectures (e.g. arm64). Signed-off-by: Heiko Stuebner <heiko@...>

Patch-Comment

arch/riscv/include/asm/alternative.h | 3 ++- arch/riscv/kernel/alternative.c | 16 ++++++++++++--- arch/riscv/kernel/module.c | 29 ++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 4 deletions(-)

Statistics

  • 44 lines added
  • 4 lines removed

Changes

--------------------- arch/riscv/include/asm/alternative.h ---------------------
index 811bdd8027db..f0657b1b3174 100644
@@ -18,8 +18,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 */
@@ -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 ead00c508266..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,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
-------------------------- 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...