18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef _ASM_X86_IRQ_STACK_H 38c2ecf20Sopenharmony_ci#define _ASM_X86_IRQ_STACK_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <linux/ptrace.h> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <asm/processor.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 108c2ecf20Sopenharmony_cistatic __always_inline bool irqstack_active(void) 118c2ecf20Sopenharmony_ci{ 128c2ecf20Sopenharmony_ci return __this_cpu_read(irq_count) != -1; 138c2ecf20Sopenharmony_ci} 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_civoid asm_call_on_stack(void *sp, void (*func)(void), void *arg); 168c2ecf20Sopenharmony_civoid asm_call_sysvec_on_stack(void *sp, void (*func)(struct pt_regs *regs), 178c2ecf20Sopenharmony_ci struct pt_regs *regs); 188c2ecf20Sopenharmony_civoid asm_call_irq_on_stack(void *sp, void (*func)(struct irq_desc *desc), 198c2ecf20Sopenharmony_ci struct irq_desc *desc); 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic __always_inline void __run_on_irqstack(void (*func)(void)) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci void *tos = __this_cpu_read(hardirq_stack_ptr); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci __this_cpu_add(irq_count, 1); 268c2ecf20Sopenharmony_ci asm_call_on_stack(tos - 8, func, NULL); 278c2ecf20Sopenharmony_ci __this_cpu_sub(irq_count, 1); 288c2ecf20Sopenharmony_ci} 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic __always_inline void 318c2ecf20Sopenharmony_ci__run_sysvec_on_irqstack(void (*func)(struct pt_regs *regs), 328c2ecf20Sopenharmony_ci struct pt_regs *regs) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci void *tos = __this_cpu_read(hardirq_stack_ptr); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci __this_cpu_add(irq_count, 1); 378c2ecf20Sopenharmony_ci asm_call_sysvec_on_stack(tos - 8, func, regs); 388c2ecf20Sopenharmony_ci __this_cpu_sub(irq_count, 1); 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic __always_inline void 428c2ecf20Sopenharmony_ci__run_irq_on_irqstack(void (*func)(struct irq_desc *desc), 438c2ecf20Sopenharmony_ci struct irq_desc *desc) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci void *tos = __this_cpu_read(hardirq_stack_ptr); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci __this_cpu_add(irq_count, 1); 488c2ecf20Sopenharmony_ci asm_call_irq_on_stack(tos - 8, func, desc); 498c2ecf20Sopenharmony_ci __this_cpu_sub(irq_count, 1); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#else /* CONFIG_X86_64 */ 538c2ecf20Sopenharmony_cistatic inline bool irqstack_active(void) { return false; } 548c2ecf20Sopenharmony_cistatic inline void __run_on_irqstack(void (*func)(void)) { } 558c2ecf20Sopenharmony_cistatic inline void __run_sysvec_on_irqstack(void (*func)(struct pt_regs *regs), 568c2ecf20Sopenharmony_ci struct pt_regs *regs) { } 578c2ecf20Sopenharmony_cistatic inline void __run_irq_on_irqstack(void (*func)(struct irq_desc *desc), 588c2ecf20Sopenharmony_ci struct irq_desc *desc) { } 598c2ecf20Sopenharmony_ci#endif /* !CONFIG_X86_64 */ 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic __always_inline bool irq_needs_irq_stack(struct pt_regs *regs) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_X86_32)) 648c2ecf20Sopenharmony_ci return false; 658c2ecf20Sopenharmony_ci if (!regs) 668c2ecf20Sopenharmony_ci return !irqstack_active(); 678c2ecf20Sopenharmony_ci return !user_mode(regs) && !irqstack_active(); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic __always_inline void run_on_irqstack_cond(void (*func)(void), 728c2ecf20Sopenharmony_ci struct pt_regs *regs) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci lockdep_assert_irqs_disabled(); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if (irq_needs_irq_stack(regs)) 778c2ecf20Sopenharmony_ci __run_on_irqstack(func); 788c2ecf20Sopenharmony_ci else 798c2ecf20Sopenharmony_ci func(); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic __always_inline void 838c2ecf20Sopenharmony_cirun_sysvec_on_irqstack_cond(void (*func)(struct pt_regs *regs), 848c2ecf20Sopenharmony_ci struct pt_regs *regs) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci lockdep_assert_irqs_disabled(); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (irq_needs_irq_stack(regs)) 898c2ecf20Sopenharmony_ci __run_sysvec_on_irqstack(func, regs); 908c2ecf20Sopenharmony_ci else 918c2ecf20Sopenharmony_ci func(regs); 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic __always_inline void 958c2ecf20Sopenharmony_cirun_irq_on_irqstack_cond(void (*func)(struct irq_desc *desc), struct irq_desc *desc, 968c2ecf20Sopenharmony_ci struct pt_regs *regs) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci lockdep_assert_irqs_disabled(); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (irq_needs_irq_stack(regs)) 1018c2ecf20Sopenharmony_ci __run_irq_on_irqstack(func, desc); 1028c2ecf20Sopenharmony_ci else 1038c2ecf20Sopenharmony_ci func(desc); 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci#endif 107