powerpc/vdso: Implement __arch_get_vdso_rng_data()
authorChristophe Leroy <christophe.leroy@csgroup.eu>
Wed, 2 Oct 2024 08:39:29 +0000 (10:39 +0200)
committerMichael Ellerman <mpe@ellerman.id.au>
Wed, 16 Oct 2024 00:14:40 +0000 (11:14 +1100)
VDSO time functions do not call any other function, so they don't
need to save/restore LR. However, retrieving the address of VDSO data
page requires using LR hence saving then restoring it, which can be
heavy on some CPUs. On the other hand, VDSO functions on powerpc are
not standard functions and require a wrapper function to call C VDSO
functions. And that wrapper has to save and restore LR in order to
call the C VDSO function, so retrieving VDSO data page address in that
wrapper doesn't require additional save/restore of LR.

For random VDSO functions it is a bit different. Because the function
calls __arch_chacha20_blocks_nostack(), it saves and restores LR.
Retrieving VDSO data page address can then be done there without
additional save/restore of LR.

So lets implement __arch_get_vdso_rng_data() and simplify the wrapper.

It starts paving the way for the day powerpc will implement a more
standard ABI for VDSO functions.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://patch.msgid.link/a1a9bd0df508f1b5c04684b7366940577dfc6262.1727858295.git.christophe.leroy@csgroup.eu
arch/powerpc/include/asm/vdso/getrandom.h
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/vdso/getrandom.S
arch/powerpc/kernel/vdso/vgetrandom.c

index 501d6bb14e8a72b2de5b0c31a7019761eace4f46..80ce0709725eb89c1f3b69e0733038b458fbf24f 100644 (file)
@@ -7,6 +7,8 @@
 
 #ifndef __ASSEMBLY__
 
+#include <asm/vdso_datapage.h>
+
 static __always_inline int do_syscall_3(const unsigned long _r0, const unsigned long _r3,
                                        const unsigned long _r4, const unsigned long _r5)
 {
@@ -43,11 +45,21 @@ static __always_inline ssize_t getrandom_syscall(void *buffer, size_t len, unsig
 
 static __always_inline struct vdso_rng_data *__arch_get_vdso_rng_data(void)
 {
-       return NULL;
+       struct vdso_arch_data *data;
+
+       asm (
+               "       bcl     20, 31, .+4 ;"
+               "0:     mflr    %0 ;"
+               "       addis   %0, %0, (_vdso_datapage - 0b)@ha ;"
+               "       addi    %0, %0, (_vdso_datapage - 0b)@l  ;"
+               : "=r" (data) : : "lr"
+       );
+
+       return &data->rng_data;
 }
 
 ssize_t __c_kernel_getrandom(void *buffer, size_t len, unsigned int flags, void *opaque_state,
-                            size_t opaque_len, const struct vdso_rng_data *vd);
+                            size_t opaque_len);
 
 #endif /* !__ASSEMBLY__ */
 
index 131a8cc10dbe8ddfa4d93d0a11a46e488b79f953..7b3feb6bc2103bc89ea14fbaac6937f1c97d4ff8 100644 (file)
@@ -335,7 +335,6 @@ int main(void)
 
        /* datapage offsets for use by vdso */
        OFFSET(VDSO_DATA_OFFSET, vdso_arch_data, data);
-       OFFSET(VDSO_RNG_DATA_OFFSET, vdso_arch_data, rng_data);
        OFFSET(CFG_TB_TICKS_PER_SEC, vdso_arch_data, tb_ticks_per_sec);
 #ifdef CONFIG_PPC64
        OFFSET(CFG_ICACHE_BLOCKSZ, vdso_arch_data, icache_block_size);
index 3deddcf89f99b481916923854b1c63b39c0f8cbe..a80d9fb436f7ee34b52cb05a6595d89874a746ed 100644 (file)
@@ -31,7 +31,6 @@
        PPC_STL         r2, PPC_MIN_STKFRM + STK_GOT(r1)
   .cfi_rel_offset r2, PPC_MIN_STKFRM + STK_GOT
 #endif
-       get_datapage    r8 VDSO_RNG_DATA_OFFSET
        bl              CFUNC(DOTSYM(\funct))
        PPC_LL          r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1)
 #ifdef __powerpc64__
index 5f855d45fb7bf9efc143e0a01ffbd3f329b9f2cb..cc79b960a5413bb71e5c6c0b6a9d2ff3f7f869f8 100644 (file)
@@ -8,7 +8,7 @@
 #include <linux/types.h>
 
 ssize_t __c_kernel_getrandom(void *buffer, size_t len, unsigned int flags, void *opaque_state,
-                            size_t opaque_len, const struct vdso_rng_data *vd)
+                            size_t opaque_len)
 {
-       return __cvdso_getrandom_data(vd, buffer, len, flags, opaque_state, opaque_len);
+       return __cvdso_getrandom(buffer, len, flags, opaque_state, opaque_len);
 }