summaryrefslogtreecommitdiffstats
path: root/mm/execmem.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/execmem.c')
-rw-r--r--mm/execmem.c67
1 files changed, 64 insertions, 3 deletions
diff --git a/mm/execmem.c b/mm/execmem.c
index 480adc69b20d..80e61c1e7319 100644
--- a/mm/execmem.c
+++ b/mm/execmem.c
@@ -11,14 +11,30 @@
#include <linux/execmem.h>
#include <linux/moduleloader.h>
-static void *__execmem_alloc(size_t size)
+static struct execmem_info *execmem_info __ro_after_init;
+
+static void *__execmem_alloc(struct execmem_range *range, size_t size)
{
- return module_alloc(size);
+ unsigned long start = range->start;
+ unsigned long end = range->end;
+ unsigned int align = range->alignment;
+ pgprot_t pgprot = range->pgprot;
+
+ return __vmalloc_node_range(size, align, start, end,
+ GFP_KERNEL, pgprot, VM_FLUSH_RESET_PERMS,
+ NUMA_NO_NODE, __builtin_return_address(0));
}
void *execmem_alloc(enum execmem_type type, size_t size)
{
- return __execmem_alloc(size);
+ struct execmem_range *range;
+
+ if (!execmem_info)
+ return module_alloc(size);
+
+ range = &execmem_info->ranges[type];
+
+ return __execmem_alloc(range, size);
}
void execmem_free(void *ptr)
@@ -30,3 +46,48 @@ void execmem_free(void *ptr)
WARN_ON(in_interrupt());
vfree(ptr);
}
+
+static bool execmem_validate(struct execmem_info *info)
+{
+ struct execmem_range *r = &info->ranges[EXECMEM_DEFAULT];
+
+ if (!r->alignment || !r->start || !r->end || !pgprot_val(r->pgprot)) {
+ pr_crit("Invalid parameters for execmem allocator, module loading will fail");
+ return false;
+ }
+
+ return true;
+}
+
+static void execmem_init_missing(struct execmem_info *info)
+{
+ struct execmem_range *default_range = &info->ranges[EXECMEM_DEFAULT];
+
+ for (int i = EXECMEM_DEFAULT + 1; i < EXECMEM_TYPE_MAX; i++) {
+ struct execmem_range *r = &info->ranges[i];
+
+ if (!r->start) {
+ r->pgprot = default_range->pgprot;
+ r->alignment = default_range->alignment;
+ r->start = default_range->start;
+ r->end = default_range->end;
+ }
+ }
+}
+
+struct execmem_info * __weak execmem_arch_setup(void)
+{
+ return NULL;
+}
+
+void __init execmem_init(void)
+{
+ struct execmem_info *info = execmem_arch_setup();
+
+ if (!info || !execmem_validate(info))
+ return;
+
+ execmem_init_missing(info);
+
+ execmem_info = info;
+}