Kernel text replication requires maintaining a separate per-node page table for kernel text. To accomplish this without affecting other kernel memory maps, it is best to place the kernel in a location that does not share L0 page table entries with any other mappings. So, limit the module_alloc() address range so that they do not overlap. Signed-off-by: Hao Jia <jiahao.os@xxxxxxxxxxxxx> --- arch/arm64/kernel/module.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c index dd851297596e..53e1c5e50907 100644 --- a/arch/arm64/kernel/module.c +++ b/arch/arm64/kernel/module.c @@ -112,6 +112,7 @@ subsys_initcall(module_init_limits); void *module_alloc(unsigned long size) { + u64 module_direct_end, module_plt_end; void *p = NULL; /* @@ -119,18 +120,33 @@ void *module_alloc(unsigned long size) * kernel such that no PLTs are necessary. */ if (module_direct_base) { +#ifdef CONFIG_REPLICATE_KTEXT + /* + * Kernel text replication requires an L0 page table entry to + * be exclusive to kernel text, so no other mappings should be + * shared with it. + */ + module_direct_end = MODULES_END; +#else + module_direct_end = module_direct_base + SZ_128M; +#endif p = __vmalloc_node_range(size, MODULE_ALIGN, module_direct_base, - module_direct_base + SZ_128M, + module_direct_end, GFP_KERNEL | __GFP_NOWARN, PAGE_KERNEL, 0, NUMA_NO_NODE, __builtin_return_address(0)); } if (!p && module_plt_base) { +#ifdef CONFIG_REPLICATE_KTEXT + module_plt_end = MODULES_END; +#else + module_plt_end = module_plt_base + SZ_2G; +#endif p = __vmalloc_node_range(size, MODULE_ALIGN, module_plt_base, - module_plt_base + SZ_2G, + module_plt_end, GFP_KERNEL | __GFP_NOWARN, PAGE_KERNEL, 0, NUMA_NO_NODE, __builtin_return_address(0)); -- 2.20.1