Skip to content

Commit 53cee50

Browse files
chleroyzx2c4
authored andcommitted
powerpc/vdso: Wire up getrandom() vDSO implementation on VDSO32
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 <[email protected]> Acked-by: Michael Ellerman <[email protected]> Signed-off-by: Jason A. Donenfeld <[email protected]>
1 parent a6b67eb commit 53cee50

File tree

13 files changed

+455
-5
lines changed

13 files changed

+455
-5
lines changed

arch/powerpc/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ config PPC
311311
select SYSCTL_EXCEPTION_TRACE
312312
select THREAD_INFO_IN_TASK
313313
select TRACE_IRQFLAGS_SUPPORT
314+
select VDSO_GETRANDOM if VDSO32
314315
#
315316
# Please keep this list sorted alphabetically.
316317
#

arch/powerpc/include/asm/mman.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
#include <uapi/asm/mman.h>
88

9-
#ifdef CONFIG_PPC64
9+
#if defined(CONFIG_PPC64) && !defined(BUILD_VDSO)
1010

1111
#include <asm/cputable.h>
1212
#include <linux/mm.h>
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Copyright (C) 2024 Christophe Leroy <[email protected]>, CS GROUP France
4+
*/
5+
#ifndef _ASM_POWERPC_VDSO_GETRANDOM_H
6+
#define _ASM_POWERPC_VDSO_GETRANDOM_H
7+
8+
#ifndef __ASSEMBLY__
9+
10+
static __always_inline int do_syscall_3(const unsigned long _r0, const unsigned long _r3,
11+
const unsigned long _r4, const unsigned long _r5)
12+
{
13+
register long r0 asm("r0") = _r0;
14+
register unsigned long r3 asm("r3") = _r3;
15+
register unsigned long r4 asm("r4") = _r4;
16+
register unsigned long r5 asm("r5") = _r5;
17+
register int ret asm ("r3");
18+
19+
asm volatile(
20+
" sc\n"
21+
" bns+ 1f\n"
22+
" neg %0, %0\n"
23+
"1:\n"
24+
: "=r" (ret), "+r" (r4), "+r" (r5), "+r" (r0)
25+
: "r" (r3)
26+
: "memory", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "cr0", "ctr");
27+
28+
return ret;
29+
}
30+
31+
/**
32+
* getrandom_syscall - Invoke the getrandom() syscall.
33+
* @buffer: Destination buffer to fill with random bytes.
34+
* @len: Size of @buffer in bytes.
35+
* @flags: Zero or more GRND_* flags.
36+
* Returns: The number of bytes written to @buffer, or a negative value indicating an error.
37+
*/
38+
static __always_inline ssize_t getrandom_syscall(void *buffer, size_t len, unsigned int flags)
39+
{
40+
return do_syscall_3(__NR_getrandom, (unsigned long)buffer,
41+
(unsigned long)len, (unsigned long)flags);
42+
}
43+
44+
static __always_inline struct vdso_rng_data *__arch_get_vdso_rng_data(void)
45+
{
46+
return NULL;
47+
}
48+
49+
ssize_t __c_kernel_getrandom(void *buffer, size_t len, unsigned int flags, void *opaque_state,
50+
size_t opaque_len, const struct vdso_rng_data *vd);
51+
52+
#endif /* !__ASSEMBLY__ */
53+
54+
#endif /* _ASM_POWERPC_VDSO_GETRANDOM_H */

arch/powerpc/include/asm/vdso/vsyscall.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ struct vdso_data *__arch_get_k_vdso_data(void)
1717
}
1818
#define __arch_get_k_vdso_data __arch_get_k_vdso_data
1919

20+
static __always_inline
21+
struct vdso_rng_data *__arch_get_k_vdso_rng_data(void)
22+
{
23+
return &vdso_data->rng_data;
24+
}
25+
2026
/* The asm-generic header needs to be included after the definitions above */
2127
#include <asm-generic/vdso/vsyscall.h>
2228

arch/powerpc/include/asm/vdso_datapage.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ struct vdso_arch_data {
8383
__u32 compat_syscall_map[SYSCALL_MAP_SIZE]; /* Map of compat syscalls */
8484

8585
struct vdso_data data[CS_BASES];
86+
struct vdso_rng_data rng_data;
8687
};
8788

8889
#else /* CONFIG_PPC64 */
@@ -95,6 +96,7 @@ struct vdso_arch_data {
9596
__u32 syscall_map[SYSCALL_MAP_SIZE]; /* Map of syscalls */
9697
__u32 compat_syscall_map[0]; /* No compat syscalls on PPC32 */
9798
struct vdso_data data[CS_BASES];
99+
struct vdso_rng_data rng_data;
98100
};
99101

100102
#endif /* CONFIG_PPC64 */

arch/powerpc/kernel/asm-offsets.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ int main(void)
335335

336336
/* datapage offsets for use by vdso */
337337
OFFSET(VDSO_DATA_OFFSET, vdso_arch_data, data);
338+
OFFSET(VDSO_RNG_DATA_OFFSET, vdso_arch_data, rng_data);
338339
OFFSET(CFG_TB_TICKS_PER_SEC, vdso_arch_data, tb_ticks_per_sec);
339340
#ifdef CONFIG_PPC64
340341
OFFSET(CFG_ICACHE_BLOCKSZ, vdso_arch_data, icache_block_size);

arch/powerpc/kernel/vdso/Makefile

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ include $(srctree)/lib/vdso/Makefile
88
obj-vdso32 = sigtramp32-32.o gettimeofday-32.o datapage-32.o cacheflush-32.o note-32.o getcpu-32.o
99
obj-vdso64 = sigtramp64-64.o gettimeofday-64.o datapage-64.o cacheflush-64.o note-64.o getcpu-64.o
1010

11+
obj-vdso32 += getrandom-32.o vgetrandom-chacha-32.o
12+
1113
ifneq ($(c-gettimeofday-y),)
1214
CFLAGS_vgettimeofday-32.o += -include $(c-gettimeofday-y)
1315
# Go prior to 1.16.x assumes r30 is not clobbered by any VDSO code. That used to be true
@@ -17,6 +19,10 @@ ifneq ($(c-gettimeofday-y),)
1719
CFLAGS_vgettimeofday-64.o += -include $(c-gettimeofday-y) $(call cc-option, -ffixed-r30)
1820
endif
1921

22+
ifneq ($(c-getrandom-y),)
23+
CFLAGS_vgetrandom-32.o += -include $(c-getrandom-y)
24+
endif
25+
2026
# Build rules
2127

2228
ifdef CROSS32_COMPILE
@@ -25,13 +31,13 @@ else
2531
VDSOCC := $(CC)
2632
endif
2733

28-
targets := $(obj-vdso32) vdso32.so.dbg vgettimeofday-32.o
34+
targets := $(obj-vdso32) vdso32.so.dbg vgettimeofday-32.o vgetrandom-32.o
2935
targets += crtsavres-32.o
3036
obj-vdso32 := $(addprefix $(obj)/, $(obj-vdso32))
3137
targets += $(obj-vdso64) vdso64.so.dbg vgettimeofday-64.o
3238
obj-vdso64 := $(addprefix $(obj)/, $(obj-vdso64))
3339

34-
ccflags-y := -fno-common -fno-builtin
40+
ccflags-y := -fno-common -fno-builtin -DBUILD_VDSO
3541
ccflags-y += $(DISABLE_LATENT_ENTROPY_PLUGIN)
3642
ccflags-y += $(call cc-option, -fno-stack-protector)
3743
ccflags-y += -DDISABLE_BRANCH_PROFILING
@@ -63,7 +69,7 @@ targets += vdso64.lds
6369
CPPFLAGS_vdso64.lds += -P -C
6470

6571
# link rule for the .so file, .lds has to be first
66-
$(obj)/vdso32.so.dbg: $(obj)/vdso32.lds $(obj-vdso32) $(obj)/vgettimeofday-32.o $(obj)/crtsavres-32.o FORCE
72+
$(obj)/vdso32.so.dbg: $(obj)/vdso32.lds $(obj-vdso32) $(obj)/vgettimeofday-32.o $(obj)/vgetrandom-32.o $(obj)/crtsavres-32.o FORCE
6773
$(call if_changed,vdso32ld_and_check)
6874
$(obj)/vdso64.so.dbg: $(obj)/vdso64.lds $(obj-vdso64) $(obj)/vgettimeofday-64.o FORCE
6975
$(call if_changed,vdso64ld_and_check)
@@ -75,6 +81,8 @@ $(obj)/crtsavres-32.o: %-32.o: $(srctree)/arch/powerpc/lib/crtsavres.S FORCE
7581
$(call if_changed_dep,vdso32as)
7682
$(obj)/vgettimeofday-32.o: %-32.o: %.c FORCE
7783
$(call if_changed_dep,vdso32cc)
84+
$(obj)/vgetrandom-32.o: %-32.o: %.c FORCE
85+
$(call if_changed_dep,vdso32cc)
7886
$(obj-vdso64): %-64.o: %.S FORCE
7987
$(call if_changed_dep,vdso64as)
8088
$(obj)/vgettimeofday-64.o: %-64.o: %.c FORCE

arch/powerpc/kernel/vdso/getrandom.S

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
/*
3+
* Userland implementation of getrandom() for processes
4+
* for use in the vDSO
5+
*
6+
* Copyright (C) 2024 Christophe Leroy <[email protected]>, CS GROUP France
7+
*/
8+
#include <asm/processor.h>
9+
#include <asm/ppc_asm.h>
10+
#include <asm/vdso.h>
11+
#include <asm/vdso_datapage.h>
12+
#include <asm/asm-offsets.h>
13+
#include <asm/unistd.h>
14+
15+
/*
16+
* The macro sets two stack frames, one for the caller and one for the callee
17+
* because there are no requirement for the caller to set a stack frame when
18+
* calling VDSO so it may have omitted to set one, especially on PPC64
19+
*/
20+
21+
.macro cvdso_call funct
22+
.cfi_startproc
23+
PPC_STLU r1, -PPC_MIN_STKFRM(r1)
24+
.cfi_adjust_cfa_offset PPC_MIN_STKFRM
25+
mflr r0
26+
PPC_STLU r1, -PPC_MIN_STKFRM(r1)
27+
.cfi_adjust_cfa_offset PPC_MIN_STKFRM
28+
PPC_STL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1)
29+
.cfi_rel_offset lr, PPC_MIN_STKFRM + PPC_LR_STKOFF
30+
get_realdatapage r8, r11
31+
addi r8, r8, VDSO_RNG_DATA_OFFSET
32+
bl CFUNC(DOTSYM(\funct))
33+
PPC_LL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1)
34+
cmpwi r3, 0
35+
mtlr r0
36+
addi r1, r1, 2 * PPC_MIN_STKFRM
37+
.cfi_restore lr
38+
.cfi_def_cfa_offset 0
39+
crclr so
40+
bgelr+
41+
crset so
42+
neg r3, r3
43+
blr
44+
.cfi_endproc
45+
.endm
46+
47+
.text
48+
V_FUNCTION_BEGIN(__kernel_getrandom)
49+
cvdso_call __c_kernel_getrandom
50+
V_FUNCTION_END(__kernel_getrandom)

arch/powerpc/kernel/vdso/vdso32.lds.S

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ VERSION
128128
#if defined(CONFIG_PPC64) || !defined(CONFIG_SMP)
129129
__kernel_getcpu;
130130
#endif
131+
__kernel_getrandom;
131132

132133
local: *;
133134
};

0 commit comments

Comments
 (0)