summaryrefslogtreecommitdiffstats
path: root/sys/i386/include/pmc_mdep.h
diff options
context:
space:
mode:
authorjkoshy <jkoshy@FreeBSD.org>2008-09-15 06:47:52 +0000
committerjkoshy <jkoshy@FreeBSD.org>2008-09-15 06:47:52 +0000
commita9cbfb55cdc6f2ac0c38c5c9877fafbaad0c70ee (patch)
treed678c3a6dd0d4adcb19f4dae801ffb2b9ad8f0d6 /sys/i386/include/pmc_mdep.h
parent557d36f2a868b261d969813154cf130ba8c32029 (diff)
downloadFreeBSD-src-a9cbfb55cdc6f2ac0c38c5c9877fafbaad0c70ee.zip
FreeBSD-src-a9cbfb55cdc6f2ac0c38c5c9877fafbaad0c70ee.tar.gz
Correct a callchain capture bug on the i386.
On the i386 architecture, the processor only saves the current value of `%esp' on stack if a privilege switch is necessary when entering the interrupt handler. Thus, `frame->tf_esp' is only valid for an entry from user mode. For interrupts taken in kernel mode, we need to determine the top-of-stack for the interrupted kernel procedure by adding the appropriate offset to the current frame pointer. Reported by: kris, Fabien Thomas Tested by: Fabien Thomas <fabien.thomas at netasq dot com>
Diffstat (limited to 'sys/i386/include/pmc_mdep.h')
-rw-r--r--sys/i386/include/pmc_mdep.h22
1 files changed, 20 insertions, 2 deletions
diff --git a/sys/i386/include/pmc_mdep.h b/sys/i386/include/pmc_mdep.h
index 7ec1f4b..de0688a 100644
--- a/sys/i386/include/pmc_mdep.h
+++ b/sys/i386/include/pmc_mdep.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2003-2005 Joseph Koshy
+ * Copyright (c) 2003-2005,2008 Joseph Koshy
* Copyright (c) 2007 The FreeBSD Foundation
* All rights reserved.
*
@@ -79,7 +79,25 @@ struct pmc;
#define PMC_TRAPFRAME_TO_PC(TF) ((TF)->tf_eip)
#define PMC_TRAPFRAME_TO_FP(TF) ((TF)->tf_ebp)
-#define PMC_TRAPFRAME_TO_SP(TF) ((TF)->tf_esp)
+
+/*
+ * The layout of the stack frame on entry into the NMI handler depends on
+ * whether a privilege level change (and consequent stack switch) was
+ * required for entry.
+ *
+ * When processing an interrupt when in user mode, the processor switches
+ * stacks, and saves the user mode stack pointer on the kernel stack. The
+ * user mode stack pointer is then available to the interrupt handler
+ * at frame->tf_esp.
+ *
+ * When processing an interrupt while in kernel mode, the processor
+ * continues to use the existing (kernel) stack. Therefore we determine
+ * the stack pointer for the interrupted kernel procedure by adding an
+ * offset to the current frame pointer.
+ */
+
+#define PMC_TRAPFRAME_TO_USER_SP(TF) ((TF)->tf_esp)
+#define PMC_TRAPFRAME_TO_KERNEL_SP(TF) ((uintptr_t) &((TF)->tf_esp))
#define PMC_IN_KERNEL_STACK(S,START,END) \
((S) >= (START) && (S) < (END))
OpenPOWER on IntegriCloud