Merge branch 'x86-asm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull low-level x86 updates from Ingo Molnar:
"In this cycle this topic tree has become one of those 'super topics'
that accumulated a lot of changes:
- Add CONFIG_VMAP_STACK=y support to the core kernel and enable it on
x86 - preceded by an array of changes. v4.8 saw preparatory changes
in this area already - this is the rest of the work. Includes the
thread stack caching performance optimization. (Andy Lutomirski)
- switch_to() cleanups and all around enhancements. (Brian Gerst)
- A large number of dumpstack infrastructure enhancements and an
unwinder abstraction. The secret long term plan is safe(r) live
patching plus maybe another attempt at debuginfo based unwinding -
but all these current bits are standalone enhancements in a frame
pointer based debug environment as well. (Josh Poimboeuf)
- More __ro_after_init and const annotations. (Kees Cook)
- Enable KASLR for the vmemmap memory region. (Thomas Garnier)"
[ The virtually mapped stack changes are pretty fundamental, and not
x86-specific per se, even if they are only used on x86 right now. ]
* 'x86-asm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (70 commits)
x86/asm: Get rid of __read_cr4_safe()
thread_info: Use unsigned long for flags
x86/alternatives: Add stack frame dependency to alternative_call_2()
x86/dumpstack: Fix show_stack() task pointer regression
x86/dumpstack: Remove dump_trace() and related callbacks
x86/dumpstack: Convert show_trace_log_lvl() to use the new unwinder
oprofile/x86: Convert x86_backtrace() to use the new unwinder
x86/stacktrace: Convert save_stack_trace_*() to use the new unwinder
perf/x86: Convert perf_callchain_kernel() to use the new unwinder
x86/unwind: Add new unwind interface and implementations
x86/dumpstack: Remove NULL task pointer convention
fork: Optimize task creation by caching two thread stacks per CPU if CONFIG_VMAP_STACK=y
sched/core: Free the stack early if CONFIG_THREAD_INFO_IN_TASK
lib/syscall: Pin the task stack in collect_syscall()
x86/process: Pin the target stack in get_wchan()
x86/dumpstack: Pin the target stack when dumping it
kthread: Pin the stack via try_get_task_stack()/put_task_stack() in to_live_kthread() function
sched/core: Add try_get_task_stack() and put_task_stack()
x86/entry/64: Fix a minor comment rebase error
iommu/amd: Don't put completion-wait semaphore on stack
...
This commit is contained in:
commit
1a4a2bc460
114 changed files with 1722 additions and 1108 deletions
|
|
@ -203,6 +203,17 @@ along to ftrace_push_return_trace() instead of a stub value of 0.
|
|||
|
||||
Similarly, when you call ftrace_return_to_handler(), pass it the frame pointer.
|
||||
|
||||
HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
|
||||
--------------------------------
|
||||
|
||||
An arch may pass in a pointer to the return address on the stack. This
|
||||
prevents potential stack unwinding issues where the unwinder gets out of
|
||||
sync with ret_stack and the wrong addresses are reported by
|
||||
ftrace_graph_ret_addr().
|
||||
|
||||
Adding support for it is easy: just define the macro in asm/ftrace.h and
|
||||
pass the return address pointer as the 'retp' argument to
|
||||
ftrace_push_return_trace().
|
||||
|
||||
HAVE_FTRACE_NMI_ENTER
|
||||
---------------------
|
||||
|
|
|
|||
34
arch/Kconfig
34
arch/Kconfig
|
|
@ -696,4 +696,38 @@ config ARCH_NO_COHERENT_DMA_MMAP
|
|||
config CPU_NO_EFFICIENT_FFS
|
||||
def_bool n
|
||||
|
||||
config HAVE_ARCH_VMAP_STACK
|
||||
def_bool n
|
||||
help
|
||||
An arch should select this symbol if it can support kernel stacks
|
||||
in vmalloc space. This means:
|
||||
|
||||
- vmalloc space must be large enough to hold many kernel stacks.
|
||||
This may rule out many 32-bit architectures.
|
||||
|
||||
- Stacks in vmalloc space need to work reliably. For example, if
|
||||
vmap page tables are created on demand, either this mechanism
|
||||
needs to work while the stack points to a virtual address with
|
||||
unpopulated page tables or arch code (switch_to() and switch_mm(),
|
||||
most likely) needs to ensure that the stack's page table entries
|
||||
are populated before running on a possibly unpopulated stack.
|
||||
|
||||
- If the stack overflows into a guard page, something reasonable
|
||||
should happen. The definition of "reasonable" is flexible, but
|
||||
instantly rebooting without logging anything would be unfriendly.
|
||||
|
||||
config VMAP_STACK
|
||||
default y
|
||||
bool "Use a virtually-mapped stack"
|
||||
depends on HAVE_ARCH_VMAP_STACK && !KASAN
|
||||
---help---
|
||||
Enable this if you want the use virtually-mapped kernel stacks
|
||||
with guard pages. This causes kernel stack overflows to be
|
||||
caught immediately rather than causing difficult-to-diagnose
|
||||
corruption.
|
||||
|
||||
This is presently incompatible with KASAN because KASAN expects
|
||||
the stack to map directly to the KASAN shadow map using a formula
|
||||
that is incorrect if the stack is in vmalloc space.
|
||||
|
||||
source "kernel/gcov/Kconfig"
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
|
|||
}
|
||||
|
||||
err = ftrace_push_return_trace(old, self_addr, &trace.depth,
|
||||
frame_pointer);
|
||||
frame_pointer, NULL);
|
||||
if (err == -EBUSY) {
|
||||
*parent = old;
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ ENDPROC(ftrace_graph_caller)
|
|||
*
|
||||
* Run ftrace_return_to_handler() before going back to parent.
|
||||
* @fp is checked against the value passed by ftrace_graph_caller()
|
||||
* only when CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST is enabled.
|
||||
* only when HAVE_FUNCTION_GRAPH_FP_TEST is enabled.
|
||||
*/
|
||||
ENTRY(return_to_handler)
|
||||
save_return_regs
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
|
|||
return;
|
||||
|
||||
err = ftrace_push_return_trace(old, self_addr, &trace.depth,
|
||||
frame_pointer);
|
||||
frame_pointer, NULL);
|
||||
if (err == -EBUSY)
|
||||
return;
|
||||
else
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ ENTRY(_ftrace_graph_caller)
|
|||
r0 = sp; /* unsigned long *parent */
|
||||
r1 = [sp]; /* unsigned long self_addr */
|
||||
# endif
|
||||
# ifdef CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST
|
||||
# ifdef HAVE_FUNCTION_GRAPH_FP_TEST
|
||||
r2 = fp; /* unsigned long frame_pointer */
|
||||
# endif
|
||||
r0 += 16; /* skip the 4 local regs on stack */
|
||||
|
|
@ -190,7 +190,7 @@ ENTRY(_return_to_handler)
|
|||
[--sp] = r1;
|
||||
|
||||
/* get original return address */
|
||||
# ifdef CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST
|
||||
# ifdef HAVE_FUNCTION_GRAPH_FP_TEST
|
||||
r0 = fp; /* Blackfin is sane, so omit this */
|
||||
# endif
|
||||
call _ftrace_return_to_handler;
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
|
|||
return;
|
||||
|
||||
if (ftrace_push_return_trace(*parent, self_addr, &trace.depth,
|
||||
frame_pointer) == -EBUSY)
|
||||
frame_pointer, NULL) == -EBUSY)
|
||||
return;
|
||||
|
||||
trace.func = self_addr;
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ struct thread_info {
|
|||
#define alloc_thread_stack_node(tsk, node) ((unsigned long *) 0)
|
||||
#define task_thread_info(tsk) ((struct thread_info *) 0)
|
||||
#endif
|
||||
#define free_thread_stack(ti) /* nothing */
|
||||
#define free_thread_stack(tsk) /* nothing */
|
||||
#define task_stack_page(tsk) ((void *)(tsk))
|
||||
|
||||
#define __HAVE_THREAD_FUNCTIONS
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
|
|||
return;
|
||||
}
|
||||
|
||||
err = ftrace_push_return_trace(old, self_addr, &trace.depth, 0);
|
||||
err = ftrace_push_return_trace(old, self_addr, &trace.depth, 0, NULL);
|
||||
if (err == -EBUSY) {
|
||||
*parent = old;
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -382,8 +382,8 @@ void prepare_ftrace_return(unsigned long *parent_ra_addr, unsigned long self_ra,
|
|||
if (unlikely(faulted))
|
||||
goto out;
|
||||
|
||||
if (ftrace_push_return_trace(old_parent_ra, self_ra, &trace.depth, fp)
|
||||
== -EBUSY) {
|
||||
if (ftrace_push_return_trace(old_parent_ra, self_ra, &trace.depth, fp,
|
||||
NULL) == -EBUSY) {
|
||||
*parent_ra_addr = old_parent_ra;
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ static void __hot prepare_ftrace_return(unsigned long *parent,
|
|||
return;
|
||||
|
||||
if (ftrace_push_return_trace(old, self_addr, &trace.depth,
|
||||
0 ) == -EBUSY)
|
||||
0, NULL) == -EBUSY)
|
||||
return;
|
||||
|
||||
/* activate parisc_return_to_handler() as return point */
|
||||
|
|
|
|||
|
|
@ -593,7 +593,8 @@ unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip)
|
|||
if (!ftrace_graph_entry(&trace))
|
||||
goto out;
|
||||
|
||||
if (ftrace_push_return_trace(parent, ip, &trace.depth, 0) == -EBUSY)
|
||||
if (ftrace_push_return_trace(parent, ip, &trace.depth, 0,
|
||||
NULL) == -EBUSY)
|
||||
goto out;
|
||||
|
||||
parent = return_hooker;
|
||||
|
|
|
|||
|
|
@ -209,7 +209,8 @@ unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip)
|
|||
/* Only trace if the calling function expects to. */
|
||||
if (!ftrace_graph_entry(&trace))
|
||||
goto out;
|
||||
if (ftrace_push_return_trace(parent, ip, &trace.depth, 0) == -EBUSY)
|
||||
if (ftrace_push_return_trace(parent, ip, &trace.depth, 0,
|
||||
NULL) == -EBUSY)
|
||||
goto out;
|
||||
parent = (unsigned long) return_to_handler;
|
||||
out:
|
||||
|
|
|
|||
|
|
@ -382,7 +382,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
|
|||
return;
|
||||
}
|
||||
|
||||
err = ftrace_push_return_trace(old, self_addr, &trace.depth, 0);
|
||||
err = ftrace_push_return_trace(old, self_addr, &trace.depth, 0, NULL);
|
||||
if (err == -EBUSY) {
|
||||
__raw_writel(old, parent);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@ config SPARC64
|
|||
def_bool 64BIT
|
||||
select HAVE_FUNCTION_TRACER
|
||||
select HAVE_FUNCTION_GRAPH_TRACER
|
||||
select HAVE_FUNCTION_GRAPH_FP_TEST
|
||||
select HAVE_KRETPROBES
|
||||
select HAVE_KPROBES
|
||||
select HAVE_RCU_TABLE_FREE if SMP
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@
|
|||
void _mcount(void);
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_MCOUNT */
|
||||
|
||||
#if defined(CONFIG_SPARC64) && !defined(CC_USE_FENTRY)
|
||||
#define HAVE_FUNCTION_GRAPH_FP_TEST
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ unsigned long prepare_ftrace_return(unsigned long parent,
|
|||
return parent + 8UL;
|
||||
|
||||
if (ftrace_push_return_trace(parent, self_addr, &trace.depth,
|
||||
frame_pointer) == -EBUSY)
|
||||
frame_pointer, NULL) == -EBUSY)
|
||||
return parent + 8UL;
|
||||
|
||||
trace.func = self_addr;
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
|
|||
*parent = return_hooker;
|
||||
|
||||
err = ftrace_push_return_trace(old, self_addr, &trace.depth,
|
||||
frame_pointer);
|
||||
frame_pointer, NULL);
|
||||
if (err == -EBUSY) {
|
||||
*parent = old;
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ config X86
|
|||
select HAVE_ARCH_TRANSPARENT_HUGEPAGE
|
||||
select HAVE_ARCH_WITHIN_STACK_FRAMES
|
||||
select HAVE_EBPF_JIT if X86_64
|
||||
select HAVE_ARCH_VMAP_STACK if X86_64
|
||||
select HAVE_CC_STACKPROTECTOR
|
||||
select HAVE_CMPXCHG_DOUBLE
|
||||
select HAVE_CMPXCHG_LOCAL
|
||||
|
|
@ -109,7 +110,6 @@ config X86
|
|||
select HAVE_EXIT_THREAD
|
||||
select HAVE_FENTRY if X86_64
|
||||
select HAVE_FTRACE_MCOUNT_RECORD
|
||||
select HAVE_FUNCTION_GRAPH_FP_TEST
|
||||
select HAVE_FUNCTION_GRAPH_TRACER
|
||||
select HAVE_FUNCTION_TRACER
|
||||
select HAVE_GCC_PLUGINS
|
||||
|
|
@ -157,6 +157,7 @@ config X86
|
|||
select SPARSE_IRQ
|
||||
select SRCU
|
||||
select SYSCTL_EXCEPTION_TRACE
|
||||
select THREAD_INFO_IN_TASK
|
||||
select USER_STACKTRACE_SUPPORT
|
||||
select VIRT_TO_BUS
|
||||
select X86_DEV_DMA_OPS if X86_64
|
||||
|
|
|
|||
|
|
@ -31,13 +31,6 @@
|
|||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/syscalls.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CONTEXT_TRACKING
|
||||
/* Called on entry from user mode with IRQs off. */
|
||||
__visible inline void enter_from_user_mode(void)
|
||||
|
|
@ -71,7 +64,7 @@ static long syscall_trace_enter(struct pt_regs *regs)
|
|||
{
|
||||
u32 arch = in_ia32_syscall() ? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64;
|
||||
|
||||
struct thread_info *ti = pt_regs_to_thread_info(regs);
|
||||
struct thread_info *ti = current_thread_info();
|
||||
unsigned long ret = 0;
|
||||
bool emulated = false;
|
||||
u32 work;
|
||||
|
|
@ -173,18 +166,17 @@ static void exit_to_usermode_loop(struct pt_regs *regs, u32 cached_flags)
|
|||
/* Disable IRQs and retry */
|
||||
local_irq_disable();
|
||||
|
||||
cached_flags = READ_ONCE(pt_regs_to_thread_info(regs)->flags);
|
||||
cached_flags = READ_ONCE(current_thread_info()->flags);
|
||||
|
||||
if (!(cached_flags & EXIT_TO_USERMODE_LOOP_FLAGS))
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Called with IRQs disabled. */
|
||||
__visible inline void prepare_exit_to_usermode(struct pt_regs *regs)
|
||||
{
|
||||
struct thread_info *ti = pt_regs_to_thread_info(regs);
|
||||
struct thread_info *ti = current_thread_info();
|
||||
u32 cached_flags;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PROVE_LOCKING) && WARN_ON(!irqs_disabled()))
|
||||
|
|
@ -209,7 +201,7 @@ __visible inline void prepare_exit_to_usermode(struct pt_regs *regs)
|
|||
* special case only applies after poking regs and before the
|
||||
* very next return to user mode.
|
||||
*/
|
||||
ti->status &= ~(TS_COMPAT|TS_I386_REGS_POKED);
|
||||
current->thread.status &= ~(TS_COMPAT|TS_I386_REGS_POKED);
|
||||
#endif
|
||||
|
||||
user_enter_irqoff();
|
||||
|
|
@ -247,7 +239,7 @@ static void syscall_slow_exit_work(struct pt_regs *regs, u32 cached_flags)
|
|||
*/
|
||||
__visible inline void syscall_return_slowpath(struct pt_regs *regs)
|
||||
{
|
||||
struct thread_info *ti = pt_regs_to_thread_info(regs);
|
||||
struct thread_info *ti = current_thread_info();
|
||||
u32 cached_flags = READ_ONCE(ti->flags);
|
||||
|
||||
CT_WARN_ON(ct_state() != CONTEXT_KERNEL);
|
||||
|
|
@ -270,7 +262,7 @@ __visible inline void syscall_return_slowpath(struct pt_regs *regs)
|
|||
#ifdef CONFIG_X86_64
|
||||
__visible void do_syscall_64(struct pt_regs *regs)
|
||||
{
|
||||
struct thread_info *ti = pt_regs_to_thread_info(regs);
|
||||
struct thread_info *ti = current_thread_info();
|
||||
unsigned long nr = regs->orig_ax;
|
||||
|
||||
enter_from_user_mode();
|
||||
|
|
@ -303,11 +295,11 @@ __visible void do_syscall_64(struct pt_regs *regs)
|
|||
*/
|
||||
static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs)
|
||||
{
|
||||
struct thread_info *ti = pt_regs_to_thread_info(regs);
|
||||
struct thread_info *ti = current_thread_info();
|
||||
unsigned int nr = (unsigned int)regs->orig_ax;
|
||||
|
||||
#ifdef CONFIG_IA32_EMULATION
|
||||
ti->status |= TS_COMPAT;
|
||||
current->thread.status |= TS_COMPAT;
|
||||
#endif
|
||||
|
||||
if (READ_ONCE(ti->flags) & _TIF_WORK_SYSCALL_ENTRY) {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue