From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752983AbbGNXHd (ORCPT ); Tue, 14 Jul 2015 19:07:33 -0400 Received: from mail-wi0-f180.google.com ([209.85.212.180]:33454 "EHLO mail-wi0-f180.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751694AbbGNXHb (ORCPT ); Tue, 14 Jul 2015 19:07:31 -0400 Date: Wed, 15 Jul 2015 01:07:27 +0200 From: Frederic Weisbecker To: keescook@chromium.org, peterz@infradead.org, vda.linux@googlemail.com, mingo@kernel.org, brgerst@gmail.com, luto@amacapital.net, torvalds@linux-foundation.org, bp@alien8.de, luto@kernel.org, oleg@redhat.com, hpa@zytor.com, linux-kernel@vger.kernel.org, dvlasenk@redhat.com, tglx@linutronix.de, riel@redhat.com Cc: linux-tip-commits@vger.kernel.org Subject: Re: [tip:x86/asm] x86/entry: Add new, comprehensible entry and exit handlers written in C Message-ID: <20150714230727.GD29441@lerouge> References: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.23 (2014-03-12) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Tue, Jul 07, 2015 at 03:51:48AM -0700, tip-bot for Andy Lutomirski wrote: > Commit-ID: c5c46f59e4e7c1ab244b8d38f2b61d317df90bba > Gitweb: http://git.kernel.org/tip/c5c46f59e4e7c1ab244b8d38f2b61d317df90bba > Author: Andy Lutomirski > AuthorDate: Fri, 3 Jul 2015 12:44:26 -0700 > Committer: Ingo Molnar > CommitDate: Tue, 7 Jul 2015 10:59:06 +0200 > > x86/entry: Add new, comprehensible entry and exit handlers written in C > > The current x86 entry and exit code, written in a mixture of assembly and > C code, is incomprehensible due to being open-coded in a lot of places > without coherent documentation. > > It appears to work primary by luck and duct tape: i.e. obvious runtime > failures were fixed on-demand, without re-thinking the design. > > Due to those reasons our confidence level in that code is low, and it is > very difficult to incrementally improve. > > Add new code written in C, in preparation for simply deleting the old > entry code. > > prepare_exit_to_usermode() is a new function that will handle all > slow path exits to user mode. It is called with IRQs disabled > and it leaves us in a state in which it is safe to immediately > return to user mode. IRQs must not be re-enabled at any point > after prepare_exit_to_usermode() returns and user mode is actually > entered. (We can, of course, fail to enter user mode and treat > that failure as a fresh entry to kernel mode.) > > All callers of do_notify_resume() will be migrated to call > prepare_exit_to_usermode() instead; prepare_exit_to_usermode() needs > to do everything that do_notify_resume() does today, but it also > takes care of scheduling and context tracking. Unlike > do_notify_resume(), it does not need to be called in a loop. > > syscall_return_slowpath() is exactly what it sounds like: it will > be called on any syscall exit slow path. It will replace > syscall_trace_leave() and it calls prepare_exit_to_usermode() on the > way out. > > Signed-off-by: Andy Lutomirski > Cc: Andy Lutomirski > Cc: Borislav Petkov > Cc: Brian Gerst > Cc: Denys Vlasenko > Cc: Denys Vlasenko > Cc: Frederic Weisbecker > Cc: H. Peter Anvin > Cc: Kees Cook > Cc: Linus Torvalds > Cc: Oleg Nesterov > Cc: Peter Zijlstra > Cc: Rik van Riel > Cc: Thomas Gleixner > Cc: paulmck@linux.vnet.ibm.com > Link: http://lkml.kernel.org/r/c57c8b87661a4152801d7d3786eac2d1a2f209dd.1435952415.git.luto@kernel.org > [ Improved the changelog a bit. ] > Signed-off-by: Ingo Molnar > --- > arch/x86/entry/common.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 111 insertions(+), 1 deletion(-) > > diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c > index 9a327ee..febc530 100644 > --- a/arch/x86/entry/common.c > +++ b/arch/x86/entry/common.c > @@ -207,6 +207,7 @@ long syscall_trace_enter(struct pt_regs *regs) > return syscall_trace_enter_phase2(regs, arch, phase1_result); > } > > +/* Deprecated. */ > void syscall_trace_leave(struct pt_regs *regs) > { > bool step; > @@ -237,8 +238,117 @@ void syscall_trace_leave(struct pt_regs *regs) > user_enter(); > } > > +static struct thread_info *pt_regs_to_thread_info(struct pt_regs *regs) > +{ > + unsigned long top_of_stack = > + (unsigned long)(regs + 1) + TOP_OF_KERNEL_STACK_PADDING; > + return (struct thread_info *)(top_of_stack - THREAD_SIZE); > +} > + > +/* Called with IRQs disabled. */ > +__visible void prepare_exit_to_usermode(struct pt_regs *regs) > +{ > + if (WARN_ON(!irqs_disabled())) > + local_irq_disable(); > + > + /* > + * In order to return to user mode, we need to have IRQs off with > + * none of _TIF_SIGPENDING, _TIF_NOTIFY_RESUME, _TIF_USER_RETURN_NOTIFY, > + * _TIF_UPROBE, or _TIF_NEED_RESCHED set. Several of these flags > + * can be set at any time on preemptable kernels if we have IRQs on, > + * so we need to loop. Disabling preemption wouldn't help: doing the > + * work to clear some of the flags can sleep. > + */ > + while (true) { > + u32 cached_flags = > + READ_ONCE(pt_regs_to_thread_info(regs)->flags); > + > + if (!(cached_flags & (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | > + _TIF_UPROBE | _TIF_NEED_RESCHED))) > + break; > + > + /* We have work to do. */ > + local_irq_enable(); > + > + if (cached_flags & _TIF_NEED_RESCHED) > + schedule(); > + > + if (cached_flags & _TIF_UPROBE) > + uprobe_notify_resume(regs); > + > + /* deal with pending signal delivery */ > + if (cached_flags & _TIF_SIGPENDING) > + do_signal(regs); > + > + if (cached_flags & _TIF_NOTIFY_RESUME) { > + clear_thread_flag(TIF_NOTIFY_RESUME); > + tracehook_notify_resume(regs); > + } > + > + if (cached_flags & _TIF_USER_RETURN_NOTIFY) > + fire_user_return_notifiers(); > + > + /* Disable IRQs and retry */ > + local_irq_disable(); > + } I dreamed so many times about this loop in C! > + > + user_enter(); So now we are sure that we have only one call to user_enter() before resuming userspace, once we've completed everything, rescheduling, signals, etc... No more context tracking hacky round on signals and rescheduling? That's great. I need to check if other archs still need schedule_user(). Thanks a lot!