162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#include <linux/context_tracking.h> 462306a36Sopenharmony_ci#include <linux/entry-common.h> 562306a36Sopenharmony_ci#include <linux/resume_user_mode.h> 662306a36Sopenharmony_ci#include <linux/highmem.h> 762306a36Sopenharmony_ci#include <linux/jump_label.h> 862306a36Sopenharmony_ci#include <linux/kmsan.h> 962306a36Sopenharmony_ci#include <linux/livepatch.h> 1062306a36Sopenharmony_ci#include <linux/audit.h> 1162306a36Sopenharmony_ci#include <linux/tick.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "common.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define CREATE_TRACE_POINTS 1662306a36Sopenharmony_ci#include <trace/events/syscalls.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* See comment for enter_from_user_mode() in entry-common.h */ 1962306a36Sopenharmony_cistatic __always_inline void __enter_from_user_mode(struct pt_regs *regs) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci arch_enter_from_user_mode(regs); 2262306a36Sopenharmony_ci lockdep_hardirqs_off(CALLER_ADDR0); 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci CT_WARN_ON(__ct_state() != CONTEXT_USER); 2562306a36Sopenharmony_ci user_exit_irqoff(); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci instrumentation_begin(); 2862306a36Sopenharmony_ci kmsan_unpoison_entry_regs(regs); 2962306a36Sopenharmony_ci trace_hardirqs_off_finish(); 3062306a36Sopenharmony_ci instrumentation_end(); 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_civoid noinstr enter_from_user_mode(struct pt_regs *regs) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci __enter_from_user_mode(regs); 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic inline void syscall_enter_audit(struct pt_regs *regs, long syscall) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci if (unlikely(audit_context())) { 4162306a36Sopenharmony_ci unsigned long args[6]; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci syscall_get_arguments(current, regs, args); 4462306a36Sopenharmony_ci audit_syscall_entry(syscall, args[0], args[1], args[2], args[3]); 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic long syscall_trace_enter(struct pt_regs *regs, long syscall, 4962306a36Sopenharmony_ci unsigned long work) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci long ret = 0; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci /* 5462306a36Sopenharmony_ci * Handle Syscall User Dispatch. This must comes first, since 5562306a36Sopenharmony_ci * the ABI here can be something that doesn't make sense for 5662306a36Sopenharmony_ci * other syscall_work features. 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_ci if (work & SYSCALL_WORK_SYSCALL_USER_DISPATCH) { 5962306a36Sopenharmony_ci if (syscall_user_dispatch(regs)) 6062306a36Sopenharmony_ci return -1L; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* Handle ptrace */ 6462306a36Sopenharmony_ci if (work & (SYSCALL_WORK_SYSCALL_TRACE | SYSCALL_WORK_SYSCALL_EMU)) { 6562306a36Sopenharmony_ci ret = ptrace_report_syscall_entry(regs); 6662306a36Sopenharmony_ci if (ret || (work & SYSCALL_WORK_SYSCALL_EMU)) 6762306a36Sopenharmony_ci return -1L; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* Do seccomp after ptrace, to catch any tracer changes. */ 7162306a36Sopenharmony_ci if (work & SYSCALL_WORK_SECCOMP) { 7262306a36Sopenharmony_ci ret = __secure_computing(NULL); 7362306a36Sopenharmony_ci if (ret == -1L) 7462306a36Sopenharmony_ci return ret; 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* Either of the above might have changed the syscall number */ 7862306a36Sopenharmony_ci syscall = syscall_get_nr(current, regs); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (unlikely(work & SYSCALL_WORK_SYSCALL_TRACEPOINT)) 8162306a36Sopenharmony_ci trace_sys_enter(regs, syscall); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci syscall_enter_audit(regs, syscall); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci return ret ? : syscall; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic __always_inline long 8962306a36Sopenharmony_ci__syscall_enter_from_user_work(struct pt_regs *regs, long syscall) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci unsigned long work = READ_ONCE(current_thread_info()->syscall_work); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (work & SYSCALL_WORK_ENTER) 9462306a36Sopenharmony_ci syscall = syscall_trace_enter(regs, syscall, work); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci return syscall; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cilong syscall_enter_from_user_mode_work(struct pt_regs *regs, long syscall) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci return __syscall_enter_from_user_work(regs, syscall); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cinoinstr long syscall_enter_from_user_mode(struct pt_regs *regs, long syscall) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci long ret; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci __enter_from_user_mode(regs); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci instrumentation_begin(); 11162306a36Sopenharmony_ci local_irq_enable(); 11262306a36Sopenharmony_ci ret = __syscall_enter_from_user_work(regs, syscall); 11362306a36Sopenharmony_ci instrumentation_end(); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci return ret; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cinoinstr void syscall_enter_from_user_mode_prepare(struct pt_regs *regs) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci __enter_from_user_mode(regs); 12162306a36Sopenharmony_ci instrumentation_begin(); 12262306a36Sopenharmony_ci local_irq_enable(); 12362306a36Sopenharmony_ci instrumentation_end(); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/* See comment for exit_to_user_mode() in entry-common.h */ 12762306a36Sopenharmony_cistatic __always_inline void __exit_to_user_mode(void) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci instrumentation_begin(); 13062306a36Sopenharmony_ci trace_hardirqs_on_prepare(); 13162306a36Sopenharmony_ci lockdep_hardirqs_on_prepare(); 13262306a36Sopenharmony_ci instrumentation_end(); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci user_enter_irqoff(); 13562306a36Sopenharmony_ci arch_exit_to_user_mode(); 13662306a36Sopenharmony_ci lockdep_hardirqs_on(CALLER_ADDR0); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_civoid noinstr exit_to_user_mode(void) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci __exit_to_user_mode(); 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci/* Workaround to allow gradual conversion of architecture code */ 14562306a36Sopenharmony_civoid __weak arch_do_signal_or_restart(struct pt_regs *regs) { } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic unsigned long exit_to_user_mode_loop(struct pt_regs *regs, 14862306a36Sopenharmony_ci unsigned long ti_work) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci /* 15162306a36Sopenharmony_ci * Before returning to user space ensure that all pending work 15262306a36Sopenharmony_ci * items have been completed. 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_ci while (ti_work & EXIT_TO_USER_MODE_WORK) { 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci local_irq_enable_exit_to_user(ti_work); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if (ti_work & _TIF_NEED_RESCHED) 15962306a36Sopenharmony_ci schedule(); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (ti_work & _TIF_UPROBE) 16262306a36Sopenharmony_ci uprobe_notify_resume(regs); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (ti_work & _TIF_PATCH_PENDING) 16562306a36Sopenharmony_ci klp_update_patch_state(current); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (ti_work & (_TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL)) 16862306a36Sopenharmony_ci arch_do_signal_or_restart(regs); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (ti_work & _TIF_NOTIFY_RESUME) 17162306a36Sopenharmony_ci resume_user_mode_work(regs); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* Architecture specific TIF work */ 17462306a36Sopenharmony_ci arch_exit_to_user_mode_work(regs, ti_work); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci /* 17762306a36Sopenharmony_ci * Disable interrupts and reevaluate the work flags as they 17862306a36Sopenharmony_ci * might have changed while interrupts and preemption was 17962306a36Sopenharmony_ci * enabled above. 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_ci local_irq_disable_exit_to_user(); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci /* Check if any of the above work has queued a deferred wakeup */ 18462306a36Sopenharmony_ci tick_nohz_user_enter_prepare(); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci ti_work = read_thread_flags(); 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* Return the latest work state for arch_exit_to_user_mode() */ 19062306a36Sopenharmony_ci return ti_work; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic void exit_to_user_mode_prepare(struct pt_regs *regs) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci unsigned long ti_work; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci lockdep_assert_irqs_disabled(); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* Flush pending rcuog wakeup before the last need_resched() check */ 20062306a36Sopenharmony_ci tick_nohz_user_enter_prepare(); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci ti_work = read_thread_flags(); 20362306a36Sopenharmony_ci if (unlikely(ti_work & EXIT_TO_USER_MODE_WORK)) 20462306a36Sopenharmony_ci ti_work = exit_to_user_mode_loop(regs, ti_work); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci arch_exit_to_user_mode_prepare(regs, ti_work); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci /* Ensure that kernel state is sane for a return to userspace */ 20962306a36Sopenharmony_ci kmap_assert_nomap(); 21062306a36Sopenharmony_ci lockdep_assert_irqs_disabled(); 21162306a36Sopenharmony_ci lockdep_sys_exit(); 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci/* 21562306a36Sopenharmony_ci * If SYSCALL_EMU is set, then the only reason to report is when 21662306a36Sopenharmony_ci * SINGLESTEP is set (i.e. PTRACE_SYSEMU_SINGLESTEP). This syscall 21762306a36Sopenharmony_ci * instruction has been already reported in syscall_enter_from_user_mode(). 21862306a36Sopenharmony_ci */ 21962306a36Sopenharmony_cistatic inline bool report_single_step(unsigned long work) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci if (work & SYSCALL_WORK_SYSCALL_EMU) 22262306a36Sopenharmony_ci return false; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci return work & SYSCALL_WORK_SYSCALL_EXIT_TRAP; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic void syscall_exit_work(struct pt_regs *regs, unsigned long work) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci bool step; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci /* 23262306a36Sopenharmony_ci * If the syscall was rolled back due to syscall user dispatching, 23362306a36Sopenharmony_ci * then the tracers below are not invoked for the same reason as 23462306a36Sopenharmony_ci * the entry side was not invoked in syscall_trace_enter(): The ABI 23562306a36Sopenharmony_ci * of these syscalls is unknown. 23662306a36Sopenharmony_ci */ 23762306a36Sopenharmony_ci if (work & SYSCALL_WORK_SYSCALL_USER_DISPATCH) { 23862306a36Sopenharmony_ci if (unlikely(current->syscall_dispatch.on_dispatch)) { 23962306a36Sopenharmony_ci current->syscall_dispatch.on_dispatch = false; 24062306a36Sopenharmony_ci return; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci audit_syscall_exit(regs); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci if (work & SYSCALL_WORK_SYSCALL_TRACEPOINT) 24762306a36Sopenharmony_ci trace_sys_exit(regs, syscall_get_return_value(current, regs)); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci step = report_single_step(work); 25062306a36Sopenharmony_ci if (step || work & SYSCALL_WORK_SYSCALL_TRACE) 25162306a36Sopenharmony_ci ptrace_report_syscall_exit(regs, step); 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci/* 25562306a36Sopenharmony_ci * Syscall specific exit to user mode preparation. Runs with interrupts 25662306a36Sopenharmony_ci * enabled. 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_cistatic void syscall_exit_to_user_mode_prepare(struct pt_regs *regs) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci unsigned long work = READ_ONCE(current_thread_info()->syscall_work); 26162306a36Sopenharmony_ci unsigned long nr = syscall_get_nr(current, regs); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci CT_WARN_ON(ct_state() != CONTEXT_KERNEL); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_PROVE_LOCKING)) { 26662306a36Sopenharmony_ci if (WARN(irqs_disabled(), "syscall %lu left IRQs disabled", nr)) 26762306a36Sopenharmony_ci local_irq_enable(); 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci rseq_syscall(regs); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* 27362306a36Sopenharmony_ci * Do one-time syscall specific work. If these work items are 27462306a36Sopenharmony_ci * enabled, we want to run them exactly once per syscall exit with 27562306a36Sopenharmony_ci * interrupts enabled. 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_ci if (unlikely(work & SYSCALL_WORK_EXIT)) 27862306a36Sopenharmony_ci syscall_exit_work(regs, work); 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic __always_inline void __syscall_exit_to_user_mode_work(struct pt_regs *regs) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci syscall_exit_to_user_mode_prepare(regs); 28462306a36Sopenharmony_ci local_irq_disable_exit_to_user(); 28562306a36Sopenharmony_ci exit_to_user_mode_prepare(regs); 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_civoid syscall_exit_to_user_mode_work(struct pt_regs *regs) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci __syscall_exit_to_user_mode_work(regs); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci__visible noinstr void syscall_exit_to_user_mode(struct pt_regs *regs) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci instrumentation_begin(); 29662306a36Sopenharmony_ci __syscall_exit_to_user_mode_work(regs); 29762306a36Sopenharmony_ci instrumentation_end(); 29862306a36Sopenharmony_ci __exit_to_user_mode(); 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cinoinstr void irqentry_enter_from_user_mode(struct pt_regs *regs) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci __enter_from_user_mode(regs); 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cinoinstr void irqentry_exit_to_user_mode(struct pt_regs *regs) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci instrumentation_begin(); 30962306a36Sopenharmony_ci exit_to_user_mode_prepare(regs); 31062306a36Sopenharmony_ci instrumentation_end(); 31162306a36Sopenharmony_ci __exit_to_user_mode(); 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cinoinstr irqentry_state_t irqentry_enter(struct pt_regs *regs) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci irqentry_state_t ret = { 31762306a36Sopenharmony_ci .exit_rcu = false, 31862306a36Sopenharmony_ci }; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if (user_mode(regs)) { 32162306a36Sopenharmony_ci irqentry_enter_from_user_mode(regs); 32262306a36Sopenharmony_ci return ret; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci /* 32662306a36Sopenharmony_ci * If this entry hit the idle task invoke ct_irq_enter() whether 32762306a36Sopenharmony_ci * RCU is watching or not. 32862306a36Sopenharmony_ci * 32962306a36Sopenharmony_ci * Interrupts can nest when the first interrupt invokes softirq 33062306a36Sopenharmony_ci * processing on return which enables interrupts. 33162306a36Sopenharmony_ci * 33262306a36Sopenharmony_ci * Scheduler ticks in the idle task can mark quiescent state and 33362306a36Sopenharmony_ci * terminate a grace period, if and only if the timer interrupt is 33462306a36Sopenharmony_ci * not nested into another interrupt. 33562306a36Sopenharmony_ci * 33662306a36Sopenharmony_ci * Checking for rcu_is_watching() here would prevent the nesting 33762306a36Sopenharmony_ci * interrupt to invoke ct_irq_enter(). If that nested interrupt is 33862306a36Sopenharmony_ci * the tick then rcu_flavor_sched_clock_irq() would wrongfully 33962306a36Sopenharmony_ci * assume that it is the first interrupt and eventually claim 34062306a36Sopenharmony_ci * quiescent state and end grace periods prematurely. 34162306a36Sopenharmony_ci * 34262306a36Sopenharmony_ci * Unconditionally invoke ct_irq_enter() so RCU state stays 34362306a36Sopenharmony_ci * consistent. 34462306a36Sopenharmony_ci * 34562306a36Sopenharmony_ci * TINY_RCU does not support EQS, so let the compiler eliminate 34662306a36Sopenharmony_ci * this part when enabled. 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_TINY_RCU) && is_idle_task(current)) { 34962306a36Sopenharmony_ci /* 35062306a36Sopenharmony_ci * If RCU is not watching then the same careful 35162306a36Sopenharmony_ci * sequence vs. lockdep and tracing is required 35262306a36Sopenharmony_ci * as in irqentry_enter_from_user_mode(). 35362306a36Sopenharmony_ci */ 35462306a36Sopenharmony_ci lockdep_hardirqs_off(CALLER_ADDR0); 35562306a36Sopenharmony_ci ct_irq_enter(); 35662306a36Sopenharmony_ci instrumentation_begin(); 35762306a36Sopenharmony_ci kmsan_unpoison_entry_regs(regs); 35862306a36Sopenharmony_ci trace_hardirqs_off_finish(); 35962306a36Sopenharmony_ci instrumentation_end(); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci ret.exit_rcu = true; 36262306a36Sopenharmony_ci return ret; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* 36662306a36Sopenharmony_ci * If RCU is watching then RCU only wants to check whether it needs 36762306a36Sopenharmony_ci * to restart the tick in NOHZ mode. rcu_irq_enter_check_tick() 36862306a36Sopenharmony_ci * already contains a warning when RCU is not watching, so no point 36962306a36Sopenharmony_ci * in having another one here. 37062306a36Sopenharmony_ci */ 37162306a36Sopenharmony_ci lockdep_hardirqs_off(CALLER_ADDR0); 37262306a36Sopenharmony_ci instrumentation_begin(); 37362306a36Sopenharmony_ci kmsan_unpoison_entry_regs(regs); 37462306a36Sopenharmony_ci rcu_irq_enter_check_tick(); 37562306a36Sopenharmony_ci trace_hardirqs_off_finish(); 37662306a36Sopenharmony_ci instrumentation_end(); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci return ret; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_civoid raw_irqentry_exit_cond_resched(void) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci if (!preempt_count()) { 38462306a36Sopenharmony_ci /* Sanity check RCU and thread stack */ 38562306a36Sopenharmony_ci rcu_irq_exit_check_preempt(); 38662306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_DEBUG_ENTRY)) 38762306a36Sopenharmony_ci WARN_ON_ONCE(!on_thread_stack()); 38862306a36Sopenharmony_ci if (need_resched()) 38962306a36Sopenharmony_ci preempt_schedule_irq(); 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci#ifdef CONFIG_PREEMPT_DYNAMIC 39362306a36Sopenharmony_ci#if defined(CONFIG_HAVE_PREEMPT_DYNAMIC_CALL) 39462306a36Sopenharmony_ciDEFINE_STATIC_CALL(irqentry_exit_cond_resched, raw_irqentry_exit_cond_resched); 39562306a36Sopenharmony_ci#elif defined(CONFIG_HAVE_PREEMPT_DYNAMIC_KEY) 39662306a36Sopenharmony_ciDEFINE_STATIC_KEY_TRUE(sk_dynamic_irqentry_exit_cond_resched); 39762306a36Sopenharmony_civoid dynamic_irqentry_exit_cond_resched(void) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci if (!static_branch_unlikely(&sk_dynamic_irqentry_exit_cond_resched)) 40062306a36Sopenharmony_ci return; 40162306a36Sopenharmony_ci raw_irqentry_exit_cond_resched(); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci#endif 40462306a36Sopenharmony_ci#endif 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cinoinstr void irqentry_exit(struct pt_regs *regs, irqentry_state_t state) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci lockdep_assert_irqs_disabled(); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* Check whether this returns to user mode */ 41162306a36Sopenharmony_ci if (user_mode(regs)) { 41262306a36Sopenharmony_ci irqentry_exit_to_user_mode(regs); 41362306a36Sopenharmony_ci } else if (!regs_irqs_disabled(regs)) { 41462306a36Sopenharmony_ci /* 41562306a36Sopenharmony_ci * If RCU was not watching on entry this needs to be done 41662306a36Sopenharmony_ci * carefully and needs the same ordering of lockdep/tracing 41762306a36Sopenharmony_ci * and RCU as the return to user mode path. 41862306a36Sopenharmony_ci */ 41962306a36Sopenharmony_ci if (state.exit_rcu) { 42062306a36Sopenharmony_ci instrumentation_begin(); 42162306a36Sopenharmony_ci /* Tell the tracer that IRET will enable interrupts */ 42262306a36Sopenharmony_ci trace_hardirqs_on_prepare(); 42362306a36Sopenharmony_ci lockdep_hardirqs_on_prepare(); 42462306a36Sopenharmony_ci instrumentation_end(); 42562306a36Sopenharmony_ci ct_irq_exit(); 42662306a36Sopenharmony_ci lockdep_hardirqs_on(CALLER_ADDR0); 42762306a36Sopenharmony_ci return; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci instrumentation_begin(); 43162306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_PREEMPTION)) 43262306a36Sopenharmony_ci irqentry_exit_cond_resched(); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci /* Covers both tracing and lockdep */ 43562306a36Sopenharmony_ci trace_hardirqs_on(); 43662306a36Sopenharmony_ci instrumentation_end(); 43762306a36Sopenharmony_ci } else { 43862306a36Sopenharmony_ci /* 43962306a36Sopenharmony_ci * IRQ flags state is correct already. Just tell RCU if it 44062306a36Sopenharmony_ci * was not watching on entry. 44162306a36Sopenharmony_ci */ 44262306a36Sopenharmony_ci if (state.exit_rcu) 44362306a36Sopenharmony_ci ct_irq_exit(); 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ciirqentry_state_t noinstr irqentry_nmi_enter(struct pt_regs *regs) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci irqentry_state_t irq_state; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci irq_state.lockdep = lockdep_hardirqs_enabled(); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci __nmi_enter(); 45462306a36Sopenharmony_ci lockdep_hardirqs_off(CALLER_ADDR0); 45562306a36Sopenharmony_ci lockdep_hardirq_enter(); 45662306a36Sopenharmony_ci ct_nmi_enter(); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci instrumentation_begin(); 45962306a36Sopenharmony_ci kmsan_unpoison_entry_regs(regs); 46062306a36Sopenharmony_ci trace_hardirqs_off_finish(); 46162306a36Sopenharmony_ci ftrace_nmi_enter(); 46262306a36Sopenharmony_ci instrumentation_end(); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci return irq_state; 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_civoid noinstr irqentry_nmi_exit(struct pt_regs *regs, irqentry_state_t irq_state) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci instrumentation_begin(); 47062306a36Sopenharmony_ci ftrace_nmi_exit(); 47162306a36Sopenharmony_ci if (irq_state.lockdep) { 47262306a36Sopenharmony_ci trace_hardirqs_on_prepare(); 47362306a36Sopenharmony_ci lockdep_hardirqs_on_prepare(); 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci instrumentation_end(); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci ct_nmi_exit(); 47862306a36Sopenharmony_ci lockdep_hardirq_exit(); 47962306a36Sopenharmony_ci if (irq_state.lockdep) 48062306a36Sopenharmony_ci lockdep_hardirqs_on(CALLER_ADDR0); 48162306a36Sopenharmony_ci __nmi_exit(); 48262306a36Sopenharmony_ci} 483