Skip to content

Commit 2dd26d5

Browse files
author
Fox Snowpatch
committed
1 parent e54c728 commit 2dd26d5

8 files changed

Lines changed: 143 additions & 62 deletions

File tree

arch/powerpc/include/asm/uaccess.h

Lines changed: 77 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
#define TASK_SIZE_MAX TASK_SIZE_USER64
1616
#endif
1717

18+
/* Threshold above which VMX copy path is used */
19+
#define VMX_COPY_THRESHOLD 3328
20+
1821
#include <asm-generic/access_ok.h>
1922

2023
/*
@@ -326,40 +329,96 @@ do { \
326329
extern unsigned long __copy_tofrom_user(void __user *to,
327330
const void __user *from, unsigned long size);
328331

329-
#ifdef __powerpc64__
330-
static inline unsigned long
331-
raw_copy_in_user(void __user *to, const void __user *from, unsigned long n)
332+
enum usercopy_mode {
333+
USERCOPY_IN,
334+
USERCOPY_FROM,
335+
USERCOPY_TO,
336+
};
337+
338+
unsigned long __copy_tofrom_user_vmx(void __user *to, const void __user *from,
339+
unsigned long size, enum usercopy_mode mode);
340+
341+
unsigned long __copy_tofrom_user_base(void __user *to,
342+
const void __user *from, unsigned long size);
343+
344+
unsigned long __copy_tofrom_user_power7_vmx(void __user *to,
345+
const void __user *from, unsigned long size);
346+
347+
348+
static inline bool will_use_vmx(unsigned long n)
349+
{
350+
return IS_ENABLED(CONFIG_ALTIVEC) &&
351+
cpu_has_feature(CPU_FTR_VMX_COPY) &&
352+
n > VMX_COPY_THRESHOLD;
353+
}
354+
355+
static inline void raw_copy_allow(void __user *to, enum usercopy_mode mode)
356+
{
357+
switch (mode) {
358+
case USERCOPY_IN:
359+
allow_user_access(to, KUAP_READ_WRITE);
360+
break;
361+
case USERCOPY_FROM:
362+
allow_user_access(NULL, KUAP_READ);
363+
break;
364+
case USERCOPY_TO:
365+
allow_user_access(to, KUAP_WRITE);
366+
break;
367+
}
368+
}
369+
370+
static inline void raw_copy_prevent(enum usercopy_mode mode)
371+
{
372+
switch (mode) {
373+
case USERCOPY_IN:
374+
prevent_user_access(KUAP_READ_WRITE);
375+
break;
376+
case USERCOPY_FROM:
377+
prevent_user_access(KUAP_READ);
378+
break;
379+
case USERCOPY_TO:
380+
prevent_user_access(KUAP_WRITE);
381+
break;
382+
}
383+
}
384+
385+
static inline unsigned long raw_copy_tofrom_user(void __user *to,
386+
const void __user *from, unsigned long n,
387+
enum usercopy_mode mode)
332388
{
333389
unsigned long ret;
334390

335-
barrier_nospec();
336-
allow_user_access(to, KUAP_READ_WRITE);
391+
if (will_use_vmx(n))
392+
return __copy_tofrom_user_vmx(to, from, n, mode);
393+
394+
raw_copy_allow(to, mode);
337395
ret = __copy_tofrom_user(to, from, n);
338-
prevent_user_access(KUAP_READ_WRITE);
396+
raw_copy_prevent(mode);
339397
return ret;
398+
399+
}
400+
401+
#ifdef __powerpc64__
402+
static inline unsigned long
403+
raw_copy_in_user(void __user *to, const void __user *from, unsigned long n)
404+
{
405+
barrier_nospec();
406+
return raw_copy_tofrom_user(to, from, n, USERCOPY_IN);
340407
}
341408
#endif /* __powerpc64__ */
342409

343410
static inline unsigned long raw_copy_from_user(void *to,
344411
const void __user *from, unsigned long n)
345412
{
346-
unsigned long ret;
347-
348-
allow_user_access(NULL, KUAP_READ);
349-
ret = __copy_tofrom_user((__force void __user *)to, from, n);
350-
prevent_user_access(KUAP_READ);
351-
return ret;
413+
return raw_copy_tofrom_user((__force void __user *)to, from,
414+
n, USERCOPY_FROM);
352415
}
353416

354417
static inline unsigned long
355418
raw_copy_to_user(void __user *to, const void *from, unsigned long n)
356419
{
357-
unsigned long ret;
358-
359-
allow_user_access(to, KUAP_WRITE);
360-
ret = __copy_tofrom_user(to, (__force const void __user *)from, n);
361-
prevent_user_access(KUAP_WRITE);
362-
return ret;
420+
return raw_copy_tofrom_user(to, (__force const void __user *)from,
421+
n, USERCOPY_TO);
363422
}
364423

365424
unsigned long __arch_clear_user(void __user *addr, unsigned long size);

arch/powerpc/lib/copyuser_64.S

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,3 +562,4 @@ exc; std r10,32(3)
562562
li r5,4096
563563
b .Ldst_aligned
564564
EXPORT_SYMBOL(__copy_tofrom_user)
565+
EXPORT_SYMBOL(__copy_tofrom_user_base)

arch/powerpc/lib/copyuser_power7.S

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,9 @@
55
*
66
* Author: Anton Blanchard <anton@au.ibm.com>
77
*/
8+
#include <linux/export.h>
89
#include <asm/ppc_asm.h>
910

10-
#ifndef SELFTEST_CASE
11-
/* 0 == don't use VMX, 1 == use VMX */
12-
#define SELFTEST_CASE 0
13-
#endif
14-
1511
#ifdef __BIG_ENDIAN__
1612
#define LVS(VRT,RA,RB) lvsl VRT,RA,RB
1713
#define VPERM(VRT,VRA,VRB,VRC) vperm VRT,VRA,VRB,VRC
@@ -47,10 +43,14 @@
4743
ld r15,STK_REG(R15)(r1)
4844
ld r14,STK_REG(R14)(r1)
4945
.Ldo_err3:
50-
bl CFUNC(exit_vmx_usercopy)
46+
ld r6,STK_REG(R31)(r1) /* original destination pointer */
47+
ld r5,STK_REG(R29)(r1) /* original number of bytes */
48+
subf r7,r6,r3 /* #bytes copied */
49+
subf r3,r7,r5 /* #bytes not copied in r3 */
5150
ld r0,STACKFRAMESIZE+16(r1)
5251
mtlr r0
53-
b .Lexit
52+
addi r1,r1,STACKFRAMESIZE
53+
blr
5454
#endif /* CONFIG_ALTIVEC */
5555

5656
.Ldo_err2:
@@ -74,20 +74,13 @@
7474

7575
_GLOBAL(__copy_tofrom_user_power7)
7676
cmpldi r5,16
77-
cmpldi cr1,r5,3328
7877

7978
std r3,-STACKFRAMESIZE+STK_REG(R31)(r1)
8079
std r4,-STACKFRAMESIZE+STK_REG(R30)(r1)
8180
std r5,-STACKFRAMESIZE+STK_REG(R29)(r1)
8281

8382
blt .Lshort_copy
8483

85-
#ifdef CONFIG_ALTIVEC
86-
test_feature = SELFTEST_CASE
87-
BEGIN_FTR_SECTION
88-
bgt cr1,.Lvmx_copy
89-
END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
90-
#endif
9184

9285
.Lnonvmx_copy:
9386
/* Get the source 8B aligned */
@@ -263,23 +256,14 @@ err1; stb r0,0(r3)
263256
15: li r3,0
264257
blr
265258

266-
.Lunwind_stack_nonvmx_copy:
267-
addi r1,r1,STACKFRAMESIZE
268-
b .Lnonvmx_copy
269-
270-
.Lvmx_copy:
271259
#ifdef CONFIG_ALTIVEC
260+
_GLOBAL(__copy_tofrom_user_power7_vmx)
272261
mflr r0
273262
std r0,16(r1)
274263
stdu r1,-STACKFRAMESIZE(r1)
275-
bl CFUNC(enter_vmx_usercopy)
276-
cmpwi cr1,r3,0
277-
ld r0,STACKFRAMESIZE+16(r1)
278-
ld r3,STK_REG(R31)(r1)
279-
ld r4,STK_REG(R30)(r1)
280-
ld r5,STK_REG(R29)(r1)
281-
mtlr r0
282264

265+
std r3,STK_REG(R31)(r1)
266+
std r5,STK_REG(R29)(r1)
283267
/*
284268
* We prefetch both the source and destination using enhanced touch
285269
* instructions. We use a stream ID of 0 for the load side and
@@ -300,8 +284,6 @@ err1; stb r0,0(r3)
300284

301285
DCBT_SETUP_STREAMS(r6, r7, r9, r10, r8)
302286

303-
beq cr1,.Lunwind_stack_nonvmx_copy
304-
305287
/*
306288
* If source and destination are not relatively aligned we use a
307289
* slower permute loop.
@@ -478,7 +460,8 @@ err3; lbz r0,0(r4)
478460
err3; stb r0,0(r3)
479461

480462
15: addi r1,r1,STACKFRAMESIZE
481-
b CFUNC(exit_vmx_usercopy) /* tail call optimise */
463+
li r3,0
464+
blr
482465

483466
.Lvmx_unaligned_copy:
484467
/* Get the destination 16B aligned */
@@ -681,5 +664,7 @@ err3; lbz r0,0(r4)
681664
err3; stb r0,0(r3)
682665

683666
15: addi r1,r1,STACKFRAMESIZE
684-
b CFUNC(exit_vmx_usercopy) /* tail call optimise */
667+
li r3,0
668+
blr
669+
EXPORT_SYMBOL(__copy_tofrom_user_power7_vmx)
685670
#endif /* CONFIG_ALTIVEC */

arch/powerpc/lib/vmx-helper.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,32 @@
1010
#include <linux/hardirq.h>
1111
#include <asm/switch_to.h>
1212

13+
unsigned long __copy_tofrom_user_vmx(void __user *to, const void __user *from,
14+
unsigned long size, enum usercopy_mode mode)
15+
{
16+
unsigned long ret;
17+
18+
if (!enter_vmx_usercopy()) {
19+
raw_copy_allow(to, mode);
20+
ret = __copy_tofrom_user(to, from, size);
21+
raw_copy_prevent(mode);
22+
return ret;
23+
}
24+
25+
raw_copy_allow(to, mode);
26+
ret = __copy_tofrom_user_power7_vmx(to, from, size);
27+
raw_copy_prevent(mode);
28+
exit_vmx_usercopy();
29+
if (unlikely(ret)) {
30+
raw_copy_allow(to, mode);
31+
ret = __copy_tofrom_user_base(to, from, size);
32+
raw_copy_prevent(mode);
33+
}
34+
35+
return ret;
36+
}
37+
EXPORT_SYMBOL(__copy_tofrom_user_vmx);
38+
1339
int enter_vmx_usercopy(void)
1440
{
1541
if (in_interrupt())

tools/testing/selftests/powerpc/copyloops/.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
copyuser_64_t0
33
copyuser_64_t1
44
copyuser_64_t2
5-
copyuser_p7_t0
6-
copyuser_p7_t1
5+
copyuser_p7
6+
copyuser_p7_vmx
77
memcpy_64_t0
88
memcpy_64_t1
99
memcpy_64_t2

tools/testing/selftests/powerpc/copyloops/Makefile

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# SPDX-License-Identifier: GPL-2.0
22
TEST_GEN_PROGS := copyuser_64_t0 copyuser_64_t1 copyuser_64_t2 \
3-
copyuser_p7_t0 copyuser_p7_t1 \
3+
copyuser_p7 copyuser_p7_vmx \
44
memcpy_64_t0 memcpy_64_t1 memcpy_64_t2 \
55
memcpy_p7_t0 memcpy_p7_t1 copy_mc_64 \
66
copyuser_64_exc_t0 copyuser_64_exc_t1 copyuser_64_exc_t2 \
@@ -28,10 +28,15 @@ $(OUTPUT)/copyuser_64_t%: copyuser_64.S $(EXTRA_SOURCES)
2828
-D SELFTEST_CASE=$(subst copyuser_64_t,,$(notdir $@)) \
2929
-o $@ $^
3030

31-
$(OUTPUT)/copyuser_p7_t%: copyuser_power7.S $(EXTRA_SOURCES)
31+
$(OUTPUT)/copyuser_p7: copyuser_power7.S $(EXTRA_SOURCES)
3232
$(CC) $(CPPFLAGS) $(CFLAGS) \
3333
-D COPY_LOOP=test___copy_tofrom_user_power7 \
34-
-D SELFTEST_CASE=$(subst copyuser_p7_t,,$(notdir $@)) \
34+
-o $@ $^
35+
36+
$(OUTPUT)/copyuser_p7_vmx: copyuser_power7.S $(EXTRA_SOURCES) ../utils.c
37+
$(CC) $(CPPFLAGS) $(CFLAGS) \
38+
-D COPY_LOOP=test___copy_tofrom_user_power7_vmx \
39+
-D VMX_TEST \
3540
-o $@ $^
3641

3742
# Strictly speaking, we only need the memcpy_64 test cases for big-endian

tools/testing/selftests/powerpc/copyloops/stubs.S

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
#include <asm/ppc_asm.h>
22

3-
FUNC_START(enter_vmx_usercopy)
4-
li r3,1
5-
blr
6-
7-
FUNC_START(exit_vmx_usercopy)
8-
li r3,0
9-
blr
10-
113
FUNC_START(enter_vmx_ops)
124
li r3,1
135
blr

tools/testing/selftests/powerpc/copyloops/validate.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
#define BUFLEN (MAX_LEN+MAX_OFFSET+2*MIN_REDZONE)
1313
#define POISON 0xa5
1414

15+
#ifdef VMX_TEST
16+
#define VMX_COPY_THRESHOLD 3328
17+
#endif
18+
1519
unsigned long COPY_LOOP(void *to, const void *from, unsigned long size);
1620

1721
static void do_one(char *src, char *dst, unsigned long src_off,
@@ -81,8 +85,12 @@ int test_copy_loop(void)
8185
/* Fill with sequential bytes */
8286
for (i = 0; i < BUFLEN; i++)
8387
fill[i] = i & 0xff;
84-
88+
#ifdef VMX_TEST
89+
/* Force sizes above kernel VMX threshold (3328) */
90+
for (len = VMX_COPY_THRESHOLD + 1; len < MAX_LEN; len++) {
91+
#else
8592
for (len = 1; len < MAX_LEN; len++) {
93+
#endif
8694
for (src_off = 0; src_off < MAX_OFFSET; src_off++) {
8795
for (dst_off = 0; dst_off < MAX_OFFSET; dst_off++) {
8896
do_one(src, dst, src_off, dst_off, len,
@@ -96,5 +104,10 @@ int test_copy_loop(void)
96104

97105
int main(void)
98106
{
107+
#ifdef VMX_TEST
108+
/* Skip if Altivec not present */
109+
SKIP_IF_MSG(!have_hwcap(PPC_FEATURE_HAS_ALTIVEC), "ALTIVEC not supported");
110+
#endif
111+
99112
return test_harness(test_copy_loop, str(COPY_LOOP));
100113
}

0 commit comments

Comments
 (0)