Skip to content
This repository was archived by the owner on Nov 21, 2022. It is now read-only.

Commit 68b3458

Browse files
npigginmpe
authored andcommitted
powerpc/64/sycall: Implement syscall entry/exit logic in C
System call entry and particularly exit code is beyond the limit of what is reasonable to implement in asm. This conversion moves all conditional branches out of the asm code, except for the case that all GPRs should be restored at exit. Null syscall test is about 5% faster after this patch, because the exit work is handled under local_irq_disable, and the hard mask and pending interrupt replay is handled after that, which avoids games with MSR. mpe: Includes subsequent fixes from Nick: This fixes 4 issues caught by TM selftests. First was a tm-syscall bug that hit due to tabort_syscall being called after interrupts were reconciled (in a subsequent patch), which led to interrupts being enabled before tabort_syscall was called. Rather than going through an un-reconciling interrupts for the return, I just go back to putting the test early in asm, the C-ification of that wasn't a big win anyway. Second is the syscall return _TIF_USER_WORK_MASK check would go into an infinite loop if _TIF_RESTORE_TM became set. The asm code uses _TIF_USER_WORK_MASK to brach to slowpath which includes restore_tm_state. Third is system call return was not calling restore_tm_state, I missed this completely (alhtough it's in the return from interrupt C conversion because when the asm syscall code encountered problems it would branch to the interrupt return code. Fourth is MSR_VEC missing from restore_math, which was caught by tm-unavailable selftest taking an unexpected facility unavailable interrupt when testing VSX unavailble exception with MSR.FP=1 MSR.VEC=1. Fourth case also has a fixup in a subsequent patch. Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Michal Suchanek <msuchanek@suse.de> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/20200225173541.1549955-26-npiggin@gmail.com
1 parent f14f8a2 commit 68b3458

File tree

13 files changed

+326
-306
lines changed

13 files changed

+326
-306
lines changed

arch/powerpc/include/asm/asm-prototypes.h

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -97,21 +97,15 @@ ppc_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp,
9797
unsigned long __init early_init(unsigned long dt_ptr);
9898
void __init machine_init(u64 dt_ptr);
9999
#endif
100+
long system_call_exception(long r3, long r4, long r5, long r6, long r7, long r8, unsigned long r0, struct pt_regs *regs);
101+
notrace unsigned long syscall_exit_prepare(unsigned long r3, struct pt_regs *regs);
100102

101103
long ppc_fadvise64_64(int fd, int advice, u32 offset_high, u32 offset_low,
102104
u32 len_high, u32 len_low);
103105
long sys_switch_endian(void);
104106
notrace unsigned int __check_irq_replay(void);
105107
void notrace restore_interrupts(void);
106108

107-
/* ptrace */
108-
long do_syscall_trace_enter(struct pt_regs *regs);
109-
void do_syscall_trace_leave(struct pt_regs *regs);
110-
111-
/* process */
112-
void restore_math(struct pt_regs *regs);
113-
void restore_tm_state(struct pt_regs *regs);
114-
115109
/* prom_init (OpenFirmware) */
116110
unsigned long __init prom_init(unsigned long r3, unsigned long r4,
117111
unsigned long pp,
@@ -122,9 +116,6 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
122116
void __init early_setup(unsigned long dt_ptr);
123117
void early_setup_secondary(void);
124118

125-
/* time */
126-
void accumulate_stolen_time(void);
127-
128119
/* misc runtime */
129120
extern u64 __bswapdi2(u64);
130121
extern s64 __lshrdi3(s64, int);

arch/powerpc/include/asm/book3s/64/kup-radix.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#define _ASM_POWERPC_BOOK3S_64_KUP_RADIX_H
44

55
#include <linux/const.h>
6+
#include <asm/reg.h>
67

78
#define AMR_KUAP_BLOCK_READ UL(0x4000000000000000)
89
#define AMR_KUAP_BLOCK_WRITE UL(0x8000000000000000)
@@ -56,7 +57,14 @@
5657

5758
#ifdef CONFIG_PPC_KUAP
5859

59-
#include <asm/reg.h>
60+
#include <asm/mmu.h>
61+
#include <asm/ptrace.h>
62+
63+
static inline void kuap_check_amr(void)
64+
{
65+
if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG) && mmu_has_feature(MMU_FTR_RADIX_KUAP))
66+
WARN_ON_ONCE(mfspr(SPRN_AMR) != AMR_KUAP_BLOCKED);
67+
}
6068

6169
/*
6270
* We support individually allowing read or write, but we don't support nesting
@@ -127,6 +135,10 @@ bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
127135
(regs->kuap & (is_write ? AMR_KUAP_BLOCK_WRITE : AMR_KUAP_BLOCK_READ)),
128136
"Bug: %s fault blocked by AMR!", is_write ? "Write" : "Read");
129137
}
138+
#else /* CONFIG_PPC_KUAP */
139+
static inline void kuap_check_amr(void)
140+
{
141+
}
130142
#endif /* CONFIG_PPC_KUAP */
131143

132144
#endif /* __ASSEMBLY__ */

arch/powerpc/include/asm/cputime.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,12 @@ static inline unsigned long cputime_to_usecs(const cputime_t ct)
4343
*/
4444
#ifdef CONFIG_PPC64
4545
#define get_accounting(tsk) (&get_paca()->accounting)
46+
#define raw_get_accounting(tsk) (&local_paca->accounting)
4647
static inline void arch_vtime_task_switch(struct task_struct *tsk) { }
48+
4749
#else
4850
#define get_accounting(tsk) (&task_thread_info(tsk)->accounting)
51+
#define raw_get_accounting(tsk) get_accounting(tsk)
4952
/*
5053
* Called from the context switch with interrupts disabled, to charge all
5154
* accumulated times to the current process, and to prepare accounting on
@@ -60,6 +63,36 @@ static inline void arch_vtime_task_switch(struct task_struct *prev)
6063
}
6164
#endif
6265

66+
/*
67+
* account_cpu_user_entry/exit runs "unreconciled", so can't trace,
68+
* can't use use get_paca()
69+
*/
70+
static notrace inline void account_cpu_user_entry(void)
71+
{
72+
unsigned long tb = mftb();
73+
struct cpu_accounting_data *acct = raw_get_accounting(current);
74+
75+
acct->utime += (tb - acct->starttime_user);
76+
acct->starttime = tb;
77+
}
78+
79+
static notrace inline void account_cpu_user_exit(void)
80+
{
81+
unsigned long tb = mftb();
82+
struct cpu_accounting_data *acct = raw_get_accounting(current);
83+
84+
acct->stime += (tb - acct->starttime);
85+
acct->starttime_user = tb;
86+
}
87+
88+
6389
#endif /* __KERNEL__ */
90+
#else /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
91+
static inline void account_cpu_user_entry(void)
92+
{
93+
}
94+
static inline void account_cpu_user_exit(void)
95+
{
96+
}
6497
#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
6598
#endif /* __POWERPC_CPUTIME_H */

arch/powerpc/include/asm/hw_irq.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,13 @@ static inline bool arch_irqs_disabled(void)
228228
#ifdef CONFIG_PPC_BOOK3E
229229
#define __hard_irq_enable() wrtee(MSR_EE)
230230
#define __hard_irq_disable() wrtee(0)
231+
#define __hard_EE_RI_disable() wrtee(0)
232+
#define __hard_RI_enable() do { } while (0)
231233
#else
232234
#define __hard_irq_enable() __mtmsrd(MSR_EE|MSR_RI, 1)
233235
#define __hard_irq_disable() __mtmsrd(MSR_RI, 1)
236+
#define __hard_EE_RI_disable() __mtmsrd(0, 1)
237+
#define __hard_RI_enable() __mtmsrd(MSR_RI, 1)
234238
#endif
235239

236240
#define hard_irq_disable() do { \

arch/powerpc/include/asm/ptrace.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ extern unsigned long profile_pc(struct pt_regs *regs);
138138
#define profile_pc(regs) instruction_pointer(regs)
139139
#endif
140140

141+
long do_syscall_trace_enter(struct pt_regs *regs);
142+
void do_syscall_trace_leave(struct pt_regs *regs);
143+
141144
#define kernel_stack_pointer(regs) ((regs)->gpr[1])
142145
static inline int is_syscall_success(struct pt_regs *regs)
143146
{

arch/powerpc/include/asm/signal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,7 @@
66
#include <uapi/asm/signal.h>
77
#include <uapi/asm/ptrace.h>
88

9+
struct pt_regs;
10+
void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags);
11+
912
#endif /* _ASM_POWERPC_SIGNAL_H */

arch/powerpc/include/asm/switch_to.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#ifndef _ASM_POWERPC_SWITCH_TO_H
66
#define _ASM_POWERPC_SWITCH_TO_H
77

8+
#include <linux/sched.h>
89
#include <asm/reg.h>
910

1011
struct thread_struct;
@@ -22,6 +23,10 @@ extern void switch_booke_debug_regs(struct debug_reg *new_debug);
2223

2324
extern int emulate_altivec(struct pt_regs *);
2425

26+
void restore_math(struct pt_regs *regs);
27+
28+
void restore_tm_state(struct pt_regs *regs);
29+
2530
extern void flush_all_to_thread(struct task_struct *);
2631
extern void giveup_all(struct task_struct *);
2732

arch/powerpc/include/asm/time.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,5 +194,8 @@ DECLARE_PER_CPU(u64, decrementers_next_tb);
194194
/* Convert timebase ticks to nanoseconds */
195195
unsigned long long tb_to_ns(unsigned long long tb_ticks);
196196

197+
/* SPLPAR */
198+
void accumulate_stolen_time(void);
199+
197200
#endif /* __KERNEL__ */
198201
#endif /* __POWERPC_TIME_H */

arch/powerpc/kernel/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ obj-y := cputable.o ptrace.o syscalls.o \
5050
of_platform.o prom_parse.o
5151
obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \
5252
signal_64.o ptrace32.o \
53-
paca.o nvram_64.o firmware.o note.o
53+
paca.o nvram_64.o firmware.o note.o \
54+
syscall_64.o
5455
obj-$(CONFIG_VDSO32) += vdso32/
5556
obj-$(CONFIG_PPC_WATCHDOG) += watchdog.o
5657
obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o

0 commit comments

Comments
 (0)