// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2018 Intel Corporation * Author: Ammy Yi (ammy.yi@intel.com) */ /* * This test will check if Intel PT(Intel Processer Trace) full trace mode is * working. * * Intel CPU of 5th-generation Core (Broadwell) or newer is required for the test. * * kconfig requirement: CONFIG_PERF_EVENTS */ #include <sched.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include "tst_test.h" #include "lapi/syscalls.h" #include "config.h" #ifdef HAVE_STRUCT_PERF_EVENT_MMAP_PAGE_AUX_HEAD # include <linux/perf_event.h> #define PAGESIZE 4096 #define INTEL_PT_MEMSIZE (17*PAGESIZE) #define BIT(nr) (1UL << (nr)) #define INTEL_PT_PATH "/sys/devices/intel_pt" #define INTEL_PT_PMU_TYPE "/sys/devices/intel_pt/type" #define INTEL_PT_FORMAT_TSC "/sys/devices/intel_pt/format/tsc" #define INTEL_PT_FORMAT_NRT "/sys/devices/intel_pt/format/noretcomp" //Intel PT event handle int fde = -1; //map head and size uint64_t **bufm; long buhsz; static uint64_t **create_map(int fde, long bufsize) { uint64_t **buf_ev; struct perf_event_mmap_page *pc; buf_ev = SAFE_MALLOC(2*sizeof(uint64_t *)); buf_ev[0] = NULL; buf_ev[1] = NULL; buf_ev[0] = SAFE_MMAP(NULL, INTEL_PT_MEMSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fde, 0); pc = (struct perf_event_mmap_page *)buf_ev[0]; pc->aux_offset = INTEL_PT_MEMSIZE; pc->aux_size = bufsize; buf_ev[1] = SAFE_MMAP(NULL, bufsize, PROT_READ | PROT_WRITE, MAP_SHARED, fde, INTEL_PT_MEMSIZE); return buf_ev; } int intel_pt_pmu_value(char *dir) { char *value; int val = 0; char delims[] = ":"; SAFE_FILE_SCANF(dir, "%m[^\n]", &value); if (strstr(value, delims) == NULL) { val = atoi(value); } else { strsep(&value, delims); val = atoi(value); } return val; } static void del_map(uint64_t **buf_ev, long bufsize) { if (buf_ev) { if (buf_ev[0]) munmap(buf_ev[0], INTEL_PT_MEMSIZE); if (buf_ev[1]) munmap(buf_ev[1], bufsize); } free(buf_ev); } static void intel_pt_full_trace_check(void) { uint64_t aux_head = 0; struct perf_event_mmap_page *pmp; /* enable tracing */ SAFE_IOCTL(fde, PERF_EVENT_IOC_RESET); SAFE_IOCTL(fde, PERF_EVENT_IOC_ENABLE); /* stop tracing */ SAFE_IOCTL(fde, PERF_EVENT_IOC_DISABLE); /* check if there is some trace generated */ pmp = (struct perf_event_mmap_page *)bufm[0]; aux_head = *(volatile uint64_t *)&pmp->aux_head; if (aux_head == 0) { tst_res(TFAIL, "There is no trace!"); return; } tst_res(TPASS, "perf trace full mode is passed!"); } static void setup(void) { struct perf_event_attr attr = {}; buhsz = 2 * PAGESIZE; if (access(INTEL_PT_PATH, F_OK)) { tst_brk(TCONF, "Requires Intel Core 5th+ generation (Broadwell and newer)" " and CONFIG_PERF_EVENTS enabled."); } /* set attr for Intel PT trace */ attr.type = intel_pt_pmu_value(INTEL_PT_PMU_TYPE); attr.read_format = PERF_FORMAT_ID | PERF_FORMAT_TOTAL_TIME_RUNNING | PERF_FORMAT_TOTAL_TIME_ENABLED; attr.disabled = 1; attr.config = BIT(intel_pt_pmu_value(INTEL_PT_FORMAT_TSC)) | BIT(intel_pt_pmu_value(INTEL_PT_FORMAT_NRT)); attr.size = sizeof(struct perf_event_attr); attr.exclude_kernel = 0; attr.exclude_user = 0; attr.mmap = 1; /* only get trace for own pid */ fde = tst_syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0); if (fde < 0) { tst_res(TINFO, "Open Intel PT event failed!"); tst_res(TFAIL, "perf trace full mode is failed!"); return; } bufm = NULL; bufm = create_map(fde, buhsz); } static void cleanup(void) { if (fde != -1) close(fde); del_map(bufm, buhsz); } static struct tst_test test = { .test_all = intel_pt_full_trace_check, .min_kver = "4.1", .setup = setup, .cleanup = cleanup, .needs_root = 1, }; #else TST_TEST_TCONF("missing aux_* fields in struct perf_event_mmap_page"); #endif /* HAVE_STRUCT_PERF_EVENT_MMAP_PAGE_AUX_HEAD */