Profile interrupt events.

Add the interrupt profile points for x86 and ARM arquitectures. This
gives information regarding the time when interrupts occur.

Change-Id: Ic876c0e7f9e8819d53e0578416f09146f4456d3d
Signed-off-by: Yonattan Louise <yonattan.a.louise.mendoza@intel.com>
diff --git a/arch/arc/defconfig b/arch/arc/defconfig
index 8e111ad..1eb306e 100644
--- a/arch/arc/defconfig
+++ b/arch/arc/defconfig
@@ -17,6 +17,7 @@
 # CONFIG_KERNEL_PROFILER is not set
 # CONFIG_PROFILER_BUFFER_SIZE is not set
 # CONFIG_PROFILER_CONTEXT_SWITCH is not set
+# CONFIG_PROFILER_INTERRUPT is not set
 
 #
 # Nanokernel Options
diff --git a/arch/arm/core/isr_wrapper.S b/arch/arm/core/isr_wrapper.S
index f7fd7b5..1ad919a 100644
--- a/arch/arm/core/isr_wrapper.S
+++ b/arch/arm/core/isr_wrapper.S
@@ -72,6 +72,12 @@
 
 	push {lr}		/* lr is now the first item on the stack */
 
+#ifdef CONFIG_PROFILER_INTERRUPT
+	push {lr}
+	bl _sys_profiler_interrupt
+	pop {lr}
+#endif
+
 #ifdef CONFIG_ADVANCED_POWER_MANAGEMENT
 	/*
 	 * All interrupts are disabled when handling idle wakeup.  For tickless
diff --git a/arch/arm/defconfig b/arch/arm/defconfig
index 62c5628..094cd39 100644
--- a/arch/arm/defconfig
+++ b/arch/arm/defconfig
@@ -18,6 +18,7 @@
 # CONFIG_KERNEL_PROFILER is not set
 # CONFIG_PROFILER_BUFFER_SIZE is not set
 # CONFIG_PROFILER_CONTEXT_SWITCH is not set
+# CONFIG_PROFILER_INTERRUPT is not set
 
 #
 # Nanokernel Options
diff --git a/arch/arm/include/profiler_arch.h b/arch/arm/include/profiler_arch.h
new file mode 100644
index 0000000..1047250
--- /dev/null
+++ b/arch/arm/include/profiler_arch.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015 Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1) Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2) Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3) Neither the name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * @file
+ * @brief Profiler support for ARM
+ */
+
+#ifndef __PROFILE_ARM_H__
+#define __PROFILE_ARM_H__
+
+#include <CortexM/asm_inline_gcc.h>
+
+/**
+ * @brief Get the identification of the current interrupt.
+ *
+ * This routine obtain the key of the interrupt that is currently processed
+ * if it is called from a ISR context.
+ *
+ * @return The key of the interrupt that is currently being processed.
+ */
+int _sys_current_irq_key_get(void)
+{
+	return _IpsrGet();
+}
+
+#endif /* __PROFILE_ARM_H__ */
diff --git a/arch/x86/core/intstub.S b/arch/x86/core/intstub.S
index 8add40c..05b5342 100644
--- a/arch/x86/core/intstub.S
+++ b/arch/x86/core/intstub.S
@@ -170,6 +170,15 @@
 	popl	%eax
 #endif
 
+#ifdef CONFIG_PROFILER_INTERRUPT
+	/*
+	 * Preserve EAX as it contains the stub return address.
+	 */
+	pushl	%eax
+	call	_sys_profiler_interrupt
+	popl	%eax
+#endif
+
 
 	/* load %ecx with &_nanokernel */
 
diff --git a/arch/x86/defconfig b/arch/x86/defconfig
index 5d7a27cc..6d8d8f3 100644
--- a/arch/x86/defconfig
+++ b/arch/x86/defconfig
@@ -20,6 +20,7 @@
 # CONFIG_KERNEL_PROFILER is not set
 # CONFIG_PROFILER_BUFFER_SIZE is not set
 # CONFIG_PROFILER_CONTEXT_SWITCH is not set
+# CONFIG_PROFILER_INTERRUPT is not set
 
 #
 # Security Options
diff --git a/arch/x86/include/profiler_arch.h b/arch/x86/include/profiler_arch.h
new file mode 100644
index 0000000..21b0a64
--- /dev/null
+++ b/arch/x86/include/profiler_arch.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015 Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1) Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2) Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3) Neither the name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * @file
+ * @brief Profiler support for x86
+ */
+
+#ifndef __PROFILE_X86_H__
+#define __PROFILE_X86_H__
+
+/**
+ * @brief Get the identification of the current interrupt.
+ *
+ * This routine obtain the key of the interrupt that is currently processed
+ * if it is called from a ISR context.
+ *
+ * @return The key of the interrupt that is currently being processed.
+ */
+int _sys_current_irq_key_get(void)
+{
+	extern int _loapic_isr_vector_get(void);
+
+	return _loapic_isr_vector_get();
+}
+
+#endif /* __PROFILE_X86_H__ */
diff --git a/drivers/interrupt_controller/loapic_intr.c b/drivers/interrupt_controller/loapic_intr.c
index 16b89cd..2c146be 100644
--- a/drivers/interrupt_controller/loapic_intr.c
+++ b/drivers/interrupt_controller/loapic_intr.c
@@ -416,3 +416,46 @@
 	*pLvt = *pLvt | LOAPIC_LVT_MASKED;
 	irq_unlock(oldLevel);
 }
+
+
+/**
+ * @brief Find the currently executing interrupt vector, if any
+ *
+ * This routine finds the vector of the interrupt that is being processed.
+ * The ISR (In-Service Register) register contain the vectors of the interrupts
+ * in service. And the higher vector is the indentification of the interrupt
+ * being currently processed.
+ *
+ * ISR registers' offsets:
+ * --------------------
+ * | Offset | bits    |
+ * --------------------
+ * | 0100H  |   0:31  |
+ * | 0110H  |  32:63  |
+ * | 0120H  |  64:95  |
+ * | 0130H  |  96:127 |
+ * | 0140H  | 128:159 |
+ * | 0150H  | 160:191 |
+ * | 0160H  | 192:223 |
+ * | 0170H  | 224:255 |
+ * --------------------
+ *
+ * @return The vector of the interrupt that is currently being processed.
+ */
+int _loapic_isr_vector_get(void)
+{
+	/* pointer to ISR vector table */
+	volatile int *pReg;
+	int block=0;
+
+	while (block < 8) {
+		pReg = (volatile int *)
+		(CONFIG_LOAPIC_BASE_ADDRESS + LOAPIC_ISR + (block * 0x10));
+		if (*pReg) {
+			return (block * 32) + (find_lsb_set(*pReg) - 1);
+		}
+		block++;
+	}
+
+	return 0;
+}
diff --git a/drivers/timer/cortex_m_systick.c b/drivers/timer/cortex_m_systick.c
index 37f4b37..26c595f 100644
--- a/drivers/timer/cortex_m_systick.c
+++ b/drivers/timer/cortex_m_systick.c
@@ -263,6 +263,12 @@
 {
 	ARG_UNUSED(unused);
 
+#ifdef CONFIG_PROFILER_INTERRUPT
+	extern void _sys_profiler_interrupt(void);
+	_sys_profiler_interrupt();
+#endif
+
+
 #ifdef CONFIG_INT_LATENCY_BENCHMARK
 	uint32_t value = __scs.systick.val;
 	uint32_t delta = __scs.systick.reload - value;
diff --git a/include/misc/profiler.h b/include/misc/profiler.h
index 3755a05..d1a4b85 100644
--- a/include/misc/profiler.h
+++ b/include/misc/profiler.h
@@ -45,6 +45,10 @@
 #define PROFILER_CONTEXT_SWITCH_EVENT_ID             0x0001
 #endif
 
+#ifdef CONFIG_PROFILER_INTERRUPT
+#define PROFILER_INTERRUPT_EVENT_ID                  0x0002
+#endif
+
 #ifndef _ASMLANGUAGE
 /**
  * Global variable of the ring buffer that allows user to implement
diff --git a/kernel/Kconfig b/kernel/Kconfig
index 236e89a..7ce0caf 100644
--- a/kernel/Kconfig
+++ b/kernel/Kconfig
@@ -140,6 +140,16 @@
 	depends on KERNEL_PROFILER
 	help
 	Enable the context switch event messages.
+
+config PROFILER_INTERRUPT
+	bool
+	prompt "Interrupt profiler point"
+	default n
+	depends on KERNEL_PROFILER
+	help
+	Enable interrupt event messages. These messages provide the following
+	information: The time when interrupts occur.
+
 endmenu
 
 menu "Security Options"
diff --git a/kernel/nanokernel/profiler.c b/kernel/nanokernel/profiler.c
index 69f5558..0ebe45e 100644
--- a/kernel/nanokernel/profiler.c
+++ b/kernel/nanokernel/profiler.c
@@ -38,6 +38,7 @@
 #include <misc/util.h>
 #include <init.h>
 #include <nano_private.h>
+#include <profiler_arch.h>
 
 uint32_t _sys_profiler_buffer[CONFIG_PROFILER_BUFFER_SIZE];
 
@@ -120,3 +121,16 @@
 	_collector_fiber = _nanokernel.current;
 }
 #endif /* CONFIG_PROFILER_CONTEXT_SWITCH */
+
+
+#ifdef CONFIG_PROFILER_INTERRUPT
+void _sys_profiler_interrupt()
+{
+	uint32_t data[2];
+
+	data[0] = nano_tick_get_32();
+	data[1] = _sys_current_irq_key_get();
+
+	sys_profiler_put(PROFILER_INTERRUPT_EVENT_ID, data, ARRAY_SIZE(data));
+}
+#endif /* CONFIG_PROFILER_INTERRUPT */