| // 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 */ |