Skip to content

Commit b5efec0

Browse files
chleroympe
authored andcommitted
powerpc/32s: Move KUEP locking/unlocking in C
This can be done in C, do it. Unrolling the loop gains approx. 15% performance. From now on, prepare_transfer_to_handler() is only for interrupts from kernel. Signed-off-by: Christophe Leroy <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/4eadd873927e9a73c3d1dfe2f9497353465514cf.1615552867.git.christophe.leroy@csgroup.eu
1 parent a2b3e09 commit b5efec0

File tree

9 files changed

+64
-48
lines changed

9 files changed

+64
-48
lines changed

arch/powerpc/include/asm/book3s/32/kup.h

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,37 +7,6 @@
77

88
#ifdef __ASSEMBLY__
99

10-
.macro kuep_update_sr gpr1, gpr2 /* NEVER use r0 as gpr2 due to addis */
11-
101: mtsrin \gpr1, \gpr2
12-
addi \gpr1, \gpr1, 0x111 /* next VSID */
13-
rlwinm \gpr1, \gpr1, 0, 0xf0ffffff /* clear VSID overflow */
14-
addis \gpr2, \gpr2, 0x1000 /* address of next segment */
15-
bdnz 101b
16-
isync
17-
.endm
18-
19-
.macro kuep_lock gpr1, gpr2
20-
#ifdef CONFIG_PPC_KUEP
21-
li \gpr1, NUM_USER_SEGMENTS
22-
li \gpr2, 0
23-
mtctr \gpr1
24-
mfsrin \gpr1, \gpr2
25-
oris \gpr1, \gpr1, SR_NX@h /* set Nx */
26-
kuep_update_sr \gpr1, \gpr2
27-
#endif
28-
.endm
29-
30-
.macro kuep_unlock gpr1, gpr2
31-
#ifdef CONFIG_PPC_KUEP
32-
li \gpr1, NUM_USER_SEGMENTS
33-
li \gpr2, 0
34-
mtctr \gpr1
35-
mfsrin \gpr1, \gpr2
36-
rlwinm \gpr1, \gpr1, 0, ~SR_NX /* Clear Nx */
37-
kuep_update_sr \gpr1, \gpr2
38-
#endif
39-
.endm
40-
4110
#ifdef CONFIG_PPC_KUAP
4211

4312
.macro kuap_update_sr gpr1, gpr2, gpr3 /* NEVER use r0 as gpr2 due to addis */

arch/powerpc/include/asm/interrupt.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@ static inline void interrupt_enter_prepare(struct pt_regs *regs, struct interrup
3333
if (!arch_irq_disabled_regs(regs))
3434
trace_hardirqs_off();
3535

36-
if (user_mode(regs))
36+
if (user_mode(regs)) {
37+
kuep_lock();
3738
account_cpu_user_entry();
39+
}
3840
#endif
3941
/*
4042
* Book3E reconciles irq soft mask in asm
@@ -89,6 +91,8 @@ static inline void interrupt_exit_prepare(struct pt_regs *regs, struct interrupt
8991
exception_exit(state->ctx_state);
9092
#endif
9193

94+
if (user_mode(regs))
95+
kuep_unlock();
9296
/*
9397
* Book3S exits to user via interrupt_exit_user_prepare(), which does
9498
* context tracking, which is a cleaner way to handle PREEMPT=y

arch/powerpc/include/asm/kup.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ void setup_kuep(bool disabled);
5555
static inline void setup_kuep(bool disabled) { }
5656
#endif /* CONFIG_PPC_KUEP */
5757

58+
#if defined(CONFIG_PPC_KUEP) && defined(CONFIG_PPC_BOOK3S_32)
59+
void kuep_lock(void);
60+
void kuep_unlock(void);
61+
#else
62+
static inline void kuep_lock(void) { }
63+
static inline void kuep_unlock(void) { }
64+
#endif
65+
5866
#ifdef CONFIG_PPC_KUAP
5967
void setup_kuap(bool disabled);
6068
#else

arch/powerpc/kernel/entry_32.S

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,9 @@
5151
#if defined(CONFIG_PPC_BOOK3S_32) || defined(CONFIG_E500)
5252
.globl prepare_transfer_to_handler
5353
prepare_transfer_to_handler:
54-
andi. r12,r9,MSR_PR
5554
addi r12,r2,THREAD
56-
beq 2f
57-
#ifdef CONFIG_PPC_BOOK3S_32
58-
kuep_lock r11, r12
59-
#endif
60-
blr
6155

6256
/* if from kernel, check interrupted DOZE/NAP mode */
63-
2:
6457
kuap_save_and_lock r11, r12, r9, r5, r6
6558
lwz r12,TI_LOCAL_FLAGS(r2)
6659
mtcrf 0x01,r12
@@ -86,9 +79,6 @@ _ASM_NOKPROBE_SYMBOL(prepare_transfer_to_handler)
8679
.globl transfer_to_syscall
8780
transfer_to_syscall:
8881
SAVE_NVGPRS(r1)
89-
#ifdef CONFIG_PPC_BOOK3S_32
90-
kuep_lock r11, r12
91-
#endif
9282

9383
/* Calling convention has r9 = orig r0, r10 = regs */
9484
addi r10,r1,STACK_FRAME_OVERHEAD
@@ -105,9 +95,6 @@ ret_from_syscall:
10595
cmplwi cr0,r5,0
10696
bne- 2f
10797
#endif /* CONFIG_PPC_47x */
108-
#ifdef CONFIG_PPC_BOOK3S_32
109-
kuep_unlock r5, r7
110-
#endif
11198
kuap_check r2, r4
11299
lwz r4,_LINK(r1)
113100
lwz r5,_CCR(r1)
@@ -311,9 +298,6 @@ interrupt_return:
311298
bne- .Lrestore_nvgprs
312299

313300
.Lfast_user_interrupt_return:
314-
#ifdef CONFIG_PPC_BOOK3S_32
315-
kuep_unlock r10, r11
316-
#endif
317301
kuap_check r2, r4
318302
lwz r11,_NIP(r1)
319303
lwz r12,_MSR(r1)

arch/powerpc/kernel/head_32.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,10 @@ _ASM_NOKPROBE_SYMBOL(\name\()_virt)
133133

134134
.macro prepare_transfer_to_handler
135135
#ifdef CONFIG_PPC_BOOK3S_32
136+
andi. r12,r9,MSR_PR
137+
bne 777f
136138
bl prepare_transfer_to_handler
139+
777:
137140
#endif
138141
.endm
139142

arch/powerpc/kernel/head_booke.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,10 @@ END_BTB_FLUSH_SECTION
105105

106106
.macro prepare_transfer_to_handler
107107
#ifdef CONFIG_E500
108+
andi. r12,r9,MSR_PR
109+
bne 777f
108110
bl prepare_transfer_to_handler
111+
777:
109112
#endif
110113
.endm
111114

arch/powerpc/kernel/interrupt.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ notrace long system_call_exception(long r3, long r4, long r5,
3333
{
3434
syscall_fn f;
3535

36+
kuep_lock();
37+
3638
regs->orig_gpr3 = r3;
3739

3840
if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG))
@@ -354,6 +356,8 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3,
354356
*/
355357
kuap_user_restore(regs);
356358
#endif
359+
kuep_unlock();
360+
357361
return ret;
358362
}
359363

arch/powerpc/mm/book3s32/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ endif
99
obj-y += mmu.o mmu_context.o
1010
obj-$(CONFIG_PPC_BOOK3S_603) += nohash_low.o
1111
obj-$(CONFIG_PPC_BOOK3S_604) += hash_low.o tlb.o
12+
obj-$(CONFIG_PPC_KUEP) += kuep.o

arch/powerpc/mm/book3s32/kuep.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
3+
#include <asm/kup.h>
4+
#include <asm/reg.h>
5+
#include <asm/task_size_32.h>
6+
#include <asm/mmu.h>
7+
8+
#define KUEP_UPDATE_TWO_USER_SEGMENTS(n) do { \
9+
if (TASK_SIZE > ((n) << 28)) \
10+
mtsr(val1, (n) << 28); \
11+
if (TASK_SIZE > (((n) + 1) << 28)) \
12+
mtsr(val2, ((n) + 1) << 28); \
13+
val1 = (val1 + 0x222) & 0xf0ffffff; \
14+
val2 = (val2 + 0x222) & 0xf0ffffff; \
15+
} while (0)
16+
17+
static __always_inline void kuep_update(u32 val)
18+
{
19+
int val1 = val;
20+
int val2 = (val + 0x111) & 0xf0ffffff;
21+
22+
KUEP_UPDATE_TWO_USER_SEGMENTS(0);
23+
KUEP_UPDATE_TWO_USER_SEGMENTS(2);
24+
KUEP_UPDATE_TWO_USER_SEGMENTS(4);
25+
KUEP_UPDATE_TWO_USER_SEGMENTS(6);
26+
KUEP_UPDATE_TWO_USER_SEGMENTS(8);
27+
KUEP_UPDATE_TWO_USER_SEGMENTS(10);
28+
KUEP_UPDATE_TWO_USER_SEGMENTS(12);
29+
KUEP_UPDATE_TWO_USER_SEGMENTS(14);
30+
}
31+
32+
void kuep_lock(void)
33+
{
34+
kuep_update(mfsr(0) | SR_NX);
35+
}
36+
37+
void kuep_unlock(void)
38+
{
39+
kuep_update(mfsr(0) & ~SR_NX);
40+
}

0 commit comments

Comments
 (0)