53cee505ae
To be consistent with other VDSO functions, the function is called __kernel_getrandom() __arch_chacha20_blocks_nostack() fonction is implemented basically with 32 bits operations. It performs 4 QUARTERROUND operations in parallele. There are enough registers to avoid using the stack: On input: r3: output bytes r4: 32-byte key input r5: 8-byte counter input/output r6: number of 64-byte blocks to write to output During operation: stack: pointer to counter (r5) and non-volatile registers (r14-131) r0: counter of blocks (initialised with r6) r4: Value '4' after key has been read, used for indexing r5-r12: key r14-r15: block counter r16-r31: chacha state At the end: r0, r6-r12: Zeroised r5, r14-r31: Restored Performance on powerpc 885 (using kernel selftest): ~# ./vdso_test_getrandom bench-single vdso: 25000000 times in 62.938002291 seconds libc: 25000000 times in 535.581916866 seconds syscall: 25000000 times in 531.525042806 seconds Performance on powerpc 8321 (using kernel selftest): ~# ./vdso_test_getrandom bench-single vdso: 25000000 times in 16.899318858 seconds libc: 25000000 times in 131.050596522 seconds syscall: 25000000 times in 129.794790389 seconds This first patch adds support for VDSO32. As selftests cannot easily be generated only for VDSO32, and because the following patch brings support for VDSO64 anyway, this patch opts out all code in __arch_chacha20_blocks_nostack() so that vdso_test_chacha will not fail to compile and will not crash on PPC64/PPC64LE, allthough the selftest itself will fail. Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu> Acked-by: Michael Ellerman <mpe@ellerman.id.au> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
55 lines
1.6 KiB
C
55 lines
1.6 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (C) 2024 Christophe Leroy <christophe.leroy@csgroup.eu>, CS GROUP France
|
|
*/
|
|
#ifndef _ASM_POWERPC_VDSO_GETRANDOM_H
|
|
#define _ASM_POWERPC_VDSO_GETRANDOM_H
|
|
|
|
#ifndef __ASSEMBLY__
|
|
|
|
static __always_inline int do_syscall_3(const unsigned long _r0, const unsigned long _r3,
|
|
const unsigned long _r4, const unsigned long _r5)
|
|
{
|
|
register long r0 asm("r0") = _r0;
|
|
register unsigned long r3 asm("r3") = _r3;
|
|
register unsigned long r4 asm("r4") = _r4;
|
|
register unsigned long r5 asm("r5") = _r5;
|
|
register int ret asm ("r3");
|
|
|
|
asm volatile(
|
|
" sc\n"
|
|
" bns+ 1f\n"
|
|
" neg %0, %0\n"
|
|
"1:\n"
|
|
: "=r" (ret), "+r" (r4), "+r" (r5), "+r" (r0)
|
|
: "r" (r3)
|
|
: "memory", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "cr0", "ctr");
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* getrandom_syscall - Invoke the getrandom() syscall.
|
|
* @buffer: Destination buffer to fill with random bytes.
|
|
* @len: Size of @buffer in bytes.
|
|
* @flags: Zero or more GRND_* flags.
|
|
* Returns: The number of bytes written to @buffer, or a negative value indicating an error.
|
|
*/
|
|
static __always_inline ssize_t getrandom_syscall(void *buffer, size_t len, unsigned int flags)
|
|
{
|
|
return do_syscall_3(__NR_getrandom, (unsigned long)buffer,
|
|
(unsigned long)len, (unsigned long)flags);
|
|
}
|
|
|
|
static __always_inline struct vdso_rng_data *__arch_get_vdso_rng_data(void)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
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);
|
|
|
|
#endif /* !__ASSEMBLY__ */
|
|
|
|
#endif /* _ASM_POWERPC_VDSO_GETRANDOM_H */
|