Skip to content

Commit 18efd0b

Browse files
xry111zx2c4
authored andcommitted
LoongArch: vDSO: Wire up getrandom() vDSO implementation
Hook up the generic vDSO implementation to the LoongArch vDSO data page by providing the required __arch_chacha20_blocks_nostack, __arch_get_k_vdso_rng_data, and getrandom_syscall implementations. Also wire up the selftests. Signed-off-by: Xi Ruoyao <[email protected]> Acked-by: Huacai Chen <[email protected]> Signed-off-by: Jason A. Donenfeld <[email protected]>
1 parent 4d456f0 commit 18efd0b

File tree

11 files changed

+316
-2
lines changed

11 files changed

+316
-2
lines changed

arch/loongarch/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ config LOONGARCH
190190
select TRACE_IRQFLAGS_SUPPORT
191191
select USE_PERCPU_NUMA_NODE_ID
192192
select USER_STACKTRACE_SUPPORT
193+
select VDSO_GETRANDOM
193194
select ZONE_DMA32
194195

195196
config 32BIT
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (C) 2024 Xi Ruoyao <[email protected]>. All Rights Reserved.
4+
*/
5+
#ifndef __ASM_VDSO_GETRANDOM_H
6+
#define __ASM_VDSO_GETRANDOM_H
7+
8+
#ifndef __ASSEMBLY__
9+
10+
#include <asm/unistd.h>
11+
#include <asm/vdso/vdso.h>
12+
13+
static __always_inline ssize_t getrandom_syscall(void *_buffer, size_t _len, unsigned int _flags)
14+
{
15+
register long ret asm("a0");
16+
register long nr asm("a7") = __NR_getrandom;
17+
register void *buffer asm("a0") = _buffer;
18+
register size_t len asm("a1") = _len;
19+
register unsigned int flags asm("a2") = _flags;
20+
21+
asm volatile(
22+
" syscall 0\n"
23+
: "+r" (ret)
24+
: "r" (nr), "r" (buffer), "r" (len), "r" (flags)
25+
: "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8",
26+
"memory");
27+
28+
return ret;
29+
}
30+
31+
static __always_inline const struct vdso_rng_data *__arch_get_vdso_rng_data(void)
32+
{
33+
return (const struct vdso_rng_data *)(get_vdso_data() + VVAR_LOONGARCH_PAGES_START *
34+
PAGE_SIZE + offsetof(struct loongarch_vdso_data, rng_data));
35+
}
36+
37+
#endif /* !__ASSEMBLY__ */
38+
39+
#endif /* __ASM_VDSO_GETRANDOM_H */

arch/loongarch/include/asm/vdso/vdso.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
* Copyright (C) 2020-2022 Loongson Technology Corporation Limited
55
*/
66

7+
#ifndef _ASM_VDSO_VDSO_H
8+
#define _ASM_VDSO_VDSO_H
9+
710
#ifndef __ASSEMBLY__
811

912
#include <asm/asm.h>
@@ -16,6 +19,7 @@ struct vdso_pcpu_data {
1619

1720
struct loongarch_vdso_data {
1821
struct vdso_pcpu_data pdata[NR_CPUS];
22+
struct vdso_rng_data rng_data;
1923
};
2024

2125
/*
@@ -63,3 +67,5 @@ static inline unsigned long get_vdso_data(void)
6367
}
6468

6569
#endif /* __ASSEMBLY__ */
70+
71+
#endif

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <vdso/datapage.h>
99

1010
extern struct vdso_data *vdso_data;
11+
extern struct vdso_rng_data *vdso_rng_data;
1112

1213
/*
1314
* Update the vDSO data page to keep in sync with kernel timekeeping.
@@ -19,6 +20,13 @@ struct vdso_data *__loongarch_get_k_vdso_data(void)
1920
}
2021
#define __arch_get_k_vdso_data __loongarch_get_k_vdso_data
2122

23+
static __always_inline
24+
struct vdso_rng_data *__loongarch_get_k_vdso_rng_data(void)
25+
{
26+
return vdso_rng_data;
27+
}
28+
#define __arch_get_k_vdso_rng_data __loongarch_get_k_vdso_rng_data
29+
2230
/* The asm-generic header needs to be included after the definitions above */
2331
#include <asm-generic/vdso/vsyscall.h>
2432

arch/loongarch/kernel/vdso.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ static union {
3737
static struct page *vdso_pages[] = { NULL };
3838
struct vdso_data *vdso_data = generic_vdso_data.data;
3939
struct vdso_pcpu_data *vdso_pdata = loongarch_vdso_data.vdata.pdata;
40+
struct vdso_rng_data *vdso_rng_data = &loongarch_vdso_data.vdata.rng_data;
4041

4142
static int vdso_mremap(const struct vm_special_mapping *sm, struct vm_area_struct *new_vma)
4243
{

arch/loongarch/vdso/Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
# Include the generic Makefile to check the built vdso.
55
include $(srctree)/lib/vdso/Makefile
66

7-
obj-vdso-y := elf.o vgetcpu.o vgettimeofday.o sigreturn.o
7+
obj-vdso-y := elf.o vgetcpu.o vgettimeofday.o vgetrandom.o \
8+
vgetrandom-chacha.o sigreturn.o
89

910
# Common compiler flags between ABIs.
1011
ccflags-vdso := \
@@ -29,6 +30,10 @@ ifneq ($(c-gettimeofday-y),)
2930
CFLAGS_vgettimeofday.o += -include $(c-gettimeofday-y)
3031
endif
3132

33+
ifneq ($(c-getrandom-y),)
34+
CFLAGS_vgetrandom.o += -include $(c-getrandom-y)
35+
endif
36+
3237
# VDSO linker flags.
3338
ldflags-y := -Bsymbolic --no-undefined -soname=linux-vdso.so.1 \
3439
$(filter -E%,$(KBUILD_CFLAGS)) -nostdlib -shared \

arch/loongarch/vdso/vdso.lds.S

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ VERSION
6262
__vdso_clock_getres;
6363
__vdso_clock_gettime;
6464
__vdso_gettimeofday;
65+
__vdso_getrandom;
6566
__vdso_rt_sigreturn;
6667
local: *;
6768
};
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (C) 2024 Xi Ruoyao <[email protected]>. All Rights Reserved.
4+
*/
5+
6+
#include <asm/asm.h>
7+
#include <asm/regdef.h>
8+
#include <linux/linkage.h>
9+
10+
.text
11+
12+
/* Salsa20 quarter-round */
13+
.macro QR a b c d
14+
add.w \a, \a, \b
15+
xor \d, \d, \a
16+
rotri.w \d, \d, 16
17+
18+
add.w \c, \c, \d
19+
xor \b, \b, \c
20+
rotri.w \b, \b, 20
21+
22+
add.w \a, \a, \b
23+
xor \d, \d, \a
24+
rotri.w \d, \d, 24
25+
26+
add.w \c, \c, \d
27+
xor \b, \b, \c
28+
rotri.w \b, \b, 25
29+
.endm
30+
31+
/*
32+
* Very basic LoongArch implementation of ChaCha20. Produces a given positive
33+
* number of blocks of output with a nonce of 0, taking an input key and
34+
* 8-byte counter. Importantly does not spill to the stack. Its arguments
35+
* are:
36+
*
37+
* a0: output bytes
38+
* a1: 32-byte key input
39+
* a2: 8-byte counter input/output
40+
* a3: number of 64-byte blocks to write to output
41+
*/
42+
SYM_FUNC_START(__arch_chacha20_blocks_nostack)
43+
44+
/* We don't need a frame pointer */
45+
#define s9 fp
46+
47+
#define output a0
48+
#define key a1
49+
#define counter a2
50+
#define nblocks a3
51+
#define i a4
52+
#define state0 s0
53+
#define state1 s1
54+
#define state2 s2
55+
#define state3 s3
56+
#define state4 s4
57+
#define state5 s5
58+
#define state6 s6
59+
#define state7 s7
60+
#define state8 s8
61+
#define state9 s9
62+
#define state10 a5
63+
#define state11 a6
64+
#define state12 a7
65+
#define state13 t0
66+
#define state14 t1
67+
#define state15 t2
68+
#define cnt_lo t3
69+
#define cnt_hi t4
70+
#define copy0 t5
71+
#define copy1 t6
72+
#define copy2 t7
73+
74+
/* Reuse i as copy3 */
75+
#define copy3 i
76+
77+
/*
78+
* The ABI requires s0-s9 saved, and sp aligned to 16-byte.
79+
* This does not violate the stack-less requirement: no sensitive data
80+
* is spilled onto the stack.
81+
*/
82+
PTR_ADDI sp, sp, (-SZREG * 10) & STACK_ALIGN
83+
REG_S s0, sp, 0
84+
REG_S s1, sp, SZREG
85+
REG_S s2, sp, SZREG * 2
86+
REG_S s3, sp, SZREG * 3
87+
REG_S s4, sp, SZREG * 4
88+
REG_S s5, sp, SZREG * 5
89+
REG_S s6, sp, SZREG * 6
90+
REG_S s7, sp, SZREG * 7
91+
REG_S s8, sp, SZREG * 8
92+
REG_S s9, sp, SZREG * 9
93+
94+
li.w copy0, 0x61707865
95+
li.w copy1, 0x3320646e
96+
li.w copy2, 0x79622d32
97+
98+
ld.w cnt_lo, counter, 0
99+
ld.w cnt_hi, counter, 4
100+
101+
.Lblock:
102+
/* state[0,1,2,3] = "expand 32-byte k" */
103+
move state0, copy0
104+
move state1, copy1
105+
move state2, copy2
106+
li.w state3, 0x6b206574
107+
108+
/* state[4,5,..,11] = key */
109+
ld.w state4, key, 0
110+
ld.w state5, key, 4
111+
ld.w state6, key, 8
112+
ld.w state7, key, 12
113+
ld.w state8, key, 16
114+
ld.w state9, key, 20
115+
ld.w state10, key, 24
116+
ld.w state11, key, 28
117+
118+
/* state[12,13] = counter */
119+
move state12, cnt_lo
120+
move state13, cnt_hi
121+
122+
/* state[14,15] = 0 */
123+
move state14, zero
124+
move state15, zero
125+
126+
li.w i, 10
127+
.Lpermute:
128+
/* odd round */
129+
QR state0, state4, state8, state12
130+
QR state1, state5, state9, state13
131+
QR state2, state6, state10, state14
132+
QR state3, state7, state11, state15
133+
134+
/* even round */
135+
QR state0, state5, state10, state15
136+
QR state1, state6, state11, state12
137+
QR state2, state7, state8, state13
138+
QR state3, state4, state9, state14
139+
140+
addi.w i, i, -1
141+
bnez i, .Lpermute
142+
143+
/*
144+
* copy[3] = "expa", materialize it here because copy[3] shares the
145+
* same register with i which just became dead.
146+
*/
147+
li.w copy3, 0x6b206574
148+
149+
/* output[0,1,2,3] = copy[0,1,2,3] + state[0,1,2,3] */
150+
add.w state0, state0, copy0
151+
add.w state1, state1, copy1
152+
add.w state2, state2, copy2
153+
add.w state3, state3, copy3
154+
st.w state0, output, 0
155+
st.w state1, output, 4
156+
st.w state2, output, 8
157+
st.w state3, output, 12
158+
159+
/* from now on state[0,1,2,3] are scratch registers */
160+
161+
/* state[0,1,2,3] = lo32(key) */
162+
ld.w state0, key, 0
163+
ld.w state1, key, 4
164+
ld.w state2, key, 8
165+
ld.w state3, key, 12
166+
167+
/* output[4,5,6,7] = state[0,1,2,3] + state[4,5,6,7] */
168+
add.w state4, state4, state0
169+
add.w state5, state5, state1
170+
add.w state6, state6, state2
171+
add.w state7, state7, state3
172+
st.w state4, output, 16
173+
st.w state5, output, 20
174+
st.w state6, output, 24
175+
st.w state7, output, 28
176+
177+
/* state[0,1,2,3] = hi32(key) */
178+
ld.w state0, key, 16
179+
ld.w state1, key, 20
180+
ld.w state2, key, 24
181+
ld.w state3, key, 28
182+
183+
/* output[8,9,10,11] = state[0,1,2,3] + state[8,9,10,11] */
184+
add.w state8, state8, state0
185+
add.w state9, state9, state1
186+
add.w state10, state10, state2
187+
add.w state11, state11, state3
188+
st.w state8, output, 32
189+
st.w state9, output, 36
190+
st.w state10, output, 40
191+
st.w state11, output, 44
192+
193+
/* output[12,13,14,15] = state[12,13,14,15] + [cnt_lo, cnt_hi, 0, 0] */
194+
add.w state12, state12, cnt_lo
195+
add.w state13, state13, cnt_hi
196+
st.w state12, output, 48
197+
st.w state13, output, 52
198+
st.w state14, output, 56
199+
st.w state15, output, 60
200+
201+
/* ++counter */
202+
addi.w cnt_lo, cnt_lo, 1
203+
sltui state0, cnt_lo, 1
204+
add.w cnt_hi, cnt_hi, state0
205+
206+
/* output += 64 */
207+
PTR_ADDI output, output, 64
208+
/* --nblocks */
209+
PTR_ADDI nblocks, nblocks, -1
210+
bnez nblocks, .Lblock
211+
212+
/* counter = [cnt_lo, cnt_hi] */
213+
st.w cnt_lo, counter, 0
214+
st.w cnt_hi, counter, 4
215+
216+
/*
217+
* Zero out the potentially sensitive regs, in case nothing uses these
218+
* again. As at now copy[0,1,2,3] just contains "expand 32-byte k" and
219+
* state[0,...,9] are s0-s9 those we'll restore in the epilogue, so we
220+
* only need to zero state[11,...,15].
221+
*/
222+
move state10, zero
223+
move state11, zero
224+
move state12, zero
225+
move state13, zero
226+
move state14, zero
227+
move state15, zero
228+
229+
REG_L s0, sp, 0
230+
REG_L s1, sp, SZREG
231+
REG_L s2, sp, SZREG * 2
232+
REG_L s3, sp, SZREG * 3
233+
REG_L s4, sp, SZREG * 4
234+
REG_L s5, sp, SZREG * 5
235+
REG_L s6, sp, SZREG * 6
236+
REG_L s7, sp, SZREG * 7
237+
REG_L s8, sp, SZREG * 8
238+
REG_L s9, sp, SZREG * 9
239+
PTR_ADDI sp, sp, -((-SZREG * 10) & STACK_ALIGN)
240+
241+
jr ra
242+
SYM_FUNC_END(__arch_chacha20_blocks_nostack)

arch/loongarch/vdso/vgetrandom.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (C) 2024 Xi Ruoyao <[email protected]>. All Rights Reserved.
4+
*/
5+
#include <linux/types.h>
6+
7+
ssize_t __vdso_getrandom(void *buffer, size_t len, unsigned int flags, void *opaque_state, size_t opaque_len)
8+
{
9+
return __cvdso_getrandom(buffer, len, flags, opaque_state, opaque_len);
10+
}

tools/arch/loongarch/vdso

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../arch/loongarch/vdso

tools/testing/selftests/vDSO/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ ifeq ($(ARCH),$(filter $(ARCH),x86 x86_64))
99
TEST_GEN_PROGS += vdso_standalone_test_x86
1010
endif
1111
TEST_GEN_PROGS += vdso_test_correctness
12-
ifeq ($(ARCH)$(CONFIG_X86_32),$(filter $(ARCH)$(CONFIG_X86_32),x86 x86_64))
12+
ifeq ($(ARCH)$(CONFIG_X86_32),$(filter $(ARCH)$(CONFIG_X86_32),x86 x86_64 loongarch))
1313
TEST_GEN_PROGS += vdso_test_getrandom
1414
TEST_GEN_PROGS += vdso_test_chacha
1515
endif

0 commit comments

Comments
 (0)