Page MenuHomeFreeBSD

D12875.id39967.diff
No OneTemporary

D12875.id39967.diff

Index: lib/Makefile
===================================================================
--- lib/Makefile
+++ lib/Makefile
@@ -175,7 +175,12 @@
_libvgl= libvgl
.endif
+.if ${MACHINE_CPUARCH} == "aarch64"
+SUBDIR.${MK_PMC}+= libopencsd
+.endif
+
.if ${MACHINE_CPUARCH} == "amd64"
+SUBDIR.${MK_PMC}+= libipt
SUBDIR.${MK_BHYVE}+= libvmmapi
.endif
Index: lib/libipt/Makefile
===================================================================
--- /dev/null
+++ lib/libipt/Makefile
@@ -0,0 +1,77 @@
+# $FreeBSD$
+
+PACKAGE=lib${LIB}
+SHLIBDIR?= /lib
+
+.include <src.opts.mk>
+
+LIBIPTSRC= ${SRCTOP}/contrib/libipt
+
+.PATH: ${LIBIPTSRC}/libipt/src \
+ ${LIBIPTSRC}/libipt/src/posix \
+ ${LIBIPTSRC}/libipt/internal/include \
+ ${LIBIPTSRC}/libipt/include \
+ ${LIBIPTSRC}/include
+
+LIB= ipt
+SHLIB_MAJOR=0
+
+SRCS= \
+ init.c \
+ pt_asid.c \
+ pt_block_cache.c \
+ pt_block_decoder.c \
+ pt_config.c \
+ pt_cpu.c \
+ pt_cpuid.c \
+ pt_decoder_function.c \
+ pt_encoder.c \
+ pt_error.c \
+ pt_event_queue.c \
+ pt_ild.c \
+ pt_image_section_cache.c \
+ pt_image.c \
+ pt_insn_decoder.c \
+ pt_insn.c \
+ pt_last_ip.c \
+ pt_packet_decoder.c \
+ pt_packet.c \
+ pt_query_decoder.c \
+ pt_retstack.c \
+ pt_section_file.c \
+ pt_section_posix.c \
+ pt_section.c \
+ pt_sync.c \
+ pt_time.c \
+ pt_tnt_cache.c \
+ pt_version.c
+
+CFLAGS+= \
+ -I${LIBIPTSRC}/libipt/internal/include/posix \
+ -I${LIBIPTSRC}/libipt/internal/include \
+ -I${LIBIPTSRC}/libipt/include \
+ -I${LIBIPTSRC}/include \
+ -I${.CURDIR}
+
+CFLAGS+= \
+ -DPT_VERSION_BUILD=0 \
+ -DPT_VERSION_EXT=\"\" \
+ -DPT_VERSION_MAJOR=1 \
+ -DPT_VERSION_MINOR=6
+
+INCS= \
+ intel-pt.h \
+ pt_cpu.h \
+ pt_last_ip.h \
+ pt_time.h \
+ pt_compiler.h
+
+INCSDIR=${INCLUDEDIR}/libipt
+
+LIBADD=
+
+WARNS?= 1
+
+HAS_TESTS=
+
+.include <bsd.lib.mk>
Index: lib/libopencsd/Makefile
===================================================================
--- /dev/null
+++ lib/libopencsd/Makefile
@@ -0,0 +1,180 @@
+# $FreeBSD$
+
+PACKAGE=lib${LIB}
+SHLIBDIR?= /lib
+
+.include <src.opts.mk>
+
+OPENCSDSRC= ${SRCTOP}/contrib/opencsd
+
+.PATH: ${OPENCSDSRC}/decoder/source/etmv4/ \
+ ${OPENCSDSRC}/decoder/source/etmv3/ \
+ ${OPENCSDSRC}/decoder/source/pkt_printers/ \
+ ${OPENCSDSRC}/decoder/source/mem_acc/ \
+ ${OPENCSDSRC}/decoder/source/i_dec/ \
+ ${OPENCSDSRC}/decoder/source/c_api/ \
+ ${OPENCSDSRC}/decoder/source/ptm/ \
+ ${OPENCSDSRC}/decoder/source/stm/ \
+ ${OPENCSDSRC}/decoder/source/ \
+ ${OPENCSDSRC}/decoder/include/opencsd/etmv4/ \
+ ${OPENCSDSRC}/decoder/include/opencsd/etmv3/ \
+ ${OPENCSDSRC}/decoder/include/opencsd/stm/ \
+ ${OPENCSDSRC}/decoder/include/opencsd/ptm/ \
+ ${OPENCSDSRC}/decoder/include/opencsd/c_api/ \
+ ${OPENCSDSRC}/decoder/include/opencsd/ \
+ ${OPENCSDSRC}/decoder/include
+
+LIB= opencsd
+SHLIB_MAJOR=0
+
+# Uncomment for debugging
+#CFLAGS += -g -O0 -DDEBUG
+#CPPFLAGS += -g -O0 -DDEBUG
+#CXXFLAGS += -g -O0 -DDEBUG
+
+# ETMv3
+SRCS= \
+ trc_cmp_cfg_etmv3.cpp \
+ trc_pkt_decode_etmv3.cpp \
+ trc_pkt_elem_etmv3.cpp \
+ trc_pkt_proc_etmv3.cpp \
+ trc_pkt_proc_etmv3_impl.cpp
+
+# ETMv4
+SRCS+= \
+ trc_cmp_cfg_etmv4.cpp \
+ trc_etmv4_stack_elem.cpp \
+ trc_pkt_decode_etmv4i.cpp \
+ trc_pkt_elem_etmv4d.cpp \
+ trc_pkt_elem_etmv4i.cpp \
+ trc_pkt_proc_etmv4.cpp \
+ trc_pkt_proc_etmv4i_impl.cpp
+
+# PKT_PRINTERS
+SRCS+= \
+ raw_frame_printer.cpp \
+ trc_print_fact.cpp
+
+# PTM
+SRCS+= \
+ trc_cmp_cfg_ptm.cpp \
+ trc_pkt_decode_ptm.cpp \
+ trc_pkt_elem_ptm.cpp \
+ trc_pkt_proc_ptm.cpp
+
+# STM
+SRCS+= \
+ trc_pkt_decode_stm.cpp \
+ trc_pkt_elem_stm.cpp \
+ trc_pkt_proc_stm.cpp
+
+# C_API
+SRCS+= \
+ ocsd_c_api_custom_obj.cpp \
+ ocsd_c_api.cpp
+
+# SRC
+SRCS+= \
+ ocsd_code_follower.cpp \
+ ocsd_dcd_tree.cpp \
+ ocsd_error.cpp \
+ ocsd_error_logger.cpp \
+ ocsd_gen_elem_list.cpp \
+ ocsd_lib_dcd_register.cpp \
+ ocsd_msg_logger.cpp \
+ ocsd_version.cpp \
+ trc_component.cpp \
+ trc_core_arch_map.cpp \
+ trc_frame_deformatter.cpp \
+ trc_gen_elem.cpp \
+ trc_printable_elem.cpp \
+ trc_ret_stack.cpp
+
+# MEM_ACC
+SRCS+= \
+ trc_mem_acc_base.cpp \
+ trc_mem_acc_cb.cpp \
+ trc_mem_acc_mapper.cpp \
+ trc_mem_acc_bufptr.cpp \
+ trc_mem_acc_file.cpp
+
+# I_DEC
+SRCS+= \
+ trc_i_decode.cpp \
+ trc_idec_arminst.cpp
+
+CFLAGS+= \
+ -I${OPENCSDSRC}/decoder/include/ \
+ -I${.CURDIR}
+
+INCS= \
+ ocsd_if_types.h \
+ trc_gen_elem_types.h \
+ trc_pkt_types.h
+
+INCSDIR=${INCLUDEDIR}/opencsd
+
+APIINCS= \
+ ocsd_c_api_cust_fact.h \
+ ocsd_c_api_cust_impl.h \
+ ocsd_c_api_custom.h \
+ ocsd_c_api_types.h \
+ opencsd_c_api.h
+
+APIINCSDIR=${INCLUDEDIR}/opencsd/c_api/
+
+ETMV4INCS= \
+ etmv4_decoder.h \
+ trc_cmp_cfg_etmv4.h \
+ trc_dcd_mngr_etmv4i.h \
+ trc_etmv4_stack_elem.h \
+ trc_pkt_decode_etmv4i.h \
+ trc_pkt_elem_etmv4d.h \
+ trc_pkt_elem_etmv4i.h \
+ trc_pkt_proc_etmv4.h \
+ trc_pkt_types_etmv4.h
+
+ETMV4INCSDIR=${INCLUDEDIR}/opencsd/etmv4/
+
+ETMV3INCS= \
+ etmv3_decoder.h \
+ trc_cmp_cfg_etmv3.h \
+ trc_dcd_mngr_etmv3.h \
+ trc_pkt_decode_etmv3.h \
+ trc_pkt_elem_etmv3.h \
+ trc_pkt_proc_etmv3.h \
+ trc_pkt_types_etmv3.h
+
+ETMV3INCSDIR=${INCLUDEDIR}/opencsd/etmv3/
+
+PTMINCS= \
+ ptm_decoder.h \
+ trc_cmp_cfg_ptm.h \
+ trc_dcd_mngr_ptm.h \
+ trc_pkt_decode_ptm.h \
+ trc_pkt_elem_ptm.h \
+ trc_pkt_proc_ptm.h \
+ trc_pkt_types_ptm.h
+
+PTMINCSDIR=${INCLUDEDIR}/opencsd/ptm/
+
+STMINCS= \
+ stm_decoder.h \
+ trc_cmp_cfg_stm.h \
+ trc_dcd_mngr_stm.h \
+ trc_pkt_decode_stm.h \
+ trc_pkt_elem_stm.h \
+ trc_pkt_proc_stm.h \
+ trc_pkt_types_stm.h
+
+STMINCSDIR=${INCLUDEDIR}/opencsd/stm/
+
+INCSGROUPS=INCS APIINCS ETMV3INCS ETMV4INCS PTMINCS STMINCS
+
+LIBADD= cxxrt cplusplus
+
+WARNS?= 1
+
+HAS_TESTS=
+
+.include <bsd.lib.mk>
Index: lib/libpmc/libpmc.c
===================================================================
--- lib/libpmc/libpmc.c
+++ lib/libpmc/libpmc.c
@@ -76,6 +76,10 @@
static int tsc_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
struct pmc_op_pmcallocate *_pmc_config);
#endif
+#if defined(__amd64__)
+static int pt_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
+ struct pmc_op_pmcallocate *_pmc_config);
+#endif
#if defined(__arm__)
#if defined(__XSCALE__)
static int xscale_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
@@ -87,6 +91,8 @@
#if defined(__aarch64__)
static int arm64_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
struct pmc_op_pmcallocate *_pmc_config);
+static int coresight_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
+ struct pmc_op_pmcallocate *_pmc_config);
#endif
#if defined(__mips__)
static int mips_allocate_pmc(enum pmc_event _pe, char* ctrspec,
@@ -239,6 +245,12 @@
__PMC_EV_ALIAS_SKYLAKE_XEON()
};
+static const struct pmc_event_descr kabylake_event_table[] =
+{
+ /* Kabylake events are similar to Skylake */
+ __PMC_EV_ALIAS_SKYLAKE()
+};
+
static const struct pmc_event_descr ivybridge_event_table[] =
{
__PMC_EV_ALIAS_IVYBRIDGE()
@@ -336,6 +348,7 @@
PMC_MDEP_TABLE(broadwell_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
PMC_MDEP_TABLE(skylake, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
PMC_MDEP_TABLE(skylake_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
+PMC_MDEP_TABLE(kabylake, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP, PMC_CLASS_PT);
PMC_MDEP_TABLE(ivybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
PMC_MDEP_TABLE(ivybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
PMC_MDEP_TABLE(sandybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
@@ -350,8 +363,8 @@
PMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_SOFT, PMC_CLASS_XSCALE);
PMC_MDEP_TABLE(cortex_a8, ARMV7, PMC_CLASS_SOFT, PMC_CLASS_ARMV7);
PMC_MDEP_TABLE(cortex_a9, ARMV7, PMC_CLASS_SOFT, PMC_CLASS_ARMV7);
-PMC_MDEP_TABLE(cortex_a53, ARMV8, PMC_CLASS_SOFT, PMC_CLASS_ARMV8);
-PMC_MDEP_TABLE(cortex_a57, ARMV8, PMC_CLASS_SOFT, PMC_CLASS_ARMV8);
+PMC_MDEP_TABLE(cortex_a53, ARMV8, PMC_CLASS_SOFT, PMC_CLASS_ARMV8, PMC_CLASS_CORESIGHT);
+PMC_MDEP_TABLE(cortex_a57, ARMV8, PMC_CLASS_SOFT, PMC_CLASS_ARMV8, PMC_CLASS_CORESIGHT);
PMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_SOFT, PMC_CLASS_MIPS24K);
PMC_MDEP_TABLE(mips74k, MIPS74K, PMC_CLASS_SOFT, PMC_CLASS_MIPS74K);
PMC_MDEP_TABLE(octeon, OCTEON, PMC_CLASS_SOFT, PMC_CLASS_OCTEON);
@@ -365,6 +378,16 @@
__PMC_EV_TSC()
};
+static const struct pmc_event_descr pt_event_table[] =
+{
+ __PMC_EV_PT()
+};
+
+static const struct pmc_event_descr coresight_event_table[] =
+{
+ __PMC_EV_CORESIGHT()
+};
+
#undef PMC_CLASS_TABLE_DESC
#define PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR) \
static const struct pmc_class_descr NAME##_class_table_descr = \
@@ -392,6 +415,7 @@
PMC_CLASS_TABLE_DESC(broadwell_xeon, IAP, broadwell_xeon, iap);
PMC_CLASS_TABLE_DESC(skylake, IAP, skylake, iap);
PMC_CLASS_TABLE_DESC(skylake_xeon, IAP, skylake_xeon, iap);
+PMC_CLASS_TABLE_DESC(kabylake, IAP, kabylake, iap);
PMC_CLASS_TABLE_DESC(ivybridge, IAP, ivybridge, iap);
PMC_CLASS_TABLE_DESC(ivybridge_xeon, IAP, ivybridge_xeon, iap);
PMC_CLASS_TABLE_DESC(sandybridge, IAP, sandybridge, iap);
@@ -419,6 +443,9 @@
#if defined(__i386__) || defined(__amd64__)
PMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc);
#endif
+#if defined(__amd64__)
+PMC_CLASS_TABLE_DESC(pt, PT, pt, pt);
+#endif
#if defined(__arm__)
#if defined(__XSCALE__)
PMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale);
@@ -429,6 +456,7 @@
#if defined(__aarch64__)
PMC_CLASS_TABLE_DESC(cortex_a53, ARMV8, cortex_a53, arm64);
PMC_CLASS_TABLE_DESC(cortex_a57, ARMV8, cortex_a57, arm64);
+PMC_CLASS_TABLE_DESC(coresight, CORESIGHT, coresight, coresight);
#endif
#if defined(__mips__)
PMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips);
@@ -732,6 +760,8 @@
#define skylake_aliases_without_iaf core2_aliases_without_iaf
#define skylake_xeon_aliases core2_aliases
#define skylake_xeon_aliases_without_iaf core2_aliases_without_iaf
+#define kabylake_aliases core2_aliases
+#define kabylake_aliases_without_iaf core2_aliases_without_iaf
#define ivybridge_aliases core2_aliases
#define ivybridge_aliases_without_iaf core2_aliases_without_iaf
#define ivybridge_xeon_aliases core2_aliases
@@ -1049,7 +1079,8 @@
return (-1);
} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_SKYLAKE ||
- cpu_info.pm_cputype == PMC_CPU_INTEL_SKYLAKE_XEON) {
+ cpu_info.pm_cputype == PMC_CPU_INTEL_SKYLAKE_XEON ||
+ cpu_info.pm_cputype == PMC_CPU_INTEL_KABYLAKE) {
if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
n = pmc_parse_mask(iap_rsp_mask_skylake, p, &rsp);
} else
@@ -2495,6 +2526,84 @@
}
#endif
+#if defined(__amd64__)
+
+#define INTEL_PT_KW_BRANCHES "branches"
+#define INTEL_PT_KW_TSC "tsc"
+#define INTEL_PT_KW_MTC "mtc"
+#define INTEL_PT_KW_DISRETC "disretc"
+#define INTEL_PT_KW_ADDRA "addra"
+#define INTEL_PT_KW_ADDRB "addrb"
+
+static int
+pt_allocate_pmc(enum pmc_event pe, char *ctrspec,
+ struct pmc_op_pmcallocate *pmc_config)
+{
+ struct pmc_md_pt_op_pmcallocate *pm_pt;
+ uint64_t addr;
+ uint32_t addrn;
+ char *p, *q, *e;
+
+ if (pe != PMC_EV_PT_PT)
+ return (-1);
+
+ pm_pt = (struct pmc_md_pt_op_pmcallocate *)&pmc_config->pm_md.pm_pt;
+
+ addrn = 0;
+ while ((p = strsep(&ctrspec, ",")) != NULL) {
+ if (KWMATCH(p, INTEL_PT_KW_BRANCHES)) {
+ pm_pt->flags |= INTEL_PT_FLAG_BRANCHES;
+ }
+
+ if (KWMATCH(p, INTEL_PT_KW_TSC)) {
+ pm_pt->flags |= INTEL_PT_FLAG_TSC;
+ }
+
+ if (KWMATCH(p, INTEL_PT_KW_MTC)) {
+ pm_pt->flags |= INTEL_PT_FLAG_MTC;
+ }
+
+ if (KWMATCH(p, INTEL_PT_KW_DISRETC)) {
+ pm_pt->flags |= INTEL_PT_FLAG_DISRETC;
+ }
+
+ if (KWPREFIXMATCH(p, INTEL_PT_KW_ADDRA "=")) {
+ q = strchr(p, '=');
+ if (*++q == '\0') /* skip '=' */
+ return (-1);
+
+ addr = strtoul(q, &e, 0);
+ if (e == q || *e != '\0')
+ return (-1);
+ pm_pt->ranges[addrn * 2] = addr;
+ }
+
+ if (KWPREFIXMATCH(p, INTEL_PT_KW_ADDRB "=")) {
+ q = strchr(p, '=');
+ if (*++q == '\0') /* skip '=' */
+ return (-1);
+
+ addr = strtoul(q, &e, 0);
+ if (e == q || *e != '\0')
+ return (-1);
+ pm_pt->ranges[addrn * 2 + 1] = addr;
+
+ if (pm_pt->ranges[addrn * 2 + 1] < pm_pt->ranges[addrn * 2])
+ return (-1);
+ addrn += 1;
+ if (addrn > PT_NADDR)
+ return (-1);
+ }
+ };
+
+ pm_pt->nranges = addrn;
+
+ pmc_config->pm_caps |= PMC_CAP_READ;
+
+ return (0);
+}
+#endif
+
static struct pmc_event_alias generic_aliases[] = {
EV_ALIAS("instructions", "SOFT-CLOCK.HARD"),
EV_ALIAS(NULL, NULL)
@@ -2583,6 +2692,61 @@
return (0);
}
+
+#define ARM_CORESIGHT_KW_ADDRA "addra"
+#define ARM_CORESIGHT_KW_ADDRB "addrb"
+
+static int
+coresight_allocate_pmc(enum pmc_event pe, char *ctrspec,
+ struct pmc_op_pmcallocate *pmc_config)
+{
+ struct pmc_md_coresight_op_pmcallocate *pm_coresight;
+ uint64_t addr;
+ uint32_t addrn;
+ char *p, *q, *e;
+
+ if (pe != PMC_EV_CORESIGHT_CORESIGHT)
+ return (-1);
+
+ pm_coresight = (struct pmc_md_coresight_op_pmcallocate *)&pmc_config->pm_md.pm_coresight;
+
+ addrn = 0;
+ while ((p = strsep(&ctrspec, ",")) != NULL) {
+ if (KWPREFIXMATCH(p, ARM_CORESIGHT_KW_ADDRA "=")) {
+ q = strchr(p, '=');
+ if (*++q == '\0') /* skip '=' */
+ return (-1);
+
+ addr = strtoul(q, &e, 0);
+ if (e == q || *e != '\0')
+ return (-1);
+ pm_coresight->ranges[addrn * 2] = addr;
+ }
+
+ if (KWPREFIXMATCH(p, ARM_CORESIGHT_KW_ADDRB "=")) {
+ q = strchr(p, '=');
+ if (*++q == '\0') /* skip '=' */
+ return (-1);
+
+ addr = strtoul(q, &e, 0);
+ if (e == q || *e != '\0')
+ return (-1);
+ pm_coresight->ranges[addrn * 2 + 1] = addr;
+
+ if (pm_coresight->ranges[addrn * 2 + 1] < pm_coresight->ranges[addrn * 2])
+ return (-1);
+ addrn += 1;
+ if (addrn > CORESIGHT_NADDR)
+ return (-1);
+ }
+ };
+
+ pm_coresight->nranges = addrn;
+
+ pmc_config->pm_caps |= PMC_CAP_READ;
+
+ return (0);
+}
#endif
#if defined(__mips__)
@@ -2780,7 +2944,8 @@
retval = -1;
if (mode != PMC_MODE_SS && mode != PMC_MODE_TS &&
- mode != PMC_MODE_SC && mode != PMC_MODE_TC) {
+ mode != PMC_MODE_SC && mode != PMC_MODE_TC &&
+ mode != PMC_MODE_ST && mode != PMC_MODE_TT) {
errno = EINVAL;
goto out;
}
@@ -2903,6 +3068,7 @@
int
pmc_cpuinfo(const struct pmc_cpuinfo **pci)
{
+
if (pmc_syscall == -1) {
errno = ENXIO;
return (-1);
@@ -3023,6 +3189,10 @@
ev = skylake_xeon_event_table;
count = PMC_EVENT_TABLE_SIZE(skylake_xeon);
break;
+ case PMC_CPU_INTEL_KABYLAKE:
+ ev = kabylake_event_table;
+ count = PMC_EVENT_TABLE_SIZE(kabylake);
+ break;
case PMC_CPU_INTEL_IVYBRIDGE:
ev = ivybridge_event_table;
count = PMC_EVENT_TABLE_SIZE(ivybridge);
@@ -3086,6 +3256,10 @@
ev = tsc_event_table;
count = PMC_EVENT_TABLE_SIZE(tsc);
break;
+ case PMC_CLASS_PT:
+ ev = pt_event_table;
+ count = PMC_EVENT_TABLE_SIZE(pt);
+ break;
case PMC_CLASS_K7:
ev = k7_event_table;
count = PMC_EVENT_TABLE_SIZE(k7);
@@ -3136,6 +3310,10 @@
break;
}
break;
+ case PMC_CLASS_CORESIGHT:
+ ev = coresight_event_table;
+ count = PMC_EVENT_TABLE_SIZE(coresight);
+ break;
case PMC_CLASS_MIPS24K:
ev = mips24k_event_table;
count = PMC_EVENT_TABLE_SIZE(mips24k);
@@ -3184,12 +3362,14 @@
int
pmc_flush_logfile(void)
{
+
return (PMC_CALL(FLUSHLOG,0));
}
int
pmc_close_logfile(void)
{
+
return (PMC_CALL(CLOSELOG,0));
}
@@ -3406,6 +3586,12 @@
case PMC_CPU_INTEL_SKYLAKE_XEON:
PMC_MDEP_INIT_INTEL_V2(skylake_xeon);
break;
+ case PMC_CPU_INTEL_KABYLAKE:
+#if defined(__amd64__)
+ pmc_class_table[n++] = &pt_class_table_descr;
+#endif
+ PMC_MDEP_INIT_INTEL_V2(kabylake);
+ break;
case PMC_CPU_INTEL_IVYBRIDGE:
PMC_MDEP_INIT_INTEL_V2(ivybridge);
break;
@@ -3455,11 +3641,13 @@
#if defined(__aarch64__)
case PMC_CPU_ARMV8_CORTEX_A53:
PMC_MDEP_INIT(cortex_a53);
- pmc_class_table[n] = &cortex_a53_class_table_descr;
+ pmc_class_table[n++] = &cortex_a53_class_table_descr;
+ pmc_class_table[n++] = &coresight_class_table_descr;
break;
case PMC_CPU_ARMV8_CORTEX_A57:
PMC_MDEP_INIT(cortex_a57);
- pmc_class_table[n] = &cortex_a57_class_table_descr;
+ pmc_class_table[n++] = &cortex_a57_class_table_descr;
+ pmc_class_table[n++] = &coresight_class_table_descr;
break;
#endif
#if defined(__mips__)
@@ -3623,6 +3811,11 @@
evfence = skylake_xeon_event_table +
PMC_EVENT_TABLE_SIZE(skylake_xeon);
break;
+ case PMC_CPU_INTEL_KABYLAKE:
+ ev = kabylake_event_table;
+ evfence = kabylake_event_table +
+ PMC_EVENT_TABLE_SIZE(kabylake);
+ break;
case PMC_CPU_INTEL_IVYBRIDGE:
ev = ivybridge_event_table;
evfence = ivybridge_event_table + PMC_EVENT_TABLE_SIZE(ivybridge);
@@ -3715,6 +3908,9 @@
default: /* Unknown CPU type. */
break;
}
+ } else if (pe == PMC_EV_CORESIGHT_CORESIGHT) {
+ ev = coresight_event_table;
+ evfence = coresight_event_table + PMC_EVENT_TABLE_SIZE(coresight);
} else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) {
ev = mips24k_event_table;
evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k);
@@ -3736,6 +3932,9 @@
} else if (pe == PMC_EV_TSC_TSC) {
ev = tsc_event_table;
evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc);
+ } else if (pe == PMC_EV_PT_PT) {
+ ev = pt_event_table;
+ evfence = pt_event_table + PMC_EVENT_TABLE_SIZE(pt);
} else if ((int)pe >= PMC_EV_SOFT_FIRST && (int)pe <= PMC_EV_SOFT_LAST) {
ev = soft_event_table;
evfence = soft_event_table + soft_event_info.pm_nevent;
@@ -3852,6 +4051,68 @@
return (0);
}
+int
+pmc_proc_unsuspend(pmc_id_t pmc, pid_t pid)
+{
+ struct pmc_op_proc_unsuspend u;
+
+ u.pm_pmcid = pmc;
+ u.pm_pid = pid;
+
+ return (PMC_CALL(THREAD_UNSUSPEND, &u));
+}
+
+int
+pmc_read_trace(uint32_t cpu, pmc_id_t pmc,
+ pmc_value_t *cycle, pmc_value_t *offset)
+{
+ struct pmc_op_trace_read pmc_trace_read;
+
+ pmc_trace_read.pm_pmcid = pmc;
+ pmc_trace_read.pm_cpu = cpu;
+ pmc_trace_read.pm_cycle = 0;
+ pmc_trace_read.pm_offset = 0;
+
+ if (PMC_CALL(TRACE_READ, &pmc_trace_read) < 0)
+ return (-1);
+
+ *cycle = pmc_trace_read.pm_cycle;
+ *offset = pmc_trace_read.pm_offset;
+
+ return (0);
+}
+
+int
+pmc_trace_config(uint32_t cpu, pmc_id_t pmc,
+ uint64_t *ranges, uint32_t nranges)
+{
+ struct pmc_op_trace_config trc;
+
+ trc.pm_pmcid = pmc;
+ trc.pm_cpu = cpu;
+ trc.nranges = nranges;
+
+ if (nranges > PMC_FILTER_MAX_IP_RANGES)
+ return (-1);
+
+ memcpy(&trc.ranges, ranges, sizeof(uint64_t) * 2 * nranges);
+
+ if (PMC_CALL(TRACE_CONFIG, &trc) < 0)
+ return (-1);
+
+ return (0);
+}
+
+int
+pmc_log_kmap(pmc_id_t pmc)
+{
+ struct pmc_op_simple pmc_log_km;
+
+ pmc_log_km.pm_pmcid = pmc;
+
+ return (PMC_CALL(LOG_KERNEL_MAP, &pmc_log_km));
+}
+
int
pmc_release(pmc_id_t pmc)
{
Index: lib/libpmc/pmc.h
===================================================================
--- lib/libpmc/pmc.h
+++ lib/libpmc/pmc.h
@@ -77,6 +77,7 @@
int pmc_allocate(const char *_ctrspec, enum pmc_mode _mode, uint32_t _flags,
int _cpu, pmc_id_t *_pmcid);
int pmc_attach(pmc_id_t _pmcid, pid_t _pid);
+int pmc_proc_unsuspend(pmc_id_t pmc, pid_t pid);
int pmc_capabilities(pmc_id_t _pmc, uint32_t *_caps);
int pmc_configure_logfile(int _fd);
int pmc_flush_logfile(void);
@@ -88,7 +89,10 @@
int pmc_get_msr(pmc_id_t _pmc, uint32_t *_msr);
int pmc_init(void);
int pmc_read(pmc_id_t _pmc, pmc_value_t *_value);
+int pmc_read_trace(uint32_t cpu, pmc_id_t pmc, pmc_value_t *cycle, pmc_value_t *offset);
+int pmc_trace_config(uint32_t cpu, pmc_id_t pmc, uint64_t *ranges, uint32_t nranges);
int pmc_release(pmc_id_t _pmc);
+int pmc_log_kmap(pmc_id_t pmc);
int pmc_rw(pmc_id_t _pmc, pmc_value_t _newvalue, pmc_value_t *_oldvalue);
int pmc_set(pmc_id_t _pmc, pmc_value_t _value);
int pmc_start(pmc_id_t _pmc);
Index: lib/libpmcstat/libpmcstat_image.c
===================================================================
--- lib/libpmcstat/libpmcstat_image.c
+++ lib/libpmcstat/libpmcstat_image.c
@@ -386,6 +386,21 @@
break;
}
}
+ } else if (eh.e_type == ET_DYN) {
+ for (i = 0; i < eh.e_phnum; i++) {
+ if (gelf_getphdr(e, i, &ph) != &ph) {
+ warnx(
+"WARNING: Retrieval of PHDR entry #%ju in \"%s\" failed: %s.",
+ (uintmax_t) i, buffer, elf_errmsg(-1));
+ goto done;
+ }
+ switch (ph.p_type) {
+ case PT_LOAD:
+ if ((ph.p_flags & PF_X) != 0)
+ image->pi_vaddr = ph.p_vaddr & (-ph.p_align);
+ break;
+ }
+ }
}
/*
Index: sys/amd64/include/pmc_mdep.h
===================================================================
--- sys/amd64/include/pmc_mdep.h
+++ sys/amd64/include/pmc_mdep.h
@@ -45,6 +45,7 @@
#include <dev/hwpmc/hwpmc_core.h>
#include <dev/hwpmc/hwpmc_piv.h>
#include <dev/hwpmc/hwpmc_tsc.h>
+#include <dev/hwpmc/hwpmc_pt.h>
#include <dev/hwpmc/hwpmc_uncore.h>
/*
@@ -57,6 +58,7 @@
#define PMC_MDEP_CLASS_INDEX_P4 2
#define PMC_MDEP_CLASS_INDEX_IAP 2
#define PMC_MDEP_CLASS_INDEX_IAF 3
+#define PMC_MDEP_CLASS_INDEX_PT 4
#define PMC_MDEP_CLASS_INDEX_UCP 4
#define PMC_MDEP_CLASS_INDEX_UCF 5
@@ -70,6 +72,7 @@
* IAF Intel fixed-function PMCs in Core2 and later CPUs.
* UCP Intel Uncore programmable PMCs.
* UCF Intel Uncore fixed-function PMCs.
+ * PT Intel PT event.
*/
union pmc_md_op_pmcallocate {
@@ -79,7 +82,8 @@
struct pmc_md_ucf_op_pmcallocate pm_ucf;
struct pmc_md_ucp_op_pmcallocate pm_ucp;
struct pmc_md_p4_op_pmcallocate pm_p4;
- uint64_t __pad[4];
+ struct pmc_md_pt_op_pmcallocate pm_pt;
+ uint64_t __pad[1];
};
/* Logging */
@@ -95,6 +99,7 @@
struct pmc_md_ucf_pmc pm_ucf;
struct pmc_md_ucp_pmc pm_ucp;
struct pmc_md_p4_pmc pm_p4;
+ struct pmc_md_pt_pmc pm_pt;
};
#define PMC_TRAPFRAME_TO_PC(TF) ((TF)->tf_rip)
Index: sys/arm64/coresight/coresight-cmd.c
===================================================================
--- /dev/null
+++ sys/arm64/coresight/coresight-cmd.c
@@ -0,0 +1,167 @@
+/*-
+ * Copyright (c) 2018 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
+ * ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+
+#include <arm64/coresight/coresight.h>
+
+extern struct coresight_device_list cs_devs;
+
+#define CORESIGHT_DISABLE 0
+#define CORESIGHT_ENABLE 1
+#define CORESIGHT_READ 2
+
+static struct coresight_device *
+coresight_next_device(struct coresight_device *cs_dev,
+ struct coresight_event *event)
+{
+ struct coresight_device *out;
+ struct endpoint *out_endp;
+ struct endpoint *endp;
+
+ TAILQ_FOREACH(endp, &cs_dev->pdata->endpoints, link) {
+ if (endp->slave != 0)
+ continue;
+
+ out = coresight_get_output_device(endp, &out_endp);
+ if (out) {
+ if (LIST_EMPTY(&event->endplist)) {
+ /* Add source device */
+ endp->cs_dev = cs_dev;
+ LIST_INSERT_HEAD(&event->endplist, endp, endplink);
+ }
+
+ /* Add output device */
+ out_endp->cs_dev = out;
+ LIST_INSERT_HEAD(&event->endplist, out_endp, endplink);
+
+ return (out);
+ }
+ }
+
+ return (NULL);
+}
+
+static int
+coresight_build_list(struct coresight_device *cs_dev,
+ struct coresight_event *event)
+{
+ struct coresight_device *out;
+
+ out = cs_dev;
+ while (out)
+ out = coresight_next_device(out, event);
+
+ return (0);
+}
+
+int
+coresight_init_event(int cpu, struct coresight_event *event)
+{
+ struct coresight_device *cs_dev;
+
+ /* Start building path from source device */
+ TAILQ_FOREACH(cs_dev, &cs_devs, link) {
+ if (cs_dev->dev_type == event->src &&
+ cs_dev->pdata->cpu == cpu) {
+ LIST_INIT(&event->endplist);
+ coresight_build_list(cs_dev, event);
+ break;
+ }
+ }
+
+ return (0);
+}
+
+static int
+coresight_cmd_one(struct coresight_device *out,
+ struct endpoint *out_endp, struct coresight_event *event, uint8_t cmd)
+{
+
+ switch (cmd) {
+ case CORESIGHT_DISABLE:
+ if (out->ops->disable == NULL)
+ break;
+ out->ops->disable(out, out_endp, event);
+ break;
+ case CORESIGHT_ENABLE:
+ if (out->ops->enable == NULL)
+ break;
+ out->ops->enable(out, out_endp, event);
+ break;
+ case CORESIGHT_READ:
+ if (out->ops->read == NULL)
+ break;
+ out->ops->read(out, out_endp, event);
+ break;
+ };
+
+ return (0);
+}
+
+
+static void
+coresight_cmd(int cpu, struct coresight_event *event, uint8_t cmd)
+{
+ struct endpoint *endp;
+
+ LIST_FOREACH(endp, &event->endplist, endplink)
+ coresight_cmd_one(endp->cs_dev, endp, event, cmd);
+}
+
+void
+coresight_enable(int cpu, struct coresight_event *event)
+{
+
+ coresight_cmd(cpu, event, CORESIGHT_ENABLE);
+}
+
+void
+coresight_disable(int cpu, struct coresight_event *event)
+{
+
+ coresight_cmd(cpu, event, CORESIGHT_DISABLE);
+}
+
+void
+coresight_read(int cpu, struct coresight_event *event)
+{
+
+ coresight_cmd(cpu, event, CORESIGHT_READ);
+}
Index: sys/arm64/coresight/coresight-cpu-debug.c
===================================================================
--- /dev/null
+++ sys/arm64/coresight/coresight-cpu-debug.c
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 2018 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm64/coresight/coresight.h>
+
+#define EDPCSR 0x0a0
+#define EDCIDSR 0x0a4
+#define EDVIDSR 0x0a8
+#define EDPCSR_HI 0x0ac
+#define EDOSLAR 0x300
+#define EDPRCR 0x310
+#define EDPRCR_COREPURQ (1 << 3)
+#define EDPRCR_CORENPDRQ (1 << 0)
+#define EDPRSR 0x314
+#define EDDEVID1 0xfc4
+#define EDDEVID 0xfc8
+
+static struct ofw_compat_data compat_data[] = {
+ { "arm,coresight-cpu-debug", 1 },
+ { NULL, 0 }
+};
+
+struct debug_softc {
+ struct resource *res;
+};
+
+static struct resource_spec debug_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE },
+ { -1, 0 }
+};
+
+static int
+debug_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+ return (ENXIO);
+
+ device_set_desc(dev, "Coresight CPU Debug");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+debug_attach(device_t dev)
+{
+ struct debug_softc *sc;
+ uint32_t reg;
+
+ sc = device_get_softc(dev);
+
+ if (bus_alloc_resources(dev, debug_spec, &sc->res) != 0) {
+ device_printf(dev, "cannot allocate resources for device\n");
+ return (ENXIO);
+ }
+
+ /* Enable CPU debug for current CPU only */
+ if (device_get_unit(dev) != 0)
+ return (0);
+
+ /* Unlock Coresight */
+ bus_write_4(sc->res, CORESIGHT_LAR, CORESIGHT_UNLOCK);
+
+ wmb();
+
+ /* Unlock Debug */
+ bus_write_4(sc->res, EDOSLAR, 0);
+
+ wmb();
+
+ /* Enable power */
+ reg = bus_read_4(sc->res, EDPRCR);
+ reg |= EDPRCR_COREPURQ;
+ bus_write_4(sc->res, EDPRCR, reg);
+
+ do {
+ reg = bus_read_4(sc->res, EDPRSR);
+ } while ((reg & EDPRCR_CORENPDRQ) == 0);
+
+ return (0);
+}
+
+static device_method_t debug_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, debug_probe),
+ DEVMETHOD(device_attach, debug_attach),
+ DEVMETHOD_END
+};
+
+static driver_t debug_driver = {
+ "debug",
+ debug_methods,
+ sizeof(struct debug_softc),
+};
+
+static devclass_t debug_devclass;
+
+EARLY_DRIVER_MODULE(debug, simplebus, debug_driver, debug_devclass,
+ 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_LATE);
+MODULE_VERSION(debug, 1);
Index: sys/arm64/coresight/coresight-dynamic-replicator.c
===================================================================
--- /dev/null
+++ sys/arm64/coresight/coresight-dynamic-replicator.c
@@ -0,0 +1,164 @@
+/*-
+ * Copyright (c) 2018 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+
+#include <arm64/coresight/coresight.h>
+
+#define REPLICATOR_IDFILTER0 0x00
+#define REPLICATOR_IDFILTER1 0x04
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+static struct ofw_compat_data compat_data[] = {
+ { "arm,coresight-dynamic-replicator", 1 },
+ { NULL, 0 }
+};
+
+struct replicator_softc {
+ struct resource *res;
+ struct coresight_platform_data *pdata;
+};
+
+static struct resource_spec replicator_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE },
+ { -1, 0 }
+};
+
+static int
+replicator_enable(struct coresight_device *out, struct endpoint *endp,
+ struct coresight_event *event)
+{
+ struct replicator_softc *sc;
+
+ sc = device_get_softc(out->dev);
+
+ /* Enable the port. Keep the other port disabled */
+
+ if (endp->reg == 0) {
+ bus_write_4(sc->res, REPLICATOR_IDFILTER0, 0x00);
+ bus_write_4(sc->res, REPLICATOR_IDFILTER1, 0xff);
+ } else {
+ bus_write_4(sc->res, REPLICATOR_IDFILTER0, 0xff);
+ bus_write_4(sc->res, REPLICATOR_IDFILTER1, 0x00);
+ }
+
+ return (0);
+}
+
+static void
+replicator_disable(struct coresight_device *out, struct endpoint *endp,
+ struct coresight_event *event)
+{
+ struct replicator_softc *sc;
+
+ sc = device_get_softc(out->dev);
+
+ bus_write_4(sc->res, REPLICATOR_IDFILTER0, 0xff);
+ bus_write_4(sc->res, REPLICATOR_IDFILTER1, 0xff);
+}
+
+static struct coresight_ops ops = {
+ .enable = &replicator_enable,
+ .disable = &replicator_disable,
+};
+
+static int
+replicator_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+ return (ENXIO);
+
+ device_set_desc(dev, "Coresight Dynamic Replicator");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+replicator_attach(device_t dev)
+{
+ struct replicator_softc *sc;
+ struct coresight_desc desc;
+
+ sc = device_get_softc(dev);
+
+ if (bus_alloc_resources(dev, replicator_spec, &sc->res) != 0) {
+ device_printf(dev, "cannot allocate resources for device\n");
+ return (ENXIO);
+ }
+
+ sc->pdata = coresight_get_platform_data(dev);
+
+ desc.pdata = sc->pdata;
+ desc.dev = dev;
+ desc.dev_type = CORESIGHT_DYNAMIC_REPLICATOR;
+ desc.ops = &ops;
+ coresight_register(&desc);
+
+ /* Unlock Coresight */
+ bus_write_4(sc->res, CORESIGHT_LAR, CORESIGHT_UNLOCK);
+
+ wmb();
+
+ return (0);
+}
+
+static device_method_t replicator_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, replicator_probe),
+ DEVMETHOD(device_attach, replicator_attach),
+ DEVMETHOD_END
+};
+
+static driver_t replicator_driver = {
+ "replicator",
+ replicator_methods,
+ sizeof(struct replicator_softc),
+};
+
+static devclass_t replicator_devclass;
+
+DRIVER_MODULE(replicator, simplebus, replicator_driver, replicator_devclass, 0, 0);
+MODULE_VERSION(replicator, 1);
Index: sys/arm64/coresight/coresight-etm4x.h
===================================================================
--- /dev/null
+++ sys/arm64/coresight/coresight-etm4x.h
@@ -0,0 +1,169 @@
+/*-
+ * Copyright (c) 2018 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ARM64_CORESIGHT_ETM4X_H_
+#define _ARM64_CORESIGHT_ETM4X_H_
+
+#define TRCPRGCTLR 0x004 /* Trace Programming Control Register */
+#define TRCPRGCTLR_EN (1 << 0) /* Trace unit enable bit */
+#define TRCPROCSELR 0x008 /* Trace PE Select Control Register */
+#define TRCSTATR 0x00C /* Trace Trace Status Register */
+#define TRCSTATR_PMSTABLE (1 << 1) /* The programmers' model is stable. */
+#define TRCSTATR_IDLE (1 << 0) /* The trace unit is idle. */
+#define TRCCONFIGR 0x010 /* Trace Trace Configuration Register */
+#define TRCCONFIGR_DV (1 << 17) /* Data value tracing is enabled when INSTP0 is not 0b00 */
+#define TRCCONFIGR_DA (1 << 16) /* Data address tracing is enabled when INSTP0 is not 0b00. */
+#define TRCCONFIGR_VMIDOPT (1 << 15) /* Control bit to configure the Virtual context identifier value */
+#define TRCCONFIGR_QE_S 13 /* Q element enable field */
+#define TRCCONFIGR_QE_M (0x3 << TRCCONFIGR_QE_S)
+#define TRCCONFIGR_RS (1 << 12) /* Return stack enable bit */
+#define TRCCONFIGR_TS (1 << 11) /* Global timestamp tracing is enabled. */
+#define TRCCONFIGR_COND_S 8 /* Conditional instruction tracing bit. */
+#define TRCCONFIGR_COND_M (0x7 << TRCCONFIGR_COND_S)
+#define TRCCONFIGR_COND_DIS 0
+#define TRCCONFIGR_COND_LDR (1 << TRCCONFIGR_COND_S) /* Conditional load instructions are traced. */
+#define TRCCONFIGR_COND_STR (2 << TRCCONFIGR_COND_S) /* Conditional store instructions are traced. */
+#define TRCCONFIGR_COND_LDRSTR (3 << TRCCONFIGR_COND_S) /* Conditional load and store instructions are traced. */
+#define TRCCONFIGR_COND_ALL (7 << TRCCONFIGR_COND_S) /* All conditional instructions are traced. */
+#define TRCCONFIGR_VMID (1 << 7) /* Virtual context identifier tracing is enabled. */
+#define TRCCONFIGR_CID (1 << 6) /* Context ID tracing is enabled. */
+#define TRCCONFIGR_CCI (1 << 4) /* Cycle counting in the instruction trace is enabled. */
+#define TRCCONFIGR_BB (1 << 3) /* Branch broadcast mode is enabled. */
+#define TRCCONFIGR_INSTP0_S 1 /* Instruction P0 field. */
+#define TRCCONFIGR_INSTP0_M (0x3 << TRCCONFIGR_INSTP0_S)
+#define TRCCONFIGR_INSTP0_NONE 0 /* Do not trace load and store instructions as P0 instructions. */
+#define TRCCONFIGR_INSTP0_LDR (1 << TRCCONFIGR_INSTP0_S) /* Trace load instructions as P0 instructions. */
+#define TRCCONFIGR_INSTP0_STR (2 << TRCCONFIGR_INSTP0_S) /* Trace store instructions as P0 instructions. */
+#define TRCCONFIGR_INSTP0_LDRSTR (3 << TRCCONFIGR_INSTP0_S) /* Trace load and store instructions as P0 instr. */
+#define TRCAUXCTLR 0x018 /* Trace Auxiliary Control Register */
+#define TRCEVENTCTL0R 0x020 /* Trace Event Control 0 Register */
+#define TRCEVENTCTL1R 0x024 /* Trace Event Control 1 Register */
+#define TRCSTALLCTLR 0x02C /* Trace Stall Control Register */
+#define TRCTSCTLR 0x030 /* Trace Global Timestamp Control Register */
+#define TRCSYNCPR 0x034 /* Trace Synchronization Period Register */
+#define TRCCCCTLR 0x038 /* Trace Cycle Count Control Register */
+#define TRCBBCTLR 0x03C /* Trace Branch Broadcast Control Register */
+#define TRCTRACEIDR 0x040 /* Trace Trace ID Register */
+#define TRCQCTLR 0x044 /* Trace Q Element Control Register */
+#define TRCQCTLR_MODE_INC (1 << 8) /* Include mode. */
+#define TRCVICTLR 0x080 /* Trace ViewInst Main Control Register */
+#define TRCVICTLR_SSSTATUS (1 << 9) /* The start/stop logic is in the started state. */
+#define TRCVICTLR_EXLEVEL_NS_S 20
+#define TRCVICTLR_EXLEVEL_NS_M (0xf << TRCVICTLR_EXLEVEL_NS_S)
+#define TRCVICTLR_EXLEVEL_NS(n) (0x1 << ((n) + TRCVICTLR_EXLEVEL_NS_S))
+#define TRCVICTLR_EXLEVEL_S_S 16
+#define TRCVICTLR_EXLEVEL_S_M (0xf << TRCVICTLR_EXLEVEL_S_S)
+#define TRCVICTLR_EXLEVEL_S(n) (0x1 << ((n) + TRCVICTLR_EXLEVEL_S_S))
+#define EVENT_SEL_S 0
+#define EVENT_SEL_M (0x1f << EVENT_SEL_S)
+#define TRCVIIECTLR 0x084 /* Trace ViewInst Include/Exclude Control Register */
+#define TRCVISSCTLR 0x088 /* Trace ViewInst Start/Stop Control Register */
+#define TRCVIPCSSCTLR 0x08C /* Trace ViewInst Start/Stop PE Comparator Control Register */
+#define TRCVDCTLR 0x0A0 /* Trace ViewData Main Control Register */
+#define TRCVDCTLR_TRCEXDATA (1 << 12) /* Exception and exception return data transfers are traced */
+#define TRCVDCTLR_TBI (1 << 11) /* The trace unit assigns bits[63:56] to have the same value as bits[63:56] of the data address. */
+#define TRCVDCTLR_PCREL (1 << 10) /* The trace unit does not trace the address or value portions of PC-relative transfers. */
+#define TRCVDCTLR_SPREL_S 8
+#define TRCVDCTLR_SPREL_M (0x3 << TRCVDCTLR_SPREL_S)
+#define TRCVDCTLR_EVENT_S 0
+#define TRCVDCTLR_EVENT_M (0xff << TRCVDCTLR_EVENT_S)
+#define TRCVDSACCTLR 0x0A4 /* Trace ViewData Include/Exclude Single Address Comparator Control Register */
+#define TRCVDARCCTLR 0x0A8 /* Trace ViewData Include/Exclude Address Range Comparator Control Register */
+#define TRCSEQEVR(n) (0x100 + (n) * 0x4) /* Trace Sequencer State Transition Control Register [n=0-2] */
+#define TRCSEQRSTEVR 0x118 /* Trace Sequencer Reset Control Register */
+#define TRCSEQSTR 0x11C /* Trace Sequencer State Register */
+#define TRCEXTINSELR 0x120 /* Trace External Input Select Register */
+#define TRCCNTRLDVR(n) (0x140 + (n) * 0x4) /* 32 Trace Counter Reload Value Register [n=0-3] */
+#define TRCCNTCTLR(n) (0x150 + (n) * 0x4) /* 32 Trace Counter Control Register [n=0-3] */
+#define TRCCNTVR(n) (0x160 + (n) * 0x4) /* 32 Trace Counter Value Register [n=0-3] */
+#define TRCIMSPEC(n) (0x1C0 + (n) * 0x4) /* Trace IMPLEMENTATION DEFINED register [n=0-7] */
+
+#define TRCIDR0(n) (0x1E0 + 0x4 * (n))
+#define TRCIDR8(n) (0x180 + 0x4 * (n))
+#define TRCIDR(n) ((n > 7) ? TRCIDR8(n) : TRCIDR0(n))
+#define TRCIDR1_TRCARCHMAJ_S 8
+#define TRCIDR1_TRCARCHMAJ_M (0xf << TRCIDR1_TRCARCHMAJ_S)
+#define TRCIDR1_TRCARCHMIN_S 4
+#define TRCIDR1_TRCARCHMIN_M (0xf << TRCIDR1_TRCARCHMIN_S)
+
+#define TRCRSCTLR(n) (0x200 + (n) * 0x4) /* Trace Resource Selection Control Register [n=2-31] */
+#define TRCSSCCR(n) (0x280 + (n) * 0x4) /* Trace Single-shot Comparator Control Register [n=0-7] */
+#define TRCSSCSR(n) (0x2A0 + (n) * 0x4) /* Trace Single-shot Comparator Status Register [n=0-7] */
+#define TRCSSPCICR(n) (0x2C0 + (n) * 0x4) /* Trace Single-shot PE Comparator Input Control [n=0-7] */
+#define TRCOSLAR 0x300 /* Management OS Lock Access Register */
+#define TRCOSLSR 0x304 /* Management OS Lock Status Register */
+#define TRCPDCR 0x310 /* Management PowerDown Control Register */
+#define TRCPDSR 0x314 /* Management PowerDown Status Register */
+#define TRCACVR(n) (0x400 + (n) * 0x8) /* Trace Address Comparator Value Register [n=0-15] */
+#define TRCACATR(n) (0x480 + (n) * 0x8) /* Trace Address Comparator Access Type Register [n=0-15] */
+#define TRCACATR_DTBM (1 << 21)
+#define TRCACATR_DATARANGE (1 << 20)
+#define TRCACATR_DATASIZE_S 18
+#define TRCACATR_DATASIZE_M (0x3 << TRCACATR_DATASIZE_S)
+#define TRCACATR_DATASIZE_B (0x0 << TRCACATR_DATASIZE_S)
+#define TRCACATR_DATASIZE_HW (0x1 << TRCACATR_DATASIZE_S)
+#define TRCACATR_DATASIZE_W (0x2 << TRCACATR_DATASIZE_S)
+#define TRCACATR_DATASIZE_DW (0x3 << TRCACATR_DATASIZE_S)
+#define TRCACATR_DATAMATCH_S 16
+#define TRCACATR_DATAMATCH_M (0x3 << TRCACATR_DATAMATCH_S)
+#define TRCACATR_EXLEVEL_S_S 8
+#define TRCACATR_EXLEVEL_S_M (0xf << TRCACATR_EXLEVEL_S_S)
+#define TRCACATR_EXLEVEL_S(n) (0x1 << ((n) + TRCACATR_EXLEVEL_S_S))
+#define TRCACATR_EXLEVEL_NS_S 12
+#define TRCACATR_EXLEVEL_NS_M (0xf << TRCACATR_EXLEVEL_NS_S)
+#define TRCACATR_EXLEVEL_NS(n) (0x1 << ((n) + TRCACATR_EXLEVEL_NS_S))
+#define TRCDVCVR(n) (0x500 + (n) * 0x8) /* Trace Data Value Comparator Value Register [n=0-7] */
+#define TRCDVCMR(n) (0x580 + (n) * 0x8) /* Trace Data Value Comparator Mask Register [n=0-7] */
+#define TRCCIDCVR(n) (0x600 + (n) * 0x8) /* Trace Context ID Comparator Value Register [n=0-7] */
+#define TRCVMIDCVR(n) (0x640 + (n) * 0x8) /* Trace Virtual context identifier Comparator Value [n=0-7] */
+#define TRCCIDCCTLR0 0x680 /* Trace Context ID Comparator Control Register 0 */
+#define TRCCIDCCTLR1 0x684 /* Trace Context ID Comparator Control Register 1 */
+#define TRCVMIDCCTLR0 0x688 /* Trace Virtual context identifier Comparator Control Register 0 */
+#define TRCVMIDCCTLR1 0x68C /* Trace Virtual context identifier Comparator Control Register 1 */
+#define TRCITCTRL 0xF00 /* Management Integration Mode Control register */
+#define TRCCLAIMSET 0xFA0 /* Trace Claim Tag Set register */
+#define TRCCLAIMCLR 0xFA4 /* Trace Claim Tag Clear register */
+#define TRCDEVAFF0 0xFA8 /* Management Device Affinity register 0 */
+#define TRCDEVAFF1 0xFAC /* Management Device Affinity register 1 */
+#define TRCLAR 0xFB0 /* Management Software Lock Access Register */
+#define TRCLSR 0xFB4 /* Management Software Lock Status Register */
+#define TRCAUTHSTATUS 0xFB8 /* Management Authentication Status register */
+#define TRCDEVARCH 0xFBC /* Management Device Architecture register */
+#define TRCDEVID 0xFC8 /* Management Device ID register */
+#define TRCDEVTYPE 0xFCC /* Management Device Type register */
+#define TRCPIDR4 0xFD0 /* Management Peripheral ID4 Register */
+#define TRCPIDR(n) (0xFE0 + (n) * 0x4) /* Management Peripheral IDn Register [n=0-3] */
+#define TRCPIDR567(n) (0xFD4 + ((n) - 5) * 0x4) /* Management Peripheral ID5 to Peripheral ID7 Registers */
+#define TRCCIDR(n) (0xFF0 + (n) * 0x4) /* Management Component IDn Register [n=0-4] */
+
+#endif /* !_ARM64_CORESIGHT_ETM4X_H_ */
Index: sys/arm64/coresight/coresight-etm4x.c
===================================================================
--- /dev/null
+++ sys/arm64/coresight/coresight-etm4x.c
@@ -0,0 +1,308 @@
+/*-
+ * Copyright (c) 2018 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm64/coresight/coresight.h>
+#include <arm64/coresight/coresight-etm4x.h>
+
+/*
+ * Typical trace flow:
+ *
+ * CPU0 -> ETM0 -> funnel1 -> funnel0 -> TMC(ETF) -> replicator -> TMC(ETR) -> DRAM
+ * CPU1 -> ETM1 -> funnel1 -^
+ * CPU2 -> ETM2 -> funnel1 -^
+ * CPU3 -> ETM3 -> funnel1 -^
+ */
+
+static struct ofw_compat_data compat_data[] = {
+ { "arm,coresight-etm4x", 1 },
+ { NULL, 0 }
+};
+
+struct etm_softc {
+ struct resource *res;
+ struct coresight_platform_data *pdata;
+};
+
+static struct resource_spec etm_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE },
+ { -1, 0 }
+};
+
+static void
+etm_unlock(struct etm_softc *sc)
+{
+
+ /* Unlocking Coresight */
+ bus_write_4(sc->res, CORESIGHT_LAR, CORESIGHT_UNLOCK);
+
+ isb();
+
+ /* Unlocking ETM */
+ bus_write_4(sc->res, TRCOSLAR, 0);
+
+ isb();
+}
+
+static int
+etm_start(device_t dev)
+{
+ struct etm_softc *sc;
+ uint32_t reg;
+
+ sc = device_get_softc(dev);
+
+ /* Enable the trace unit */
+ bus_write_4(sc->res, TRCPRGCTLR, 1);
+
+ /* Wait for an IDLE bit to be LOW */
+ do {
+ reg = bus_read_4(sc->res, TRCSTATR);
+ } while ((reg & TRCSTATR_IDLE) == 1);
+
+ if ((bus_read_4(sc->res, TRCPRGCTLR) & 1) == 0)
+ panic("etm is not enabled\n");
+
+ return (0);
+}
+
+static int
+etm_stop(device_t dev)
+{
+ struct etm_softc *sc;
+ uint32_t reg;
+
+ sc = device_get_softc(dev);
+
+ /* Disable the trace unit */
+ bus_write_4(sc->res, TRCPRGCTLR, 0);
+
+ /* Wait for an IDLE bit */
+ do {
+ reg = bus_read_4(sc->res, TRCSTATR);
+ } while ((reg & TRCSTATR_IDLE) == 0);
+
+ return (0);
+}
+
+static int
+etm_prepare(struct coresight_device *out, struct coresight_event *config)
+{
+ struct etm_softc *sc;
+ uint32_t reg;
+
+ sc = device_get_softc(out->dev);
+
+ /* Configure ETM */
+
+ /* Enable the return stack, global timestamping, Context ID, and Virtual context identifier tracing. */
+ reg = TRCCONFIGR_RS | TRCCONFIGR_TS | TRCCONFIGR_CID | TRCCONFIGR_VMID;
+ reg |= TRCCONFIGR_INSTP0_LDRSTR;
+ reg |= TRCCONFIGR_COND_ALL;
+ bus_write_4(sc->res, TRCCONFIGR, reg);
+
+ /* Disable all event tracing. */
+ bus_write_4(sc->res, TRCEVENTCTL0R, 0);
+ bus_write_4(sc->res, TRCEVENTCTL1R, 0);
+
+ /* Disable stalling, if implemented. */
+ bus_write_4(sc->res, TRCSTALLCTLR, 0);
+
+ /* Enable trace synchronization every 4096 bytes of trace. */
+ bus_write_4(sc->res, TRCSYNCPR, 0xC);
+
+ /* Set a value for the trace ID, with bit[0]=0. */
+ bus_write_4(sc->res, TRCTRACEIDR, 0x10);
+
+ /*
+ * Disable the timestamp event. The trace unit still generates
+ * timestamps due to other reasons such as trace synchronization.
+ */
+ bus_write_4(sc->res, TRCTSCTLR, 0);
+
+ /* Enable ViewInst to trace everything, with the start/stop logic started. */
+ reg = TRCVICTLR_SSSTATUS;
+
+ /* The number of the single resource used to activate the event. */
+ reg |= (1 << EVENT_SEL_S);
+
+ if (config->excp_level > 2)
+ return (-1);
+
+ reg |= TRCVICTLR_EXLEVEL_NS_M;
+ reg &= ~TRCVICTLR_EXLEVEL_NS(config->excp_level);
+ reg |= TRCVICTLR_EXLEVEL_S_M;
+ reg &= ~TRCVICTLR_EXLEVEL_S(config->excp_level);
+ bus_write_4(sc->res, TRCVICTLR, reg);
+
+ bus_write_4(sc->res, TRCRSCTLR(0), (5 << 16) | (1 << 0));
+
+ int i;
+ for (i = 0; i < config->naddr * 2; i++) {
+ printf("configure range %d, address %lx\n", i, config->addr[i]);
+ bus_write_8(sc->res, TRCACVR(i), config->addr[i]);
+
+ reg = 0;
+ /* Secure state */
+ reg |= TRCACATR_EXLEVEL_S_M;
+ reg &= ~TRCACATR_EXLEVEL_S(config->excp_level);
+ /* Non-secure state */
+ reg |= TRCACATR_EXLEVEL_NS_M;
+ reg &= ~TRCACATR_EXLEVEL_NS(config->excp_level);
+ bus_write_4(sc->res, TRCACATR(i), reg);
+ }
+
+ /* No address filtering for ViewData. */
+ bus_write_4(sc->res, TRCVDARCCTLR, 0);
+
+ /* Clear the STATUS bit to zero */
+ bus_write_4(sc->res, TRCSSCSR(0), 0);
+
+ /* No address range filtering for ViewInst. */
+ if (config->naddr == 0)
+ bus_write_4(sc->res, TRCVIIECTLR, 0);
+ else
+ bus_write_4(sc->res, TRCVIIECTLR, (1 << 0));
+
+ /* No start or stop points for ViewInst. */
+ bus_write_4(sc->res, TRCVISSCTLR, 0);
+
+ /* Disable ViewData */
+ bus_write_4(sc->res, TRCVDCTLR, 0);
+
+ /* No address filtering for ViewData. */
+ bus_write_4(sc->res, TRCVDSACCTLR, 0);
+
+ return (0);
+}
+
+static int
+etm_enable(struct coresight_device *out, struct endpoint *endp,
+ struct coresight_event *event)
+{
+
+ etm_prepare(out, event);
+ etm_start(out->dev);
+
+ return (0);
+}
+
+static void
+etm_disable(struct coresight_device *out, struct endpoint *endp,
+ struct coresight_event *event)
+{
+
+ etm_stop(out->dev);
+}
+
+static struct coresight_ops ops = {
+ .enable = &etm_enable,
+ .disable = &etm_disable,
+};
+
+static int
+etm_probe(device_t dev)
+{
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+ return (ENXIO);
+
+ device_set_desc(dev, "AArch64 Embedded Trace Macrocell");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+etm_attach(device_t dev)
+{
+ struct coresight_desc desc;
+ struct etm_softc *sc;
+ uint32_t reg;
+
+ sc = device_get_softc(dev);
+
+ if (bus_alloc_resources(dev, etm_spec, &sc->res) != 0) {
+ device_printf(dev, "cannot allocate resources for device\n");
+ return (ENXIO);
+ }
+
+ if (device_get_unit(dev) == 0) {
+ /* TODO */
+ etm_unlock(sc);
+ reg = bus_read_4(sc->res, TRCIDR(1));
+ printf("ETM Version: %d.%d\n",
+ (reg & TRCIDR1_TRCARCHMAJ_M) >> TRCIDR1_TRCARCHMAJ_S,
+ (reg & TRCIDR1_TRCARCHMIN_M) >> TRCIDR1_TRCARCHMIN_S);
+ }
+
+ sc->pdata = coresight_get_platform_data(dev);
+
+ desc.pdata = sc->pdata;
+ desc.dev = dev;
+ desc.dev_type = CORESIGHT_ETMV4;
+ desc.ops = &ops;
+ coresight_register(&desc);
+
+ return (0);
+}
+
+static device_method_t etm_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, etm_probe),
+ DEVMETHOD(device_attach, etm_attach),
+ DEVMETHOD_END
+};
+
+static driver_t etm_driver = {
+ "etm",
+ etm_methods,
+ sizeof(struct etm_softc),
+};
+
+static devclass_t etm_devclass;
+
+DRIVER_MODULE(etm, simplebus, etm_driver, etm_devclass, 0, 0);
+MODULE_VERSION(etm, 1);
Index: sys/arm64/coresight/coresight-funnel.h
===================================================================
--- /dev/null
+++ sys/arm64/coresight/coresight-funnel.h
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 2018 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ARM64_CORESIGHT_CORESIGHT_FUNNEL_H_
+#define _ARM64_CORESIGHT_CORESIGHT_FUNNEL_H_
+
+#define FUNNEL_FUNCTL 0x000 /* Funnel Control Register */
+#define FUNCTL_HOLDTIME_SHIFT 8
+#define FUNCTL_HOLDTIME_MASK (0xf << FUNCTL_HOLDTIME_SHIFT)
+#define FUNNEL_PRICTL 0x004 /* Priority Control Register */
+#define FUNNEL_ITATBDATA0 0xEEC /* Integration Register, ITATBDATA0 */
+#define FUNNEL_ITATBCTR2 0xEF0 /* Integration Register, ITATBCTR2 */
+#define FUNNEL_ITATBCTR1 0xEF4 /* Integration Register, ITATBCTR1 */
+#define FUNNEL_ITATBCTR0 0xEF8 /* Integration Register, ITATBCTR0 */
+#define FUNNEL_IMCR 0xF00 /* Integration Mode Control Register */
+#define FUNNEL_CTSR 0xFA0 /* Claim Tag Set Register */
+#define FUNNEL_CTCR 0xFA4 /* Claim Tag Clear Register */
+#define FUNNEL_LOCKACCESS 0xFB0 /* Lock Access */
+#define FUNNEL_LOCKSTATUS 0xFB4 /* Lock Status */
+#define FUNNEL_AUTHSTATUS 0xFB8 /* Authentication status */
+#define FUNNEL_DEVICEID 0xFC8 /* Device ID */
+#define FUNNEL_DEVICETYPE 0xFCC /* Device Type Identifier */
+#define FUNNEL_PERIPH4 0xFD0 /* Peripheral ID4 */
+#define FUNNEL_PERIPH5 0xFD4 /* Peripheral ID5 */
+#define FUNNEL_PERIPH6 0xFD8 /* Peripheral ID6 */
+#define FUNNEL_PERIPH7 0xFDC /* Peripheral ID7 */
+#define FUNNEL_PERIPH0 0xFE0 /* Peripheral ID0 */
+#define FUNNEL_PERIPH1 0xFE4 /* Peripheral ID1 */
+#define FUNNEL_PERIPH2 0xFE8 /* Peripheral ID2 */
+#define FUNNEL_PERIPH3 0xFEC /* Peripheral ID3 */
+#define FUNNEL_COMP0 0xFF0 /* Component ID0 */
+#define FUNNEL_COMP1 0xFF4 /* Component ID1 */
+#define FUNNEL_COMP2 0xFF8 /* Component ID2 */
+#define FUNNEL_COMP3 0xFFC /* Component ID3 */
+
+#endif /* !_ARM64_CORESIGHT_CORESIGHT_FUNNEL_H_ */
Index: sys/arm64/coresight/coresight-funnel.c
===================================================================
--- /dev/null
+++ sys/arm64/coresight/coresight-funnel.c
@@ -0,0 +1,163 @@
+/*-
+ * Copyright (c) 2018 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+
+#include <arm64/coresight/coresight.h>
+#include <arm64/coresight/coresight-funnel.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+static struct ofw_compat_data compat_data[] = {
+ { "arm,coresight-funnel", 1 },
+ { NULL, 0 }
+};
+
+struct funnel_softc {
+ struct resource *res;
+ struct coresight_platform_data *pdata;
+};
+
+static struct resource_spec funnel_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE },
+ { -1, 0 }
+};
+
+static int
+funnel_enable(struct coresight_device *out, struct endpoint *endp,
+ struct coresight_event *event)
+{
+ struct funnel_softc *sc;
+ uint32_t reg;
+
+ sc = device_get_softc(out->dev);
+
+ reg = bus_read_4(sc->res, FUNNEL_FUNCTL);
+ reg &= ~(FUNCTL_HOLDTIME_MASK);
+ reg |= (7 << FUNCTL_HOLDTIME_SHIFT);
+ reg |= (1 << endp->reg);
+ bus_write_4(sc->res, FUNNEL_FUNCTL, reg);
+
+ return (0);
+}
+
+static void
+funnel_disable(struct coresight_device *out, struct endpoint *endp,
+ struct coresight_event *event)
+{
+ struct funnel_softc *sc;
+ uint32_t reg;
+
+ sc = device_get_softc(out->dev);
+
+ reg = bus_read_4(sc->res, FUNNEL_FUNCTL);
+ reg &= ~(1 << endp->reg);
+ bus_write_4(sc->res, FUNNEL_FUNCTL, reg);
+}
+
+static struct coresight_ops ops = {
+ .enable = &funnel_enable,
+ .disable = &funnel_disable,
+};
+
+static int
+funnel_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+ return (ENXIO);
+
+ device_set_desc(dev, "Coresight Funnel");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+funnel_attach(device_t dev)
+{
+ struct coresight_desc desc;
+ struct funnel_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ if (bus_alloc_resources(dev, funnel_spec, &sc->res) != 0) {
+ device_printf(dev, "cannot allocate resources for device\n");
+ return (ENXIO);
+ }
+
+ sc->pdata = coresight_get_platform_data(dev);
+
+ desc.pdata = sc->pdata;
+ desc.dev = dev;
+ desc.dev_type = CORESIGHT_FUNNEL;
+ desc.ops = &ops;
+ coresight_register(&desc);
+
+ /* Unlock Coresight */
+ bus_write_4(sc->res, CORESIGHT_LAR, CORESIGHT_UNLOCK);
+
+ wmb();
+
+ printf("Device ID: %x\n", bus_read_4(sc->res, FUNNEL_DEVICEID));
+
+ return (0);
+}
+
+static device_method_t funnel_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, funnel_probe),
+ DEVMETHOD(device_attach, funnel_attach),
+ DEVMETHOD_END
+};
+
+static driver_t funnel_driver = {
+ "funnel",
+ funnel_methods,
+ sizeof(struct funnel_softc),
+};
+
+static devclass_t funnel_devclass;
+
+DRIVER_MODULE(funnel, simplebus, funnel_driver, funnel_devclass, 0, 0);
+MODULE_VERSION(funnel, 1);
Index: sys/arm64/coresight/coresight-tmc.h
===================================================================
--- /dev/null
+++ sys/arm64/coresight/coresight-tmc.h
@@ -0,0 +1,117 @@
+/*-
+ * Copyright (c) 2018 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
+ * ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#ifndef _ARM64_CORESIGHT_CORESIGHT_TMC_H_
+#define _ARM64_CORESIGHT_CORESIGHT_TMC_H_
+
+#define TMC_RSZ 0x004 /* RAM Size Register */
+#define TMC_STS 0x00C /* Status Register */
+#define STS_MEMERR (1 << 5)
+#define STS_EMPTY (1 << 4)
+#define STS_FTEMPTY (1 << 3)
+#define STS_TMCREADY (1 << 2)
+#define STS_TRIGGERED (1 << 1)
+#define STS_FULL (1 << 0)
+#define TMC_RRD 0x010 /* RAM Read Data Register */
+#define TMC_RRP 0x014 /* RAM Read Pointer Register */
+#define TMC_RWP 0x018 /* RAM Write Pointer Register */
+#define TMC_TRG 0x01C /* Trigger Counter Register */
+#define TMC_CTL 0x020 /* Control Register */
+#define CTL_TRACECAPTEN (1 << 0) /* Controls trace capture. */
+#define TMC_RWD 0x024 /* RAM Write Data Register */
+#define TMC_MODE 0x028 /* Mode Register */
+#define MODE_HW_FIFO 2
+#define MODE_SW_FIFO 1
+#define MODE_CIRCULAR_BUFFER 0
+#define TMC_LBUFLEVEL 0x02C /* Latched Buffer Fill Level */
+#define TMC_CBUFLEVEL 0x030 /* Current Buffer Fill Level */
+#define TMC_BUFWM 0x034 /* Buffer Level Water Mark */
+#define TMC_RRPHI 0x038 /* RAM Read Pointer High Register */
+#define TMC_RWPHI 0x03C /* RAM Write Pointer High Register */
+#define TMC_AXICTL 0x110 /* AXI Control Register */
+#define AXICTL_WRBURSTLEN_S 8
+#define AXICTL_WRBURSTLEN_M (0xf << AXICTL_WRBURSTLEN_S)
+#define AXICTL_WRBURSTLEN_16 (0xf << AXICTL_WRBURSTLEN_S)
+#define AXICTL_SG_MODE (1 << 7) /* Scatter Gather Mode */
+#define AXICTL_CACHE_CTRL_BIT3 (1 << 5)
+#define AXICTL_CACHE_CTRL_BIT2 (1 << 4)
+#define AXICTL_CACHE_CTRL_BIT1 (1 << 3)
+#define AXICTL_CACHE_CTRL_BIT0 (1 << 2)
+#define AXICTL_AXCACHE_OS (0xf << 2)
+#define AXICTL_PROT_CTRL_BIT1 (1 << 1)
+#define AXICTL_PROT_CTRL_BIT0 (1 << 0)
+#define TMC_DBALO 0x118 /* Data Buffer Address Low Register */
+#define TMC_DBAHI 0x11C /* Data Buffer Address High Register */
+#define TMC_FFSR 0x300 /* Formatter and Flush Status Register */
+#define TMC_FFCR 0x304 /* Formatter and Flush Control Register */
+#define FFCR_EN_FMT (1 << 0)
+#define FFCR_EN_TI (1 << 1)
+#define FFCR_FON_FLIN (1 << 4)
+#define FFCR_FON_TRIG_EVT (1 << 5)
+#define FFCR_FLUSH_MAN (1 << 6)
+#define FFCR_TRIGON_TRIGIN (1 << 8)
+#define TMC_PSCR 0x308 /* Periodic Synchronization Counter Register */
+#define TMC_ITATBMDATA0 0xED0 /* Integration Test ATB Master Data Register 0 */
+#define TMC_ITATBMCTR2 0xED4 /* Integration Test ATB Master Interface Control 2 Register */
+#define TMC_ITATBMCTR1 0xED8 /* Integration Test ATB Master Control Register 1 */
+#define TMC_ITATBMCTR0 0xEDC /* Integration Test ATB Master Interface Control 0 Register */
+#define TMC_ITMISCOP0 0xEE0 /* Integration Test Miscellaneous Output Register 0 */
+#define TMC_ITTRFLIN 0xEE8 /* Integration Test Trigger In and Flush In Register */
+#define TMC_ITATBDATA0 0xEEC /* Integration Test ATB Data Register 0 */
+#define TMC_ITATBCTR2 0xEF0 /* Integration Test ATB Control 2 Register */
+#define TMC_ITATBCTR1 0xEF4 /* Integration Test ATB Control 1 Register */
+#define TMC_ITATBCTR0 0xEF8 /* Integration Test ATB Control 0 Register */
+#define TMC_ITCTRL 0xF00 /* Integration Mode Control Register */
+#define TMC_CLAIMSET 0xFA0 /* Claim Tag Set Register */
+#define TMC_CLAIMCLR 0xFA4 /* Claim Tag Clear Register */
+#define TMC_LAR 0xFB0 /* Lock Access Register */
+#define TMC_LSR 0xFB4 /* Lock Status Register */
+#define TMC_AUTHSTATUS 0xFB8 /* Authentication Status Register */
+#define TMC_DEVID 0xFC8 /* Device Configuration Register */
+#define DEVID_CONFIGTYPE_S 6
+#define DEVID_CONFIGTYPE_M (0x3 << DEVID_CONFIGTYPE_S)
+#define DEVID_CONFIGTYPE_ETB (0 << DEVID_CONFIGTYPE_S)
+#define DEVID_CONFIGTYPE_ETR (1 << DEVID_CONFIGTYPE_S)
+#define DEVID_CONFIGTYPE_ETF (2 << DEVID_CONFIGTYPE_S)
+#define TMC_DEVTYPE 0xFCC /* Device Type Identifier Register */
+#define TMC_PERIPHID4 0xFD0 /* Peripheral ID4 Register */
+#define TMC_PERIPHID5 0xFD4 /* Peripheral ID5 Register */
+#define TMC_PERIPHID6 0xFD8 /* Peripheral ID6 Register */
+#define TMC_PERIPHID7 0xFDC /* Peripheral ID7 Register */
+#define TMC_PERIPHID0 0xFE0 /* Peripheral ID0 Register */
+#define TMC_PERIPHID1 0xFE4 /* Peripheral ID1 Register */
+#define TMC_PERIPHID2 0xFE8 /* Peripheral ID2 Register */
+#define TMC_PERIPHID3 0xFEC /* Peripheral ID3 Register */
+#define TMC_COMPID0 0xFF0 /* Component ID0 Register */
+#define TMC_COMPID1 0xFF4 /* Component ID1 Register */
+#define TMC_COMPID2 0xFF8 /* Component ID2 Register */
+#define TMC_COMPID3 0xFFC /* Component ID3 Register */
+
+#endif /* !_ARM64_CORESIGHT_CORESIGHT_TMC_H_ */
Index: sys/arm64/coresight/coresight-tmc.c
===================================================================
--- /dev/null
+++ sys/arm64/coresight/coresight-tmc.c
@@ -0,0 +1,349 @@
+/*-
+ * Copyright (c) 2018 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
+ * ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+
+#include <arm64/coresight/coresight.h>
+#include <arm64/coresight/coresight-tmc.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+static struct ofw_compat_data compat_data[] = {
+ { "arm,coresight-tmc", 1 },
+ { NULL, 0 }
+};
+
+struct tmc_softc {
+ struct resource *res;
+ device_t dev;
+ uint64_t cycle;
+ struct coresight_platform_data *pdata;
+};
+
+static struct resource_spec tmc_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE },
+ { -1, 0 }
+};
+
+static int
+tmc_unlock(struct tmc_softc *sc)
+{
+
+ /* Unlock Coresight */
+ bus_write_4(sc->res, CORESIGHT_LAR, CORESIGHT_UNLOCK);
+ wmb();
+
+ /* Unlock TMC */
+ bus_write_4(sc->res, TMC_LAR, CORESIGHT_UNLOCK);
+ wmb();
+
+ return (0);
+}
+
+static int
+tmc_start(device_t dev)
+{
+ struct tmc_softc *sc;
+ uint32_t reg;
+
+ sc = device_get_softc(dev);
+
+ if (bus_read_4(sc->res, TMC_CTL) & CTL_TRACECAPTEN)
+ return (-1);
+
+ /* Enable TMC */
+ bus_write_4(sc->res, TMC_CTL, CTL_TRACECAPTEN);
+ if ((bus_read_4(sc->res, TMC_CTL) & CTL_TRACECAPTEN) == 0)
+ panic("not enabled0\n");
+
+ do {
+ reg = bus_read_4(sc->res, TMC_STS);
+ } while ((reg & STS_TMCREADY) == 1);
+
+ if ((bus_read_4(sc->res, TMC_CTL) & CTL_TRACECAPTEN) == 0)
+ panic("not enabled1\n");
+
+ return (0);
+}
+
+static int
+tmc_stop(device_t dev)
+{
+ struct tmc_softc *sc;
+ uint32_t reg;
+
+ sc = device_get_softc(dev);
+
+ reg = bus_read_4(sc->res, TMC_CTL);
+ reg &= ~CTL_TRACECAPTEN;
+ bus_write_4(sc->res, TMC_CTL, reg);
+
+ do {
+ reg = bus_read_4(sc->res, TMC_STS);
+ } while ((reg & STS_TMCREADY) == 1);
+
+ return (0);
+}
+
+static int
+tmc_read(struct coresight_device *out, struct endpoint *endp,
+ struct coresight_event *event)
+{
+ struct tmc_softc *sc;
+ uint32_t cur_ptr;
+
+ sc = device_get_softc(out->dev);
+
+ if (bus_read_4(sc->res, TMC_STS) & STS_FULL) {
+ event->etr.offset = 0;
+ event->etr.cycle++;
+ tmc_stop(out->dev);
+ tmc_start(out->dev);
+ } else {
+ cur_ptr = bus_read_4(sc->res, TMC_RWP);
+ event->etr.offset = (cur_ptr - event->etr.low);
+ }
+
+ return (0);
+}
+
+static int
+tmc_configure_etf(device_t dev)
+{
+ struct tmc_softc *sc;
+ uint32_t reg;
+
+ sc = device_get_softc(dev);
+
+ tmc_unlock(sc);
+
+ do {
+ reg = bus_read_4(sc->res, TMC_STS);
+ } while ((reg & STS_TMCREADY) == 0);
+
+ bus_write_4(sc->res, TMC_MODE, MODE_HW_FIFO);
+ bus_write_4(sc->res, TMC_FFCR, FFCR_EN_FMT | FFCR_EN_TI);
+ bus_write_4(sc->res, TMC_BUFWM, 0x800-1);
+
+ tmc_start(dev);
+
+ printf("%s: STS %x, CTL %x, RSZ %x, RRP %x, RWP %x, LBUFLEVEL %x, CBUFLEVEL %x, \n", __func__,
+ bus_read_4(sc->res, TMC_STS),
+ bus_read_4(sc->res, TMC_CTL),
+ bus_read_4(sc->res, TMC_RSZ),
+ bus_read_4(sc->res, TMC_RRP),
+ bus_read_4(sc->res, TMC_RWP),
+ bus_read_4(sc->res, TMC_CBUFLEVEL),
+ bus_read_4(sc->res, TMC_LBUFLEVEL));
+
+ return (0);
+}
+
+static int
+tmc_configure_etr(struct coresight_device *out, struct endpoint *endp,
+ struct coresight_event *event)
+{
+ struct tmc_softc *sc;
+ uint32_t reg;
+
+ sc = device_get_softc(out->dev);
+
+ tmc_unlock(sc);
+ tmc_stop(out->dev);
+
+ do {
+ reg = bus_read_4(sc->res, TMC_STS);
+ } while ((reg & STS_TMCREADY) == 0);
+
+ /* Configure TMC */
+ bus_write_4(sc->res, TMC_MODE, MODE_CIRCULAR_BUFFER);
+
+ reg = AXICTL_PROT_CTRL_BIT1;
+ reg |= AXICTL_WRBURSTLEN_16;
+
+ /*
+ * SG operation is broken on DragonBoard 410c
+ * reg |= AXICTL_SG_MODE;
+ */
+
+ reg |= AXICTL_AXCACHE_OS;
+ bus_write_4(sc->res, TMC_AXICTL, reg);
+
+ reg = FFCR_EN_FMT | FFCR_EN_TI | FFCR_FON_FLIN |
+ FFCR_FON_TRIG_EVT | FFCR_TRIGON_TRIGIN;
+ bus_write_4(sc->res, TMC_FFCR, reg);
+
+ bus_write_4(sc->res, TMC_TRG, 8);
+
+ bus_write_4(sc->res, TMC_DBALO, event->etr.low);
+ bus_write_4(sc->res, TMC_DBAHI, event->etr.high);
+ bus_write_4(sc->res, TMC_RSZ, event->etr.bufsize / 4);
+
+ bus_write_4(sc->res, TMC_RRP, event->etr.low);
+ bus_write_4(sc->res, TMC_RWP, event->etr.low);
+
+ reg = bus_read_4(sc->res, TMC_STS);
+ reg &= ~STS_FULL;
+ bus_write_4(sc->res, TMC_STS, reg);
+
+ tmc_start(out->dev);
+
+ return (0);
+}
+
+static int
+tmc_enable(struct coresight_device *out, struct endpoint *endp,
+ struct coresight_event *event)
+{
+ struct tmc_softc *sc;
+
+ sc = device_get_softc(out->dev);
+
+ /* ETF configuration is static */
+ switch (out->dev_type) {
+ case CORESIGHT_ETF:
+ return (0);
+ case CORESIGHT_ETR:
+ if (event->etr.started)
+ return (0);
+ tmc_unlock(sc);
+ tmc_stop(out->dev);
+ tmc_configure_etr(out, endp, event);
+ tmc_start(out->dev);
+ event->etr.started = 1;
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+static void
+tmc_disable(struct coresight_device *out, struct endpoint *endp,
+ struct coresight_event *event)
+{
+
+ /*
+ * Can't restore the state: can't specify buffer offset
+ * to continue operation from. So we do not disable TMC here.
+ */
+}
+
+static struct coresight_ops ops = {
+ .read = &tmc_read,
+ .enable = &tmc_enable,
+ .disable = &tmc_disable,
+};
+
+static int
+tmc_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+ return (ENXIO);
+
+ device_set_desc(dev, "Coresight Trace Memory Controller (TMC)");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+tmc_attach(device_t dev)
+{
+ struct coresight_desc desc;
+ struct tmc_softc *sc;
+ uint32_t reg;
+
+ sc = device_get_softc(dev);
+
+ sc->dev = dev;
+
+ if (bus_alloc_resources(dev, tmc_spec, &sc->res) != 0) {
+ device_printf(dev, "cannot allocate resources for device\n");
+ return (ENXIO);
+ }
+
+ sc->pdata = coresight_get_platform_data(dev);
+
+ desc.pdata = sc->pdata;
+ desc.dev = dev;
+ desc.ops = &ops;
+
+ reg = bus_read_4(sc->res, TMC_DEVID);
+ reg &= DEVID_CONFIGTYPE_M;
+ switch (reg) {
+ case DEVID_CONFIGTYPE_ETR:
+ desc.dev_type = CORESIGHT_ETR;
+ coresight_register(&desc);
+ device_printf(dev, "ETR configuration found\n");
+ break;
+ case DEVID_CONFIGTYPE_ETF:
+ desc.dev_type = CORESIGHT_ETF;
+ coresight_register(&desc);
+ tmc_configure_etf(dev);
+ device_printf(dev, "ETF configuration found\n");
+ break;
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+static device_method_t tmc_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, tmc_probe),
+ DEVMETHOD(device_attach, tmc_attach),
+ DEVMETHOD_END
+};
+
+static driver_t tmc_driver = {
+ "tmc",
+ tmc_methods,
+ sizeof(struct tmc_softc),
+};
+
+static devclass_t tmc_devclass;
+
+DRIVER_MODULE(tmc, simplebus, tmc_driver, tmc_devclass, 0, 0);
+MODULE_VERSION(tmc, 1);
Index: sys/arm64/coresight/coresight.h
===================================================================
--- /dev/null
+++ sys/arm64/coresight/coresight.h
@@ -0,0 +1,137 @@
+/*-
+ * Copyright (c) 2018 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
+ * ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ARM64_CORESIGHT_CORESIGHT_H_
+#define _ARM64_CORESIGHT_CORESIGHT_H_
+
+#include <dev/ofw/openfirm.h>
+
+#define CORESIGHT_ITCTRL 0xf00
+#define CORESIGHT_CLAIMSET 0xfa0
+#define CORESIGHT_CLAIMCLR 0xfa4
+#define CORESIGHT_LAR 0xfb0
+#define CORESIGHT_UNLOCK 0xc5acce55
+#define CORESIGHT_LSR 0xfb4
+#define CORESIGHT_AUTHSTATUS 0xfb8
+#define CORESIGHT_DEVID 0xfc8
+#define CORESIGHT_DEVTYPE 0xfcc
+
+enum cs_dev_type {
+ CORESIGHT_ETMV4,
+ CORESIGHT_ETR,
+ CORESIGHT_ETF,
+ CORESIGHT_DYNAMIC_REPLICATOR,
+ CORESIGHT_FUNNEL,
+};
+
+struct coresight_device {
+ TAILQ_ENTRY(coresight_device) link;
+ device_t dev;
+ phandle_t node;
+ enum cs_dev_type dev_type;
+ struct coresight_ops *ops;
+ struct coresight_platform_data *pdata;
+};
+
+struct endpoint {
+ TAILQ_ENTRY(endpoint) link;
+ phandle_t my_node;
+ phandle_t their_node;
+ phandle_t dev_node;
+ boolean_t slave;
+ int reg;
+ struct coresight_device *cs_dev;
+ LIST_ENTRY(endpoint) endplink;
+};
+
+struct coresight_platform_data {
+ int cpu;
+ int in_ports;
+ int out_ports;
+ struct mtx mtx_lock;
+ TAILQ_HEAD(endpoint_list, endpoint) endpoints;
+};
+
+struct coresight_desc {
+ struct coresight_platform_data *pdata;
+ device_t dev;
+ enum cs_dev_type dev_type;
+ struct coresight_ops *ops;
+};
+
+TAILQ_HEAD(coresight_device_list, coresight_device);
+
+#define ETM_N_COMPRATOR 16
+
+struct etr_status {
+ boolean_t started;
+ uint32_t cycle;
+ uint32_t offset;
+ uint32_t low;
+ uint32_t high;
+ uint32_t bufsize;
+};
+
+struct coresight_event {
+ LIST_HEAD(, endpoint) endplist;
+
+ uint64_t addr[ETM_N_COMPRATOR];
+ uint32_t naddr;
+ uint8_t excp_level;
+ enum cs_dev_type src;
+ enum cs_dev_type sink;
+
+ struct etr_status etr;
+};
+
+struct coresight_ops {
+ int (*read)(struct coresight_device *out, struct endpoint *endp, struct coresight_event *event);
+ int (*enable)(struct coresight_device *out, struct endpoint *endp, struct coresight_event *event);
+ void (*disable)(struct coresight_device *out, struct endpoint *endp, struct coresight_event *event);
+};
+
+struct etm_config {
+ uint64_t addr[ETM_N_COMPRATOR];
+ uint32_t naddr;
+ uint8_t excp_level;
+};
+
+struct coresight_platform_data * coresight_get_platform_data(device_t dev);
+struct endpoint * coresight_get_output_endpoint(struct coresight_platform_data *pdata);
+struct coresight_device * coresight_get_output_device(struct endpoint *endp, struct endpoint **);
+int coresight_register(struct coresight_desc *desc);
+int coresight_init_event(int cpu, struct coresight_event *event);
+void coresight_enable(int cpu, struct coresight_event *event);
+void coresight_disable(int cpu, struct coresight_event *event);
+void coresight_read(int cpu, struct coresight_event *event);
+
+#endif /* !_ARM64_CORESIGHT_CORESIGHT_H_ */
Index: sys/arm64/coresight/coresight.c
===================================================================
--- /dev/null
+++ sys/arm64/coresight/coresight.c
@@ -0,0 +1,215 @@
+/*-
+ * Copyright (c) 2018 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
+ * ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm64/coresight/coresight.h>
+
+MALLOC_DEFINE(M_CORESIGHT, "coresight", "ARM Coresight");
+static struct mtx cs_mtx;
+
+struct coresight_device_list cs_devs;
+
+static int
+coresight_get_ports(phandle_t dev_node,
+ struct coresight_platform_data *pdata)
+{
+ phandle_t node, child;
+ pcell_t port_reg;
+ phandle_t xref;
+ char *name;
+ int ret;
+ phandle_t endpoint_child;
+ struct endpoint *endp;
+
+ child = ofw_bus_find_child(dev_node, "ports");
+ if (child)
+ node = child;
+ else
+ node = dev_node;
+
+ for (child = OF_child(node); child != 0; child = OF_peer(child)) {
+ ret = OF_getprop_alloc(child, "name", sizeof(*name), (void **)&name);
+ if (ret == -1)
+ continue;
+
+ if (strcasecmp(name, "port") ||
+ strncasecmp(name, "port@", 6)) {
+
+ port_reg = -1;
+ OF_getencprop(child, "reg", (void *)&port_reg, sizeof(port_reg));
+
+ endpoint_child = ofw_bus_find_child(child, "endpoint");
+ if (endpoint_child) {
+ if (OF_getencprop(endpoint_child, "remote-endpoint", &xref,
+ sizeof(xref)) == -1) {
+ printf("failed\n");
+ continue;
+ }
+ endp = malloc(sizeof(struct endpoint), M_CORESIGHT,
+ M_WAITOK | M_ZERO);
+ endp->my_node = endpoint_child;
+ endp->their_node = OF_node_from_xref(xref);
+ endp->dev_node = dev_node;
+ endp->reg = port_reg;
+ if (OF_getproplen(endpoint_child, "slave-mode") >= 0) {
+ pdata->in_ports++;
+ endp->slave = 1;
+ } else {
+ pdata->out_ports++;
+ }
+
+ mtx_lock(&pdata->mtx_lock);
+ TAILQ_INSERT_TAIL(&pdata->endpoints, endp, link);
+ mtx_unlock(&pdata->mtx_lock);
+ }
+ }
+ }
+
+ return (0);
+}
+
+int
+coresight_register(struct coresight_desc *desc)
+{
+ struct coresight_device *cs_dev;
+
+ cs_dev = malloc(sizeof(struct coresight_device), M_CORESIGHT, M_WAITOK | M_ZERO);
+ cs_dev->dev = desc->dev;
+ cs_dev->node = ofw_bus_get_node(desc->dev);
+ cs_dev->pdata = desc->pdata;
+ cs_dev->dev_type = desc->dev_type;
+ cs_dev->ops = desc->ops;
+
+ mtx_lock(&cs_mtx);
+ TAILQ_INSERT_TAIL(&cs_devs, cs_dev, link);
+ mtx_unlock(&cs_mtx);
+
+ return (0);
+}
+
+struct endpoint *
+coresight_get_output_endpoint(struct coresight_platform_data *pdata)
+{
+ struct endpoint *endp;
+
+ if (pdata->out_ports != 1) {
+ return (NULL);
+ }
+
+ TAILQ_FOREACH(endp, &pdata->endpoints, link) {
+ if (endp->slave == 0)
+ return (endp);
+ }
+
+ return (NULL);
+}
+
+struct coresight_device *
+coresight_get_output_device(struct endpoint *endp, struct endpoint **out_endp)
+{
+ struct coresight_device *cs_dev;
+ struct endpoint *endp2;
+
+ TAILQ_FOREACH(cs_dev, &cs_devs, link) {
+ TAILQ_FOREACH(endp2, &cs_dev->pdata->endpoints, link) {
+ if (endp->their_node == endp2->my_node) {
+ *out_endp = endp2;
+ return (cs_dev);
+ }
+ }
+ }
+
+ return (NULL);
+}
+
+static int
+coresight_get_cpu(phandle_t node,
+ struct coresight_platform_data *pdata)
+{
+ phandle_t cpu_node;
+ pcell_t xref;
+ pcell_t cpu_reg;
+
+ if (OF_getencprop(node, "cpu", &xref, sizeof(xref)) != -1) {
+ cpu_node = OF_node_from_xref(xref);
+ if (OF_getencprop(cpu_node, "reg", (void *)&cpu_reg,
+ sizeof(cpu_reg)) > 0) {
+ pdata->cpu = cpu_reg;
+
+ return (0);
+ }
+ }
+
+ return (-1);
+}
+
+struct coresight_platform_data *
+coresight_get_platform_data(device_t dev)
+{
+ struct coresight_platform_data *pdata;
+ phandle_t node;
+
+ node = ofw_bus_get_node(dev);
+
+ pdata = malloc(sizeof(struct coresight_platform_data),
+ M_CORESIGHT, M_WAITOK | M_ZERO);
+ mtx_init(&pdata->mtx_lock, "Coresight Platform Data", NULL, MTX_DEF);
+ TAILQ_INIT(&pdata->endpoints);
+
+ coresight_get_cpu(node, pdata);
+ coresight_get_ports(node, pdata);
+
+ printf("Total ports: in %d out %d\n", pdata->in_ports, pdata->out_ports);
+
+ return (pdata);
+}
+
+static void
+coresight_init(void)
+{
+
+ mtx_init(&cs_mtx, "ARM Coresight", NULL, MTX_DEF);
+ TAILQ_INIT(&cs_devs);
+}
+
+SYSINIT(coresight, SI_SUB_DRIVERS, SI_ORDER_FIRST, coresight_init, NULL);
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -1800,6 +1800,7 @@
dev/hptiop/hptiop.c optional hptiop scbus
dev/hwpmc/hwpmc_logging.c optional hwpmc
dev/hwpmc/hwpmc_mod.c optional hwpmc
+dev/hwpmc/hwpmc_vm.c optional hwpmc
dev/hwpmc/hwpmc_soft.c optional hwpmc
dev/ichiic/ig4_acpi.c optional ig4 acpi iicbus
dev/ichiic/ig4_iic.c optional ig4 iicbus
Index: sys/dev/hwpmc/hwpmc_arm64.c
===================================================================
--- sys/dev/hwpmc/hwpmc_arm64.c
+++ sys/dev/hwpmc/hwpmc_arm64.c
@@ -480,6 +480,7 @@
struct pmc_mdep *pmc_mdep;
struct pmc_classdep *pcd;
int idcode;
+ int ncpus;
int reg;
reg = arm64_pmcr_read();
@@ -495,8 +496,8 @@
arm64_pcpu = malloc(sizeof(struct arm64_cpu *) * pmc_cpu_max(),
M_PMC, M_WAITOK | M_ZERO);
- /* Just one class */
- pmc_mdep = pmc_mdep_alloc(1);
+ /* CPU counters and ETM */
+ pmc_mdep = pmc_mdep_alloc(2);
switch (idcode) {
case PMCR_IDCODE_CORTEX_A57:
@@ -534,6 +535,9 @@
pmc_mdep->pmd_npmc += arm64_npmcs;
+ ncpus = pmc_cpu_max();
+ pmc_coresight_initialize(pmc_mdep, ncpus);
+
return (pmc_mdep);
}
@@ -541,4 +545,5 @@
pmc_arm64_finalize(struct pmc_mdep *md)
{
+ pmc_coresight_finalize(md);
}
Index: sys/dev/hwpmc/hwpmc_core.c
===================================================================
--- sys/dev/hwpmc/hwpmc_core.c
+++ sys/dev/hwpmc/hwpmc_core.c
@@ -2287,6 +2287,7 @@
break;
case PMC_CPU_INTEL_SKYLAKE:
case PMC_CPU_INTEL_SKYLAKE_XEON:
+ case PMC_CPU_INTEL_KABYLAKE:
case PMC_CPU_INTEL_BROADWELL:
case PMC_CPU_INTEL_BROADWELL_XEON:
case PMC_CPU_INTEL_SANDYBRIDGE:
@@ -2325,6 +2326,7 @@
cpuflag = IAP_F_SLX;
break;
case PMC_CPU_INTEL_SKYLAKE:
+ case PMC_CPU_INTEL_KABYLAKE:
cpuflag = IAP_F_SL;
break;
case PMC_CPU_INTEL_BROADWELL_XEON:
@@ -2846,6 +2848,12 @@
struct core_cpu *cc;
pmc_value_t v;
+ error = pmc_pt_intr(cpu, tf);
+ if (error) {
+ /* Found */
+ return (1);
+ }
+
PMCDBG3(MDP,INT, 1, "cpu=%d tf=0x%p um=%d", cpu, (void *) tf,
TRAPF_USERMODE(tf));
Index: sys/dev/hwpmc/hwpmc_cs.h
===================================================================
--- /dev/null
+++ sys/dev/hwpmc/hwpmc_cs.h
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 2017 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#ifndef _DEV_HWPMC_CS_H_
+#define _DEV_HWPMC_CS_H_
+
+#include <sys/types.h>
+#include <sys/malloc.h>
+#include <vm/vm.h>
+
+#include <machine/frame.h>
+
+#define CORESIGHT_NADDR 4
+#define CORESIGHT_NPMCS 1
+
+struct pmc_md_coresight_op_pmcallocate {
+ uint32_t flags;
+ uint64_t ranges[2 * CORESIGHT_NADDR];
+ int nranges;
+};
+
+#ifdef _KERNEL
+struct coresight_buffer {
+ uint64_t phys_base;
+ vm_object_t obj;
+};
+
+/* MD extension for 'struct pmc' */
+struct pmc_md_coresight_pmc {
+ struct coresight_buffer coresight_buffers[MAXCPU];
+};
+
+/*
+ * Prototypes.
+ */
+
+int pmc_coresight_initialize(struct pmc_mdep *_md, int _maxcpu);
+void pmc_coresight_finalize(struct pmc_mdep *_md);
+int pmc_coresight_intr(int cpu, struct trapframe *tf);
+
+#endif /* !_KERNEL */
+#endif /* !_DEV_HWPMC_CS_H_ */
Index: sys/dev/hwpmc/hwpmc_cs.c
===================================================================
--- /dev/null
+++ sys/dev/hwpmc/hwpmc_cs.c
@@ -0,0 +1,707 @@
+/*-
+ * Copyright (c) 2018 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/pmc.h>
+#include <sys/pmckern.h>
+#include <sys/systm.h>
+#include <sys/ioccom.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+#include <sys/conf.h>
+#include <sys/module.h>
+#include <sys/mman.h>
+#include <sys/proc.h>
+#include <sys/vmem.h>
+#include <sys/vmmeter.h>
+#include <sys/kthread.h>
+#include <sys/pmclog.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_phys.h>
+#include <vm/vm_radix.h>
+#include <vm/pmap.h>
+
+#include <arm64/coresight/coresight.h>
+
+#include <dev/hwpmc/hwpmc_vm.h>
+
+static MALLOC_DEFINE(M_CORESIGHT, "coresight", "CORESIGHT driver");
+
+extern struct cdev *pmc_cdev[MAXCPU];
+
+/*
+ * ARM CORESIGHT support.
+ *
+ * Limitation of hardware:
+ * - Scatter-gather operation is broken in hardware on Qualcomm Snapdragon 410e processor.
+ * - None of coresight interconnect devices provides an interrupt line.
+ * - Circular-buffer is the only mode of operation for TMC(ETR).
+ *
+ * I.e. once buffer filled the operation will not be halted, instead the buffer will be
+ * overwritten from start and none of interrupt provided.
+ */
+
+#define CORESIGHT_CAPS (PMC_CAP_READ | PMC_CAP_INTERRUPT | PMC_CAP_SYSTEM | PMC_CAP_USER)
+
+#define PMC_CORESIGHT_DEBUG
+#undef PMC_CORESIGHT_DEBUG
+
+#ifdef PMC_CORESIGHT_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
+struct coresight_descr {
+ struct pmc_descr pm_descr; /* "base class" */
+};
+
+static struct coresight_descr coresight_pmcdesc[CORESIGHT_NPMCS] =
+{
+ {
+ .pm_descr =
+ {
+ .pd_name = "CORESIGHT",
+ .pd_class = PMC_CLASS_CORESIGHT,
+ .pd_caps = CORESIGHT_CAPS,
+ .pd_width = 64
+ }
+ }
+};
+
+/*
+ * Per-CPU data structure for PTs.
+ */
+
+struct coresight_cpu {
+ struct pmc_hw tc_hw;
+ uint32_t l0_eax;
+ uint32_t l0_ebx;
+ uint32_t l0_ecx;
+ uint32_t l1_eax;
+ uint32_t l1_ebx;
+ struct pmc *pm_mmap;
+ uint32_t flags;
+#define FLAG_CORESIGHT_ALLOCATED (1 << 0)
+ struct coresight_event event;
+};
+
+static struct coresight_cpu **coresight_pcpu;
+
+static int
+coresight_buffer_allocate(uint32_t cpu, struct coresight_buffer *coresight_buf,
+ uint32_t bufsize)
+{
+ struct pmc_vm_map *map;
+ struct coresight_cpu *coresight_pc;
+ uint64_t phys_base;
+ struct cdev_cpu *cc;
+ vm_object_t obj;
+ vm_page_t m;
+ int npages;
+
+ dprintf("%s\n", __func__);
+
+ coresight_pc = coresight_pcpu[cpu];
+
+ coresight_buf->obj = obj = vm_pager_allocate(OBJT_PHYS, 0, bufsize,
+ PROT_READ, 0, curthread->td_ucred);
+
+ npages = bufsize / PAGE_SIZE;
+
+ VM_OBJECT_WLOCK(obj);
+ m = vm_page_alloc_contig(obj, 0, VM_ALLOC_NOBUSY | VM_ALLOC_ZERO,
+ npages, 0, ~0, PAGE_SIZE, 0, VM_MEMATTR_DEFAULT);
+ if (m == NULL) {
+ VM_OBJECT_WUNLOCK(obj);
+ printf("%s: Can't allocate memory.\n", __func__);
+ vm_object_deallocate(obj);
+ return (-1);
+ }
+ phys_base = VM_PAGE_TO_PHYS(m);
+ for (; m != NULL; m = vm_page_next(m)) {
+ if ((m->flags & PG_ZERO) == 0)
+ pmap_zero_page(m);
+ m->valid = VM_PAGE_BITS_ALL;
+ }
+ vm_object_reference_locked(obj);
+ VM_OBJECT_WUNLOCK(obj);
+
+ map = malloc(sizeof(struct pmc_vm_map), M_CORESIGHT, M_WAITOK | M_ZERO);
+ map->t = curthread;
+ map->obj = obj;
+ map->buf = (void *)coresight_buf;
+
+ cc = pmc_cdev[cpu]->si_drv1;
+
+ mtx_lock(&cc->vm_mtx);
+ TAILQ_INSERT_HEAD(&cc->pmc_maplist, map, map_next);
+ mtx_unlock(&cc->vm_mtx);
+
+ coresight_buf->phys_base = phys_base;
+
+ return (0);
+}
+
+static int
+coresight_buffer_deallocate(uint32_t cpu, struct coresight_buffer *coresight_buf)
+{
+ struct pmc_vm_map *map, *map_tmp;
+ struct cdev_cpu *cc;
+
+ cc = pmc_cdev[cpu]->si_drv1;
+
+ dprintf("%s\n", __func__);
+
+ mtx_lock(&cc->vm_mtx);
+ TAILQ_FOREACH_SAFE(map, &cc->pmc_maplist, map_next, map_tmp) {
+ KASSERT(map->t == curthread,
+ ("Deallocation should be done in same thread as allocation"));
+ if (map->buf == (void *)coresight_buf) {
+ TAILQ_REMOVE(&cc->pmc_maplist, map, map_next);
+ free(map, M_CORESIGHT);
+ break;
+ }
+ }
+ mtx_unlock(&cc->vm_mtx);
+
+ vm_object_deallocate(coresight_buf->obj);
+
+ return (0);
+}
+
+static int
+coresight_buffer_prepare(uint32_t cpu, struct pmc *pm,
+ const struct pmc_op_pmcallocate *a)
+{
+ const struct pmc_md_coresight_op_pmcallocate *pm_coresighta;
+ struct coresight_cpu *coresight_pc;
+ struct pmc_md_coresight_pmc *pm_coresight;
+ struct coresight_buffer *coresight_buf;
+ uint32_t bufsize;
+ enum pmc_mode mode;
+ uint32_t phys_lo;
+ uint32_t phys_hi;
+ int error;
+ struct coresight_event *event;
+
+ coresight_pc = coresight_pcpu[cpu];
+ event = &coresight_pc->event;
+
+ pm_coresighta = (const struct pmc_md_coresight_op_pmcallocate *)&a->pm_md.pm_coresight;
+ pm_coresight = (struct pmc_md_coresight_pmc *)&pm->pm_md;
+ coresight_buf = &pm_coresight->coresight_buffers[cpu];
+
+ bufsize = 16 * 1024 * 1024;
+ error = coresight_buffer_allocate(cpu, coresight_buf, bufsize);
+ if (error != 0) {
+ dprintf("%s: can't allocate buffers\n", __func__);
+ return (EINVAL);
+ }
+
+ phys_lo = coresight_buf->phys_base & 0xffffffff;
+ phys_hi = (coresight_buf->phys_base >> 32) & 0xffffffff;
+ event->naddr = 0;
+
+ event->etr.started = 0;
+ event->etr.low = phys_lo;
+ event->etr.high = phys_hi;
+
+ mode = PMC_TO_MODE(pm);
+ if (mode == PMC_MODE_ST)
+ event->excp_level = 1;
+ else if (mode == PMC_MODE_TT)
+ event->excp_level = 0;
+ else {
+ dprintf("%s: unsupported mode %d\n", __func__, mode);
+ return (-1);
+ }
+
+ event->src = CORESIGHT_ETMV4;
+ event->sink = CORESIGHT_ETR;
+
+ coresight_init_event(cpu, event);
+
+ return (0);
+}
+
+static int
+coresight_allocate_pmc(int cpu, int ri, struct pmc *pm,
+ const struct pmc_op_pmcallocate *a)
+{
+ struct coresight_cpu *coresight_pc;
+ int i;
+
+ coresight_pc = coresight_pcpu[cpu];
+
+ dprintf("%s: curthread %lx, cpu %d (curcpu %d)\n", __func__,
+ (uint64_t)curthread, cpu, PCPU_GET(cpuid));
+ dprintf("%s: cpu %d (curcpu %d)\n", __func__,
+ cpu, PCPU_GET(cpuid));
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[coresight,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri >= 0 && ri < CORESIGHT_NPMCS,
+ ("[coresight,%d] illegal row index %d", __LINE__, ri));
+
+ if (a->pm_class != PMC_CLASS_CORESIGHT)
+ return (EINVAL);
+
+ if (a->pm_ev != PMC_EV_CORESIGHT_CORESIGHT)
+ return (EINVAL);
+
+ if ((pm->pm_caps & CORESIGHT_CAPS) == 0)
+ return (EINVAL);
+
+ if ((pm->pm_caps & ~CORESIGHT_CAPS) != 0)
+ return (EPERM);
+
+ if (a->pm_mode != PMC_MODE_ST &&
+ a->pm_mode != PMC_MODE_TT)
+ return (EINVAL);
+
+ /* Can't allocate multiple ST */
+ if (a->pm_mode == PMC_MODE_ST &&
+ coresight_pc->flags & FLAG_CORESIGHT_ALLOCATED) {
+ dprintf("error: coresight is already allocated for CPU %d\n", cpu);
+ return (EUSERS);
+ }
+
+ if (a->pm_mode == PMC_MODE_TT)
+ for (i = 0; i < pmc_cpu_max(); i++) {
+ if (coresight_buffer_prepare(i, pm, a))
+ return (EINVAL);
+ }
+ else
+ if (coresight_buffer_prepare(cpu, pm, a))
+ return (EINVAL);
+
+ if (a->pm_mode == PMC_MODE_ST)
+ coresight_pc->flags |= FLAG_CORESIGHT_ALLOCATED;
+
+ return (0);
+}
+
+static int
+coresight_config_pmc(int cpu, int ri, struct pmc *pm)
+{
+ struct coresight_cpu *coresight_pc;
+ struct pmc_hw *phw;
+
+ dprintf("%s: cpu %d (pm %lx)\n", __func__, cpu, (uint64_t)pm);
+
+ PMCDBG3(MDP,CFG,1, "cpu=%d ri=%d pm=%p", cpu, ri, pm);
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[coresight,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri == 0, ("[coresight,%d] illegal row-index %d", __LINE__, ri));
+
+ coresight_pc = coresight_pcpu[cpu];
+ phw = &coresight_pc->tc_hw;
+
+ KASSERT(pm == NULL || phw->phw_pmc == NULL,
+ ("[coresight,%d] pm=%p phw->pm=%p hwpmc not unconfigured", __LINE__,
+ pm, phw->phw_pmc));
+
+ phw->phw_pmc = pm;
+
+ return (0);
+}
+
+static int
+coresight_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc)
+{
+ const struct coresight_descr *pd;
+ struct pmc_hw *phw;
+ size_t copied;
+ int error;
+
+ dprintf("%s\n", __func__);
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[coresight,%d] illegal CPU %d", __LINE__, cpu));
+ KASSERT(ri == 0, ("[coresight,%d] illegal row-index %d", __LINE__, ri));
+
+ phw = &coresight_pcpu[cpu]->tc_hw;
+ pd = &coresight_pmcdesc[ri];
+
+ if ((error = copystr(pd->pm_descr.pd_name, pi->pm_name,
+ PMC_NAME_MAX, &copied)) != 0)
+ return (error);
+
+ pi->pm_class = pd->pm_descr.pd_class;
+
+ if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) {
+ pi->pm_enabled = TRUE;
+ *ppmc = phw->phw_pmc;
+ } else {
+ pi->pm_enabled = FALSE;
+ *ppmc = NULL;
+ }
+
+ return (0);
+}
+
+static int
+coresight_get_config(int cpu, int ri, struct pmc **ppm)
+{
+ struct coresight_cpu *coresight_pc;
+ struct pmc_hw *phw;
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[coresight,%d] illegal CPU %d", __LINE__, cpu));
+ KASSERT(ri == 0, ("[coresight,%d] illegal row-index %d", __LINE__, ri));
+
+ coresight_pc = coresight_pcpu[cpu];
+ phw = &coresight_pc->tc_hw;
+
+ *ppm = phw->phw_pmc;
+
+ return (0);
+}
+
+static int
+coresight_pcpu_init(struct pmc_mdep *md, int cpu)
+{
+ struct pmc_cpu *pc;
+ struct coresight_cpu *coresight_pc;
+ int ri;
+
+ dprintf("%s: cpu %d\n", __func__, cpu);
+
+ KASSERT(cpu == PCPU_GET(cpuid), ("Init on wrong CPU\n"));
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[coresight,%d] illegal cpu %d", __LINE__, cpu));
+ KASSERT(coresight_pcpu, ("[coresight,%d] null pcpu", __LINE__));
+ KASSERT(coresight_pcpu[cpu] == NULL, ("[coresight,%d] non-null per-cpu",
+ __LINE__));
+
+ coresight_pc = malloc(sizeof(struct coresight_cpu), M_CORESIGHT, M_WAITOK | M_ZERO);
+ coresight_pc->tc_hw.phw_state = PMC_PHW_FLAG_IS_ENABLED |
+ PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(0) |
+ PMC_PHW_FLAG_IS_SHAREABLE;
+
+ coresight_pcpu[cpu] = coresight_pc;
+
+ ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_CORESIGHT].pcd_ri;
+
+ KASSERT(pmc_pcpu, ("[coresight,%d] null generic pcpu", __LINE__));
+
+ pc = pmc_pcpu[cpu];
+
+ KASSERT(pc, ("[coresight,%d] null generic per-cpu", __LINE__));
+
+ pc->pc_hwpmcs[ri] = &coresight_pc->tc_hw;
+
+ return (0);
+}
+
+static int
+coresight_pcpu_fini(struct pmc_mdep *md, int cpu)
+{
+ int ri;
+ struct pmc_cpu *pc;
+ struct coresight_cpu *coresight_pc;
+
+ dprintf("%s: cpu %d\n", __func__, cpu);
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[coresight,%d] illegal cpu %d", __LINE__, cpu));
+ KASSERT(coresight_pcpu[cpu] != NULL, ("[coresight,%d] null pcpu", __LINE__));
+
+ coresight_pc = coresight_pcpu[cpu];
+
+ free(coresight_pcpu[cpu], M_CORESIGHT);
+ coresight_pcpu[cpu] = NULL;
+
+ ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_CORESIGHT].pcd_ri;
+
+ pc = pmc_pcpu[cpu];
+ pc->pc_hwpmcs[ri] = NULL;
+
+ return (0);
+}
+
+static int
+coresight_trace_config(int cpu, int ri, struct pmc *pm,
+ uint64_t *ranges, uint32_t nranges)
+{
+ struct coresight_event *event;
+ struct coresight_cpu *coresight_pc;
+ int i;
+
+ dprintf("%s\n", __func__);
+
+ coresight_pc = coresight_pcpu[cpu];
+ event = &coresight_pc->event;
+
+ KASSERT(cpu == PCPU_GET(cpuid), ("Configuring wrong CPU\n"));
+
+ for (i = 0; i < nranges * 2; i++)
+ event->addr[i] = ranges[i];
+
+ event->naddr = nranges;
+
+ enum pmc_mode mode;
+ mode = PMC_TO_MODE(pm);
+ if (mode == PMC_MODE_ST)
+ event->excp_level = 1;
+ else
+ event->excp_level = 0;
+
+ event->src = CORESIGHT_ETMV4;
+ event->sink = CORESIGHT_ETR;
+
+ return (0);
+}
+
+static int
+coresight_read_trace(int cpu, int ri, struct pmc *pm,
+ pmc_value_t *vcycle, pmc_value_t *voffset)
+{
+ struct pmc_md_coresight_pmc *pm_coresight;
+ struct coresight_event *event;
+ struct coresight_buffer *coresight_buf;
+ struct coresight_cpu *coresight_pc;
+ uint64_t offset;
+ uint64_t cycle;
+
+ dprintf("%s\n", __func__);
+
+ coresight_pc = coresight_pcpu[cpu];
+ coresight_pc->pm_mmap = pm;
+ event = &coresight_pc->event;
+
+ coresight_read(cpu, event);
+
+ cycle = event->etr.cycle;
+ offset = event->etr.offset;
+
+ pm_coresight = (struct pmc_md_coresight_pmc *)&pm->pm_md;
+ coresight_buf = &pm_coresight->coresight_buffers[cpu];
+
+ *vcycle = cycle;
+ *voffset = offset;
+
+ return (0);
+}
+
+static int
+coresight_read_pmc(int cpu, int ri, pmc_value_t *v)
+{
+
+ dprintf("%s\n", __func__);
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[coresight,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri == 0, ("[coresight,%d] illegal ri %d", __LINE__, ri));
+
+ *v = 0;
+
+ return (0);
+}
+
+static int
+coresight_release_pmc(int cpu, int ri, struct pmc *pm)
+{
+ struct pmc_md_coresight_pmc *pm_coresight;
+ struct coresight_event *event;
+ struct coresight_cpu *coresight_pc;
+ enum pmc_mode mode;
+ struct pmc_hw *phw;
+ int i;
+
+ pm_coresight = (struct pmc_md_coresight_pmc *)&pm->pm_md;
+ coresight_pc = coresight_pcpu[cpu];
+ event = &coresight_pc->event;
+
+ dprintf("%s: cpu %d (curcpu %d)\n", __func__, cpu, PCPU_GET(cpuid));
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[coresight,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri == 0,
+ ("[coresight,%d] illegal row-index %d", __LINE__, ri));
+
+ phw = &coresight_pcpu[cpu]->tc_hw;
+ phw->phw_pmc = NULL;
+
+ KASSERT(phw->phw_pmc == NULL,
+ ("[coresight,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc));
+
+ coresight_disable(cpu, event);
+
+ mode = PMC_TO_MODE(pm);
+ if (mode == PMC_MODE_TT)
+ for (i = 0; i < pmc_cpu_max(); i++)
+ coresight_buffer_deallocate(i, &pm_coresight->coresight_buffers[i]);
+ else
+ coresight_buffer_deallocate(cpu, &pm_coresight->coresight_buffers[cpu]);
+
+ if (mode == PMC_MODE_ST)
+ coresight_pc->flags &= ~FLAG_CORESIGHT_ALLOCATED;
+
+ return (0);
+}
+
+static int
+coresight_start_pmc(int cpu, int ri)
+{
+ struct coresight_event *event;
+ struct coresight_cpu *coresight_pc;
+ struct pmc_hw *phw;
+
+ dprintf("%s: cpu %d (curcpu %d)\n", __func__, cpu, PCPU_GET(cpuid));
+
+ coresight_pc = coresight_pcpu[cpu];
+ event = &coresight_pc->event;
+ phw = &coresight_pc->tc_hw;
+ if (phw == NULL || phw->phw_pmc == NULL)
+ return (-1);
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[coresight,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri == 0, ("[coresight,%d] illegal row-index %d", __LINE__, ri));
+
+ coresight_enable(cpu, event);
+
+ return (0);
+}
+
+static int
+coresight_stop_pmc(int cpu, int ri)
+{
+ struct coresight_event *event;
+ struct coresight_cpu *coresight_pc;
+
+ dprintf("%s\n", __func__);
+
+ coresight_pc = coresight_pcpu[cpu];
+ event = &coresight_pc->event;
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[coresight,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri == 0, ("[coresight,%d] illegal row-index %d", __LINE__, ri));
+
+ coresight_disable(cpu, event);
+
+ return (0);
+}
+
+static int
+coresight_write_pmc(int cpu, int ri, pmc_value_t v)
+{
+
+ dprintf("%s\n", __func__);
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[coresight,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri == 0, ("[coresight,%d] illegal row-index %d", __LINE__, ri));
+
+ return (0);
+}
+
+int
+pmc_coresight_initialize(struct pmc_mdep *md, int maxcpu)
+{
+ struct pmc_classdep *pcd;
+
+ dprintf("%s\n", __func__);
+
+ KASSERT(md != NULL, ("[coresight,%d] md is NULL", __LINE__));
+ KASSERT(md->pmd_nclass >= 1, ("[coresight,%d] dubious md->nclass %d",
+ __LINE__, md->pmd_nclass));
+
+ coresight_pcpu = malloc(sizeof(struct coresight_cpu *) * maxcpu, M_CORESIGHT,
+ M_WAITOK | M_ZERO);
+
+ pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_CORESIGHT];
+
+ pcd->pcd_caps = CORESIGHT_CAPS;
+ pcd->pcd_class = PMC_CLASS_CORESIGHT;
+ pcd->pcd_num = CORESIGHT_NPMCS;
+ pcd->pcd_ri = md->pmd_npmc;
+ pcd->pcd_width = 64;
+
+ pcd->pcd_allocate_pmc = coresight_allocate_pmc;
+ pcd->pcd_config_pmc = coresight_config_pmc;
+ pcd->pcd_describe = coresight_describe;
+ pcd->pcd_get_config = coresight_get_config;
+ pcd->pcd_pcpu_init = coresight_pcpu_init;
+ pcd->pcd_pcpu_fini = coresight_pcpu_fini;
+ pcd->pcd_read_pmc = coresight_read_pmc;
+ pcd->pcd_read_trace = coresight_read_trace;
+ pcd->pcd_trace_config = coresight_trace_config;
+ pcd->pcd_release_pmc = coresight_release_pmc;
+ pcd->pcd_start_pmc = coresight_start_pmc;
+ pcd->pcd_stop_pmc = coresight_stop_pmc;
+ pcd->pcd_write_pmc = coresight_write_pmc;
+
+ md->pmd_npmc += CORESIGHT_NPMCS;
+
+ return (0);
+}
+
+void
+pmc_coresight_finalize(struct pmc_mdep *md)
+{
+
+ dprintf("%s\n", __func__);
+
+#ifdef INVARIANTS
+ int i, ncpus;
+
+ ncpus = pmc_cpu_max();
+ for (i = 0; i < ncpus; i++)
+ KASSERT(coresight_pcpu[i] == NULL, ("[coresight,%d] non-null pcpu cpu %d",
+ __LINE__, i));
+
+ KASSERT(md->pmd_classdep[PMC_MDEP_CLASS_INDEX_CORESIGHT].pcd_class ==
+ PMC_CLASS_CORESIGHT, ("[coresight,%d] class mismatch", __LINE__));
+#endif
+
+ free(coresight_pcpu, M_CORESIGHT);
+ coresight_pcpu = NULL;
+}
Index: sys/dev/hwpmc/hwpmc_intel.c
===================================================================
--- sys/dev/hwpmc/hwpmc_intel.c
+++ sys/dev/hwpmc/hwpmc_intel.c
@@ -181,12 +181,8 @@
cputype = PMC_CPU_INTEL_IVYBRIDGE_XEON;
nclasses = 3;
break;
- /* Skylake */
case 0x4e:
case 0x5e:
- /* Kabylake */
- case 0x8E: /* Per Intel document 325462-063US July 2017. */
- case 0x9E: /* Per Intel document 325462-063US July 2017. */
cputype = PMC_CPU_INTEL_SKYLAKE;
nclasses = 3;
break;
@@ -220,6 +216,11 @@
nclasses = 3;
break;
}
+ case 0x8E: /* Per Intel document 325462-063US July 2017. */
+ case 0x9E: /* Per Intel document 325462-063US July 2017. */
+ cputype = PMC_CPU_INTEL_KABYLAKE;
+ nclasses = 4;
+ break;
break;
#if defined(__i386__) || defined(__amd64__)
case 0xF00: /* P4 */
@@ -237,7 +238,7 @@
/* Allocate base class and initialize machine dependent struct */
pmc_mdep = pmc_mdep_alloc(nclasses);
- pmc_mdep->pmd_cputype = cputype;
+ pmc_mdep->pmd_cputype = cputype;
pmc_mdep->pmd_switch_in = intel_switch_in;
pmc_mdep->pmd_switch_out = intel_switch_out;
@@ -256,6 +257,7 @@
case PMC_CPU_INTEL_BROADWELL_XEON:
case PMC_CPU_INTEL_SKYLAKE_XEON:
case PMC_CPU_INTEL_SKYLAKE:
+ case PMC_CPU_INTEL_KABYLAKE:
case PMC_CPU_INTEL_CORE:
case PMC_CPU_INTEL_CORE2:
case PMC_CPU_INTEL_CORE2EXTREME:
@@ -312,10 +314,10 @@
goto error;
}
+#if defined(__i386__) || defined(__amd64__)
/*
* Init the uncore class.
*/
-#if defined(__i386__) || defined(__amd64__)
switch (cputype) {
/*
* Intel Corei7 and Westmere processors.
@@ -330,7 +332,19 @@
default:
break;
}
+
+ /*
+ * Intel Processor Tracing (PT).
+ */
+ if (cputype == PMC_CPU_INTEL_KABYLAKE) {
+ error = pmc_pt_initialize(pmc_mdep, ncpus);
+ if (error) {
+ pmc_pt_finalize(pmc_mdep);
+ goto error;
+ }
+ }
#endif
+
error:
if (error) {
pmc_mdep_free(pmc_mdep);
@@ -353,6 +367,7 @@
case PMC_CPU_INTEL_BROADWELL_XEON:
case PMC_CPU_INTEL_SKYLAKE_XEON:
case PMC_CPU_INTEL_SKYLAKE:
+ case PMC_CPU_INTEL_KABYLAKE:
case PMC_CPU_INTEL_CORE:
case PMC_CPU_INTEL_CORE2:
case PMC_CPU_INTEL_CORE2EXTREME:
@@ -389,10 +404,10 @@
KASSERT(0, ("[intel,%d] unknown CPU type", __LINE__));
}
+#if defined(__i386__) || defined(__amd64__)
/*
* Uncore.
*/
-#if defined(__i386__) || defined(__amd64__)
switch (md->pmd_cputype) {
case PMC_CPU_INTEL_BROADWELL:
case PMC_CPU_INTEL_COREI7:
@@ -404,5 +419,11 @@
default:
break;
}
+
+ /*
+ * Intel Processor Tracing (PT).
+ */
+ if (md->pmd_cputype == PMC_CPU_INTEL_KABYLAKE)
+ pmc_pt_finalize(md);
#endif
}
Index: sys/dev/hwpmc/hwpmc_mod.c
===================================================================
--- sys/dev/hwpmc/hwpmc_mod.c
+++ sys/dev/hwpmc/hwpmc_mod.c
@@ -74,6 +74,7 @@
#include <vm/vm_object.h>
#include "hwpmc_soft.h"
+#include "hwpmc_vm.h"
/*
* Types
@@ -1295,6 +1296,8 @@
pp->pp_pmcs[ri].pp_pmcval;
pp->pp_pmcs[ri].pp_pmcval = pm->pm_sc.pm_reloadcount;
mtx_pool_unlock_spin(pmc_mtxpool, pm);
+ } else if (PMC_TO_MODE(pm) == PMC_MODE_TT) {
+ /* Nothing */
} else {
KASSERT(PMC_TO_MODE(pm) == PMC_MODE_TC,
("[pmc,%d] illegal mode=%d", __LINE__,
@@ -1310,7 +1313,8 @@
pcd->pcd_write_pmc(cpu, adjri, newvalue);
/* If a sampling mode PMC, reset stalled state. */
- if (PMC_TO_MODE(pm) == PMC_MODE_TS)
+ if (PMC_TO_MODE(pm) == PMC_MODE_TS ||
+ PMC_TO_MODE(pm) == PMC_MODE_TT)
CPU_CLR_ATOMIC(cpu, &pm->pm_stalled);
/* Indicate that we desire this to run. */
@@ -1472,7 +1476,8 @@
pp->pp_pmcs[ri].pp_pmcval,
pm->pm_sc.pm_reloadcount));
mtx_pool_unlock_spin(pmc_mtxpool, pm);
-
+ } else if (mode == PMC_MODE_TT) {
+ /* Nothing */
} else {
tmp = newvalue - PMC_PCPU_SAVED(cpu,ri);
@@ -1528,6 +1533,10 @@
const struct pmc *pm;
struct pmc_owner *po;
const struct pmc_process *pp;
+ struct proc *p;
+ bool pause_thread;
+
+ sx_slock(&pmc_sx);
freepath = fullpath = NULL;
pmc_getfilename((struct vnode *) pkm->pm_file, &fullpath, &freepath);
@@ -1539,17 +1548,42 @@
if (po->po_flags & PMC_PO_OWNS_LOGFILE)
pmclog_process_map_in(po, pid, pkm->pm_address, fullpath);
- if ((pp = pmc_find_process_descriptor(td->td_proc, 0)) == NULL)
+ if ((pp = pmc_find_process_descriptor(td->td_proc, 0)) == NULL) {
+ sx_sunlock(&pmc_sx);
goto done;
+ }
+
+ p = td->td_proc;
+ if ((p->p_flag & P_HWPMC) == 0) {
+ sx_sunlock(&pmc_sx);
+ goto done;
+ }
+
+ pause_thread = 0;
/*
* Inform sampling PMC owners tracking this process.
*/
- for (ri = 0; ri < md->pmd_npmc; ri++)
- if ((pm = pp->pp_pmcs[ri].pp_pmc) != NULL &&
- PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
+ for (ri = 0; ri < md->pmd_npmc; ri++) {
+ if ((pm = pp->pp_pmcs[ri].pp_pmc) == NULL)
+ continue;
+ if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)) ||
+ PMC_TO_MODE(pm) == PMC_MODE_TT)
pmclog_process_map_in(pm->pm_owner,
pid, pkm->pm_address, fullpath);
+ if (PMC_TO_MODE(pm) == PMC_MODE_TT)
+ pause_thread = 1;
+ }
+
+ sx_sunlock(&pmc_sx);
+
+ if (pause_thread) {
+ PROC_LOCK(td->td_proc);
+ PROC_SLOCK(td->td_proc);
+ thread_suspend_switch(td, td->td_proc);
+ PROC_SUNLOCK(td->td_proc);
+ PROC_UNLOCK(td->td_proc);
+ }
done:
if (freepath)
@@ -1580,11 +1614,14 @@
if ((pp = pmc_find_process_descriptor(td->td_proc, 0)) == NULL)
return;
- for (ri = 0; ri < md->pmd_npmc; ri++)
- if ((pm = pp->pp_pmcs[ri].pp_pmc) != NULL &&
- PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
+ for (ri = 0; ri < md->pmd_npmc; ri++) {
+ if ((pm = pp->pp_pmcs[ri].pp_pmc) == NULL)
+ continue;
+ if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)) ||
+ PMC_TO_MODE(pm) == PMC_MODE_TT)
pmclog_process_map_out(pm->pm_owner, pid,
pkm->pm_address, pkm->pm_address + pkm->pm_size);
+ }
}
/*
@@ -1598,7 +1635,8 @@
struct pmckern_map_in *km, *kmbase;
sx_assert(&pmc_sx, SX_LOCKED);
- KASSERT(PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)),
+ KASSERT(PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)) ||
+ PMC_TO_MODE(pm) == PMC_MODE_ST,
("[pmc,%d] non-sampling PMC (%p) desires mapping information",
__LINE__, (void *) pm));
@@ -1999,7 +2037,6 @@
break;
case PMC_FN_MMAP:
- sx_assert(&pmc_sx, SX_LOCKED);
pmc_process_mmap(td, (struct pmckern_map_in *) arg);
break;
@@ -2115,8 +2152,8 @@
mtx_lock_spin(&pmc_processhash_mtx);
LIST_FOREACH(pp, pph, pp_next)
- if (pp->pp_proc == p)
- break;
+ if (pp->pp_proc == p)
+ break;
if ((mode & PMC_FLAG_REMOVE) && pp != NULL)
LIST_REMOVE(pp, pp_next);
@@ -2652,7 +2689,8 @@
* If this is a sampling mode PMC, log mapping information for
* the kernel modules that are currently loaded.
*/
- if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
+ if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)) ||
+ PMC_TO_MODE(pm) == PMC_MODE_ST)
pmc_log_kernel_mappings(pm);
if (PMC_IS_VIRTUAL_MODE(mode)) {
@@ -3306,9 +3344,14 @@
mode = pa.pm_mode;
cpu = pa.pm_cpu;
- if ((mode != PMC_MODE_SS && mode != PMC_MODE_SC &&
- mode != PMC_MODE_TS && mode != PMC_MODE_TC) ||
- (cpu != (u_int) PMC_CPU_ANY && cpu >= pmc_cpu_max())) {
+ if (mode != PMC_MODE_SS && mode != PMC_MODE_TS &&
+ mode != PMC_MODE_SC && mode != PMC_MODE_TC &&
+ mode != PMC_MODE_ST && mode != PMC_MODE_TT) {
+ error = EINVAL;
+ break;
+ }
+
+ if (cpu != (u_int) PMC_CPU_ANY && cpu >= pmc_cpu_max()) {
error = EINVAL;
break;
}
@@ -3755,6 +3798,175 @@
}
break;
+ case PMC_OP_LOG_KERNEL_MAP:
+ {
+ struct pmc_op_simple sp;
+ struct pmc *pm;
+
+ if ((error = copyin(arg, &sp, sizeof(sp))) != 0)
+ break;
+
+ /* locate pmc descriptor */
+ if ((error = pmc_find_pmc(sp.pm_pmcid, &pm)) != 0)
+ break;
+
+ if (PMC_TO_MODE(pm) != PMC_MODE_ST)
+ break;
+
+ if (pm->pm_state != PMC_STATE_ALLOCATED &&
+ pm->pm_state != PMC_STATE_STOPPED &&
+ pm->pm_state != PMC_STATE_RUNNING) {
+ error = EINVAL;
+ break;
+ }
+
+ pmc_log_kernel_mappings(pm);
+ }
+ break;
+
+ case PMC_OP_THREAD_UNSUSPEND:
+ {
+ struct pmc_op_proc_unsuspend u;
+ struct proc *p;
+ struct pmc *pm;
+
+ if ((error = copyin(arg, &u, sizeof(u))) != 0)
+ break;
+
+ /* locate pmc descriptor */
+ if ((error = pmc_find_pmc(u.pm_pmcid, &pm)) != 0)
+ break;
+
+ /* lookup pid */
+ if ((p = pfind(u.pm_pid)) == NULL) {
+ error = ESRCH;
+ break;
+ }
+
+ if ((p->p_flag & P_HWPMC) == 0)
+ break;
+
+ PROC_SLOCK(p);
+ thread_unsuspend(p);
+ PROC_SUNLOCK(p);
+ PROC_UNLOCK(p);
+ }
+ break;
+
+ case PMC_OP_TRACE_CONFIG:
+ {
+ struct pmc_op_trace_config trc;
+ uint64_t *ranges;
+ struct pmc *pm;
+ struct pmc_binding pb;
+ struct pmc_classdep *pcd;
+ uint32_t nranges;
+ uint32_t cpu;
+ uint32_t ri;
+ int adjri;
+
+ if ((error = copyin(arg, &trc, sizeof(trc))) != 0)
+ break;
+
+ /* locate pmc descriptor */
+ if ((error = pmc_find_pmc(trc.pm_pmcid, &pm)) != 0)
+ break;
+
+ if (PMC_TO_MODE(pm) != PMC_MODE_ST &&
+ PMC_TO_MODE(pm) != PMC_MODE_TT)
+ break;
+
+ /* Can't proceed with PMC that hasn't been started. */
+ if (pm->pm_state != PMC_STATE_ALLOCATED &&
+ pm->pm_state != PMC_STATE_STOPPED &&
+ pm->pm_state != PMC_STATE_RUNNING) {
+ error = EINVAL;
+ break;
+ }
+
+ cpu = trc.pm_cpu;
+
+ ri = PMC_TO_ROWINDEX(pm);
+ pcd = pmc_ri_to_classdep(md, ri, &adjri);
+ if (pcd->pcd_trace_config == NULL)
+ break;
+
+ /* switch to CPU 'cpu' */
+ pmc_save_cpu_binding(&pb);
+ pmc_select_cpu(cpu);
+
+ ranges = trc.ranges;
+ nranges = trc.nranges;
+
+ mtx_pool_lock_spin(pmc_mtxpool, pm);
+ error = (*pcd->pcd_trace_config)(cpu, adjri,
+ pm, ranges, nranges);
+ mtx_pool_unlock_spin(pmc_mtxpool, pm);
+
+ pmc_restore_cpu_binding(&pb);
+ }
+ break;
+
+ /*
+ * Read a PMC trace buffer ptr.
+ */
+ case PMC_OP_TRACE_READ:
+ {
+ struct pmc_op_trace_read trr;
+ struct pmc_op_trace_read *trr_ret;
+ struct pmc_binding pb;
+ struct pmc_classdep *pcd;
+ struct pmc *pm;
+ pmc_value_t cycle;
+ pmc_value_t offset;
+ uint32_t cpu;
+ uint32_t ri;
+ int adjri;
+
+ if ((error = copyin(arg, &trr, sizeof(trr))) != 0)
+ break;
+
+ /* locate pmc descriptor */
+ if ((error = pmc_find_pmc(trr.pm_pmcid, &pm)) != 0)
+ break;
+
+ if (PMC_TO_MODE(pm) != PMC_MODE_ST &&
+ PMC_TO_MODE(pm) != PMC_MODE_TT)
+ break;
+
+ /* Can't read a PMC that hasn't been started. */
+ if (pm->pm_state != PMC_STATE_ALLOCATED &&
+ pm->pm_state != PMC_STATE_STOPPED &&
+ pm->pm_state != PMC_STATE_RUNNING) {
+ error = EINVAL;
+ break;
+ }
+
+ cpu = trr.pm_cpu;
+
+ ri = PMC_TO_ROWINDEX(pm);
+ pcd = pmc_ri_to_classdep(md, ri, &adjri);
+
+ /* switch to CPU 'cpu' */
+ pmc_save_cpu_binding(&pb);
+ pmc_select_cpu(cpu);
+
+ mtx_pool_lock_spin(pmc_mtxpool, pm);
+ error = (*pcd->pcd_read_trace)(cpu, adjri,
+ pm, &cycle, &offset);
+ mtx_pool_unlock_spin(pmc_mtxpool, pm);
+
+ pmc_restore_cpu_binding(&pb);
+
+ trr_ret = (struct pmc_op_trace_read *)arg;
+ if ((error = copyout(&cycle, &trr_ret->pm_cycle,
+ sizeof(trr.pm_cycle))))
+ break;
+ if ((error = copyout(&offset, &trr_ret->pm_offset,
+ sizeof(trr.pm_offset))))
+ break;
+ }
+ break;
/*
* Read and/or write a PMC.
@@ -3858,7 +4070,7 @@
/* save old value */
if (prw.pm_flags & PMC_F_OLDVALUE)
if ((error = (*pcd->pcd_read_pmc)(cpu, adjri,
- &oldvalue)))
+ &oldvalue)))
goto error;
/* write out new value */
if (prw.pm_flags & PMC_F_NEWVALUE)
@@ -5029,6 +5241,8 @@
printf("\n");
}
+ pmc_vm_initialize(md);
+
return (error);
}
@@ -5181,6 +5395,7 @@
}
pmclog_shutdown();
+ pmc_vm_finalize();
sx_xunlock(&pmc_sx); /* we are done */
}
Index: sys/dev/hwpmc/hwpmc_pt.h
===================================================================
--- /dev/null
+++ sys/dev/hwpmc/hwpmc_pt.h
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 2017 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#ifndef _DEV_HWPMC_PT_H_
+#define _DEV_HWPMC_PT_H_
+
+#include <sys/types.h>
+#include <sys/malloc.h>
+#include <vm/vm.h>
+
+#include <machine/frame.h>
+
+#define PT_CPUID 0x14
+#define PT_NADDR 4
+#define PT_NPMCS 1
+
+struct pmc_md_pt_op_pmcallocate {
+ uint32_t flags;
+#define INTEL_PT_FLAG_BRANCHES (1 << 0)
+#define INTEL_PT_FLAG_TSC (1 << 1)
+#define INTEL_PT_FLAG_MTC (1 << 2)
+#define INTEL_PT_FLAG_DISRETC (1 << 3)
+ uint64_t ranges[2 * PT_NADDR];
+ int nranges;
+};
+
+#ifdef _KERNEL
+struct xsave_header {
+ uint64_t xsave_bv;
+ uint64_t xcomp_bv;
+ uint8_t reserved[48];
+};
+
+struct pt_ext_area {
+ uint64_t rtit_ctl;
+ uint64_t rtit_output_base;
+ uint64_t rtit_output_mask_ptrs;
+ uint64_t rtit_status;
+ uint64_t rtit_cr3_match;
+ uint64_t rtit_addr0_a;
+ uint64_t rtit_addr0_b;
+ uint64_t rtit_addr1_a;
+ uint64_t rtit_addr1_b;
+};
+
+struct pt_save_area {
+ uint8_t legacy_state[512];
+ struct xsave_header header;
+ struct pt_ext_area pt_ext_area;
+} __aligned(64);
+
+struct topa_entry {
+ uint64_t base;
+ uint64_t size;
+ uint64_t offset;
+};
+
+struct pt_buffer {
+ uint64_t *topa_hw;
+ struct topa_entry *topa_sw;
+ uint64_t cycle;
+ vm_object_t obj;
+};
+
+/* MD extension for 'struct pmc' */
+struct pmc_md_pt_pmc {
+ struct pt_buffer pt_buffers[MAXCPU];
+};
+
+/*
+ * Prototypes.
+ */
+
+int pmc_pt_initialize(struct pmc_mdep *_md, int _maxcpu);
+void pmc_pt_finalize(struct pmc_mdep *_md);
+int pmc_pt_intr(int cpu, struct trapframe *tf);
+
+#endif /* !_KERNEL */
+#endif /* !_DEV_HWPMC_PT_H */
Index: sys/dev/hwpmc/hwpmc_pt.c
===================================================================
--- /dev/null
+++ sys/dev/hwpmc/hwpmc_pt.c
@@ -0,0 +1,952 @@
+/*-
+ * Copyright (c) 2017 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/pmc.h>
+#include <sys/pmckern.h>
+#include <sys/systm.h>
+#include <sys/ioccom.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+#include <sys/conf.h>
+#include <sys/module.h>
+#include <sys/mman.h>
+#include <sys/proc.h>
+#include <sys/vmem.h>
+#include <sys/vmmeter.h>
+#include <sys/bus.h>
+#include <sys/kthread.h>
+#include <sys/pmclog.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_phys.h>
+#include <vm/vm_radix.h>
+#include <vm/pmap.h>
+
+#include <machine/intr_machdep.h>
+#include <machine/specialreg.h>
+
+#include <dev/hwpmc/hwpmc_vm.h>
+
+#include <x86/apicvar.h>
+#include <x86/x86_var.h>
+
+static MALLOC_DEFINE(M_PT, "pt", "PT driver");
+static uint64_t pt_xsave_mask;
+
+extern struct cdev *pmc_cdev[MAXCPU];
+
+/*
+ * Intel PT support.
+ */
+
+#define PT_CAPS (PMC_CAP_READ | PMC_CAP_INTERRUPT | PMC_CAP_SYSTEM | PMC_CAP_USER)
+
+#define PMC_PT_DEBUG
+#undef PMC_PT_DEBUG
+
+#ifdef PMC_PT_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
+struct pt_descr {
+ struct pmc_descr pm_descr; /* "base class" */
+};
+
+static struct pt_descr pt_pmcdesc[PT_NPMCS] =
+{
+ {
+ .pm_descr =
+ {
+ .pd_name = "PT",
+ .pd_class = PMC_CLASS_PT,
+ .pd_caps = PT_CAPS,
+ .pd_width = 64
+ }
+ }
+};
+
+/*
+ * Per-CPU data structure for PTs.
+ */
+
+struct pt_cpu {
+ struct pmc_hw tc_hw;
+ uint32_t l0_eax;
+ uint32_t l0_ebx;
+ uint32_t l0_ecx;
+ uint32_t l1_eax;
+ uint32_t l1_ebx;
+ struct pmc *pm_mmap;
+ uint32_t flags;
+#define FLAG_PT_ALLOCATED (1 << 0)
+ struct pt_save_area save_area;
+};
+
+static struct pt_cpu **pt_pcpu;
+
+static __inline void
+xrstors(char *addr, uint64_t mask)
+{
+ uint32_t low, hi;
+
+ low = mask;
+ hi = mask >> 32;
+ __asm __volatile("xrstors %0" : : "m" (*addr), "a" (low), "d" (hi));
+}
+
+static __inline void
+xsaves(char *addr, uint64_t mask)
+{
+ uint32_t low, hi;
+
+ low = mask;
+ hi = mask >> 32;
+ __asm __volatile("xsaves %0" : "=m" (*addr) : "a" (low), "d" (hi) :
+ "memory");
+}
+
+static void
+pt_save_restore(struct pt_cpu *pt_pc, bool save)
+{
+ uint64_t val;
+
+ clts();
+ val = rxcr(XCR0);
+ load_xcr(XCR0, pt_xsave_mask);
+ wrmsr(MSR_IA32_XSS, XFEATURE_ENABLED_PT);
+ if (save) {
+ KASSERT((rdmsr(MSR_IA32_RTIT_CTL) & RTIT_CTL_TRACEEN) != 0,
+ ("%s: PT is disabled", __func__));
+ xsaves((char *)&pt_pc->save_area, XFEATURE_ENABLED_PT);
+ } else {
+ KASSERT((rdmsr(MSR_IA32_RTIT_CTL) & RTIT_CTL_TRACEEN) == 0,
+ ("%s: PT is enabled", __func__));
+ xrstors((char *)&pt_pc->save_area, XFEATURE_ENABLED_PT);
+ }
+ load_xcr(XCR0, val);
+ load_cr0(rcr0() | CR0_TS);
+}
+
+static void
+pt_configure_ranges(struct pt_cpu *pt_pc, const uint64_t *ranges,
+ uint32_t nranges)
+{
+ struct pt_ext_area *pt_ext;
+ struct pt_save_area *save_area;
+ int nranges_supp;
+ int n;
+
+ save_area = &pt_pc->save_area;
+ pt_ext = &save_area->pt_ext_area;
+
+ if (pt_pc->l0_ebx & CPUPT_IPF) {
+ /* How many ranges CPU does support ? */
+ nranges_supp = (pt_pc->l1_eax & CPUPT_NADDR_M) >> CPUPT_NADDR_S;
+
+ /* xsave/xrstor supports two ranges only */
+ if (nranges_supp > 2)
+ nranges_supp = 2;
+
+ n = nranges > nranges_supp ? nranges_supp : nranges;
+
+ switch (n) {
+ case 2:
+ pt_ext->rtit_ctl |= (1UL << RTIT_CTL_ADDR_CFG_S(1));
+ pt_ext->rtit_addr1_a = ranges[2];
+ pt_ext->rtit_addr1_b = ranges[3];
+ case 1:
+ pt_ext->rtit_ctl |= (1UL << RTIT_CTL_ADDR_CFG_S(0));
+ pt_ext->rtit_addr0_a = ranges[0];
+ pt_ext->rtit_addr0_b = ranges[1];
+ default:
+ break;
+ };
+ }
+}
+
+static int
+pt_buffer_allocate(uint32_t cpu, struct pt_buffer *pt_buf)
+{
+ struct pmc_vm_map *map;
+ struct pt_cpu *pt_pc;
+ uint64_t topa_size;
+ uint64_t segsize;
+ uint64_t offset;
+ uint32_t size;
+ uint32_t bufsize;
+ struct cdev_cpu *cc;
+ vm_object_t obj;
+ vm_page_t m;
+ int npages;
+ int ntopa;
+ int req;
+ int i, j;
+
+ pt_pc = pt_pcpu[cpu];
+
+ bufsize = 16 * 1024 * 1024;
+
+ if (pt_pc->l0_ecx & CPUPT_TOPA_MULTI)
+ topa_size = TOPA_SIZE_4K;
+ else
+ topa_size = TOPA_SIZE_16M;
+
+ segsize = PAGE_SIZE << (topa_size >> TOPA_SIZE_S);
+ ntopa = bufsize / segsize;
+ npages = segsize / PAGE_SIZE;
+
+ pt_buf->obj = obj = vm_pager_allocate(OBJT_PHYS, 0, bufsize,
+ PROT_READ, 0, curthread->td_ucred);
+
+ size = roundup2((ntopa + 1) * 8, PAGE_SIZE);
+ pt_buf->topa_hw = malloc(size, M_PT, M_WAITOK | M_ZERO);
+ pt_buf->topa_sw = malloc(ntopa * sizeof(struct topa_entry), M_PT,
+ M_WAITOK | M_ZERO);
+
+ VM_OBJECT_WLOCK(obj);
+ vm_object_reference_locked(obj);
+ offset = 0;
+ for (i = 0; i < ntopa; i++) {
+ req = VM_ALLOC_NOBUSY | VM_ALLOC_ZERO;
+ if (npages == 1)
+ m = vm_page_alloc(obj, i, req);
+ else
+ m = vm_page_alloc_contig(obj, i, req, npages, 0, ~0,
+ bufsize, 0, VM_MEMATTR_DEFAULT);
+ if (m == NULL) {
+ VM_OBJECT_WUNLOCK(obj);
+ printf("%s: Can't allocate memory.\n", __func__);
+ goto error;
+ }
+ for (j = 0; j < npages; j++)
+ m[j].valid = VM_PAGE_BITS_ALL;
+ pt_buf->topa_sw[i].size = segsize;
+ pt_buf->topa_sw[i].offset = offset;
+ pt_buf->topa_hw[i] = VM_PAGE_TO_PHYS(m) | topa_size;
+ if (i == (ntopa - 1))
+ pt_buf->topa_hw[i] |= TOPA_INT;
+
+ offset += segsize;
+ }
+ VM_OBJECT_WUNLOCK(obj);
+
+ /* The last entry is a pointer to the base table. */
+ pt_buf->topa_hw[ntopa] = vtophys(pt_buf->topa_hw) | TOPA_END;
+ pt_buf->cycle = 0;
+
+ map = malloc(sizeof(struct pmc_vm_map), M_PT, M_WAITOK | M_ZERO);
+ map->t = curthread;
+ map->obj = obj;
+ map->buf = pt_buf;
+
+ cc = pmc_cdev[cpu]->si_drv1;
+
+ mtx_lock(&cc->vm_mtx);
+ TAILQ_INSERT_HEAD(&cc->pmc_maplist, map, map_next);
+ mtx_unlock(&cc->vm_mtx);
+
+ return (0);
+
+error:
+ free(pt_buf->topa_hw, M_PT);
+ free(pt_buf->topa_sw, M_PT);
+ vm_object_deallocate(obj);
+
+ return (-1);
+}
+
+static int
+pt_buffer_deallocate(uint32_t cpu, struct pt_buffer *pt_buf)
+{
+ struct pmc_vm_map *map, *map_tmp;
+ struct cdev_cpu *cc;
+
+ cc = pmc_cdev[cpu]->si_drv1;
+
+ mtx_lock(&cc->vm_mtx);
+ TAILQ_FOREACH_SAFE(map, &cc->pmc_maplist, map_next, map_tmp) {
+ if (map->buf == pt_buf) {
+ TAILQ_REMOVE(&cc->pmc_maplist, map, map_next);
+ free(map, M_PT);
+ break;
+ }
+ }
+ mtx_unlock(&cc->vm_mtx);
+
+ free(pt_buf->topa_hw, M_PT);
+ free(pt_buf->topa_sw, M_PT);
+ vm_object_deallocate(pt_buf->obj);
+
+ return (0);
+}
+
+static int
+pt_buffer_prepare(uint32_t cpu, struct pmc *pm,
+ const struct pmc_op_pmcallocate *a)
+{
+ const struct pmc_md_pt_op_pmcallocate *pm_pta;
+ struct pt_cpu *pt_pc;
+ struct pmc_md_pt_pmc *pm_pt;
+ struct pt_buffer *pt_buf;
+ struct xsave_header *hdr;
+ struct pt_ext_area *pt_ext;
+ struct pt_save_area *save_area;
+ enum pmc_mode mode;
+ int error;
+
+ pt_pc = pt_pcpu[cpu];
+ if ((pt_pc->l0_ecx & CPUPT_TOPA) == 0)
+ return (ENXIO); /* We rely on TOPA support */
+
+ pm_pta = (const struct pmc_md_pt_op_pmcallocate *)&a->pm_md.pm_pt;
+ pm_pt = (struct pmc_md_pt_pmc *)&pm->pm_md;
+ pt_buf = &pm_pt->pt_buffers[cpu];
+
+ error = pt_buffer_allocate(cpu, pt_buf);
+ if (error != 0) {
+ dprintf("%s: can't allocate buffers\n", __func__);
+ return (EINVAL);
+ }
+
+ save_area = &pt_pc->save_area;
+ bzero(save_area, sizeof(struct pt_save_area));
+
+ hdr = &save_area->header;
+ hdr->xsave_bv = XFEATURE_ENABLED_PT;
+ hdr->xcomp_bv = XFEATURE_ENABLED_PT | (1ULL << 63) /* compaction */;
+
+ pt_ext = &save_area->pt_ext_area;
+
+ pt_ext->rtit_ctl = RTIT_CTL_TOPA | RTIT_CTL_TRACEEN;
+ pt_ext->rtit_output_base = (uint64_t)vtophys(pt_buf->topa_hw);
+ pt_ext->rtit_output_mask_ptrs = 0x7f;
+
+ pt_configure_ranges(pt_pc, pm_pta->ranges, pm_pta->nranges);
+
+ /*
+ * TODO
+ * if (sc->l0_ebx & CPUPT_PRW) {
+ * reg |= RTIT_CTL_FUPONPTW;
+ * reg |= RTIT_CTL_PTWEN;
+ * }
+ */
+
+ mode = PMC_TO_MODE(pm);
+ if (mode == PMC_MODE_ST)
+ pt_ext->rtit_ctl |= RTIT_CTL_OS;
+ else if (mode == PMC_MODE_TT)
+ pt_ext->rtit_ctl |= RTIT_CTL_USER;
+ else {
+ dprintf("%s: unsupported mode %d\n", __func__, mode);
+ return (-1);
+ }
+
+ /* Enable FUP, TIP, TIP.PGE, TIP.PGD, TNT, MODE.Exec and MODE.TSX packets */
+ if (pm_pta->flags & INTEL_PT_FLAG_BRANCHES)
+ pt_ext->rtit_ctl |= RTIT_CTL_BRANCHEN;
+
+ if (pm_pta->flags & INTEL_PT_FLAG_TSC)
+ pt_ext->rtit_ctl |= RTIT_CTL_TSCEN;
+
+ if ((pt_pc->l0_ebx & CPUPT_MTC) &&
+ (pm_pta->flags & INTEL_PT_FLAG_MTC))
+ pt_ext->rtit_ctl |= RTIT_CTL_MTCEN;
+
+ if (pm_pta->flags & INTEL_PT_FLAG_DISRETC)
+ pt_ext->rtit_ctl |= RTIT_CTL_DISRETC;
+
+ /*
+ * TODO: specify MTC frequency
+ * Note: Check Bitmap of supported MTC Period Encodings
+ * pt_ext->rtit_ctl |= RTIT_CTL_MTC_FREQ(6);
+ */
+
+ return (0);
+}
+
+static int
+pt_allocate_pmc(int cpu, int ri, struct pmc *pm,
+ const struct pmc_op_pmcallocate *a)
+{
+ struct pt_cpu *pt_pc;
+ int i;
+
+ if ((cpu_stdext_feature & CPUID_STDEXT_PROCTRACE) == 0)
+ return (ENXIO);
+
+ pt_pc = pt_pcpu[cpu];
+
+ dprintf("%s: curthread %lx, cpu %d (curcpu %d)\n", __func__,
+ (uint64_t)curthread, cpu, PCPU_GET(cpuid));
+ dprintf("%s: cpu %d (curcpu %d)\n", __func__,
+ cpu, PCPU_GET(cpuid));
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[pt,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri >= 0 && ri < PT_NPMCS,
+ ("[pt,%d] illegal row index %d", __LINE__, ri));
+
+ if (a->pm_class != PMC_CLASS_PT)
+ return (EINVAL);
+
+ if (a->pm_ev != PMC_EV_PT_PT)
+ return (EINVAL);
+
+ if ((pm->pm_caps & PT_CAPS) == 0)
+ return (EINVAL);
+
+ if ((pm->pm_caps & ~PT_CAPS) != 0)
+ return (EPERM);
+
+ if (a->pm_mode != PMC_MODE_ST &&
+ a->pm_mode != PMC_MODE_TT)
+ return (EINVAL);
+
+ /* Can't allocate multiple ST */
+ if (a->pm_mode == PMC_MODE_ST &&
+ pt_pc->flags & FLAG_PT_ALLOCATED) {
+ dprintf("error: pt is already allocated for CPU %d\n", cpu);
+ return (EUSERS);
+ }
+
+ if (a->pm_mode == PMC_MODE_TT)
+ for (i = 0; i < pmc_cpu_max(); i++) {
+ if (pt_buffer_prepare(i, pm, a))
+ return (EINVAL);
+ }
+ else
+ if (pt_buffer_prepare(cpu, pm, a))
+ return (EINVAL);
+
+ if (a->pm_mode == PMC_MODE_ST)
+ pt_pc->flags |= FLAG_PT_ALLOCATED;
+
+ return (0);
+}
+
+int
+pmc_pt_intr(int cpu, struct trapframe *tf)
+{
+ struct pmc_md_pt_pmc *pm_pt;
+ struct pt_buffer *pt_buf;
+ struct pt_cpu *pt_pc;
+ struct pmc_hw *phw;
+ struct pmc *pm;
+
+ if (pt_pcpu == NULL)
+ return (0);
+
+ pt_pc = pt_pcpu[cpu];
+ if (pt_pc == NULL)
+ return (0);
+
+ phw = &pt_pc->tc_hw;
+ if (phw == NULL || phw->phw_pmc == NULL)
+ return (0);
+
+ pm = phw->phw_pmc;
+ if (pm == NULL)
+ return (0);
+
+ KASSERT(pm != NULL, ("pm is NULL\n"));
+
+ pm_pt = (struct pmc_md_pt_pmc *)&pm->pm_md;
+ pt_buf = &pm_pt->pt_buffers[cpu];
+
+ atomic_add_long(&pt_buf->cycle, 1);
+
+ lapic_reenable_pmc();
+
+ return (1);
+}
+
+static int
+pt_config_pmc(int cpu, int ri, struct pmc *pm)
+{
+ struct pt_cpu *pt_pc;
+ struct pmc_hw *phw;
+
+ dprintf("%s: cpu %d (pm %lx)\n", __func__, cpu, (uint64_t)pm);
+
+ PMCDBG3(MDP,CFG,1, "cpu=%d ri=%d pm=%p", cpu, ri, pm);
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[pt,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri == 0, ("[pt,%d] illegal row-index %d", __LINE__, ri));
+
+ pt_pc = pt_pcpu[cpu];
+ phw = &pt_pc->tc_hw;
+
+ KASSERT(pm == NULL || phw->phw_pmc == NULL,
+ ("[pt,%d] pm=%p phw->pm=%p hwpmc not unconfigured", __LINE__,
+ pm, phw->phw_pmc));
+
+ phw->phw_pmc = pm;
+
+ return (0);
+}
+
+static int
+pt_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc)
+{
+ const struct pt_descr *pd;
+ struct pmc_hw *phw;
+ size_t copied;
+ int error;
+
+ dprintf("%s\n", __func__);
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[pt,%d] illegal CPU %d", __LINE__, cpu));
+ KASSERT(ri == 0, ("[pt,%d] illegal row-index %d", __LINE__, ri));
+
+ phw = &pt_pcpu[cpu]->tc_hw;
+ pd = &pt_pmcdesc[ri];
+
+ if ((error = copystr(pd->pm_descr.pd_name, pi->pm_name,
+ PMC_NAME_MAX, &copied)) != 0)
+ return (error);
+
+ pi->pm_class = pd->pm_descr.pd_class;
+
+ if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) {
+ pi->pm_enabled = TRUE;
+ *ppmc = phw->phw_pmc;
+ } else {
+ pi->pm_enabled = FALSE;
+ *ppmc = NULL;
+ }
+
+ return (0);
+}
+
+static int
+pt_get_config(int cpu, int ri, struct pmc **ppm)
+{
+ struct pmc_hw *phw;
+ struct pt_cpu *pt_pc;
+
+ dprintf("%s\n", __func__);
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[pt,%d] illegal CPU %d", __LINE__, cpu));
+ KASSERT(ri == 0, ("[pt,%d] illegal row-index %d", __LINE__, ri));
+
+ pt_pc = pt_pcpu[cpu];
+ phw = &pt_pc->tc_hw;
+
+ *ppm = phw->phw_pmc;
+
+ return (0);
+}
+
+static void
+pt_enumerate(struct pt_cpu *pt_pc)
+{
+ u_int cp[4];
+ u_int *eax;
+ u_int *ebx;
+ u_int *ecx;
+
+ eax = &cp[0];
+ ebx = &cp[1];
+ ecx = &cp[2];
+
+ dprintf("Enumerating part 1\n");
+
+ cpuid_count(PT_CPUID, 0, cp);
+ dprintf("%s: Maximum valid sub-leaf Index: %x\n", __func__, cp[0]);
+ dprintf("%s: ebx %x\n", __func__, cp[1]);
+ dprintf("%s: ecx %x\n", __func__, cp[2]);
+
+ pt_pc->l0_eax = cp[0];
+ pt_pc->l0_ebx = cp[1];
+ pt_pc->l0_ecx = cp[2];
+
+ dprintf("Enumerating part 2\n");
+
+ cpuid_count(PT_CPUID, 1, cp);
+ dprintf("%s: eax %x\n", __func__, cp[0]);
+ dprintf("%s: ebx %x\n", __func__, cp[1]);
+
+ pt_pc->l1_eax = cp[0];
+ pt_pc->l1_ebx = cp[1];
+}
+
+static int
+pt_pcpu_init(struct pmc_mdep *md, int cpu)
+{
+ struct pmc_cpu *pc;
+ struct pt_cpu *pt_pc;
+ u_int cp[4];
+ int ri;
+
+ dprintf("%s: cpu %d\n", __func__, cpu);
+
+ /* We rely on XSAVE support */
+ if ((cpu_feature2 & CPUID2_XSAVE) == 0) {
+ printf("Intel PT: XSAVE is not supported\n");
+ return (ENXIO);
+ }
+
+ cpuid_count(0xd, 0x0, cp);
+ if ((cp[0] & pt_xsave_mask) != pt_xsave_mask) {
+ printf("Intel PT: CPU0 does not support X87 or SSE: %x", cp[0]);
+ return (ENXIO);
+ }
+
+ cpuid_count(0xd, 0x1, cp);
+ if ((cp[0] & (1 << 0)) == 0) {
+ printf("Intel PT: XSAVE compaction is not supported\n");
+ return (ENXIO);
+ }
+
+ if ((cp[0] & (1 << 3)) == 0) {
+ printf("Intel PT: XSAVES/XRSTORS are not supported\n");
+ return (ENXIO);
+ }
+
+ /* Enable XSAVE */
+ load_cr4(rcr4() | CR4_XSAVE);
+
+ KASSERT(cpu == PCPU_GET(cpuid), ("Init on wrong CPU\n"));
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[pt,%d] illegal cpu %d", __LINE__, cpu));
+ KASSERT(pt_pcpu, ("[pt,%d] null pcpu", __LINE__));
+ KASSERT(pt_pcpu[cpu] == NULL, ("[pt,%d] non-null per-cpu",
+ __LINE__));
+
+ pt_pc = malloc(sizeof(struct pt_cpu), M_PT, M_WAITOK | M_ZERO);
+
+ pt_pc->tc_hw.phw_state = PMC_PHW_FLAG_IS_ENABLED |
+ PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(0) |
+ PMC_PHW_FLAG_IS_SHAREABLE;
+
+ pt_pcpu[cpu] = pt_pc;
+
+ ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_PT].pcd_ri;
+
+ KASSERT(pmc_pcpu, ("[pt,%d] null generic pcpu", __LINE__));
+
+ pc = pmc_pcpu[cpu];
+
+ KASSERT(pc, ("[pt,%d] null generic per-cpu", __LINE__));
+
+ pc->pc_hwpmcs[ri] = &pt_pc->tc_hw;
+
+ pt_enumerate(pt_pc);
+
+ return (0);
+}
+
+static int
+pt_pcpu_fini(struct pmc_mdep *md, int cpu)
+{
+ int ri;
+ struct pmc_cpu *pc;
+ struct pt_cpu *pt_pc;
+
+ dprintf("%s: cpu %d\n", __func__, cpu);
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[pt,%d] illegal cpu %d", __LINE__, cpu));
+ KASSERT(pt_pcpu[cpu] != NULL, ("[pt,%d] null pcpu", __LINE__));
+
+ pt_pc = pt_pcpu[cpu];
+
+ free(pt_pcpu[cpu], M_PT);
+ pt_pcpu[cpu] = NULL;
+
+ ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_PT].pcd_ri;
+
+ pc = pmc_pcpu[cpu];
+ pc->pc_hwpmcs[ri] = NULL;
+
+ return (0);
+}
+
+static int
+pt_trace_config(int cpu, int ri, struct pmc *pm,
+ uint64_t *ranges, uint32_t nranges)
+{
+ struct pt_cpu *pt_pc;
+ uint64_t reg;
+
+ dprintf("%s\n", __func__);
+
+ pt_pc = pt_pcpu[cpu];
+
+ KASSERT(cpu == PCPU_GET(cpuid), ("Configuring wrong CPU\n"));
+
+ /* Ensure tracing is turned off */
+ reg = rdmsr(MSR_IA32_RTIT_CTL);
+ if (reg & RTIT_CTL_TRACEEN)
+ pt_save_restore(pt_pc, true);
+
+ pt_configure_ranges(pt_pc, ranges, nranges);
+
+ return (0);
+}
+
+static int
+pt_read_trace(int cpu, int ri, struct pmc *pm,
+ pmc_value_t *cycle, pmc_value_t *voffset)
+{
+ struct pt_ext_area *pt_ext;
+ struct pt_save_area *save_area;
+ struct pmc_md_pt_pmc *pm_pt;
+ struct pt_buffer *pt_buf;
+ struct pt_cpu *pt_pc;
+ uint64_t offset;
+ uint64_t reg;
+ uint32_t idx;
+
+ pt_pc = pt_pcpu[cpu];
+ pt_pc->pm_mmap = pm;
+
+ pm_pt = (struct pmc_md_pt_pmc *)&pm->pm_md;
+ pt_buf = &pm_pt->pt_buffers[cpu];
+
+ save_area = &pt_pc->save_area;
+ pt_ext = &save_area->pt_ext_area;
+
+ reg = rdmsr(MSR_IA32_RTIT_CTL);
+ if (reg & RTIT_CTL_TRACEEN)
+ reg = rdmsr(MSR_IA32_RTIT_OUTPUT_MASK_PTRS);
+ else
+ reg = pt_ext->rtit_output_mask_ptrs;
+
+ idx = (reg & 0xffffffff) >> 7;
+ *cycle = pt_buf->cycle;
+
+ offset = reg >> 32;
+ *voffset = pt_buf->topa_sw[idx].offset + offset;
+
+ dprintf("%s: %lx\n", __func__, rdmsr(MSR_IA32_RTIT_OUTPUT_MASK_PTRS));
+ dprintf("%s: cycle %ld offset %ld\n", __func__, pt_buf->cycle, offset);
+
+ return (0);
+}
+
+static int
+pt_read_pmc(int cpu, int ri, pmc_value_t *v)
+{
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[pt,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri == 0, ("[pt,%d] illegal ri %d", __LINE__, ri));
+
+ *v = 0;
+
+ return (0);
+}
+
+static int
+pt_release_pmc(int cpu, int ri, struct pmc *pm)
+{
+ struct pmc_md_pt_pmc *pm_pt;
+ struct pt_cpu *pt_pc;
+ enum pmc_mode mode;
+ struct pmc_hw *phw;
+ int i;
+
+ pm_pt = (struct pmc_md_pt_pmc *)&pm->pm_md;
+ pt_pc = pt_pcpu[cpu];
+
+ dprintf("%s: cpu %d (curcpu %d)\n", __func__, cpu, PCPU_GET(cpuid));
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[pt,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri == 0,
+ ("[pt,%d] illegal row-index %d", __LINE__, ri));
+
+ phw = &pt_pcpu[cpu]->tc_hw;
+ phw->phw_pmc = NULL;
+
+ KASSERT(phw->phw_pmc == NULL,
+ ("[pt,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc));
+
+ dprintf("%s: cpu %d, output base %lx\n",
+ __func__, cpu, rdmsr(MSR_IA32_RTIT_OUTPUT_BASE));
+ dprintf("%s: cpu %d, output base ptr %lx\n",
+ __func__, cpu, rdmsr(MSR_IA32_RTIT_OUTPUT_MASK_PTRS));
+
+ mode = PMC_TO_MODE(pm);
+ if (mode == PMC_MODE_TT)
+ for (i = 0; i < pmc_cpu_max(); i++)
+ pt_buffer_deallocate(i, &pm_pt->pt_buffers[i]);
+ else
+ pt_buffer_deallocate(cpu, &pm_pt->pt_buffers[cpu]);
+
+ if (mode == PMC_MODE_ST)
+ pt_pc->flags &= ~FLAG_PT_ALLOCATED;
+
+ return (0);
+}
+
+static int
+pt_start_pmc(int cpu, int ri)
+{
+ struct pt_cpu *pt_pc;
+ struct pmc_hw *phw;
+
+ dprintf("%s: cpu %d (curcpu %d)\n", __func__, cpu, PCPU_GET(cpuid));
+
+ pt_pc = pt_pcpu[cpu];
+ phw = &pt_pc->tc_hw;
+ if (phw == NULL || phw->phw_pmc == NULL)
+ return (-1);
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[pt,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri == 0, ("[pt,%d] illegal row-index %d", __LINE__, ri));
+
+ pt_save_restore(pt_pc, false);
+
+ return (0);
+}
+
+static int
+pt_stop_pmc(int cpu, int ri)
+{
+ struct pt_cpu *pt_pc;
+
+ pt_pc = pt_pcpu[cpu];
+
+ dprintf("%s: cpu %d, output base %lx, ptr %lx\n", __func__, cpu,
+ rdmsr(MSR_IA32_RTIT_OUTPUT_BASE),
+ rdmsr(MSR_IA32_RTIT_OUTPUT_MASK_PTRS));
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[pt,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri == 0, ("[pt,%d] illegal row-index %d", __LINE__, ri));
+
+ /*
+ * Save the PT state to memory.
+ * This operation will disable tracing.
+ */
+ pt_save_restore(pt_pc, true);
+
+ return (0);
+}
+
+static int
+pt_write_pmc(int cpu, int ri, pmc_value_t v)
+{
+
+ KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
+ ("[pt,%d] illegal CPU value %d", __LINE__, cpu));
+ KASSERT(ri == 0, ("[pt,%d] illegal row-index %d", __LINE__, ri));
+
+ return (0);
+}
+
+int
+pmc_pt_initialize(struct pmc_mdep *md, int maxcpu)
+{
+ struct pmc_classdep *pcd;
+
+ dprintf("%s\n", __func__);
+
+ pt_xsave_mask = XFEATURE_ENABLED_X87 | XFEATURE_ENABLED_SSE;
+
+ KASSERT(md != NULL, ("[pt,%d] md is NULL", __LINE__));
+ KASSERT(md->pmd_nclass >= 1, ("[pt,%d] dubious md->nclass %d",
+ __LINE__, md->pmd_nclass));
+
+ pt_pcpu = malloc(sizeof(struct pt_cpu *) * maxcpu, M_PT,
+ M_WAITOK | M_ZERO);
+
+ pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_PT];
+
+ pcd->pcd_caps = PT_CAPS;
+ pcd->pcd_class = PMC_CLASS_PT;
+ pcd->pcd_num = PT_NPMCS;
+ pcd->pcd_ri = md->pmd_npmc;
+ pcd->pcd_width = 64;
+
+ pcd->pcd_allocate_pmc = pt_allocate_pmc;
+ pcd->pcd_config_pmc = pt_config_pmc;
+ pcd->pcd_describe = pt_describe;
+ pcd->pcd_get_config = pt_get_config;
+ pcd->pcd_pcpu_init = pt_pcpu_init;
+ pcd->pcd_pcpu_fini = pt_pcpu_fini;
+ pcd->pcd_read_pmc = pt_read_pmc;
+ pcd->pcd_read_trace = pt_read_trace;
+ pcd->pcd_trace_config = pt_trace_config;
+ pcd->pcd_release_pmc = pt_release_pmc;
+ pcd->pcd_start_pmc = pt_start_pmc;
+ pcd->pcd_stop_pmc = pt_stop_pmc;
+ pcd->pcd_write_pmc = pt_write_pmc;
+
+ md->pmd_npmc += PT_NPMCS;
+
+ return (0);
+}
+
+void
+pmc_pt_finalize(struct pmc_mdep *md)
+{
+
+ dprintf("%s\n", __func__);
+
+#ifdef INVARIANTS
+ int i, ncpus;
+
+ ncpus = pmc_cpu_max();
+ for (i = 0; i < ncpus; i++)
+ KASSERT(pt_pcpu[i] == NULL, ("[pt,%d] non-null pcpu cpu %d",
+ __LINE__, i));
+
+ KASSERT(md->pmd_classdep[PMC_MDEP_CLASS_INDEX_PT].pcd_class ==
+ PMC_CLASS_PT, ("[pt,%d] class mismatch", __LINE__));
+#endif
+
+ free(pt_pcpu, M_PT);
+ pt_pcpu = NULL;
+}
Index: sys/dev/hwpmc/hwpmc_vm.h
===================================================================
--- /dev/null
+++ sys/dev/hwpmc/hwpmc_vm.h
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2017 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_HWPMC_VM_H_
+#define _DEV_HWPMC_VM_H_
+
+int pmc_vm_initialize(struct pmc_mdep *md);
+int pmc_vm_finalize(void);
+
+struct pmc_vm_map {
+ TAILQ_ENTRY(pmc_vm_map) map_next;
+ struct thread *t;
+ vm_object_t obj;
+ void * buf;
+};
+
+struct cdev_cpu {
+ struct pmc_mdep *md;
+ struct mtx vm_mtx;
+ TAILQ_HEAD(, pmc_vm_map) pmc_maplist;
+ uint32_t cpu;
+};
+
+#endif /* !_DEV_HWPMC_VM_H_ */
Index: sys/dev/hwpmc/hwpmc_vm.c
===================================================================
--- /dev/null
+++ sys/dev/hwpmc/hwpmc_vm.c
@@ -0,0 +1,134 @@
+/*-
+ * Copyright (c) 2017 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/pmckern.h>
+#include <sys/conf.h>
+#include <sys/malloc.h>
+#include <sys/mman.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+
+#define PMC_VM_DEBUG
+#undef PMC_VM_DEBUG
+
+#ifdef PMC_VM_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
+#include "hwpmc_vm.h"
+
+struct cdev *pmc_cdev[MAXCPU];
+
+static int
+pmc_mmap_single(struct cdev *cdev, vm_ooffset_t *offset,
+ vm_size_t mapsize, struct vm_object **objp, int nprot)
+{
+ struct pmc_vm_map *map, *map_tmp;
+ struct cdev_cpu *cc;
+
+ cc = cdev->si_drv1;
+
+ if (nprot != PROT_READ || *offset != 0)
+ return (ENXIO);
+
+ mtx_lock(&cc->vm_mtx);
+ TAILQ_FOREACH_SAFE(map, &cc->pmc_maplist, map_next, map_tmp) {
+ if (map->t == curthread) {
+ mtx_unlock(&cc->vm_mtx);
+ *objp = map->obj;
+ return (0);
+ }
+ }
+ mtx_unlock(&cc->vm_mtx);
+
+ return (ENXIO);
+}
+
+static struct cdevsw pmc_cdevsw = {
+ .d_version = D_VERSION,
+ .d_mmap_single = pmc_mmap_single,
+ .d_name = "HWPMC",
+};
+
+int
+pmc_vm_initialize(struct pmc_mdep *md)
+{
+ unsigned int maxcpu;
+ struct cdev_cpu *cc;
+ int cpu;
+
+ maxcpu = pmc_cpu_max();
+
+ for (cpu = 0; cpu < maxcpu; cpu++) {
+ cc = malloc(sizeof(struct cdev_cpu), M_PMC, M_WAITOK | M_ZERO);
+ cc->cpu = cpu;
+ cc->md = md;
+ mtx_init(&cc->vm_mtx, "PMC VM", NULL, MTX_DEF);
+ TAILQ_INIT(&cc->pmc_maplist);
+
+ pmc_cdev[cpu] = make_dev(&pmc_cdevsw, 0, UID_ROOT, GID_WHEEL,
+ 0666, "pmc%d", cpu);
+ pmc_cdev[cpu]->si_drv1 = cc;
+ }
+
+ return (0);
+}
+
+int
+pmc_vm_finalize(void)
+{
+ unsigned int maxcpu;
+ struct cdev_cpu *cc;
+ int cpu;
+
+ maxcpu = pmc_cpu_max();
+
+ for (cpu = 0; cpu < maxcpu; cpu++) {
+ cc = pmc_cdev[cpu]->si_drv1;
+ mtx_destroy(&cc->vm_mtx);
+ free(cc, M_PMC);
+ destroy_dev(pmc_cdev[cpu]);
+ }
+
+ return (0);
+}
Index: sys/dev/hwpmc/pmc_events.h
===================================================================
--- sys/dev/hwpmc/pmc_events.h
+++ sys/dev/hwpmc/pmc_events.h
@@ -4843,6 +4843,20 @@
#define PMC_EV_TSC_FIRST PMC_EV_TSC_TSC
#define PMC_EV_TSC_LAST PMC_EV_TSC_TSC
+/* Intel PT */
+#define __PMC_EV_PT() \
+ __PMC_EV(PT, PT)
+
+#define PMC_EV_PT_FIRST PMC_EV_PT_PT
+#define PMC_EV_PT_LAST PMC_EV_PT_PT
+
+/* ARM CORESIGHT */
+#define __PMC_EV_CORESIGHT() \
+ __PMC_EV(CORESIGHT, CORESIGHT)
+
+#define PMC_EV_CORESIGHT_FIRST PMC_EV_CORESIGHT_CORESIGHT
+#define PMC_EV_CORESIGHT_LAST PMC_EV_CORESIGHT_CORESIGHT
+
/*
* Software events are dynamically defined.
*/
@@ -7141,6 +7155,7 @@
* START #EVENTS DESCRIPTION
* 0 0x1000 Reserved
* 0x1000 0x0001 TSC
+ * 0x1100 0x0001 PT
* 0x2000 0x0080 AMD K7 events
* 0x2080 0x0100 AMD K8 events
* 0x10000 0x0080 INTEL architectural fixed-function events
@@ -7157,11 +7172,14 @@
* 0x13300 0x00FF Freescale e500 events
* 0x14000 0x0100 ARMv7 events
* 0x14100 0x0100 ARMv8 events
+ * 0x14200 0x0001 ARM Coresight
* 0x20000 0x1000 Software events
*/
#define __PMC_EVENTS() \
__PMC_EV_BLOCK(TSC, 0x01000) \
__PMC_EV_TSC() \
+ __PMC_EV_BLOCK(PT, 0x1100) \
+ __PMC_EV_PT() \
__PMC_EV_BLOCK(K7, 0x2000) \
__PMC_EV_K7() \
__PMC_EV_BLOCK(K8, 0x2080) \
@@ -7197,7 +7215,9 @@
__PMC_EV_BLOCK(ARMV7, 0x14000) \
__PMC_EV_ARMV7() \
__PMC_EV_BLOCK(ARMV8, 0x14100) \
- __PMC_EV_ARMV8()
+ __PMC_EV_ARMV8() \
+ __PMC_EV_BLOCK(CORESIGHT, 0x14200) \
+ __PMC_EV_CORESIGHT()
#define PMC_EVENT_FIRST PMC_EV_TSC_TSC
#define PMC_EVENT_LAST PMC_EV_SOFT_LAST
Index: sys/kern/vfs_vnops.c
===================================================================
--- sys/kern/vfs_vnops.c
+++ sys/kern/vfs_vnops.c
@@ -2489,7 +2489,7 @@
if ((prot & VM_PROT_EXECUTE) != 0 && error == 0) {
pkm.pm_file = vp;
pkm.pm_address = (uintptr_t) *addr;
- PMC_CALL_HOOK(td, PMC_FN_MMAP, (void *) &pkm);
+ PMC_CALL_HOOK_UNLOCKED(td, PMC_FN_MMAP, (void *) &pkm);
}
}
#endif
Index: sys/modules/hwpmc/Makefile
===================================================================
--- sys/modules/hwpmc/Makefile
+++ sys/modules/hwpmc/Makefile
@@ -6,14 +6,16 @@
KMOD= hwpmc
-SRCS= hwpmc_mod.c hwpmc_logging.c hwpmc_soft.c vnode_if.h
+SRCS= hwpmc_mod.c hwpmc_logging.c hwpmc_soft.c hwpmc_vm.c vnode_if.h
.if ${MACHINE_CPUARCH} == "aarch64"
SRCS+= hwpmc_arm64.c hwpmc_arm64_md.c
+SRCS+= hwpmc_cs.c
.endif
.if ${MACHINE_CPUARCH} == "amd64"
SRCS+= hwpmc_amd.c hwpmc_core.c hwpmc_intel.c hwpmc_piv.c hwpmc_tsc.c
+SRCS+= hwpmc_pt.c
SRCS+= hwpmc_x86.c hwpmc_uncore.c
SRCS+= device_if.h bus_if.h
.endif
Index: sys/sys/pmc.h
===================================================================
--- sys/sys/pmc.h
+++ sys/sys/pmc.h
@@ -101,6 +101,7 @@
__PMC_CPU(INTEL_BROADWELL_XEON, 0x97, "Intel Broadwell Xeon") \
__PMC_CPU(INTEL_SKYLAKE, 0x98, "Intel Skylake") \
__PMC_CPU(INTEL_SKYLAKE_XEON, 0x99, "Intel Skylake Xeon") \
+ __PMC_CPU(INTEL_KABYLAKE, 0x9A, "Intel Kabylake") \
__PMC_CPU(INTEL_XSCALE, 0x100, "Intel XScale") \
__PMC_CPU(MIPS_24K, 0x200, "MIPS 24K") \
__PMC_CPU(MIPS_OCTEON, 0x201, "Cavium Octeon") \
@@ -151,7 +152,9 @@
__PMC_CLASS(ARMV7, 0x10, "ARMv7") \
__PMC_CLASS(ARMV8, 0x11, "ARMv8") \
__PMC_CLASS(MIPS74K, 0x12, "MIPS 74K") \
- __PMC_CLASS(E500, 0x13, "Freescale e500 class")
+ __PMC_CLASS(E500, 0x13, "Freescale e500 class") \
+ __PMC_CLASS(PT, 0x14, "Intel PT") \
+ __PMC_CLASS(CORESIGHT, 0x15, "ARM Coresight")
enum pmc_class {
#undef __PMC_CLASS
@@ -160,7 +163,7 @@
};
#define PMC_CLASS_FIRST PMC_CLASS_TSC
-#define PMC_CLASS_LAST PMC_CLASS_E500
+#define PMC_CLASS_LAST PMC_CLASS_CORESIGHT
/*
* A PMC can be in the following states:
@@ -231,7 +234,9 @@
__PMC_MODE(SS, 0) \
__PMC_MODE(SC, 1) \
__PMC_MODE(TS, 2) \
- __PMC_MODE(TC, 3)
+ __PMC_MODE(TC, 3) \
+ __PMC_MODE(ST, 4) \
+ __PMC_MODE(TT, 5)
enum pmc_mode {
#undef __PMC_MODE
@@ -245,11 +250,11 @@
#define PMC_IS_COUNTING_MODE(mode) \
((mode) == PMC_MODE_SC || (mode) == PMC_MODE_TC)
#define PMC_IS_SYSTEM_MODE(mode) \
- ((mode) == PMC_MODE_SS || (mode) == PMC_MODE_SC)
+ ((mode) == PMC_MODE_SS || (mode) == PMC_MODE_SC || (mode) == PMC_MODE_ST)
#define PMC_IS_SAMPLING_MODE(mode) \
((mode) == PMC_MODE_SS || (mode) == PMC_MODE_TS)
#define PMC_IS_VIRTUAL_MODE(mode) \
- ((mode) == PMC_MODE_TS || (mode) == PMC_MODE_TC)
+ ((mode) == PMC_MODE_TS || (mode) == PMC_MODE_TC || (mode) == PMC_MODE_TT)
/*
* PMC row disposition
@@ -341,7 +346,11 @@
__PMC_OP(PMCSTOP, "Stop a PMC") \
__PMC_OP(WRITELOG, "Write a cookie to the log file") \
__PMC_OP(CLOSELOG, "Close log file") \
- __PMC_OP(GETDYNEVENTINFO, "Get dynamic events list")
+ __PMC_OP(GETDYNEVENTINFO, "Get dynamic events list") \
+ __PMC_OP(LOG_KERNEL_MAP, "Log kernel mappings") \
+ __PMC_OP(THREAD_UNSUSPEND, "Thread unsuspend") \
+ __PMC_OP(TRACE_READ, "Read trace buffer pointer") \
+ __PMC_OP(TRACE_CONFIG, "Setup trace IP ranges")
enum pmc_ops {
@@ -487,7 +496,6 @@
pmc_value_t pm_value; /* new&returned value */
};
-
/*
* OP GETPMCINFO
*
@@ -513,6 +521,40 @@
struct pmc_info pm_pmcs[]; /* space for 'npmc' structures */
};
+/*
+ * OP PROC_UNSUSPEND
+ *
+ * Unsuspend all threads of proc.
+ */
+
+struct pmc_op_proc_unsuspend {
+ pmc_id_t pm_pmcid;
+ pid_t pm_pid;
+};
+
+/*
+ * OP TRACE_CONFIG
+ */
+
+#define PMC_FILTER_MAX_IP_RANGES 4
+
+struct pmc_op_trace_config {
+ pmc_id_t pm_pmcid;
+ uint32_t pm_cpu; /* CPU number or PMC_CPU_ANY */
+ uint64_t ranges[2 * PMC_FILTER_MAX_IP_RANGES];
+ uint32_t nranges;
+};
+
+/*
+ * OP TRACE_READ
+ */
+
+struct pmc_op_trace_read {
+ pmc_id_t pm_pmcid;
+ uint32_t pm_cpu;
+ pmc_value_t pm_cycle; /* returned value */
+ pmc_value_t pm_offset; /* returned value */
+};
/*
* OP GETCPUINFO
@@ -520,7 +562,6 @@
* Retrieve system CPU information.
*/
-
struct pmc_classinfo {
enum pmc_class pm_class; /* class id */
uint32_t pm_caps; /* counter capabilities */
@@ -951,6 +992,12 @@
int (*pcd_read_pmc)(int _cpu, int _ri, pmc_value_t *_value);
int (*pcd_write_pmc)(int _cpu, int _ri, pmc_value_t _value);
+ /* trace */
+ int (*pcd_read_trace)(int _cpu, int _ri, struct pmc *_pm,
+ pmc_value_t *_cycle, pmc_value_t *_offset);
+ int (*pcd_trace_config)(int _cpu, int _ri, struct pmc *_pm,
+ uint64_t *ranges, uint32_t nranges);
+
/* pmc allocation/release */
int (*pcd_allocate_pmc)(int _cpu, int _ri, struct pmc *_t,
const struct pmc_op_pmcallocate *_a);
@@ -978,7 +1025,7 @@
* Machine dependent bits needed per CPU type.
*/
-struct pmc_mdep {
+struct pmc_mdep {
uint32_t pmd_cputype; /* from enum pmc_cputype */
uint32_t pmd_npmc; /* number of PMCs per CPU */
uint32_t pmd_nclass; /* number of PMC classes present */
Index: sys/x86/include/specialreg.h
===================================================================
--- sys/x86/include/specialreg.h
+++ sys/x86/include/specialreg.h
@@ -104,6 +104,7 @@
#define XFEATURE_ENABLED_OPMASK 0x00000020
#define XFEATURE_ENABLED_ZMM_HI256 0x00000040
#define XFEATURE_ENABLED_HI16_ZMM 0x00000080
+#define XFEATURE_ENABLED_PT 0x00000100
#define XFEATURE_AVX \
(XFEATURE_ENABLED_X87 | XFEATURE_ENABLED_SSE | XFEATURE_ENABLED_AVX)
Index: usr.sbin/Makefile
===================================================================
--- usr.sbin/Makefile
+++ usr.sbin/Makefile
@@ -183,6 +183,7 @@
SUBDIR.${MK_PMC}+= pmccontrol
SUBDIR.${MK_PMC}+= pmcstat
SUBDIR.${MK_PMC}+= pmcstudy
+SUBDIR.${MK_PMC}+= pmctrace
SUBDIR.${MK_PORTSNAP}+= portsnap
SUBDIR.${MK_PPP}+= ppp
SUBDIR.${MK_QUOTAS}+= edquota
Index: usr.sbin/pmctrace/Makefile
===================================================================
--- /dev/null
+++ usr.sbin/pmctrace/Makefile
@@ -0,0 +1,22 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+# $FreeBSD$
+
+PROG= pmctrace
+SRCS= pmctrace.c
+MAN=
+
+LIBADD= elf pmc pmcstat
+
+.if ${MACHINE_CPUARCH} == "amd64"
+SRCS+= pmctrace_pt.c \
+ pmctrace_pt.h
+LIBADD+= ipt
+.endif
+
+.if ${MACHINE_CPUARCH} == "aarch64"
+SRCS+= pmctrace_cs.c \
+ pmctrace_cs.h
+LIBADD+= opencsd
+.endif
+
+.include <bsd.prog.mk>
Index: usr.sbin/pmctrace/pmctrace.h
===================================================================
--- /dev/null
+++ usr.sbin/pmctrace/pmctrace.h
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 2017 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _PMCTRACE_H_
+#define _PMCTRACE_H_
+
+struct mtrace_data {
+ uint64_t ip;
+ int cpu;
+ struct pmcstat_process *pp;
+ uint32_t flags;
+};
+
+struct trace_cpu {
+ uint32_t cycle;
+ uint64_t offset;
+ struct mtrace_data mdata;
+ uint32_t bufsize;
+ void *base;
+ int fd;
+};
+
+struct trace_dev_methods {
+ int (*process)(struct trace_cpu *, struct pmcstat_process *,
+ uint32_t cpu, uint32_t cycle, uint64_t offset);
+ int (*init)(struct trace_cpu *tc);
+ int (*option)(int option);
+};
+
+struct trace_dev {
+ const char *ev_spec;
+ struct trace_dev_methods *methods;
+};
+
+struct pmctrace_config {
+ struct trace_dev *trace_dev;
+ uint32_t flags;
+};
+
+#endif /* !_PMCTRACE_H_ */
Index: usr.sbin/pmctrace/pmctrace.c
===================================================================
--- /dev/null
+++ usr.sbin/pmctrace/pmctrace.c
@@ -0,0 +1,683 @@
+/*-
+ * Copyright (c) 2017 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/event.h>
+#include <sys/cpuset.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+#include <sys/mman.h>
+#include <sys/uio.h>
+#include <sys/signal.h>
+#include <sys/types.h>
+
+#include <assert.h>
+#include <signal.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <gelf.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <libgen.h>
+#include <pmc.h>
+#include <pmclog.h>
+#include <sysexits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include <libpmcstat.h>
+
+#include "pmctrace.h"
+#if defined(__amd64__)
+#include "pmctrace_pt.h"
+#endif
+#if defined(__aarch64__)
+#include "pmctrace_cs.h"
+#endif
+
+#define MAX_CPU 4096
+
+#define PMCTRACE_DEBUG
+#undef PMCTRACE_DEBUG
+
+#ifdef PMCTRACE_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
+static struct pmcstat_args args;
+static struct kevent kev;
+static struct pmcstat_process *pmcstat_kernproc;
+static struct pmcstat_stats pmcstat_stats;
+static struct trace_cpu *trace_cpus[MAX_CPU];
+static struct pmc_plugins plugins[] = {};
+
+static int pmcstat_sockpair[NSOCKPAIRFD];
+static int pmcstat_kq;
+static int pmcstat_npmcs;
+static int pmcstat_mergepmc;
+static int ps_samples_period;
+
+struct pmcstat_image_hash_list pmcstat_image_hash[PMCSTAT_NHASH];
+struct pmcstat_process_hash_list pmcstat_process_hash[PMCSTAT_NHASH];
+struct pmcstat_pmcs pmcstat_pmcs = LIST_HEAD_INITIALIZER(pmcstat_pmcs);
+
+static struct trace_dev trace_devs[] = {
+#if defined(__amd64__)
+ { "pt", &ipt_methods },
+#elif defined(__aarch64__)
+ { "coresight", &cs_methods },
+#endif
+ { NULL, NULL }
+};
+
+static struct pmctrace_config pmctrace_cfg;
+
+static int
+pmctrace_ncpu(void)
+{
+ size_t ncpu_size;
+ int error;
+ int ncpu;
+
+ ncpu_size = sizeof(ncpu);
+ error = sysctlbyname("hw.ncpu", &ncpu, &ncpu_size, NULL, 0);
+ if (error)
+ return (-1);
+
+ return (ncpu);
+}
+
+static int
+pmctrace_init_cpu(uint32_t cpu)
+{
+ struct trace_cpu *tc;
+ char filename[16];
+ struct mtrace_data *mdata;
+
+ tc = trace_cpus[cpu];
+ mdata = &tc->mdata;
+ mdata->ip = 0;
+ mdata->cpu = cpu;
+
+ sprintf(filename, "/dev/pmc%d", cpu);
+
+ tc->fd = open(filename, O_RDWR);
+ if (tc->fd < 0) {
+ printf("Can't open %s\n", filename);
+ return (-1);
+ }
+
+ tc->bufsize = 16 * 1024 * 1024;
+ tc->cycle = 0;
+ tc->offset = 0;
+
+ tc->base = mmap(NULL, tc->bufsize, PROT_READ, MAP_SHARED, tc->fd, 0);
+ if (tc->base == MAP_FAILED) {
+ printf("mmap failed: err %d\n", errno);
+ return (-1);
+ }
+ dprintf("%s: tc->base %lx, *tc->base %lx\n", __func__,
+ (uint64_t)tc->base, *(uint64_t *)tc->base);
+
+ if (pmctrace_cfg.trace_dev->methods->init != NULL)
+ pmctrace_cfg.trace_dev->methods->init(tc);
+
+ return (0);
+}
+
+static int
+pmctrace_process_cpu(int cpu, struct pmcstat_ev *ev)
+{
+ struct pmcstat_process *pp;
+ struct pmcstat_target *pt;
+ pmc_value_t offset;
+ pmc_value_t cycle;
+ struct trace_cpu *tc;
+ struct trace_dev *trace_dev;
+
+ trace_dev = pmctrace_cfg.trace_dev;
+ tc = trace_cpus[cpu];
+
+ pmc_read_trace(cpu, ev->ev_pmcid, &cycle, &offset);
+
+ dprintf("cpu %d cycle %lx offset %lx\n", cpu, cycle, offset);
+
+ pt = SLIST_FIRST(&args.pa_targets);
+ if (pt != NULL)
+ pp = pmcstat_process_lookup(pt->pt_pid, 0);
+ else
+ pp = pmcstat_kernproc;
+
+ if (pp)
+ trace_dev->methods->process(tc, pp, cpu, cycle, offset);
+ else
+ dprintf("pp not found\n");
+
+ return (0);
+}
+
+static int
+pmctrace_process_all(int user_mode)
+{
+ struct pmcstat_ev *ev;
+ int ncpu;
+ int i;
+
+ ncpu = pmctrace_ncpu();
+ if (ncpu < 0)
+ errx(EX_SOFTWARE, "ERROR: Can't get cpus\n");
+
+ if (user_mode) {
+ ev = STAILQ_FIRST(&args.pa_events);
+ for (i = 0; i < ncpu; i++)
+ pmctrace_process_cpu(i, ev);
+ } else
+ STAILQ_FOREACH(ev, &args.pa_events, ev_next)
+ pmctrace_process_cpu(ev->ev_cpu, ev);
+
+ return (0);
+}
+
+static void
+pmctrace_cleanup(void)
+{
+ struct pmcstat_ev *ev;
+
+ /* release allocated PMCs. */
+ STAILQ_FOREACH(ev, &args.pa_events, ev_next)
+ if (ev->ev_pmcid != PMC_ID_INVALID) {
+ if (pmc_stop(ev->ev_pmcid) < 0)
+ err(EX_OSERR,
+ "ERROR: cannot stop pmc 0x%x \"%s\"",
+ ev->ev_pmcid, ev->ev_name);
+ if (pmc_release(ev->ev_pmcid) < 0)
+ err(EX_OSERR,
+ "ERROR: cannot release pmc 0x%x \"%s\"",
+ ev->ev_pmcid, ev->ev_name);
+ }
+
+ /* de-configure the log file if present. */
+ if (args.pa_flags & (FLAG_HAS_PIPE | FLAG_HAS_OUTPUT_LOGFILE))
+ (void) pmc_configure_logfile(-1);
+
+ if (args.pa_logparser) {
+ pmclog_close(args.pa_logparser);
+ args.pa_logparser = NULL;
+ }
+
+ pmcstat_shutdown_logging(&args, plugins, &pmcstat_stats);
+}
+
+static void
+pmctrace_start_pmcs(void)
+{
+ struct pmcstat_ev *ev;
+
+ STAILQ_FOREACH(ev, &args.pa_events, ev_next) {
+ dprintf("starting ev->ev_cpu %d\n", ev->ev_cpu);
+ assert(ev->ev_pmcid != PMC_ID_INVALID);
+ if (pmc_start(ev->ev_pmcid) < 0) {
+ warn("ERROR: Cannot start pmc 0x%x \"%s\"",
+ ev->ev_pmcid, ev->ev_name);
+ pmctrace_cleanup();
+ exit(EX_OSERR);
+ }
+ }
+}
+
+static int
+pmctrace_open_logfile(void)
+{
+ int pipefd[2];
+
+ /*
+ * process the log on the fly by reading it in
+ * through a pipe.
+ */
+ if (pipe(pipefd) < 0)
+ err(EX_OSERR, "ERROR: pipe(2) failed");
+
+ if (fcntl(pipefd[READPIPEFD], F_SETFL, O_NONBLOCK) < 0)
+ err(EX_OSERR, "ERROR: fcntl(2) failed");
+
+ EV_SET(&kev, pipefd[READPIPEFD], EVFILT_READ, EV_ADD,
+ 0, 0, NULL);
+
+ if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0)
+ err(EX_OSERR, "ERROR: Cannot register kevent");
+
+ args.pa_logfd = pipefd[WRITEPIPEFD];
+ args.pa_flags |= FLAG_HAS_PIPE;
+ args.pa_logparser = pmclog_open(pipefd[READPIPEFD]);
+
+ if (pmc_configure_logfile(args.pa_logfd) < 0)
+ err(EX_OSERR, "ERROR: Cannot configure log file");
+
+ return (0);
+}
+
+static int
+pmctrace_find_kernel(void)
+{
+ struct stat sb;
+ char buffer[PATH_MAX];
+ size_t len;
+ char *tmp;
+
+ /* Default to using the running system kernel. */
+ len = 0;
+ if (sysctlbyname("kern.bootfile", NULL, &len, NULL, 0) == -1)
+ err(EX_OSERR, "ERROR: Cannot determine path of running kernel");
+ args.pa_kernel = malloc(len);
+ if (args.pa_kernel == NULL)
+ errx(EX_SOFTWARE, "ERROR: Out of memory.");
+ if (sysctlbyname("kern.bootfile", args.pa_kernel, &len, NULL, 0) == -1)
+ err(EX_OSERR, "ERROR: Cannot determine path of running kernel");
+
+ /*
+ * Check if 'kerneldir' refers to a file rather than a
+ * directory. If so, use `dirname path` to determine the
+ * kernel directory.
+ */
+ (void) snprintf(buffer, sizeof(buffer), "%s%s", args.pa_fsroot,
+ args.pa_kernel);
+ if (stat(buffer, &sb) < 0)
+ err(EX_OSERR, "ERROR: Cannot locate kernel \"%s\"",
+ buffer);
+ if (!S_ISREG(sb.st_mode) && !S_ISDIR(sb.st_mode))
+ errx(EX_USAGE, "ERROR: \"%s\": Unsupported file type.",
+ buffer);
+ if (!S_ISDIR(sb.st_mode)) {
+ tmp = args.pa_kernel;
+ args.pa_kernel = strdup(dirname(args.pa_kernel));
+ if (args.pa_kernel == NULL)
+ errx(EX_SOFTWARE, "ERROR: Out of memory");
+ free(tmp);
+ (void) snprintf(buffer, sizeof(buffer), "%s%s",
+ args.pa_fsroot, args.pa_kernel);
+ if (stat(buffer, &sb) < 0)
+ err(EX_OSERR, "ERROR: Cannot stat \"%s\"",
+ buffer);
+ if (!S_ISDIR(sb.st_mode))
+ errx(EX_USAGE,
+ "ERROR: \"%s\" is not a directory.",
+ buffer);
+ }
+
+ return (0);
+}
+
+static void
+pmctrace_setup_cpumask(cpuset_t *cpumask)
+{
+ cpuset_t rootmask;
+
+ /*
+ * The initial CPU mask specifies the root mask of this process
+ * which is usually all CPUs in the system.
+ */
+ if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
+ sizeof(rootmask), &rootmask) == -1)
+ err(EX_OSERR, "ERROR: Cannot determine the root set of CPUs");
+ CPU_COPY(&rootmask, cpumask);
+}
+
+static int
+pmctrace_delayed_start(bool user_mode, char *func_name, char *func_image)
+{
+ uint64_t ranges[2];
+ struct pmcstat_symbol *sym;
+ struct pmcstat_target *pt;
+ struct pmcstat_process *pp;
+ struct pmcstat_ev *ev;
+ uintptr_t addr_start;
+ uintptr_t addr_end;
+ int ncpu;
+ int i;
+
+ if (func_name == NULL || func_image == NULL)
+ return (0);
+
+ ncpu = pmctrace_ncpu();
+ if (ncpu < 0)
+ errx(EX_SOFTWARE, "ERROR: Can't get cpus\n");
+
+ if (user_mode) {
+ pt = SLIST_FIRST(&args.pa_targets);
+ if (pt == NULL)
+ errx(EX_SOFTWARE, "ERROR: can't get target.");
+ pp = pmcstat_process_lookup(pt->pt_pid, 0);
+ if (pp == NULL)
+ errx(EX_SOFTWARE, "ERROR: pp is NULL, pid %d\n",
+ (uint32_t)pt->pt_pid);
+ } else
+ pp = pmcstat_kernproc;
+
+ sym = pmcstat_symbol_search_by_name(pp, func_image, func_name,
+ &addr_start, &addr_end);
+ if (!sym)
+ return (0);
+
+ dprintf("%s: SYM addr start %lx end %lx\n",
+ __func__, addr_start, addr_end);
+
+ ranges[0] = addr_start;
+ ranges[1] = addr_end;
+
+ if (user_mode) {
+ ev = STAILQ_FIRST(&args.pa_events);
+ for (i = 0; i < ncpu; i++)
+ pmc_trace_config(i, ev->ev_pmcid, &ranges[0], 1);
+ } else {
+ STAILQ_FOREACH(ev, &args.pa_events, ev_next)
+ pmc_trace_config(ev->ev_cpu,
+ ev->ev_pmcid, &ranges[0], 1);
+ }
+
+ pmctrace_start_pmcs();
+
+ return (1);
+}
+
+
+static int
+pmctrace_run(bool user_mode, char *func_name, char *func_image)
+{
+ struct pmcstat_target *pt;
+ struct pmcstat_process *pp;
+ struct pmcstat_ev *ev;
+ int stopping;
+ int running;
+ int started;
+ int c;
+
+ stopping = 0;
+ running = 3;
+ started = 0;
+
+ if (user_mode) {
+ pmcstat_create_process(pmcstat_sockpair, &args, pmcstat_kq);
+ pmcstat_attach_pmcs(&args);
+ if (func_name == NULL || func_image == NULL) {
+ pmctrace_start_pmcs();
+ started = 1;
+ }
+ pmcstat_start_process(pmcstat_sockpair);
+ } else {
+ if (func_name == NULL || func_image == NULL) {
+ pmctrace_start_pmcs();
+ started = 1;
+ } else {
+ ev = STAILQ_FIRST(&args.pa_events);
+ STAILQ_FOREACH(ev, &args.pa_events, ev_next) {
+ pmc_log_kmap(ev->ev_pmcid);
+ }
+ }
+ }
+
+ do {
+ if ((c = kevent(pmcstat_kq, NULL, 0, &kev, 1, NULL)) <= 0) {
+ if (errno != EINTR)
+ err(EX_OSERR, "ERROR: kevent failed");
+ else
+ continue;
+ }
+
+ dprintf("%s: pmcstat event: filter %d, ident %ld\n",
+ __func__, kev.filter, kev.ident);
+
+ if (kev.flags & EV_ERROR)
+ errc(EX_OSERR, kev.data, "ERROR: kevent failed");
+
+ switch (kev.filter) {
+ case EVFILT_PROC:
+ stopping = 1;
+ break;
+ case EVFILT_READ:
+ args.pa_flags |= FLAG_DO_ANALYSIS;
+ pmcstat_analyze_log(&args, plugins, &pmcstat_stats,
+ pmcstat_kernproc, pmcstat_mergepmc, &pmcstat_npmcs,
+ &ps_samples_period);
+
+ if (started == 0 &&
+ pmctrace_delayed_start(user_mode, func_name, func_image) == 1)
+ started = 1;
+
+ if (user_mode) {
+ pt = SLIST_FIRST(&args.pa_targets);
+ ev = STAILQ_FIRST(&args.pa_events);
+ pmc_proc_unsuspend(ev->ev_pmcid, pt->pt_pid);
+ }
+
+ break;
+ case EVFILT_TIMER:
+ pmc_flush_logfile();
+
+ pp = pmcstat_kernproc;
+ if (!user_mode && TAILQ_EMPTY(&pp->pp_map))
+ break;
+
+ pmctrace_process_all(user_mode);
+
+ if (stopping)
+ running -= 1;
+ break;
+ }
+ } while (running > 0);
+
+ return (0);
+}
+
+static void
+usage(void)
+{
+
+ errx(EX_USAGE,
+ "[options] [commandline]\n"
+ "\t -s device\t\tTrace kernel\n"
+ "\t -u device\t\tTrace userspace\n"
+ );
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct pmcstat_ev *ev;
+ bool user_mode;
+ bool supervisor_mode;
+ int option;
+ cpuset_t cpumask;
+ char *func_name;
+ char *func_image;
+ int ncpu;
+ int i;
+
+ bzero(&args, sizeof(struct pmcstat_args));
+ bzero(&pmctrace_cfg, sizeof(struct pmctrace_config));
+
+ func_name = NULL;
+ func_image = NULL;
+
+ user_mode = 0;
+ supervisor_mode = 0;
+
+ STAILQ_INIT(&args.pa_events);
+ SLIST_INIT(&args.pa_targets);
+ CPU_ZERO(&cpumask);
+
+ args.pa_fsroot = strdup("/"); /* TODO */
+
+ pmctrace_find_kernel();
+ pmctrace_setup_cpumask(&cpumask);
+
+ while ((option = getopt(argc, argv,
+ "htu:s:i:f:")) != -1)
+ switch (option) {
+ case 'i':
+ func_image = strdup(optarg);
+ break;
+ case 'f':
+ func_name = strdup(optarg);
+ break;
+ case 'u':
+ case 's':
+ if (ev != NULL)
+ usage();
+
+ if ((ev = malloc(sizeof(struct pmcstat_ev))) == NULL)
+ errx(EX_SOFTWARE, "ERROR: Out of memory.");
+ if (option == 'u') {
+ user_mode = 1;
+ ev->ev_mode = PMC_MODE_TT;
+ args.pa_flags |= FLAG_HAS_PROCESS_PMCS;
+ } else {
+ ev->ev_mode = PMC_MODE_ST;
+ supervisor_mode = 1;
+ }
+ ev->ev_spec = strdup(optarg);
+ if (ev->ev_spec == NULL)
+ errx(EX_SOFTWARE, "ERROR: Out of memory.");
+
+ for (i = 0; trace_devs[i].ev_spec != NULL; i++) {
+ if (strncmp(trace_devs[i].ev_spec, ev->ev_spec,
+ strlen(trace_devs[i].ev_spec)) == 0) {
+ /* found */
+ pmctrace_cfg.trace_dev = &trace_devs[i];
+ break;
+ }
+ }
+
+ if (pmctrace_cfg.trace_dev == NULL)
+ errx(EX_SOFTWARE, "ERROR: trace device not found");
+ break;
+ case 't':
+ if (ev == NULL)
+ usage();
+
+ if (pmctrace_cfg.trace_dev->methods->option != NULL)
+ pmctrace_cfg.trace_dev->methods->option(option);
+ break;
+ case 'h':
+ usage();
+ default:
+ break;
+ };
+
+ if ((user_mode == 0 && supervisor_mode == 0) ||
+ (user_mode == 1 && supervisor_mode == 1))
+ errx(EX_USAGE, "ERROR: specify -u or -s");
+
+ if ((func_image == NULL && func_name != NULL) ||
+ (func_image != NULL && func_name == NULL))
+ errx(EX_USAGE, "ERROR: specify both or neither -i and -f");
+
+ args.pa_argc = (argc -= optind);
+ args.pa_argv = (argv += optind);
+ args.pa_cpumask = cpumask;
+
+ if (user_mode && !argc)
+ errx(EX_USAGE, "ERROR: user mode requires command to be specified");
+ if (supervisor_mode && argc)
+ errx(EX_USAGE, "ERROR: supervisor mode does not require command");
+
+ args.pa_required |= (FLAG_HAS_PIPE | FLAG_HAS_OUTPUT_LOGFILE);
+
+ ev->ev_saved = 0LL;
+ ev->ev_pmcid = PMC_ID_INVALID;
+ ev->ev_name = strdup("pmctrace");
+ ev->ev_flags = 0;
+
+ if (!user_mode)
+ ev->ev_cpu = CPU_FFS(&cpumask) - 1;
+ else
+ ev->ev_cpu = PMC_CPU_ANY;
+
+ STAILQ_INSERT_TAIL(&args.pa_events, ev, ev_next);
+
+ if (!user_mode) {
+ CPU_CLR(ev->ev_cpu, &cpumask);
+ pmcstat_clone_event_descriptor(ev, &cpumask, &args);
+ CPU_SET(ev->ev_cpu, &cpumask);
+ }
+
+ ncpu = pmctrace_ncpu();
+ if (ncpu < 0)
+ errx(EX_SOFTWARE, "ERROR: Can't get cpus\n");
+
+ if (pmc_init() < 0)
+ err(EX_UNAVAILABLE, "ERROR: Initialization of the pmc(3) library failed");
+
+ if ((pmcstat_kq = kqueue()) < 0)
+ err(EX_OSERR, "ERROR: Cannot allocate kqueue");
+
+ pmctrace_open_logfile();
+
+ STAILQ_FOREACH(ev, &args.pa_events, ev_next) {
+ if (pmc_allocate(ev->ev_spec, ev->ev_mode,
+ ev->ev_flags, ev->ev_cpu, &ev->ev_pmcid) < 0)
+ err(EX_OSERR,
+ "ERROR: Cannot allocate %s-mode pmc with specification \"%s\"",
+ PMC_IS_SYSTEM_MODE(ev->ev_mode) ?
+ "system" : "process", ev->ev_spec);
+ }
+
+ for (i = 0; i < ncpu; i++) {
+ trace_cpus[i] = malloc(sizeof(struct trace_cpu));
+ pmctrace_init_cpu(i);
+ }
+
+ EV_SET(&kev, 0, EVFILT_TIMER, EV_ADD, 0, 100, NULL);
+
+ if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0)
+ err(EX_OSERR, "ERROR: Cannot register kevent for timer");
+
+ pmcstat_initialize_logging(&pmcstat_kernproc,
+ &args, plugins, &pmcstat_npmcs, &pmcstat_mergepmc);
+
+ pmctrace_run(user_mode, func_name, func_image);
+
+ return (0);
+}
Index: usr.sbin/pmctrace/pmctrace_cs.h
===================================================================
--- /dev/null
+++ usr.sbin/pmctrace/pmctrace_cs.h
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2017 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _PMCTRACE_CS_H_
+#define _PMCTRACE_CS_H_
+
+extern struct trace_dev_methods cs_methods;
+
+#endif /* !_PMCTRACE_CS_H_ */
Index: usr.sbin/pmctrace/pmctrace_cs.c
===================================================================
--- /dev/null
+++ usr.sbin/pmctrace/pmctrace_cs.c
@@ -0,0 +1,537 @@
+/*-
+ * Copyright (c) 2018 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/cpuset.h>
+#include <sys/event.h>
+#include <sys/queue.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/ttycom.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+
+#include <assert.h>
+#include <curses.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <gelf.h>
+#include <kvm.h>
+#include <libgen.h>
+#include <limits.h>
+#include <math.h>
+#include <pmc.h>
+#include <pmclog.h>
+#include <regex.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <gelf.h>
+#include <inttypes.h>
+
+#include <libpmcstat.h>
+
+#include "pmctrace.h"
+#include "pmctrace_cs.h"
+
+#include <opencsd/c_api/ocsd_c_api_types.h>
+#include <opencsd/c_api/opencsd_c_api.h>
+
+#define PMCTRACE_CS_DEBUG
+#undef PMCTRACE_CS_DEBUG
+
+#ifdef PMCTRACE_CS_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
+#define PACKET_STR_LEN 1024
+static char packet_str[PACKET_STR_LEN];
+
+static dcd_tree_handle_t dcdtree_handle;
+
+static int cs_flags;
+#define FLAG_FORMAT (1 << 0)
+#define FLAG_FRAME_RAW_UNPACKED (1 << 1)
+#define FLAG_FRAME_RAW_PACKED (1 << 2)
+#define FLAG_CALLBACK_MEM_ACC (1 << 3)
+
+static struct pmcstat_symbol *
+symbol_lookup(const struct mtrace_data *mdata, uint64_t ip, struct pmcstat_image **img)
+{
+ struct pmcstat_image *image;
+ struct pmcstat_symbol *sym;
+ struct pmcstat_pcmap *map;
+ uint64_t newpc;
+
+ map = pmcstat_process_find_map(mdata->pp, ip);
+ if (map != NULL) {
+ image = map->ppm_image;
+ newpc = ip - (map->ppm_lowpc +
+ (image->pi_vaddr - image->pi_start));
+
+ sym = pmcstat_symbol_search(image, newpc);
+ *img = image;
+
+ if (sym == NULL)
+ dprintf("cpu%d: symbol 0x%lx not found\n", mdata->cpu, newpc);
+
+ return (sym);
+ } else {
+ dprintf("cpu%d: 0x%lx map not found\n", mdata->cpu, ip);
+ }
+
+ return (NULL);
+}
+
+static ocsd_err_t
+attach_raw_printers(dcd_tree_handle_t dcd_tree_h)
+{
+ ocsd_err_t err;
+ int flags;
+
+ flags = 0;
+ err = OCSD_OK;
+
+ if (cs_flags & FLAG_FRAME_RAW_UNPACKED)
+ flags |= OCSD_DFRMTR_UNPACKED_RAW_OUT;
+
+ if (cs_flags & FLAG_FRAME_RAW_PACKED)
+ flags |= OCSD_DFRMTR_PACKED_RAW_OUT;
+
+ if (flags)
+ err = ocsd_dt_set_raw_frame_printer(dcd_tree_h, flags);
+
+ return err;
+}
+
+static int
+print_data_array(const uint8_t *p_array, const int array_size,
+ char *p_buffer, int buf_size)
+{
+ int bytes_processed;
+ int chars_printed;
+
+ chars_printed = 0;
+ p_buffer[0] = 0;
+
+ if (buf_size > 9) {
+ strcat(p_buffer, "[ ");
+ chars_printed += 2;
+
+ for (bytes_processed = 0; bytes_processed < array_size;
+ bytes_processed++) {
+ sprintf(p_buffer + chars_printed, "0x%02X ",
+ p_array[bytes_processed]);
+ chars_printed += 5;
+ if ((chars_printed + 5) > buf_size)
+ break;
+ }
+
+ strcat(p_buffer, "];");
+ chars_printed += 2;
+ } else if (buf_size >= 4) {
+ sprintf(p_buffer, "[];");
+ chars_printed += 3;
+ }
+
+ return (chars_printed);
+}
+
+static void
+packet_monitor(void *context __unused,
+ const ocsd_datapath_op_t op,
+ const ocsd_trc_index_t index_sop,
+ const void *p_packet_in,
+ const uint32_t size,
+ const uint8_t *p_data)
+{
+ int offset;
+
+ offset = 0;
+
+ switch(op) {
+ case OCSD_OP_DATA:
+ sprintf(packet_str, "Idx:%" OCSD_TRC_IDX_STR ";", index_sop);
+ offset = strlen(packet_str);
+ offset += print_data_array(p_data, size, packet_str + offset,
+ PACKET_STR_LEN - offset);
+
+ /*
+ * Got a packet -- convert to string and use the libraries'
+ * message output to print to file and stdoout
+ */
+
+ if (ocsd_pkt_str(OCSD_PROTOCOL_ETMV4I, p_packet_in, packet_str + offset,
+ PACKET_STR_LEN - offset) == OCSD_OK) {
+ /* add in <CR> */
+ if (strlen(packet_str) == PACKET_STR_LEN - 1) /* maximum length */
+ packet_str[PACKET_STR_LEN - 2] = '\n';
+ else
+ strcat(packet_str,"\n");
+
+ /* print it using the library output logger. */
+ ocsd_def_errlog_msgout(packet_str);
+ }
+ break;
+
+ case OCSD_OP_EOT:
+ sprintf(packet_str,"**** END OF TRACE ****\n");
+ ocsd_def_errlog_msgout(packet_str);
+ break;
+ default:
+ printf("%s: unknown op %d\n", __func__, op);
+ break;
+ }
+}
+
+static uint32_t
+cs_cs_decoder__mem_access(const void *context __unused,
+ const ocsd_vaddr_t address __unused, const ocsd_mem_space_acc_t mem_space __unused,
+ const uint32_t req_size __unused, uint8_t *buffer __unused)
+{
+
+ /* TODO */
+
+ return (0);
+}
+
+static ocsd_err_t
+create_test_memory_acc(dcd_tree_handle_t handle, uint64_t base, uint64_t start, uint64_t end)
+{
+ ocsd_vaddr_t address;
+ uint8_t *p_mem_buffer;
+ uint32_t mem_length;
+ int ret;
+
+ dprintf("%s: base %lx start %lx end %lx\n", __func__, base, start, end);
+
+ address = (ocsd_vaddr_t)base;
+ p_mem_buffer = (uint8_t *)(base + start);
+ mem_length = (end-start);
+
+ if (cs_flags & FLAG_CALLBACK_MEM_ACC)
+ ret = ocsd_dt_add_callback_mem_acc(handle, base+start, base+end-1,
+ OCSD_MEM_SPACE_ANY, cs_cs_decoder__mem_access, NULL);
+ else
+ ret = ocsd_dt_add_buffer_mem_acc(handle, address, OCSD_MEM_SPACE_ANY,
+ p_mem_buffer, mem_length);
+
+ if (ret != OCSD_OK)
+ printf("%s: can't create memory accessor: ret %d\n", __func__, ret);
+
+ return (ret);
+}
+
+static ocsd_err_t
+create_generic_decoder(dcd_tree_handle_t handle, const char *p_name, const void *p_cfg,
+ const void *p_context __unused, uint64_t base, uint64_t start, uint64_t end)
+{
+ ocsd_err_t ret;
+ uint8_t CSID;
+
+ CSID = 0;
+
+ dprintf("%s\n", __func__);
+
+ ret = ocsd_dt_create_decoder(handle, p_name, OCSD_CREATE_FLG_FULL_DECODER,
+ p_cfg, &CSID);
+ if(ret != OCSD_OK)
+ return (-1);
+
+ if (cs_flags & FLAG_FORMAT) {
+ ret = ocsd_dt_attach_packet_callback(handle, CSID,
+ OCSD_C_API_CB_PKT_MON, packet_monitor, p_context);
+ if (ret != OCSD_OK)
+ return (-1);
+ }
+
+ /* attach a memory accessor */
+ ret = create_test_memory_acc(handle, base, start, end);
+ if(ret != OCSD_OK)
+ ocsd_dt_remove_decoder(handle,CSID);
+
+ return (ret);
+}
+
+static ocsd_err_t
+create_decoder_etmv4(dcd_tree_handle_t dcd_tree_h, uint64_t base,
+ uint64_t start, uint64_t end)
+{
+ ocsd_etmv4_cfg trace_config;
+ ocsd_err_t ret;
+
+ trace_config.arch_ver = ARCH_V8;
+ trace_config.core_prof = profile_CortexA;
+
+ trace_config.reg_configr = 0x000000C1;
+ trace_config.reg_traceidr = 0x00000010; /* Trace ID */
+
+ trace_config.reg_idr0 = 0x28000EA1;
+ trace_config.reg_idr1 = 0x4100F403;
+ trace_config.reg_idr2 = 0x00000488;
+ trace_config.reg_idr8 = 0x0;
+ trace_config.reg_idr9 = 0x0;
+ trace_config.reg_idr10 = 0x0;
+ trace_config.reg_idr11 = 0x0;
+ trace_config.reg_idr12 = 0x0;
+ trace_config.reg_idr13 = 0x0;
+
+ ret = create_generic_decoder(dcd_tree_h, OCSD_BUILTIN_DCD_ETMV4I,
+ (void *)&trace_config, 0, base, start, end);
+ return (ret);
+}
+
+static ocsd_datapath_resp_t
+gen_trace_elem_print_lookup(const void *p_context, const ocsd_trc_index_t index_sop __unused,
+ const uint8_t trc_chan_id __unused, const ocsd_generic_trace_elem *elem __unused)
+{
+ const struct mtrace_data *mdata;
+ ocsd_datapath_resp_t resp;
+ struct pmcstat_symbol *sym;
+ struct pmcstat_image *image;
+
+ mdata = (const struct mtrace_data *)p_context;
+
+ resp = OCSD_RESP_CONT;
+
+#if 0
+ dprintf("%s: Idx:%d ELEM TYPE %d, st_addr %lx, en_addr %lx\n",
+ __func__, index_sop, elem->elem_type, elem->st_addr, elem->en_addr);
+#endif
+
+ if (elem->st_addr == 0)
+ return (0);
+ sym = symbol_lookup(mdata, elem->st_addr, &image);
+ if (sym)
+ printf("cpu%d: IP 0x%lx %s %s\n", mdata->cpu, elem->st_addr,
+ pmcstat_string_unintern(image->pi_name),
+ pmcstat_string_unintern(sym->ps_name));
+
+ switch (elem->elem_type) {
+ case OCSD_GEN_TRC_ELEM_UNKNOWN:
+ break;
+ case OCSD_GEN_TRC_ELEM_NO_SYNC:
+ /* Trace off */
+ break;
+ case OCSD_GEN_TRC_ELEM_TRACE_ON:
+ break;
+ case OCSD_GEN_TRC_ELEM_INSTR_RANGE:
+ printf("range\n");
+ break;
+ case OCSD_GEN_TRC_ELEM_EXCEPTION:
+ case OCSD_GEN_TRC_ELEM_EXCEPTION_RET:
+ case OCSD_GEN_TRC_ELEM_PE_CONTEXT:
+ case OCSD_GEN_TRC_ELEM_EO_TRACE:
+ case OCSD_GEN_TRC_ELEM_ADDR_NACC:
+ case OCSD_GEN_TRC_ELEM_TIMESTAMP:
+ case OCSD_GEN_TRC_ELEM_CYCLE_COUNT:
+ case OCSD_GEN_TRC_ELEM_ADDR_UNKNOWN:
+ case OCSD_GEN_TRC_ELEM_EVENT:
+ case OCSD_GEN_TRC_ELEM_SWTRACE:
+ case OCSD_GEN_TRC_ELEM_CUSTOM:
+ default:
+ break;
+ };
+
+ return (resp);
+}
+
+static int
+cs_process_chunk(struct mtrace_data *mdata __unused, uint64_t base,
+ uint64_t start, uint64_t end)
+{
+ uint32_t bytes_done;
+ uint32_t block_size;
+ uint8_t *p_block;
+ int bytes_this_time;
+ int block_index;
+ int dp_ret;
+ int ret;
+
+ dprintf("%s: start %lx end %lx\n", __func__, start, end);
+
+ bytes_this_time = 0;
+ block_index = 0;
+ bytes_done = 0;
+ block_size = (end - start);
+ p_block = (uint8_t *)(base + start);
+
+ ret = OCSD_OK;
+ dp_ret = OCSD_RESP_CONT;
+
+ while (bytes_done < (uint32_t)block_size && (ret == OCSD_OK)) {
+
+ if (OCSD_DATA_RESP_IS_CONT(dp_ret)) {
+ dprintf("process data, block_size %d\n", block_size - bytes_done);
+ dp_ret = ocsd_dt_process_data(dcdtree_handle, OCSD_OP_DATA,
+ block_index + bytes_done,
+ block_size - bytes_done,
+ ((uint8_t *)p_block) + bytes_done,
+ &bytes_this_time);
+ bytes_done += bytes_this_time;
+ dprintf("BYTES DONE %d\n", bytes_done);
+ } else if (OCSD_DATA_RESP_IS_WAIT(dp_ret)) {
+ dp_ret = ocsd_dt_process_data(dcdtree_handle, OCSD_OP_FLUSH,
+ 0, 0, NULL, NULL);
+ } else {
+ ret = OCSD_ERR_DATA_DECODE_FATAL;
+ }
+ }
+
+ ocsd_dt_process_data(dcdtree_handle, OCSD_OP_EOT, 0, 0, NULL, NULL);
+
+ return (0);
+}
+
+static int cs_init(struct trace_cpu *tc);
+
+static int
+cs_process(struct trace_cpu *tc, struct pmcstat_process *pp,
+ uint32_t cpu, uint32_t cycle, uint64_t offset)
+{
+ struct mtrace_data *mdata;
+
+ mdata = &tc->mdata;
+ mdata->pp = pp;
+
+ cs_init(tc);
+
+ dprintf("%s: cpu %d, cycle %d, offset %ld, tc->base %lx, *tc->base %lx\n",
+ __func__, cpu, cycle, offset, (uint64_t)tc->base, *(uint64_t *)tc->base);
+
+ if (offset == tc->offset)
+ return (0);
+
+ if (cycle == tc->cycle) {
+ if (offset > tc->offset) {
+ cs_process_chunk(mdata, (uint64_t)tc->base, tc->offset, offset);
+ tc->offset = offset;
+ } else if (offset < tc->offset) {
+ err(EXIT_FAILURE, "cpu%d: offset already processed %lx %lx",
+ cpu, offset, tc->offset);
+ }
+ } else if (cycle > tc->cycle) {
+ if ((cycle - tc->cycle) > 1)
+ err(EXIT_FAILURE, "cpu%d: trace buffers fills up faster than"
+ " we can process it (%d/%d). Consider setting trace filters",
+ cpu, cycle, tc->cycle);
+ cs_process_chunk(mdata, (uint64_t)tc->base, tc->offset, tc->bufsize);
+ tc->offset = 0;
+ tc->cycle += 1;
+ tc->offset = offset;
+ }
+
+ return (0);
+}
+
+static int
+cs_init(struct trace_cpu *tc)
+{
+ uint64_t start;
+ uint64_t end;
+ int ret;
+
+ ocsd_def_errlog_init(OCSD_ERR_SEV_INFO, 1);
+ ocsd_def_errlog_init(0, 0);
+
+#if 0
+ ret = ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_FILE |
+ C_API_MSGLOGOUT_FLG_STDOUT, "c_api_test.log");
+ if (ret != OCSD_OK)
+ return (-1);
+#endif
+
+ dcdtree_handle = ocsd_create_dcd_tree(OCSD_TRC_SRC_FRAME_FORMATTED,
+ OCSD_DFRMTR_FRAME_MEM_ALIGN);
+ if(dcdtree_handle == C_API_INVALID_TREE_HANDLE) {
+ printf("can't find dcd tree\n");
+ return (-1);
+ }
+
+ start = (uint64_t)tc->base;
+ end = (uint64_t)tc->base + tc->bufsize;
+
+ ret = create_decoder_etmv4(dcdtree_handle, (uint64_t)tc->base, start, end);
+ if (ret != OCSD_OK) {
+ printf("can't create decoder: base %lx start %lx end %lx\n",
+ (uint64_t)tc->base, start, end);
+ return (-2);
+ }
+
+#ifdef PMCTRACE_CS_DEBUG
+ ocsd_tl_log_mapped_mem_ranges(dcdtree_handle);
+#endif
+
+ if (cs_flags & FLAG_FORMAT)
+ ocsd_dt_set_gen_elem_printer(dcdtree_handle);
+ else
+ ocsd_dt_set_gen_elem_outfn(dcdtree_handle, gen_trace_elem_print_lookup,
+ (const struct mtrace_data *)&tc->mdata);
+
+ attach_raw_printers(dcdtree_handle);
+
+ return (0);
+}
+
+static int
+cs_option(int option)
+{
+
+ switch (option) {
+ case 't':
+ cs_flags |= FLAG_FORMAT;
+ break;
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+struct trace_dev_methods cs_methods = {
+ .init = cs_init,
+ .process = cs_process,
+ .option = cs_option,
+};
Index: usr.sbin/pmctrace/pmctrace_pt.h
===================================================================
--- /dev/null
+++ usr.sbin/pmctrace/pmctrace_pt.h
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2017 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _PMCTRACE_PT_H_
+#define _PMCTRACE_PT_H_
+
+extern struct trace_dev_methods ipt_methods;
+
+#endif /* !_PMCTRACE_PT_H_ */
Index: usr.sbin/pmctrace/pmctrace_pt.c
===================================================================
--- /dev/null
+++ usr.sbin/pmctrace/pmctrace_pt.c
@@ -0,0 +1,371 @@
+/*-
+ * Copyright (c) 2017 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/cpuset.h>
+#include <sys/event.h>
+#include <sys/queue.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/ttycom.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+
+#include <assert.h>
+#include <curses.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <gelf.h>
+#include <kvm.h>
+#include <libgen.h>
+#include <limits.h>
+#include <math.h>
+#include <pmc.h>
+#include <pmclog.h>
+#include <regex.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <gelf.h>
+#include <inttypes.h>
+
+#include <libpmcstat.h>
+
+#include "pmctrace.h"
+#include "pmctrace_pt.h"
+
+#include <libipt/pt_cpu.h>
+#include <libipt/pt_last_ip.h>
+#include <libipt/pt_time.h>
+#include <libipt/pt_compiler.h>
+#include <libipt/intel-pt.h>
+
+#define PMCTRACE_PT_DEBUG
+#undef PMCTRACE_PT_DEBUG
+
+#ifdef PMCTRACE_PT_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
+static int ipt_flags;
+#define FLAG_BRANCH_TNT (1 << 0) /* Taken/Not Taken */
+
+static struct pmcstat_symbol *
+symbol_lookup(struct mtrace_data *mdata)
+{
+ struct pmcstat_image *image;
+ struct pmcstat_symbol *sym;
+ struct pmcstat_pcmap *map;
+ uint64_t newpc;
+ uint64_t ip;
+
+ if (mdata->ip & (1UL << 47))
+ ip = mdata->ip | 0xffffUL << 48;
+ else
+ ip = mdata->ip;
+
+ map = pmcstat_process_find_map(mdata->pp, ip);
+ if (map != NULL) {
+ image = map->ppm_image;
+ newpc = ip - (map->ppm_lowpc +
+ (image->pi_vaddr - image->pi_start));
+ sym = pmcstat_symbol_search(image, newpc);
+ return (sym);
+ } else
+ dprintf("cpu%d: 0x%lx map not found\n", mdata->cpu, ip);
+
+ return (NULL);
+}
+
+static int
+print_tnt_payload(struct mtrace_data *mdata, uint64_t offset __unused,
+ const struct pt_packet_tnt *packet)
+{
+ char payload[48];
+ uint64_t tnt;
+ uint8_t bits;
+ char *begin;
+ char *end;
+
+ bits = packet->bit_size;
+ tnt = packet->payload;
+ begin = &payload[0];
+ end = begin + bits;
+
+ if (sizeof(payload) < bits)
+ end = begin + sizeof(payload);
+
+ for (; begin < end; ++begin, --bits)
+ *begin = tnt & (1ull << (bits - 1)) ? '!' : '.';
+
+ printf("cpu%d: TNT %s\n", mdata->cpu, payload);
+
+ return (0);
+}
+
+static int
+print_ip_payload(struct mtrace_data *mdata, uint64_t offset __unused,
+ const struct pt_packet_ip *packet)
+{
+ struct pmcstat_symbol *sym;
+
+ switch (packet->ipc) {
+ case pt_ipc_suppressed:
+ break;
+ case pt_ipc_update_16:
+ mdata->ip &= ~0xffffUL;
+ mdata->ip |= (packet->ip & 0xffffUL);
+ break;
+ case pt_ipc_update_32:
+ mdata->ip &= ~0xffffffffUL;
+ mdata->ip |= (packet->ip & 0xffffffffUL);
+ break;
+ case pt_ipc_update_48:
+ mdata->ip &= ~0xffffffffffffUL;
+ mdata->ip |= (packet->ip & 0xffffffffffffUL);
+ break;
+ case pt_ipc_sext_48:
+ mdata->ip &= ~0xffffffffffffUL;
+ mdata->ip |= (packet->ip & 0xffffffffffffUL);
+ symbol_lookup(mdata);
+ case pt_ipc_full:
+ mdata->ip = packet->ip;
+ break;
+ default:
+ printf("unknown ipc: %d\n", packet->ipc);
+ return (0);
+ }
+
+ sym = symbol_lookup(mdata);
+ if (sym) {
+ printf("cpu%d: IP 0x%lx %s\n", mdata->cpu, mdata->ip,
+ pmcstat_string_unintern(sym->ps_name));
+ } else
+ dprintf("cpu%d: 0x%lx not found\n", mdata->cpu, mdata->ip);
+
+ return (0);
+}
+
+static int
+dump_packets(struct mtrace_data *mdata, struct pt_packet_decoder *decoder,
+ const struct pt_config *config __unused)
+{
+ struct pt_packet packet;
+ uint64_t offset;
+ int error;
+
+ dprintf("%s\n", __func__);
+
+ while (1) {
+ error = pt_pkt_get_offset(decoder, &offset);
+ if (error < 0)
+ errx(EX_SOFTWARE, "ERROR: can't get offset, err %d\n", error);
+
+ error = pt_pkt_next(decoder, &packet, sizeof(packet));
+ if (error < 0) {
+ dprintf("%s: error %d\n", __func__, error);
+ break;
+ }
+
+ switch (packet.type) {
+ case ppt_invalid:
+ case ppt_unknown:
+ case ppt_pad:
+ case ppt_psb:
+ case ppt_psbend:
+ break;
+ case ppt_fup:
+ case ppt_tip:
+ case ppt_tip_pge:
+ case ppt_tip_pgd:
+ print_ip_payload(mdata, offset, &packet.payload.ip);
+ break;
+ case ppt_tnt_8:
+ case ppt_tnt_64:
+ if (ipt_flags & FLAG_BRANCH_TNT)
+ print_tnt_payload(mdata, offset, &packet.payload.tnt);
+ break;
+ case ppt_mode:
+ case ppt_pip:
+ case ppt_vmcs:
+ case ppt_cbr:
+ break;
+ case ppt_tsc:
+ printf("cpu%d: TSC %ld\n", mdata->cpu, packet.payload.tsc.tsc);
+ break;
+ case ppt_tma:
+ break;
+ case ppt_mtc:
+ printf("cpu%d: MTC %x\n", mdata->cpu, packet.payload.mtc.ctc);
+ break;
+ case ppt_cyc:
+ case ppt_stop:
+ case ppt_ovf:
+ case ppt_mnt:
+ case ppt_exstop:
+ case ppt_mwait:
+ case ppt_pwre:
+ case ppt_pwrx:
+ case ppt_ptw:
+ default:
+ break;
+ }
+ }
+
+ return (0);
+}
+
+static int
+ipt_process_chunk(struct mtrace_data *mdata, uint64_t base,
+ uint64_t start, uint64_t end)
+{
+ struct pt_packet_decoder *decoder;
+ struct pt_config config;
+ int error;
+
+ dprintf("%s\n", __func__);
+
+ memset(&config, 0, sizeof(config));
+ pt_config_init(&config);
+
+ error = pt_cpu_read(&config.cpu);
+ if (error < 0)
+ errx(EX_SOFTWARE, "ERROR: pt_cpu_read failed, err %d\n", error);
+ error = pt_cpu_errata(&config.errata, &config.cpu);
+ if (error < 0)
+ errx(EX_SOFTWARE, "ERROR: can't get errata, err %d\n", error);
+
+ config.begin = (uint8_t *)(base + start);
+ config.end = (uint8_t *)(base + end);
+
+ dprintf("%s: begin %lx end %lx\n", __func__,
+ (uint64_t)config.begin, (uint64_t)config.end);
+
+ decoder = pt_pkt_alloc_decoder(&config);
+ if (decoder == NULL) {
+ printf("Can't allocate decoder\n");
+ return (-1);
+ }
+
+ error = pt_pkt_sync_set(decoder, 0ull);
+ if (error < 0)
+ errx(EX_SOFTWARE, "ERROR: sync_set failed, err %d\n", error);
+ error = pt_pkt_sync_forward(decoder);
+ if (error < 0 && error != -pte_eos)
+ errx(EX_SOFTWARE, "ERROR: sync_forward failed, err %d\n", error);
+
+ while (1) {
+ error = dump_packets(mdata, decoder, &config);
+ if (error == 0)
+ break;
+
+ error = pt_pkt_sync_forward(decoder);
+ if (error < 0) {
+ if (error == -pte_eos)
+ return (0);
+ }
+ }
+
+ return (0);
+}
+
+static int
+ipt_process(struct trace_cpu *tc, struct pmcstat_process *pp,
+ uint32_t cpu, uint32_t cycle, uint64_t offset)
+{
+ struct mtrace_data *mdata;
+
+ mdata = &tc->mdata;
+ mdata->pp = pp;
+
+ dprintf("%s: cpu %d, cycle %d, offset %ld\n",
+ __func__, cpu, cycle, offset);
+
+ if (offset == tc->offset)
+ return (0);
+
+ if (cycle == tc->cycle) {
+ if (offset > tc->offset) {
+ ipt_process_chunk(mdata, (uint64_t)tc->base, tc->offset, offset);
+ tc->offset = offset;
+ } else if (offset < tc->offset) {
+ err(EXIT_FAILURE, "cpu%d: offset already processed %lx %lx",
+ cpu, offset, tc->offset);
+ }
+ } else if (cycle > tc->cycle) {
+ if ((cycle - tc->cycle) > 1)
+ err(EXIT_FAILURE, "cpu%d: trace buffers fills up faster than"
+ " we can process it (%d/%d). Consider setting trace filters",
+ cpu, cycle, tc->cycle);
+ ipt_process_chunk(mdata, (uint64_t)tc->base, tc->offset, tc->bufsize);
+ tc->offset = 0;
+ tc->cycle += 1;
+ ipt_process_chunk(mdata, (uint64_t)tc->base, tc->offset, offset);
+ tc->offset = offset;
+ }
+
+ return (0);
+}
+
+static int
+ipt_option(int option)
+{
+
+ switch (option) {
+ case 't':
+ /* Decode 'Taken/Not_Taken branch' packet. */
+ ipt_flags |= FLAG_BRANCH_TNT;
+ break;
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+struct trace_dev_methods ipt_methods = {
+ .process = ipt_process,
+ .option = ipt_option,
+};

File Metadata

Mime Type
text/plain
Expires
Wed, Apr 29, 9:16 AM (48 m, 58 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
32337888
Default Alt Text
D12875.id39967.diff (208 KB)

Event Timeline