summary refs log tree commit diff
path: root/tools
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-11-17 14:23:52 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2017-11-17 14:23:52 -0800
commite71d5126e77c68b7ed1fad275fdc8825e9597448 (patch)
tree038f23568881d65cb269c9c4b92e65a2d7131456 /tools
parentc3e9c04b89059a4c93c792da883ca284de182da5 (diff)
parentab35727eb879ccc9487c6df0a3796be124ed39d3 (diff)
downloadlinux-e71d5126e77c68b7ed1fad275fdc8825e9597448.tar.gz
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull second round of s390 updates from Martin Schwidefsky:

 - rework of the vdso code to avoid the use of the access register mode

 - use perf AUX buffers for the transport of diagnostic sample data

 - add perf_regs and user stack dump support

 - enable perf call graphs for user space programs

 - add perf register support for floating-point registers

 - all remaining s390 related timer_setup conversions

 - bug fixes and cleanups

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (30 commits)
  s390: remove unused parameter from Makefile
  zfcp: purely mechanical update using timer API, plus blank lines
  s390/scsi: Convert timers to use timer_setup()
  s390/cpum_sf: correctly set the PID and TID in perf samples
  s390/cpum_sf: load program parameter at sampler enablement
  s390/perf: add perf register support for floating-point registers
  s390/perf: extend perf_regs support to include floating-point registers
  s390/perf: define common DWARF register string table
  s390/perf: add support for perf_regs and libdw
  s390/perf: add perf_regs support and user stack dump
  s390/cpum_sf: do not register PMU if no sampling mode is authorized
  s390/cpumf: remove raw event support in basic-only sampling mode
  s390/perf: add callback to perf to enable using AUX buffer
  s390/cpumf: enable using AUX buffer
  s390/cpumf: introduce AUX buffer for dump diagnostic sample data
  s390/disassembler: increase show_code buffer size
  s390: Remove CONFIG_HARDENED_USERCOPY
  s390: enable CPU alternatives unconditionally
  s390/nmi: remove unused code
  s390/mm: remove unused code
  ...
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Makefile.config6
-rw-r--r--tools/perf/arch/s390/include/dwarf-regs-table.h71
-rw-r--r--tools/perf/arch/s390/include/perf_regs.h95
-rw-r--r--tools/perf/arch/s390/util/Build3
-rw-r--r--tools/perf/arch/s390/util/auxtrace.c118
-rw-r--r--tools/perf/arch/s390/util/dwarf-regs.c11
-rw-r--r--tools/perf/arch/s390/util/unwind-libdw.c63
7 files changed, 354 insertions, 13 deletions
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index 63f534a0902f..ed65e82f034e 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -53,6 +53,10 @@ ifeq ($(SRCARCH),arm64)
   LIBUNWIND_LIBS = -lunwind -lunwind-aarch64
 endif
 
+ifeq ($(ARCH),s390)
+  NO_PERF_REGS := 0
+endif
+
 ifeq ($(NO_PERF_REGS),0)
   $(call detected,CONFIG_PERF_REGS)
 endif
@@ -61,7 +65,7 @@ endif
 # Disable it on all other architectures in case libdw unwind
 # support is detected in system. Add supported architectures
 # to the check.
-ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm powerpc))
+ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm powerpc s390))
   NO_LIBDW_DWARF_UNWIND := 1
 endif
 
diff --git a/tools/perf/arch/s390/include/dwarf-regs-table.h b/tools/perf/arch/s390/include/dwarf-regs-table.h
index 792d4c277225..671553525f41 100644
--- a/tools/perf/arch/s390/include/dwarf-regs-table.h
+++ b/tools/perf/arch/s390/include/dwarf-regs-table.h
@@ -1,9 +1,72 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-#ifdef DEFINE_DWARF_REGSTR_TABLE
-/* This is included in perf/util/dwarf-regs.c */
+#ifndef S390_DWARF_REGS_TABLE_H
+#define S390_DWARF_REGS_TABLE_H
 
-static const char * const s390_regstr_tbl[] = {
+#define REG_DWARFNUM_NAME(reg, idx)	[idx] = "%" #reg
+
+/*
+ * For reference, see DWARF register mapping:
+ * http://refspecs.linuxfoundation.org/ELF/zSeries/lzsabi0_s390/x1542.html
+ */
+static const char * const s390_dwarf_regs[] = {
 	"%r0", "%r1",  "%r2",  "%r3",  "%r4",  "%r5",  "%r6",  "%r7",
 	"%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
+	REG_DWARFNUM_NAME(f0, 16),
+	REG_DWARFNUM_NAME(f1, 20),
+	REG_DWARFNUM_NAME(f2, 17),
+	REG_DWARFNUM_NAME(f3, 21),
+	REG_DWARFNUM_NAME(f4, 18),
+	REG_DWARFNUM_NAME(f5, 22),
+	REG_DWARFNUM_NAME(f6, 19),
+	REG_DWARFNUM_NAME(f7, 23),
+	REG_DWARFNUM_NAME(f8, 24),
+	REG_DWARFNUM_NAME(f9, 28),
+	REG_DWARFNUM_NAME(f10, 25),
+	REG_DWARFNUM_NAME(f11, 29),
+	REG_DWARFNUM_NAME(f12, 26),
+	REG_DWARFNUM_NAME(f13, 30),
+	REG_DWARFNUM_NAME(f14, 27),
+	REG_DWARFNUM_NAME(f15, 31),
+	REG_DWARFNUM_NAME(c0, 32),
+	REG_DWARFNUM_NAME(c1, 33),
+	REG_DWARFNUM_NAME(c2, 34),
+	REG_DWARFNUM_NAME(c3, 35),
+	REG_DWARFNUM_NAME(c4, 36),
+	REG_DWARFNUM_NAME(c5, 37),
+	REG_DWARFNUM_NAME(c6, 38),
+	REG_DWARFNUM_NAME(c7, 39),
+	REG_DWARFNUM_NAME(c8, 40),
+	REG_DWARFNUM_NAME(c9, 41),
+	REG_DWARFNUM_NAME(c10, 42),
+	REG_DWARFNUM_NAME(c11, 43),
+	REG_DWARFNUM_NAME(c12, 44),
+	REG_DWARFNUM_NAME(c13, 45),
+	REG_DWARFNUM_NAME(c14, 46),
+	REG_DWARFNUM_NAME(c15, 47),
+	REG_DWARFNUM_NAME(a0, 48),
+	REG_DWARFNUM_NAME(a1, 49),
+	REG_DWARFNUM_NAME(a2, 50),
+	REG_DWARFNUM_NAME(a3, 51),
+	REG_DWARFNUM_NAME(a4, 52),
+	REG_DWARFNUM_NAME(a5, 53),
+	REG_DWARFNUM_NAME(a6, 54),
+	REG_DWARFNUM_NAME(a7, 55),
+	REG_DWARFNUM_NAME(a8, 56),
+	REG_DWARFNUM_NAME(a9, 57),
+	REG_DWARFNUM_NAME(a10, 58),
+	REG_DWARFNUM_NAME(a11, 59),
+	REG_DWARFNUM_NAME(a12, 60),
+	REG_DWARFNUM_NAME(a13, 61),
+	REG_DWARFNUM_NAME(a14, 62),
+	REG_DWARFNUM_NAME(a15, 63),
+	REG_DWARFNUM_NAME(pswm, 64),
+	REG_DWARFNUM_NAME(pswa, 65),
 };
-#endif
+
+#ifdef DEFINE_DWARF_REGSTR_TABLE
+/* This is included in perf/util/dwarf-regs.c */
+
+#define s390_regstr_tbl s390_dwarf_regs
+
+#endif	/* DEFINE_DWARF_REGSTR_TABLE */
+#endif	/* S390_DWARF_REGS_TABLE_H */
diff --git a/tools/perf/arch/s390/include/perf_regs.h b/tools/perf/arch/s390/include/perf_regs.h
new file mode 100644
index 000000000000..d2df54a6bc5a
--- /dev/null
+++ b/tools/perf/arch/s390/include/perf_regs.h
@@ -0,0 +1,95 @@
+#ifndef ARCH_PERF_REGS_H
+#define ARCH_PERF_REGS_H
+
+#include <stdlib.h>
+#include <linux/types.h>
+#include <../../../../arch/s390/include/uapi/asm/perf_regs.h>
+
+void perf_regs_load(u64 *regs);
+
+#define PERF_REGS_MASK ((1ULL << PERF_REG_S390_MAX) - 1)
+#define PERF_REGS_MAX PERF_REG_S390_MAX
+#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64
+
+#define PERF_REG_IP PERF_REG_S390_PC
+#define PERF_REG_SP PERF_REG_S390_R15
+
+static inline const char *perf_reg_name(int id)
+{
+	switch (id) {
+	case PERF_REG_S390_R0:
+		return "R0";
+	case PERF_REG_S390_R1:
+		return "R1";
+	case PERF_REG_S390_R2:
+		return "R2";
+	case PERF_REG_S390_R3:
+		return "R3";
+	case PERF_REG_S390_R4:
+		return "R4";
+	case PERF_REG_S390_R5:
+		return "R5";
+	case PERF_REG_S390_R6:
+		return "R6";
+	case PERF_REG_S390_R7:
+		return "R7";
+	case PERF_REG_S390_R8:
+		return "R8";
+	case PERF_REG_S390_R9:
+		return "R9";
+	case PERF_REG_S390_R10:
+		return "R10";
+	case PERF_REG_S390_R11:
+		return "R11";
+	case PERF_REG_S390_R12:
+		return "R12";
+	case PERF_REG_S390_R13:
+		return "R13";
+	case PERF_REG_S390_R14:
+		return "R14";
+	case PERF_REG_S390_R15:
+		return "R15";
+	case PERF_REG_S390_FP0:
+		return "FP0";
+	case PERF_REG_S390_FP1:
+		return "FP1";
+	case PERF_REG_S390_FP2:
+		return "FP2";
+	case PERF_REG_S390_FP3:
+		return "FP3";
+	case PERF_REG_S390_FP4:
+		return "FP4";
+	case PERF_REG_S390_FP5:
+		return "FP5";
+	case PERF_REG_S390_FP6:
+		return "FP6";
+	case PERF_REG_S390_FP7:
+		return "FP7";
+	case PERF_REG_S390_FP8:
+		return "FP8";
+	case PERF_REG_S390_FP9:
+		return "FP9";
+	case PERF_REG_S390_FP10:
+		return "FP10";
+	case PERF_REG_S390_FP11:
+		return "FP11";
+	case PERF_REG_S390_FP12:
+		return "FP12";
+	case PERF_REG_S390_FP13:
+		return "FP13";
+	case PERF_REG_S390_FP14:
+		return "FP14";
+	case PERF_REG_S390_FP15:
+		return "FP15";
+	case PERF_REG_S390_MASK:
+		return "MASK";
+	case PERF_REG_S390_PC:
+		return "PC";
+	default:
+		return NULL;
+	}
+
+	return NULL;
+}
+
+#endif /* ARCH_PERF_REGS_H */
diff --git a/tools/perf/arch/s390/util/Build b/tools/perf/arch/s390/util/Build
index 5bd7b9260cc0..4a233683c684 100644
--- a/tools/perf/arch/s390/util/Build
+++ b/tools/perf/arch/s390/util/Build
@@ -2,5 +2,8 @@ libperf-y += header.o
 libperf-y += kvm-stat.o
 
 libperf-$(CONFIG_DWARF) += dwarf-regs.o
+libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
 
 libperf-y += machine.o
+
+libperf-$(CONFIG_AUXTRACE) += auxtrace.o
diff --git a/tools/perf/arch/s390/util/auxtrace.c b/tools/perf/arch/s390/util/auxtrace.c
new file mode 100644
index 000000000000..6cb48e4cffd9
--- /dev/null
+++ b/tools/perf/arch/s390/util/auxtrace.c
@@ -0,0 +1,118 @@
+#include <stdbool.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/log2.h>
+
+#include "../../util/evlist.h"
+#include "../../util/auxtrace.h"
+#include "../../util/evsel.h"
+
+#define PERF_EVENT_CPUM_SF		0xB0000 /* Event: Basic-sampling */
+#define PERF_EVENT_CPUM_SF_DIAG		0xBD000 /* Event: Combined-sampling */
+#define DEFAULT_AUX_PAGES		128
+#define DEFAULT_FREQ			4000
+
+static void cpumsf_free(struct auxtrace_record *itr)
+{
+	free(itr);
+}
+
+static size_t cpumsf_info_priv_size(struct auxtrace_record *itr __maybe_unused,
+				    struct perf_evlist *evlist __maybe_unused)
+{
+	return 0;
+}
+
+static int
+cpumsf_info_fill(struct auxtrace_record *itr __maybe_unused,
+		 struct perf_session *session __maybe_unused,
+		 struct auxtrace_info_event *auxtrace_info __maybe_unused,
+		 size_t priv_size __maybe_unused)
+{
+	return 0;
+}
+
+static unsigned long
+cpumsf_reference(struct auxtrace_record *itr __maybe_unused)
+{
+	return 0;
+}
+
+static int
+cpumsf_recording_options(struct auxtrace_record *ar __maybe_unused,
+			 struct perf_evlist *evlist __maybe_unused,
+			 struct record_opts *opts)
+{
+	unsigned int factor = 1;
+	unsigned int pages;
+
+	opts->full_auxtrace = true;
+
+	/*
+	 * The AUX buffer size should be set properly to avoid
+	 * overflow of samples if it is not set explicitly.
+	 * DEFAULT_AUX_PAGES is an proper size when sampling frequency
+	 * is DEFAULT_FREQ. It is expected to hold about 1/2 second
+	 * of sampling data. The size used for AUX buffer will scale
+	 * according to the specified frequency and DEFAULT_FREQ.
+	 */
+	if (!opts->auxtrace_mmap_pages) {
+		if (opts->user_freq != UINT_MAX)
+			factor = (opts->user_freq + DEFAULT_FREQ
+				  - 1) / DEFAULT_FREQ;
+		pages = DEFAULT_AUX_PAGES * factor;
+		opts->auxtrace_mmap_pages = roundup_pow_of_two(pages);
+	}
+
+	return 0;
+}
+
+static int
+cpumsf_parse_snapshot_options(struct auxtrace_record *itr __maybe_unused,
+			      struct record_opts *opts __maybe_unused,
+			      const char *str __maybe_unused)
+{
+	return 0;
+}
+
+/*
+ * auxtrace_record__init is called when perf record
+ * check if the event really need auxtrace
+ */
+struct auxtrace_record *auxtrace_record__init(struct perf_evlist *evlist,
+					      int *err)
+{
+	struct auxtrace_record *aux;
+	struct perf_evsel *pos;
+	int diagnose = 0;
+
+	if (evlist->nr_entries == 0)
+		return NULL;
+
+	evlist__for_each_entry(evlist, pos) {
+		if (pos->attr.config == PERF_EVENT_CPUM_SF_DIAG) {
+			diagnose = 1;
+			break;
+		}
+	}
+
+	if (!diagnose)
+		return NULL;
+
+	/* sampling in diagnose mode. alloc aux buffer */
+	aux = zalloc(sizeof(*aux));
+	if (aux == NULL) {
+		*err = -ENOMEM;
+		return NULL;
+	}
+
+	aux->parse_snapshot_options = cpumsf_parse_snapshot_options;
+	aux->recording_options = cpumsf_recording_options;
+	aux->info_priv_size = cpumsf_info_priv_size;
+	aux->info_fill = cpumsf_info_fill;
+	aux->free = cpumsf_free;
+	aux->reference = cpumsf_reference;
+
+	return aux;
+}
diff --git a/tools/perf/arch/s390/util/dwarf-regs.c b/tools/perf/arch/s390/util/dwarf-regs.c
index 0dff5b2ed1e5..f47576ce13ea 100644
--- a/tools/perf/arch/s390/util/dwarf-regs.c
+++ b/tools/perf/arch/s390/util/dwarf-regs.c
@@ -9,15 +9,10 @@
 
 #include <stddef.h>
 #include <dwarf-regs.h>
-
-#define NUM_GPRS 16
-
-static const char *gpr_names[NUM_GPRS] = {
-	"%r0", "%r1",  "%r2",  "%r3",  "%r4",  "%r5",  "%r6",  "%r7",
-	"%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
-};
+#include <linux/kernel.h>
+#include "dwarf-regs-table.h"
 
 const char *get_arch_regstr(unsigned int n)
 {
-	return (n >= NUM_GPRS) ? NULL : gpr_names[n];
+	return (n >= ARRAY_SIZE(s390_dwarf_regs)) ? NULL : s390_dwarf_regs[n];
 }
diff --git a/tools/perf/arch/s390/util/unwind-libdw.c b/tools/perf/arch/s390/util/unwind-libdw.c
new file mode 100644
index 000000000000..387c698cdd1b
--- /dev/null
+++ b/tools/perf/arch/s390/util/unwind-libdw.c
@@ -0,0 +1,63 @@
+#include <linux/kernel.h>
+#include <elfutils/libdwfl.h>
+#include "../../util/unwind-libdw.h"
+#include "../../util/perf_regs.h"
+#include "../../util/event.h"
+#include "dwarf-regs-table.h"
+
+
+bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
+{
+	struct unwind_info *ui = arg;
+	struct regs_dump *user_regs = &ui->sample->user_regs;
+	Dwarf_Word dwarf_regs[ARRAY_SIZE(s390_dwarf_regs)];
+
+#define REG(r) ({						\
+	Dwarf_Word val = 0;					\
+	perf_reg_value(&val, user_regs, PERF_REG_S390_##r);	\
+	val;							\
+})
+	/*
+	 * For DWARF register mapping details,
+	 * see also perf/arch/s390/include/dwarf-regs-table.h
+	 */
+	dwarf_regs[0]  = REG(R0);
+	dwarf_regs[1]  = REG(R1);
+	dwarf_regs[2]  = REG(R2);
+	dwarf_regs[3]  = REG(R3);
+	dwarf_regs[4]  = REG(R4);
+	dwarf_regs[5]  = REG(R5);
+	dwarf_regs[6]  = REG(R6);
+	dwarf_regs[7]  = REG(R7);
+	dwarf_regs[8]  = REG(R8);
+	dwarf_regs[9]  = REG(R9);
+	dwarf_regs[10] = REG(R10);
+	dwarf_regs[11] = REG(R11);
+	dwarf_regs[12] = REG(R12);
+	dwarf_regs[13] = REG(R13);
+	dwarf_regs[14] = REG(R14);
+	dwarf_regs[15] = REG(R15);
+
+	dwarf_regs[16] = REG(FP0);
+	dwarf_regs[17] = REG(FP2);
+	dwarf_regs[18] = REG(FP4);
+	dwarf_regs[19] = REG(FP6);
+	dwarf_regs[20] = REG(FP1);
+	dwarf_regs[21] = REG(FP3);
+	dwarf_regs[22] = REG(FP5);
+	dwarf_regs[23] = REG(FP7);
+	dwarf_regs[24] = REG(FP8);
+	dwarf_regs[25] = REG(FP10);
+	dwarf_regs[26] = REG(FP12);
+	dwarf_regs[27] = REG(FP14);
+	dwarf_regs[28] = REG(FP9);
+	dwarf_regs[29] = REG(FP11);
+	dwarf_regs[30] = REG(FP13);
+	dwarf_regs[31] = REG(FP15);
+
+	dwarf_regs[64] = REG(MASK);
+	dwarf_regs[65] = REG(PC);
+
+	dwfl_thread_state_register_pc(thread, dwarf_regs[65]);
+	return dwfl_thread_state_registers(thread, 0, 32, dwarf_regs);
+}