11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This file contains the lowest level x86_64-specific interrupt
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * entry and irq statistics code. All the remaining irq logic is
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * done by the generic kernel/irq/ code and in the
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * x86_64-specific irq controller code. (e.g. i8259.c and
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * io_apic.c.)
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel_stat.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/seq_file.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
1576e4f660d9f4c6d1bb473f72be2988c35eaca948Ashok Raj#include <linux/delay.h>
16bcbc4f20b52c2c40c43a4d2337707dcdfe81bc3aFrederic Weisbecker#include <linux/ftrace.h>
175f66b2a0d919e84ee921dc21c9dbfddd1215c0e9Jaswinder Singh Rajput#include <linux/uaccess.h>
185f66b2a0d919e84ee921dc21c9dbfddd1215c0e9Jaswinder Singh Rajput#include <linux/smp.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io_apic.h>
2095833c83f3b812c78e48db4eaa19f6c74958470bAndi Kleen#include <asm/idle.h>
213819cd489ec5d18a4cbd2f05acdc516473caa105Brian Gerst#include <asm/apic.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231b437c8c73a36daa471dd54a63c426d72af5723dBrian GerstDEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
241b437c8c73a36daa471dd54a63c426d72af5723dBrian GerstEXPORT_PER_CPU_SYMBOL(irq_stat);
251b437c8c73a36daa471dd54a63c426d72af5723dBrian Gerst
26d650a5148593b65a3c3f9a344f46b91b7dfe7713Brian GerstDEFINE_PER_CPU(struct pt_regs *, irq_regs);
27d650a5148593b65a3c3f9a344f46b91b7dfe7713Brian GerstEXPORT_PER_CPU_SYMBOL(irq_regs);
28d650a5148593b65a3c3f9a344f46b91b7dfe7713Brian Gerst
2955af77969fbd7a841838220ea2287432e0da8ae5Mitsuo Hayasakaint sysctl_panic_on_stackoverflow;
3055af77969fbd7a841838220ea2287432e0da8ae5Mitsuo Hayasaka
314961f10e2205d0ededa291e12ec634efc58aa93cEric Sandeen/*
324961f10e2205d0ededa291e12ec634efc58aa93cEric Sandeen * Probabilistic stack overflow check:
334961f10e2205d0ededa291e12ec634efc58aa93cEric Sandeen *
344961f10e2205d0ededa291e12ec634efc58aa93cEric Sandeen * Only check the stack in process context, because everything else
354961f10e2205d0ededa291e12ec634efc58aa93cEric Sandeen * runs on the big interrupt stacks. Checking reliably is too expensive,
364961f10e2205d0ededa291e12ec634efc58aa93cEric Sandeen * so we just check from interrupts.
374961f10e2205d0ededa291e12ec634efc58aa93cEric Sandeen */
384961f10e2205d0ededa291e12ec634efc58aa93cEric Sandeenstatic inline void stack_overflow_check(struct pt_regs *regs)
394961f10e2205d0ededa291e12ec634efc58aa93cEric Sandeen{
40f377fa123d0ec621e8e361ecc3f2a8ee70e81a2eIngo Molnar#ifdef CONFIG_DEBUG_STACKOVERFLOW
41d2db6610219cbcadceea6c43ee03d89068b7d759Mitsuo Hayasaka#define STACK_TOP_MARGIN	128
4237fe6a42b3433b79a159ceb06a94cd1ef00e279dMitsuo Hayasaka	struct orig_ist *oist;
4337fe6a42b3433b79a159ceb06a94cd1ef00e279dMitsuo Hayasaka	u64 irq_stack_top, irq_stack_bottom;
4437fe6a42b3433b79a159ceb06a94cd1ef00e279dMitsuo Hayasaka	u64 estack_top, estack_bottom;
45c9f4f06d3191bd91c1a081b54a6c8e913e7b8a83Roman Zippel	u64 curbase = (u64)task_stack_page(current);
46f377fa123d0ec621e8e361ecc3f2a8ee70e81a2eIngo Molnar
4769682b625a043b567873e6cda397969b502f0054Mitsuo Hayasaka	if (user_mode_vm(regs))
4869682b625a043b567873e6cda397969b502f0054Mitsuo Hayasaka		return;
4969682b625a043b567873e6cda397969b502f0054Mitsuo Hayasaka
50467e6b7a7c0eb792ebaf322ddb7363742b4ead40Mitsuo Hayasaka	if (regs->sp >= curbase + sizeof(struct thread_info) +
51d2db6610219cbcadceea6c43ee03d89068b7d759Mitsuo Hayasaka				  sizeof(struct pt_regs) + STACK_TOP_MARGIN &&
52467e6b7a7c0eb792ebaf322ddb7363742b4ead40Mitsuo Hayasaka	    regs->sp <= curbase + THREAD_SIZE)
5337fe6a42b3433b79a159ceb06a94cd1ef00e279dMitsuo Hayasaka		return;
5437fe6a42b3433b79a159ceb06a94cd1ef00e279dMitsuo Hayasaka
5589cbc76768c2fa4ed95545bf961f3a14ddfeed21Christoph Lameter	irq_stack_top = (u64)this_cpu_ptr(irq_stack_union.irq_stack) +
56d2db6610219cbcadceea6c43ee03d89068b7d759Mitsuo Hayasaka			STACK_TOP_MARGIN;
5789cbc76768c2fa4ed95545bf961f3a14ddfeed21Christoph Lameter	irq_stack_bottom = (u64)__this_cpu_read(irq_stack_ptr);
5837fe6a42b3433b79a159ceb06a94cd1ef00e279dMitsuo Hayasaka	if (regs->sp >= irq_stack_top && regs->sp <= irq_stack_bottom)
5937fe6a42b3433b79a159ceb06a94cd1ef00e279dMitsuo Hayasaka		return;
6037fe6a42b3433b79a159ceb06a94cd1ef00e279dMitsuo Hayasaka
6189cbc76768c2fa4ed95545bf961f3a14ddfeed21Christoph Lameter	oist = this_cpu_ptr(&orig_ist);
62d2db6610219cbcadceea6c43ee03d89068b7d759Mitsuo Hayasaka	estack_top = (u64)oist->ist[0] - EXCEPTION_STKSZ + STACK_TOP_MARGIN;
6337fe6a42b3433b79a159ceb06a94cd1ef00e279dMitsuo Hayasaka	estack_bottom = (u64)oist->ist[N_EXCEPTION_STACKS - 1];
6437fe6a42b3433b79a159ceb06a94cd1ef00e279dMitsuo Hayasaka	if (regs->sp >= estack_top && regs->sp <= estack_bottom)
6537fe6a42b3433b79a159ceb06a94cd1ef00e279dMitsuo Hayasaka		return;
66f377fa123d0ec621e8e361ecc3f2a8ee70e81a2eIngo Molnar
6737fe6a42b3433b79a159ceb06a94cd1ef00e279dMitsuo Hayasaka	WARN_ONCE(1, "do_IRQ(): %s has overflown the kernel stack (cur:%Lx,sp:%lx,irq stk top-bottom:%Lx-%Lx,exception stk top-bottom:%Lx-%Lx)\n",
6837fe6a42b3433b79a159ceb06a94cd1ef00e279dMitsuo Hayasaka		current->comm, curbase, regs->sp,
6937fe6a42b3433b79a159ceb06a94cd1ef00e279dMitsuo Hayasaka		irq_stack_top, irq_stack_bottom,
7037fe6a42b3433b79a159ceb06a94cd1ef00e279dMitsuo Hayasaka		estack_top, estack_bottom);
7155af77969fbd7a841838220ea2287432e0da8ae5Mitsuo Hayasaka
7255af77969fbd7a841838220ea2287432e0da8ae5Mitsuo Hayasaka	if (sysctl_panic_on_stackoverflow)
7355af77969fbd7a841838220ea2287432e0da8ae5Mitsuo Hayasaka		panic("low stack detected by irq handler - check messages\n");
744961f10e2205d0ededa291e12ec634efc58aa93cEric Sandeen#endif
75f377fa123d0ec621e8e361ecc3f2a8ee70e81a2eIngo Molnar}
764961f10e2205d0ededa291e12ec634efc58aa93cEric Sandeen
779b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardingebool handle_irq(unsigned irq, struct pt_regs *regs)
789b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge{
799b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge	struct irq_desc *desc;
809b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge
819b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge	stack_overflow_check(regs);
829b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge
839b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge	desc = irq_to_desc(irq);
849b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge	if (unlikely(!desc))
859b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge		return false;
869b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge
879b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge	generic_handle_irq_desc(irq, desc);
889b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge	return true;
899b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge}
90