Christophe Leroy's on August 28, 2019 7:55 pm: > > > Le 28/08/2019 à 11:49, Nicholas Piggin a écrit : >> Christophe Leroy's on August 28, 2019 7:06 pm: >>> >>> >>> Le 27/08/2019 à 15:55, Nicholas Piggin a écrit : >>>> Accounted for some feedback. >>>> >>>> Nicholas Piggin (4): >>>> powerpc: convert to copy_thread_tls >>>> powerpc/64: remove support for kernel-mode syscalls >>>> powerpc/64: system call remove non-volatile GPR save optimisation >>>> powerpc/64: system call implement the bulk of the logic in C >>> >>> Would it be possible to split in the following parts: >>> >>> 1/ Implement in C whatever can be implemented without removing >>> non-volatile GPR save optimisation >>> 2/ Remove non-volatile GPR save optimisation >>> 3/ Implement in C everything else >> >> Hmm. I'll have a look but I would rather not go back and add the >> intermediate state I was hoping to avoid. I'll think about it and >> if it's not too difficult I will try to add something. I have an >> idea. >> >> With your nvregs performance test on ppc32, are you doing the >> nvgpr restore? The fast path should be able to avoid that. > > I only added the SAVE_NVGPRS call in the syscall entry macro just after > the saving of volatile regs, and changed the trap from \trapno+1 to \trapno
So... this actually seems to work. Haven't booted it, but the compiler seems to do what we want. This may be the way to go for ppc32 I think. I had a look at various ways you could save nvgprs with some early tests and returning early from the C call if it hits trouble without all registers saved. Most of it becomes quite ugly. Thanks, Nick diff --git a/arch/powerpc/kernel/syscall_64.c b/arch/powerpc/kernel/syscall_64.c index d42519b86ddd..b11346447882 100644 --- a/arch/powerpc/kernel/syscall_64.c +++ b/arch/powerpc/kernel/syscall_64.c @@ -14,6 +14,52 @@ extern void __noreturn tabort_syscall(void); typedef long (*syscall_fn)(long, long, long, long, long, long); +register unsigned long r31 asm("r31"); +register unsigned long r30 asm("r30"); +register unsigned long r29 asm("r29"); +register unsigned long r28 asm("r28"); +register unsigned long r27 asm("r27"); +register unsigned long r26 asm("r26"); +register unsigned long r25 asm("r25"); +register unsigned long r24 asm("r24"); +register unsigned long r23 asm("r23"); +register unsigned long r22 asm("r22"); +register unsigned long r21 asm("r21"); +register unsigned long r20 asm("r20"); +register unsigned long r19 asm("r19"); +register unsigned long r18 asm("r18"); +register unsigned long r17 asm("r17"); +register unsigned long r16 asm("r16"); +register unsigned long r15 asm("r15"); +register unsigned long r14 asm("r14"); + +static inline void save_nvgprs(struct pt_regs *regs) +{ + if (!(regs->trap & 1)) + return; + + regs->gpr[14] = r14; + regs->gpr[15] = r15; + regs->gpr[16] = r16; + regs->gpr[17] = r17; + regs->gpr[18] = r18; + regs->gpr[19] = r19; + regs->gpr[20] = r20; + regs->gpr[21] = r21; + regs->gpr[22] = r22; + regs->gpr[23] = r23; + regs->gpr[24] = r24; + regs->gpr[25] = r25; + regs->gpr[26] = r26; + regs->gpr[27] = r27; + regs->gpr[28] = r28; + regs->gpr[29] = r29; + regs->gpr[30] = r30; + regs->gpr[31] = r31; + + regs->trap &= 0x1; +} + long system_call_exception(long r3, long r4, long r5, long r6, long r7, long r8, unsigned long r0, struct pt_regs *regs) { unsigned long ti_flags; @@ -66,6 +112,7 @@ long system_call_exception(long r3, long r4, long r5, long r6, long r7, long r8, * do_syscall_trace_enter() returns an invalid syscall number * and the test below against NR_syscalls will fail. */ + save_nvgprs(regs); r0 = do_syscall_trace_enter(regs); } @@ -132,6 +179,7 @@ unsigned long syscall_exit_prepare(unsigned long r3, struct pt_regs *regs) if (ti_flags & _TIF_NEED_RESCHED) { schedule(); } else { + save_nvgprs(regs); /* * SIGPENDING must restore signal handler function * argument GPRs, and some non-volatiles (e.g., r1).