On book3s/32, when STRICT_KERNEL_RWX is selected, modules are
allocated on the segment just before kernel text, ie on the
0xb0000000-0xbfffffff when PAGE_OFFSET is 0xc0000000.
On the 8xx, TASK_SIZE is 0x80000000. The space between TASK_SIZE and
PAGE_OFFSET is not used and could be used for modules.
The idea comes from ARM architecture.
Having modules just below PAGE_OFFSET offers an opportunity to
minimise the distance between kernel text and modules and avoid
trampolines in modules to access kernel functions or other module
functions.
When MODULES_VADDR is defined, powerpc has it's own module_alloc()
function. In that function, first try to allocate the module
above the limit defined by '_etext - 32M'. Then if the allocation
fails, fallback to the entire MODULES area.
DEBUG logs in module_32.c without the patch:
[ 1572.588822] module_32: Applying ADD relocate section 13 to 12
[ 1572.588891] module_32: Doing plt for call to 0xc00671a4 at 0xcae04024
[ 1572.588964] module_32: Initialized plt for 0xc00671a4 at 
cae04000
[ 1572.589037] module_32: REL24 value = 
CAE04000. location = 
CAE04024
[ 1572.589110] module_32: Location before: 
48000001.
[ 1572.589171] module_32: Location after: 
4BFFFFDD.
[ 1572.589231] module_32: ie. jump to 
03FFFFDC+
CAE04024 = 
CEE04000
[ 1572.589317] module_32: Applying ADD relocate section 15 to 14
[ 1572.589386] module_32: Doing plt for call to 0xc00671a4 at 0xcadfc018
[ 1572.589457] module_32: Initialized plt for 0xc00671a4 at 
cadfc000
[ 1572.589529] module_32: REL24 value = 
CADFC000. location = 
CADFC018
[ 1572.589601] module_32: Location before: 
48000000.
[ 1572.589661] module_32: Location after: 
4BFFFFE8.
[ 1572.589723] module_32: ie. jump to 
03FFFFE8+
CADFC018 = 
CEDFC000
With the patch:
[  279.404671] module_32: Applying ADD relocate section 13 to 12
[  279.404741] module_32: REL24 value = 
C00671B4. location = 
BF808024
[  279.404814] module_32: Location before: 
48000001.
[  279.404874] module_32: Location after: 
4885F191.
[  279.404933] module_32: ie. jump to 
0085F190+
BF808024 = 
C00671B4
[  279.405016] module_32: Applying ADD relocate section 15 to 14
[  279.405085] module_32: REL24 value = 
C00671B4. location = 
BF800018
[  279.405156] module_32: Location before: 
48000000.
[  279.405215] module_32: Location after: 
4886719C.
[  279.405275] module_32: ie. jump to 
0086719C+
BF800018 = 
C00671B4
We see that with the patch, no plt entries are set.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/0c3d5cb8a4dfdf6ca1b8aeb385c01470d6628d55.1617283827.git.christophe.leroy@csgroup.eu
 #include <asm/firmware.h>
 #include <linux/sort.h>
 #include <asm/setup.h>
+#include <asm/sections.h>
 
 static LIST_HEAD(module_bug_list);
 
 }
 
 #ifdef MODULES_VADDR
+static __always_inline void *
+__module_alloc(unsigned long size, unsigned long start, unsigned long end)
+{
+       return __vmalloc_node_range(size, 1, start, end, GFP_KERNEL,
+                                   PAGE_KERNEL_EXEC, VM_FLUSH_RESET_PERMS, NUMA_NO_NODE,
+                                   __builtin_return_address(0));
+}
+
 void *module_alloc(unsigned long size)
 {
+       unsigned long limit = (unsigned long)_etext - SZ_32M;
+       void *ptr = NULL;
+
        BUILD_BUG_ON(TASK_SIZE > MODULES_VADDR);
 
-       return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, GFP_KERNEL,
-                                   PAGE_KERNEL_EXEC, VM_FLUSH_RESET_PERMS, NUMA_NO_NODE,
-                                   __builtin_return_address(0));
+       /* First try within 32M limit from _etext to avoid branch trampolines */
+       if (MODULES_VADDR < PAGE_OFFSET && MODULES_END > limit)
+               ptr = __module_alloc(size, limit, MODULES_END);
+
+       if (!ptr)
+               ptr = __module_alloc(size, MODULES_VADDR, MODULES_END);
+
+       return ptr;
 }
 #endif