lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Mon, 12 Nov 2012 17:18:56 +0530
From:	<Vineet.Gupta1@...opsys.com>
To:	<linux-arch@...r.kernel.org>, <linux-kernel@...r.kernel.org>
CC:	<tglx@...utronix.de>, <arnd@...db.de>,
	Vineet Gupta <Vineet.Gupta1@...opsys.com>
Subject: [RFC Patch v1 38/55] ARC: Low level event capture/logging

From: Vineet Gupta <vgupta@...opsys.com>

Poorman's version of LTT

Signed-off-by: Vineet Gupta <vgupta@...opsys.com>
---
 arch/arc/Kconfig                     |    7 +
 arch/arc/Makefile                    |    3 +
 arch/arc/include/asm/event-log-asm.h |  185 +++++++++++++++++++++
 arch/arc/include/asm/event-log.h     |  102 ++++++++++++
 arch/arc/kernel/Makefile             |    1 +
 arch/arc/kernel/asm-offsets.c        |   15 ++
 arch/arc/kernel/entry.S              |   31 ++++
 arch/arc/kernel/event-log.c          |  304 ++++++++++++++++++++++++++++++++++
 arch/arc/kernel/signal.c             |    3 +
 arch/arc/mm/tlb.c                    |    3 +
 arch/arc/mm/tlbex.S                  |    7 +
 11 files changed, 661 insertions(+), 0 deletions(-)
 create mode 100644 arch/arc/include/asm/event-log-asm.h
 create mode 100644 arch/arc/include/asm/event-log.h
 create mode 100644 arch/arc/kernel/event-log.c

diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
index e096545..15d740c 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -323,6 +323,13 @@ config ARC_DBG_TLB_PARANOIA
 	depends on ARC_DBG
 	default n
 
+config ARC_DBG_EVENT_TIMELINE
+	bool "Low level event capture"
+	depends on ARC_DBG
+	default n
+	help
+	  Capture low level events: IRQ/Trap/Exception
+
 config ARC_DBG_TLB_MISS_COUNT
 	bool "Profile TLB Misses"
 	default n
diff --git a/arch/arc/Makefile b/arch/arc/Makefile
index 7ef6767..a533546 100644
--- a/arch/arc/Makefile
+++ b/arch/arc/Makefile
@@ -47,6 +47,9 @@ endif
 disable_small_data := y
 cflags-$(disable_small_data)		+= -mno-sdata -fcall-used-gp
 
+# Low level event tracing with Metaware debugger assist needs symbol info
+cflags-$(CONFIG_ARC_DBG_EVENT_TIMELINE) += -g
+
 cflags-$(CONFIG_CPU_BIG_ENDIAN)		+= -mbig-endian
 ldflags-$(CONFIG_CPU_BIG_ENDIAN)	+= -EB
 
diff --git a/arch/arc/include/asm/event-log-asm.h b/arch/arc/include/asm/event-log-asm.h
new file mode 100644
index 0000000..bc29e7d
--- /dev/null
+++ b/arch/arc/include/asm/event-log-asm.h
@@ -0,0 +1,185 @@
+/*
+ *  Low level Event Capture API callable from Assembly Code
+ *  vineetg: Feb 2008
+ *
+ *  TBD: SMP Safe
+ *
+ * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARC_EVENT_LOG_ASM_H
+#define __ASM_ARC_EVENT_LOG_ASM_H
+
+#include <asm/event-log.h>
+
+#ifdef __ASSEMBLY__
+
+#ifndef CONFIG_ARC_DBG_EVENT_TIMELINE
+
+.macro TAKE_SNAP_ASM reg_scratch, reg_ptr, type
+.endm
+
+.macro TAKE_SNAP_C_FROM_ASM type
+.endm
+
+#else
+
+#include <asm/asm-offsets.h>
+
+/*
+ * Macro to invoke the ASM event logger routine from assmebly code
+ * This is generated in-place in caller.
+ *
+ * @reg_scratch and @reg_ptr:
+ *	Registers provided by caller for coding the macro itself.
+ *	At this point if call, say Low level ISR, the Reg-File might not have
+ *	been saved, so only use reg safe.
+ * @type:
+ *	The low level event, defined in event-log.h
+ */
+.macro TAKE_SNAP_ASM reg_scratch, reg_ptr, type
+
+	/*
+	 * Earlier we used to save only reg_scratch and clobber reg_ptr and rely
+	 * on caller to understand this. Too much trouble.
+	 * Now we save both
+	 */
+	st \reg_scratch, [tmp_save_reg]
+	st \reg_ptr, [tmp_save_reg2]
+
+	ld \reg_ptr, [timeline_ctr]
+
+	/* HACK to detect if the circular log buffer is being overflowed */
+	brne \reg_ptr, MAX_SNAPS, 1f
+	flag 1
+	nop
+1:
+#ifdef CONFIG_ARC_HAS_HW_MPY
+	mpyu \reg_ptr, \reg_ptr, EVLOG_RECORD_SZ
+#else
+#error "even logger broken for !CONFIG_ARC_HAS_HW_MPY
+#endif
+
+	add \reg_ptr, timeline_log, \reg_ptr
+
+	/*############ Common data ########## */
+
+	/* TIMER1 count in timeline_log[timeline_ctr].time */
+	lr \reg_scratch, [ARC_REG_TIMER1_CNT]
+	st \reg_scratch, [\reg_ptr, EVLOG_FIELD_TIME]
+
+	/* current task ptr in timeline_log[timeline_ctr].task */
+	ld \reg_scratch, [_current_task]
+	ld \reg_scratch, [\reg_scratch, TASK_TGID]
+	st \reg_scratch, [\reg_ptr, EVLOG_FIELD_TASK]
+
+	/* Type of event (Intr/Excp/Trap etc) */
+	mov \reg_scratch, \type
+	st \reg_scratch, [\reg_ptr, EVLOG_FIELD_EVENT_ID]
+
+	/* save SP at time of exception */
+	st sp, [\reg_ptr, EVLOG_FIELD_SP]
+
+	st 0, [\reg_ptr, EVLOG_FIELD_EXTRA]
+	st 0, [\reg_ptr, EVLOG_FIELD_CAUSE]
+	st 0, [\reg_ptr, EVLOG_FIELD_EXTRA3]
+
+	lr \reg_scratch, [status32]
+	st \reg_scratch, [\reg_ptr, EVLOG_FIELD_EXTRA2]
+
+	/* ############ Event specific data ########## */
+	mov \reg_scratch, \type
+	and.f 0, \reg_scratch, EVENT_CLASS_EXIT
+	bz 1f
+
+	/* Stuff to do for all kernel exit events */
+	ld \reg_scratch, [sp, PT_status32]
+	st \reg_scratch, [\reg_ptr, EVLOG_FIELD_EXTRA]
+
+	/* preempt count in log->sp */
+	and \reg_scratch, sp, ~(0x2000 - 1)
+	ld \reg_scratch, [\reg_scratch, THREAD_INFO_PREEMPT_COUNT]
+	st \reg_scratch, [\reg_ptr, EVLOG_FIELD_SP]
+
+	ld \reg_scratch, [sp, PT_ret]
+	st \reg_scratch, [\reg_ptr, EVLOG_FIELD_EFA]
+
+	mov \reg_scratch, \type
+1:
+2:
+	/* for Trap, Syscall number  */
+	cmp \reg_scratch, SNAP_TRAP_IN
+	bnz 3f
+	st r8, [\reg_ptr, EVLOG_FIELD_CAUSE]
+	lr \reg_scratch, [erstatus]
+	st \reg_scratch, [\reg_ptr, EVLOG_FIELD_EXTRA]
+	j 99f
+3:
+5:
+	/* For Exceptions (TLB/ProtV etc) */
+	cmp \reg_scratch, SNAP_EXCP_IN
+	bnz 6f
+
+	lr \reg_scratch, [ecr]
+	st \reg_scratch, [\reg_ptr, EVLOG_FIELD_CAUSE]
+	lr \reg_scratch, [eret]
+	st \reg_scratch, [\reg_ptr, EVLOG_FIELD_EFA]
+	lr \reg_scratch, [erstatus]
+	st \reg_scratch, [\reg_ptr, EVLOG_FIELD_EXTRA]
+	lr \reg_scratch, [efa]
+	st \reg_scratch, [\reg_ptr, EVLOG_FIELD_EXTRA3]
+	j 99f
+
+6:	/* for Interrupts, IRQ */
+	cmp \reg_scratch, SNAP_INTR_OUT
+	bnz 7f
+	lr \reg_scratch, [icause1]
+	st \reg_scratch, [\reg_ptr, EVLOG_FIELD_CAUSE]
+	j 99f
+
+7:
+	cmp \reg_scratch, SNAP_INTR_OUT2
+	bnz 8f
+	lr \reg_scratch, [icause2]
+	st \reg_scratch, [\reg_ptr, EVLOG_FIELD_CAUSE]
+	j 99f
+
+8:
+	cmp \reg_scratch, SNAP_EXCP_OUT_FAST
+	bnz 9f
+	lr \reg_scratch, [erstatus]
+	st \reg_scratch, [\reg_ptr, EVLOG_FIELD_EXTRA]
+	j 99f
+
+	/* place holder for next */
+9:
+
+99:
+	/* increment timeline_ctr  with mode on max */
+	ld \reg_scratch, [timeline_ctr]
+	add \reg_scratch, \reg_scratch, 1
+	and \reg_scratch, \reg_scratch, MAX_SNAPS_MASK
+	st \reg_scratch, [timeline_ctr]
+
+	/* Restore back orig scratch reg */
+	ld \reg_scratch, [tmp_save_reg]
+	ld \reg_ptr, [tmp_save_reg2]
+.endm
+
+/*
+ * Macro to invoke the "C" event logger routine from assmebly code
+ */
+.macro TAKE_SNAP_C_FROM_ASM type
+	mov r0, \type
+	bl take_snap2
+.endm
+
+#endif	/* CONFIG_ARC_DBG_EVENT_TIMELINE */
+
+#endif	/* __ASSEMBLY__ */
+
+#endif
diff --git a/arch/arc/include/asm/event-log.h b/arch/arc/include/asm/event-log.h
new file mode 100644
index 0000000..423f549
--- /dev/null
+++ b/arch/arc/include/asm/event-log.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  vineetg: Dec 2009
+ *      Reworked the numbering scheme into Event Classes for making it easier to
+ *      do class specific things in the snapshot routines
+ *
+ *  vineetg: Feb 2008
+ *      System Event Logging APIs
+ */
+
+#ifndef __ASM_ARC_EVENT_LOG_H
+#define __ASM_ARC_EVENT_LOG_H
+
+/*######################################################################
+ *
+ *    Event Logging API
+ *
+ *#####################################################################*/
+
+/* Size of the log buffer */
+#define MAX_SNAPS	1024
+#define MAX_SNAPS_MASK	(MAX_SNAPS-1)
+
+/* Helpers to setup Event IDs:
+ * 8 classes of events possible
+ * 23 unique events for each Class
+ * Right now we have only 3 classes:
+ * Entry into kernel, exit from kernel and everything else is custom event
+ *
+ * Need for this fancy numbering scheme so that in event logger, class specific
+ * things, common for all events in class, could be easily done
+ */
+#define EVENT_ID(x)             (0x100 << x)
+#define EVENT_CLASS_ENTER       0x01	/* Need to start from 1, not 0 */
+#define EVENT_CLASS_EXIT        0x02
+#define EVENT_CLASS_CUSTOM      0x80
+
+#define KERNEL_ENTER_EVENT(x)   (EVENT_ID(x)|EVENT_CLASS_ENTER)
+#define KERNEL_EXIT_EVENT(x)    (EVENT_ID(x)|EVENT_CLASS_EXIT)
+#define CUSTOM_EVENT(x)         (EVENT_ID(x)|EVENT_CLASS_CUSTOM)
+
+/* Actual Event IDs used in kernel code */
+#define SNAP_INTR_IN            KERNEL_ENTER_EVENT(0)
+#define SNAP_EXCP_IN            KERNEL_ENTER_EVENT(1)
+#define SNAP_TRAP_IN            KERNEL_ENTER_EVENT(2)
+#define SNAP_INTR_IN2           KERNEL_ENTER_EVENT(3)
+
+#define SNAP_INTR_OUT           KERNEL_EXIT_EVENT(0)
+#define SNAP_EXCP_OUT           KERNEL_EXIT_EVENT(1)
+#define SNAP_TRAP_OUT           KERNEL_EXIT_EVENT(2)
+#define SNAP_INTR_OUT2          KERNEL_EXIT_EVENT(3)
+#define SNAP_EXCP_OUT_FAST      KERNEL_EXIT_EVENT(4)
+
+#define SNAP_PRE_CTXSW_2_U      CUSTOM_EVENT(0)
+#define SNAP_PRE_CTXSW_2_K      CUSTOM_EVENT(1)
+#define SNAP_DO_PF_ENTER        CUSTOM_EVENT(2)
+#define SNAP_DO_PF_EXIT         CUSTOM_EVENT(3)
+#define SNAP_TLB_FLUSH_ALL      CUSTOM_EVENT(4)
+#define SNAP_PREEMPT_SCH_IRQ    CUSTOM_EVENT(5)
+#define SNAP_PREEMPT_SCH        CUSTOM_EVENT(6)
+#define SNAP_SIGRETURN          CUSTOM_EVENT(7)
+#define SNAP_BEFORE_SIG         CUSTOM_EVENT(8)
+
+#define SNAP_SENTINEL           CUSTOM_EVENT(22)
+
+#ifndef CONFIG_ARC_DBG_EVENT_TIMELINE
+
+#define take_snap(type, extra, ptreg)
+#define sort_snaps(halt_after_sort)
+
+#else
+
+#ifndef __ASSEMBLY__
+
+typedef struct {
+
+	/*  0 */ char nm[16];
+	/* 16 */ unsigned int extra; /* Traps: Syscall num, Intr: IRQ, Excep */
+	/* 20 */ unsigned int fault_addr;
+	/* 24 */ unsigned int cause;
+	/* 28 */ unsigned int task;
+	/* 32 */ unsigned long time;
+	/* 36 */ unsigned int event;
+	/* 40 */ unsigned int sp;
+	/* 44 */ unsigned int extra2;
+	/* 40 */ unsigned int extra3;
+
+} timeline_log_t;
+
+void take_snap(int type, unsigned int extra, unsigned int extra2);
+void sort_snaps(int halt_after_sort);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* CONFIG_ARC_DBG_EVENT_TIMELINE */
+
+#endif /* __ASM_ARC_EVENT_PROFILE_H */
diff --git a/arch/arc/kernel/Makefile b/arch/arc/kernel/Makefile
index 9151bbe..ec1f130 100644
--- a/arch/arc/kernel/Makefile
+++ b/arch/arc/kernel/Makefile
@@ -12,6 +12,7 @@ obj-y	:= arcksyms.o setup.o irq.o time.o reset.o ptrace.o entry.o process.o \
 	   signal.o traps.o sys.o troubleshoot.o stacktrace.o
 
 obj-$(CONFIG_MODULES)			+= arcksyms.o module.o
+obj-$(CONFIG_ARC_DBG_EVENT_TIMELINE)	+= event-log.o
 obj-$(CONFIG_ARC_FPU_SAVE_RESTORE)	+= fpu.o
 CFLAGS_fpu.o   += -mdpfp
 
diff --git a/arch/arc/kernel/asm-offsets.c b/arch/arc/kernel/asm-offsets.c
index b0e7254..0c06b7a 100644
--- a/arch/arc/kernel/asm-offsets.c
+++ b/arch/arc/kernel/asm-offsets.c
@@ -13,6 +13,7 @@
 #include <linux/thread_info.h>
 #include <asm/page.h>
 #include <linux/kbuild.h>
+#include <asm/event-log.h>
 
 int main(void)
 {
@@ -45,5 +46,19 @@ int main(void)
 
 	DEFINE(MM_CTXT_ASID, offsetof(mm_context_t, asid));
 
+#ifdef CONFIG_ARC_DBG_EVENT_TIMELINE
+	BLANK();
+	DEFINE(EVLOG_FIELD_EXTRA, offsetof(timeline_log_t, extra));
+	DEFINE(EVLOG_FIELD_EFA, offsetof(timeline_log_t, fault_addr));
+	DEFINE(EVLOG_FIELD_CAUSE, offsetof(timeline_log_t, cause));
+	DEFINE(EVLOG_FIELD_TASK, offsetof(timeline_log_t, task));
+	DEFINE(EVLOG_FIELD_TIME, offsetof(timeline_log_t, time));
+	DEFINE(EVLOG_FIELD_EVENT_ID, offsetof(timeline_log_t, event));
+	DEFINE(EVLOG_FIELD_SP, offsetof(timeline_log_t, sp));
+	DEFINE(EVLOG_RECORD_SZ, sizeof(timeline_log_t));
+	DEFINE(EVLOG_FIELD_EXTRA2, offsetof(timeline_log_t, extra2));
+	DEFINE(EVLOG_FIELD_EXTRA3, offsetof(timeline_log_t, extra3));
+#endif
+
 	return 0;
 }
diff --git a/arch/arc/kernel/entry.S b/arch/arc/kernel/entry.S
index 13a0052..5babb8a 100644
--- a/arch/arc/kernel/entry.S
+++ b/arch/arc/kernel/entry.S
@@ -148,6 +148,7 @@ VECTOR   reserved                ; Reserved Exceptions
 #include <asm/errno.h>
 #include <asm/arcregs.h>
 #include <asm/irqflags.h>
+#include <asm/event-log-asm.h>
 
 ;##################### Scratch Mem for IRQ stack switching #############
 
@@ -213,6 +214,8 @@ ARC_ENTRY handle_interrupt_level2
 	st      r9, [r10, THREAD_INFO_PREEMPT_COUNT]
 
 1:
+	TAKE_SNAP_C_FROM_ASM  SNAP_INTR_IN2
+
 	;------------------------------------------------------
 	; setup params for Linux common ISR and invoke it
 	;------------------------------------------------------
@@ -245,6 +248,9 @@ ARC_ENTRY handle_interrupt_level1
 	SWITCH_TO_KERNEL_STK
 	SAVE_ALL_INT1
 
+	; snapshot routine takes care of disabling nested intr
+	TAKE_SNAP_C_FROM_ASM  SNAP_INTR_IN
+
 	lr  r0, [icause1]
 	and r0, r0, 0x1f
 
@@ -267,6 +273,8 @@ ARC_ENTRY instr_service
 
 	EXCPN_PROLOG_FREEUP_REG r9
 
+	TAKE_SNAP_ASM r8, r9, SNAP_EXCP_IN
+
 	lr  r9, [erstatus]
 
 	SWITCH_TO_KERNEL_STK
@@ -291,6 +299,8 @@ ARC_ENTRY mem_service
 
 	EXCPN_PROLOG_FREEUP_REG r9
 
+	TAKE_SNAP_ASM r8, r9, SNAP_EXCP_IN
+
 	lr  r9, [erstatus]
 
 	SWITCH_TO_KERNEL_STK
@@ -342,6 +352,8 @@ ARC_ENTRY EV_TLBProtV
 
 	EXCPN_PROLOG_FREEUP_REG r9
 
+	TAKE_SNAP_ASM r8, r9, SNAP_EXCP_IN
+
 	;Which mode (user/kernel) was the system in when Exception occured
 	lr  r9, [erstatus]
 
@@ -400,6 +412,8 @@ ARC_ENTRY EV_PrivilegeV
 
 	EXCPN_PROLOG_FREEUP_REG r9
 
+	TAKE_SNAP_ASM r8, r9, SNAP_EXCP_IN
+
 	lr  r9, [erstatus]
 
 	SWITCH_TO_KERNEL_STK
@@ -526,6 +540,8 @@ ARC_ENTRY EV_Trap
 	; Need at least 1 reg to code the early exception prolog
 	EXCPN_PROLOG_FREEUP_REG r9
 
+	TAKE_SNAP_ASM r10, r9,  SNAP_TRAP_IN
+
 	;Which mode (user/kernel) was the system in when intr occured
 	lr  r9, [erstatus]
 
@@ -733,6 +749,7 @@ not_exception:
 	st      r9, [r10, THREAD_INFO_PREEMPT_COUNT]
 
 149:
+	TAKE_SNAP_C_FROM_ASM SNAP_INTR_OUT2
 	;return from level 2
 	RESTORE_ALL_INT2
 debug_marker_l2:
@@ -745,6 +762,7 @@ not_level2_interrupt:
 	bbit0  r10, STATUS_A1_BIT, not_level1_interrupt
 
 	;return from level 1
+	TAKE_SNAP_C_FROM_ASM SNAP_INTR_OUT
 
 	RESTORE_ALL_INT1
 debug_marker_l1:
@@ -754,6 +772,19 @@ not_level1_interrupt:
 
 	;this case is for syscalls or Exceptions (with fake rtie)
 
+#ifdef CONFIG_ARC_DBG_EVENT_TIMELINE
+	ld r8, [sp, PT_orig_r8]
+	cmp r8, NR_syscalls+1
+	jeq  149f
+	TAKE_SNAP_ASM r9, r10, SNAP_TRAP_OUT
+	j 150f
+
+149:
+	TAKE_SNAP_ASM r9, r10, SNAP_EXCP_OUT
+150:
+
+#endif
+
 	RESTORE_ALL_SYS
 debug_marker_syscall:
 	rtie
diff --git a/arch/arc/kernel/event-log.c b/arch/arc/kernel/event-log.c
new file mode 100644
index 0000000..f8ab807
--- /dev/null
+++ b/arch/arc/kernel/event-log.c
@@ -0,0 +1,304 @@
+/*
+ * event-log.c : Poorman's version of LTT for low level event capturing
+ *
+ * captures IRQ/Exceptions/Sys-Calls/arbitrary function call
+ * XXX: Not SMP Safe
+ *
+ * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  vineetg Jan 2009
+ *      -Converted strcpy to strncpy
+ *
+ *  vineetg: Feb 2008: Event capturing Framework
+ *      -Captures the event-id and related info in circular log buffer
+ *
+ *      -USAGE:
+ *          Events are defined in API file, include/asm-arc/event-log.h
+ *          To log the event, "C" code calls API
+ *              take_snap(event-id, event-specific-info)
+ *          To log the event, ASM caller calls a "asm" macro
+ *              TAKE_SNAP_ASM reg-x, reg-y, event-id
+ *          To stop the capture and sort the log buffer,
+ *              sort_snaps(halt-after-sort)
+ *
+ *      -The reason for 2 APIs is that in low level handlers
+ *          which we are interested in capturing, often don't have
+ *          stack switched, thus a "C" API wont work. Also there
+ *          is a very strict requirement of which registers are usable
+ *          hence the 2 regs
+ *
+ *      -Done primarily to chase the Random Segmentation Faults
+ *          when we switched from gcc 3.4 to 4.2
+ */
+
+#include <linux/sort.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <asm/current.h>
+#include <asm/event-log.h>
+#include <linux/module.h>
+#include <linux/reboot.h>
+
+#ifdef CONFIG_ARC_CURR_IN_REG
+/*
+ * current on ARC is a register variable "r25" setup on entry to kernel and
+ * restored back to user value on return.
+ * However if the event snap shotting return is called very late from
+ * ISR/Exception return code, r25 might already have been restored to user
+ * value, hence would no longer point to current task. This can cause weird
+ * de-referencing crashes. Safest option is to undef it and instead define
+ * it in terms of current_thread_info() which is derived from SP
+ */
+#undef current
+#define current (current_thread_info()->task)
+#endif
+
+/*
+ * Log buffer which stores the event info
+ *
+ *  There is race condition when the counter goes 1 more than
+ *  max-value (if IRQ sneaks in in the logging routine. Since
+ *  we don't want to do fancy intr-enable-disable etc,
+ *  we keep 1 extra element in log buffer
+ */
+timeline_log_t timeline_log[MAX_SNAPS + 1];
+
+/* counter in log bugger for next entry */
+int timeline_ctr;
+
+/* Used in the low level asm handler to free up a reg */
+int tmp_save_reg, tmp_save_reg2;
+int l2_ctr;
+
+/* Event capture API */
+void take_snap(int event, unsigned int arg1, unsigned int arg2)
+{
+	timeline_log_t *entry = &timeline_log[timeline_ctr];
+
+	entry->time = read_aux_reg(ARC_REG_TIMER1_CNT);
+	entry->task = current->pid;
+	entry->event = event;
+	entry->extra2 = read_aux_reg(0xa);	/* status32 */
+
+	entry->cause = read_aux_reg(0x403);	/* ecr */
+	entry->fault_addr = read_aux_reg(0x404);	/* efa */
+
+	entry->extra = arg1;
+	entry->sp = arg2;
+
+	entry->extra3 =
+	    (unsigned int)__builtin_return_address(0);
+
+	if (timeline_ctr == (MAX_SNAPS - 1))
+		timeline_ctr = 0;
+	else
+		timeline_ctr++;
+
+}
+EXPORT_SYMBOL(take_snap);
+
+void take_snap2(int event)
+{
+	unsigned long x, flags = 0, stat32;
+	timeline_log_t *entry = &timeline_log[timeline_ctr];
+
+	stat32 = read_aux_reg(0xa);	/* status32 */
+
+	/* In case this is for Level 1 ISR, disable further Interrupts
+	 * so that timeline_ctr is not clobbered
+	 */
+	if (event == SNAP_INTR_IN)
+		local_irq_save(flags);
+
+	entry->time = read_aux_reg(ARC_REG_TIMER1_CNT);
+	entry->task = current->pid;
+	entry->event = event;
+	entry->extra2 = stat32;
+
+	entry->sp = current_thread_info()->preempt_count;
+
+	if (event == SNAP_INTR_IN2) {
+		entry->cause = read_aux_reg(0x40B);	/* icause2 */
+		entry->extra = read_aux_reg(0x0C);	/* statsu32_l2 */
+		__asm__ __volatile__("mov %0, ilink2   \r\n" : "=r"(x));
+		entry->fault_addr = x;
+	} else if (event == SNAP_INTR_IN) {
+		entry->cause = read_aux_reg(0x40A);	/* icause1 */
+		entry->extra = read_aux_reg(0x0B);	/* statsu32_l1 */
+		__asm__ __volatile__("mov %0, ilink1   \r\n" : "=r"(x));
+		entry->fault_addr = x;
+	}
+
+	if (timeline_ctr == (MAX_SNAPS - 1))
+		timeline_ctr = 0;
+	else
+		timeline_ctr++;
+
+	if (current_thread_info()->preempt_count == 0xFFFFFFFF)
+		sort_snaps(1);
+
+	if (event == SNAP_INTR_IN)
+		local_irq_restore(flags);
+}
+EXPORT_SYMBOL(take_snap2);
+
+/* CMP routine called by event sort
+ * When comparing the click time entries of @a to @b:
+ *  gt: returns 1
+ *  lt:  -1
+ *  eq: returns 0
+ */
+static int snap_cmp(const void *a, const void *b)
+{
+	timeline_log_t *click_a, *click_b;
+
+	click_a = (timeline_log_t *) a;
+	click_b = (timeline_log_t *) b;
+
+	if (click_a->time == click_b->time)
+		return 0;
+	else if (click_a->time < click_b->time)
+		return -1;
+
+	return 1;
+}
+
+/* Event Sort API, so that counter Rollover is not visibel to user */
+void sort_snaps(int halt_after_sort)
+{
+	int i;
+	unsigned int flags, tmp;
+
+	/* TODO SMP */
+	local_irq_save(flags);
+
+	take_snap(SNAP_SENTINEL, 0, 0);
+
+	sort(timeline_log, MAX_SNAPS, sizeof(timeline_log_t), snap_cmp, NULL);
+
+	for (i = 0; i < MAX_SNAPS; i++) {
+		memset(timeline_log[i].nm, 0, 16);
+
+		switch (timeline_log[i].event) {
+		case SNAP_TLB_FLUSH_ALL:
+			strcpy(timeline_log[i].nm, "TLB FLUSH ALL");
+			break;
+		case 85:
+			strcpy(timeline_log[i].nm, "FORK");
+			break;
+		case 86:
+			strcpy(timeline_log[i].nm, "EXEC");
+			break;
+		case 99:
+			strcpy(timeline_log[i].nm, "Slow-TLB-Write");
+			break;
+		case SNAP_EXCP_IN:
+			switch (timeline_log[i].cause >> 16) {
+			case 0x21:
+				strcpy(timeline_log[i].nm, "I-TLB");
+				break;
+			case 0x22:
+				strcpy(timeline_log[i].nm, "D-TLB");
+				break;
+			case 0x23:
+				strcpy(timeline_log[i].nm, "PROT-V-TLB");
+				break;
+			default:
+				strcpy(timeline_log[i].nm, "?#?");
+				break;
+			}
+			break;
+		case SNAP_EXCP_OUT_FAST:
+			strcpy(timeline_log[i].nm, "TLB Refill");
+			break;
+		case SNAP_EXCP_OUT:
+			strcpy(timeline_log[i].nm, "Excp-RET");
+			break;
+		case SNAP_TRAP_IN:
+			strcpy(timeline_log[i].nm, "SyCall :");
+			switch (timeline_log[i].cause) {
+			case 1:
+				strcat(timeline_log[i].nm, "Exit");
+				break;
+			case 2:
+				strcat(timeline_log[i].nm, "fork");
+				break;
+			case 114:
+				strcat(timeline_log[i].nm, "wait4");
+				break;
+			default:
+				strcat(timeline_log[i].nm, "???");
+			}
+			break;
+		case SNAP_TRAP_OUT:
+			strcpy(timeline_log[i].nm, "SyCall-RET");
+			break;
+		case SNAP_PRE_CTXSW_2_U:
+			strcpy(timeline_log[i].nm, "2-U-Ctx-sw");
+			break;
+		case SNAP_SENTINEL:
+			memset(&timeline_log[i], 0, sizeof(timeline_log[i]));
+			strcpy(timeline_log[i].nm, "----------");
+			break;
+		case SNAP_PRE_CTXSW_2_K:
+			strcpy(timeline_log[i].nm, "2-K-Ctx-sw");
+			break;
+		case SNAP_INTR_OUT:
+			strcpy(timeline_log[i].nm, "IRQ-OUT");
+			break;
+		case SNAP_INTR_OUT2:
+			strcpy(timeline_log[i].nm, "IRQ(2)-OUT");
+			break;
+		case SNAP_INTR_IN:
+			strcpy(timeline_log[i].nm, "IRQ-in");
+			break;
+		case SNAP_INTR_IN2:
+			strcpy(timeline_log[i].nm, "IRQ(2)-in");
+			break;
+		case SNAP_DO_PF_EXIT:
+			strcpy(timeline_log[i].nm, "PF-RET");
+			break;
+		case SNAP_PREEMPT_SCH_IRQ:
+			strcpy(timeline_log[i].nm, "Prem-Sch IRQ");
+			break;
+		case SNAP_PREEMPT_SCH:
+			strcpy(timeline_log[i].nm, "Prem-Sch");
+			break;
+		case SNAP_DO_PF_ENTER:
+			tmp = timeline_log[i].cause >> 16;
+			switch (tmp) {
+			case 0x21:
+				strcpy(timeline_log[i].nm, "PF-in:I-TLB");
+				break;
+			case 0x22:
+				strcpy(timeline_log[i].nm, "PF-in:D-TLB");
+				break;
+			case 0x23:
+				strcpy(timeline_log[i].nm, "PF-in:PROTV");
+				break;
+			default:
+				strcpy(timeline_log[i].nm, "PF-in:???");
+				break;
+			}
+			break;
+		case SNAP_SIGRETURN:
+			strcpy(timeline_log[i].nm, "sigreturn");
+			break;
+		case SNAP_BEFORE_SIG:
+			strcpy(timeline_log[i].nm, "before sig");
+			break;
+		}
+
+	}
+
+	if (halt_after_sort)
+		__asm__("flag 1");
+	else
+		local_irq_restore(flags);
+
+}
+EXPORT_SYMBOL(sort_snaps);
diff --git a/arch/arc/kernel/signal.c b/arch/arc/kernel/signal.c
index bc834da..2ec908b 100644
--- a/arch/arc/kernel/signal.c
+++ b/arch/arc/kernel/signal.c
@@ -54,6 +54,7 @@
 #include <linux/syscalls.h>
 #include <linux/tracehook.h>
 #include <asm/ucontext.h>
+#include <asm/event-log.h>
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
@@ -137,6 +138,8 @@ SYSCALL_DEFINE0(rt_sigreturn)
 		if (do_sigaltstack(&sf->uc.uc_stack, NULL, regs->sp) == -EFAULT)
 			goto badframe;
 
+	take_snap(SNAP_SIGRETURN, 0, 0);
+
 	return regs->r0;
 
 badframe:
diff --git a/arch/arc/mm/tlb.c b/arch/arc/mm/tlb.c
index c10111d..0e5cb9f 100644
--- a/arch/arc/mm/tlb.c
+++ b/arch/arc/mm/tlb.c
@@ -56,6 +56,7 @@
 #include <asm/setup.h>
 #include <asm/mmu_context.h>
 #include <asm/tlb.h>
+#include <asm/event-log.h>
 
 /*			Need for ARC MMU v2
  *
@@ -191,6 +192,8 @@ noinline void local_flush_tlb_all(void)
 	unsigned int entry;
 	struct cpuinfo_arc_mmu *mmu = &cpuinfo_arc700[smp_processor_id()].mmu;
 
+	take_snap(SNAP_TLB_FLUSH_ALL, 0, 0);
+
 	local_irq_save(flags);
 
 	/* Load PD0 and PD1 with template for a Blank Entry */
diff --git a/arch/arc/mm/tlbex.S b/arch/arc/mm/tlbex.S
index fc5b971..86804d3 100644
--- a/arch/arc/mm/tlbex.S
+++ b/arch/arc/mm/tlbex.S
@@ -41,6 +41,7 @@
 #include <asm/entry.h>
 #include <asm/tlb.h>
 #include <asm/pgtable.h>
+#include <asm/event-log-asm.h>
 #include <asm/arcregs.h>
 #include <asm/cache.h>
 #include <asm/processor.h>
@@ -194,6 +195,9 @@ ex_saved_reg1:
 	st_s  r2, [r0, 8]
 	st_s  r3, [r0, 12]
 
+	; take a snapshot of upon entering FAST Path TLB Hdlr
+	TAKE_SNAP_ASM r0, r1, SNAP_EXCP_IN
+
 	; VERIFY if the ASID in MMU-PID Reg is same as
 	; one in Linux data structures
 
@@ -317,6 +321,9 @@ do_slow_path_pf:
 	; That requires freeing up r9
 	EXCPN_PROLOG_FREEUP_REG r9
 
+	; take a snapshot of upon entering SLOW Path TLB Hdlr
+	TAKE_SNAP_ASM r8, r9, SNAP_DO_PF_ENTER
+
 	lr  r9, [erstatus]
 
 	SWITCH_TO_KERNEL_STK
-- 
1.7.4.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ