[PATCH 3/4] x86/intel lbr: down with test_thread_flag(TIF_IA32)

Dmitry Safonov <[email protected]>
Newsgroups gmane.linux.kernel,gmane.linux.oprofile
Message-ID <[email protected]>
Use user_mode64_bit to check process state. For that pass
interrupt register set from irq handler.
This should fix opcode decoder misinterpreting ABI for
tasks that change their code selector.

Signed-off-by: Dmitry Safonov <[email protected]>
---
 arch/x86/events/intel/core.c |  2 +-
 arch/x86/events/intel/lbr.c  | 17 ++++++++++-------
 arch/x86/events/perf_event.h |  2 +-
 3 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index 68fa55b4d42e..df13d1d6dbf6 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -1860,7 +1860,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)
 
 	loops = 0;
 again:
-	intel_pmu_lbr_read();
+	intel_pmu_lbr_read(regs);
 	intel_pmu_ack_status(status);
 	if (++loops > 100) {
 		static bool warned = false;
diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c
index 6c3b7c1780c9..f1a1dbc77dea 100644
--- a/arch/x86/events/intel/lbr.c
+++ b/arch/x86/events/intel/lbr.c
@@ -136,7 +136,9 @@ enum {
 	 X86_BR_IRQ		|\
 	 X86_BR_INT)
 
-static void intel_pmu_lbr_filter(struct cpu_hw_events *cpuc);
+
+static void
+intel_pmu_lbr_filter(struct pt_regs *regs, struct cpu_hw_events *cpuc);
 
 /*
  * We only support LBR implementations that have FREEZE_LBRS_ON_PMI
@@ -500,7 +502,7 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
 	cpuc->lbr_stack.nr = out;
 }
 
-void intel_pmu_lbr_read(void)
+void intel_pmu_lbr_read(struct pt_regs *regs)
 {
 	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
 
@@ -512,7 +514,7 @@ void intel_pmu_lbr_read(void)
 	else
 		intel_pmu_lbr_read_64(cpuc);
 
-	intel_pmu_lbr_filter(cpuc);
+	intel_pmu_lbr_filter(regs, cpuc);
 }
 
 /*
@@ -658,7 +660,8 @@ int intel_pmu_setup_lbr_filter(struct perf_event *event)
  * decoded (e.g., text page not present), then X86_BR_NONE is
  * returned.
  */
-static int branch_type(unsigned long from, unsigned long to, int abort)
+static int branch_type(unsigned long from, unsigned long to, int abort,
+		struct pt_regs *regs)
 {
 	struct insn insn;
 	void *addr;
@@ -724,7 +727,7 @@ static int branch_type(unsigned long from, unsigned long to, int abort)
 	 * on 64-bit systems running 32-bit apps
 	 */
 #ifdef CONFIG_X86_64
-	is64 = kernel_ip((unsigned long)addr) || !test_thread_flag(TIF_IA32);
+	is64 = kernel_ip((unsigned long)addr) || user_64bit_mode(regs);
 #endif
 	insn_init(&insn, addr, bytes_read, is64);
 	insn_get_opcode(&insn);
@@ -830,7 +833,7 @@ static int branch_type(unsigned long from, unsigned long to, int abort)
  * in PERF_SAMPLE_BRANCH_STACK sample may vary.
  */
 static void
-intel_pmu_lbr_filter(struct cpu_hw_events *cpuc)
+intel_pmu_lbr_filter(struct pt_regs *regs, struct cpu_hw_events *cpuc)
 {
 	u64 from, to;
 	int br_sel = cpuc->br_sel;
@@ -846,7 +849,7 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc)
 		from = cpuc->lbr_entries[i].from;
 		to = cpuc->lbr_entries[i].to;
 
-		type = branch_type(from, to, cpuc->lbr_entries[i].abort);
+		type = branch_type(from, to, cpuc->lbr_entries[i].abort, regs);
 		if (type != X86_BR_NONE && (br_sel & X86_BR_ANYTX)) {
 			if (cpuc->lbr_entries[i].in_tx)
 				type |= X86_BR_IN_TX;
diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h
index ad4dc7ffffb5..da1ec8240097 100644
--- a/arch/x86/events/perf_event.h
+++ b/arch/x86/events/perf_event.h
@@ -899,7 +899,7 @@ void intel_pmu_lbr_enable_all(bool pmi);
 
 void intel_pmu_lbr_disable_all(void);
 
-void intel_pmu_lbr_read(void);
+void intel_pmu_lbr_read(struct pt_regs *regs);
 
 void intel_pmu_lbr_init_core(void);
 
-- 
2.8.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.