summaryrefslogtreecommitdiff
path: root/arch/riscv/kernel/module.c
diff options
context:
space:
mode:
authorPalmer Dabbelt <palmer@rivosinc.com>2022-05-12 09:12:09 -0700
committerPalmer Dabbelt <palmer@rivosinc.com>2022-05-12 09:12:09 -0700
commit93c0651617a62a69717299f1464dda798af8bebb (patch)
tree43091139fcd158f95366c3a98bc67f5ab5f7434a /arch/riscv/kernel/module.c
parentd26eee72d9b9048ba8621e3d47553792729db01f (diff)
parenta35707c3d850dda0ceefb75b1b3bd191921d5765 (diff)
riscv: support for Svpbmt and D1 memory types
Adds support for Svpbmt, the "Supervisor-mode: page-based memory types" extension, which allows pages to be marked as non-cacheable and/or I/O. This also includes support for the Allwinner D1's page table attributes via the alternatives framework, which differ from Svpbmt in various ways but are necessary to make the D1 function. * palmer/riscv-d1: riscv: add memory-type errata for T-Head riscv: don't use global static vars to store alternative data riscv: remove FIXMAP_PAGE_IO and fall back to its default value riscv: add RISC-V Svpbmt extension support riscv: Fix accessing pfn bits in PTEs for non-32bit variants riscv: move boot alternatives to after fill_hwcap riscv: prevent compressed instructions in alternatives riscv: extend concatenated alternatives-lines to the same length riscv: implement ALTERNATIVE_2 macro riscv: implement module alternatives riscv: allow different stages with alternatives riscv: integrate alternatives better into the main architecture
Diffstat (limited to 'arch/riscv/kernel/module.c')
-rw-r--r--arch/riscv/kernel/module.c29
1 files changed, 29 insertions, 0 deletions
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;
+}