1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /*
4 * Copyright (C) 2018 Intel Corporation
5 * Author: Ammy Yi (ammy.yi@intel.com)
6 */
7
8 /*
9 * This test will check if Intel PT(Intel Processer Trace) full trace mode is
10 * working.
11 *
12 * Intel CPU of 5th-generation Core (Broadwell) or newer is required for the test.
13 *
14 * kconfig requirement: CONFIG_PERF_EVENTS
15 */
16
17 #include <sched.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include "tst_test.h"
22 #include "lapi/syscalls.h"
23 #include "config.h"
24
25 #ifdef HAVE_STRUCT_PERF_EVENT_MMAP_PAGE_AUX_HEAD
26 # include <linux/perf_event.h>
27
28 #define PAGESIZE 4096
29 #define INTEL_PT_MEMSIZE (17*PAGESIZE)
30
31 #define BIT(nr) (1UL << (nr))
32
33 #define INTEL_PT_PATH "/sys/devices/intel_pt"
34 #define INTEL_PT_PMU_TYPE "/sys/devices/intel_pt/type"
35 #define INTEL_PT_FORMAT_TSC "/sys/devices/intel_pt/format/tsc"
36 #define INTEL_PT_FORMAT_NRT "/sys/devices/intel_pt/format/noretcomp"
37
38 //Intel PT event handle
39 int fde = -1;
40 //map head and size
41 uint64_t **bufm;
42 long buhsz;
43
create_map(int fde,long bufsize)44 static uint64_t **create_map(int fde, long bufsize)
45 {
46 uint64_t **buf_ev;
47 struct perf_event_mmap_page *pc;
48
49 buf_ev = SAFE_MALLOC(2*sizeof(uint64_t *));
50 buf_ev[0] = NULL;
51 buf_ev[1] = NULL;
52 buf_ev[0] = SAFE_MMAP(NULL, INTEL_PT_MEMSIZE, PROT_READ | PROT_WRITE,
53 MAP_SHARED, fde, 0);
54
55 pc = (struct perf_event_mmap_page *)buf_ev[0];
56 pc->aux_offset = INTEL_PT_MEMSIZE;
57 pc->aux_size = bufsize;
58 buf_ev[1] = SAFE_MMAP(NULL, bufsize, PROT_READ | PROT_WRITE,
59 MAP_SHARED, fde, INTEL_PT_MEMSIZE);
60 return buf_ev;
61 }
62
63
intel_pt_pmu_value(char * dir)64 int intel_pt_pmu_value(char *dir)
65 {
66 char *value;
67 int val = 0;
68 char delims[] = ":";
69
70 SAFE_FILE_SCANF(dir, "%m[^\n]", &value);
71 if (strstr(value, delims) == NULL) {
72 val = atoi(value);
73 } else {
74 strsep(&value, delims);
75 val = atoi(value);
76 }
77 return val;
78 }
79
del_map(uint64_t ** buf_ev,long bufsize)80 static void del_map(uint64_t **buf_ev, long bufsize)
81 {
82 if (buf_ev) {
83 if (buf_ev[0])
84 munmap(buf_ev[0], INTEL_PT_MEMSIZE);
85 if (buf_ev[1])
86 munmap(buf_ev[1], bufsize);
87 }
88
89 free(buf_ev);
90 }
91
intel_pt_full_trace_check(void)92 static void intel_pt_full_trace_check(void)
93 {
94 uint64_t aux_head = 0;
95 struct perf_event_mmap_page *pmp;
96 /* enable tracing */
97 SAFE_IOCTL(fde, PERF_EVENT_IOC_RESET);
98 SAFE_IOCTL(fde, PERF_EVENT_IOC_ENABLE);
99
100 /* stop tracing */
101 SAFE_IOCTL(fde, PERF_EVENT_IOC_DISABLE);
102
103 /* check if there is some trace generated */
104 pmp = (struct perf_event_mmap_page *)bufm[0];
105 aux_head = *(volatile uint64_t *)&pmp->aux_head;
106 if (aux_head == 0) {
107 tst_res(TFAIL, "There is no trace!");
108 return;
109 }
110
111 tst_res(TPASS, "perf trace full mode is passed!");
112 }
113
setup(void)114 static void setup(void)
115 {
116 struct perf_event_attr attr = {};
117
118 buhsz = 2 * PAGESIZE;
119 if (access(INTEL_PT_PATH, F_OK)) {
120 tst_brk(TCONF,
121 "Requires Intel Core 5th+ generation (Broadwell and newer)"
122 " and CONFIG_PERF_EVENTS enabled.");
123 }
124
125 /* set attr for Intel PT trace */
126 attr.type = intel_pt_pmu_value(INTEL_PT_PMU_TYPE);
127 attr.read_format = PERF_FORMAT_ID | PERF_FORMAT_TOTAL_TIME_RUNNING |
128 PERF_FORMAT_TOTAL_TIME_ENABLED;
129 attr.disabled = 1;
130 attr.config = BIT(intel_pt_pmu_value(INTEL_PT_FORMAT_TSC)) |
131 BIT(intel_pt_pmu_value(INTEL_PT_FORMAT_NRT));
132 attr.size = sizeof(struct perf_event_attr);
133 attr.exclude_kernel = 0;
134 attr.exclude_user = 0;
135 attr.mmap = 1;
136
137 /* only get trace for own pid */
138 fde = tst_syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0);
139 if (fde < 0) {
140 tst_res(TINFO, "Open Intel PT event failed!");
141 tst_res(TFAIL, "perf trace full mode is failed!");
142 return;
143 }
144 bufm = NULL;
145 bufm = create_map(fde, buhsz);
146
147 }
148
cleanup(void)149 static void cleanup(void)
150 {
151 if (fde != -1)
152 close(fde);
153
154 del_map(bufm, buhsz);
155 }
156
157 static struct tst_test test = {
158 .test_all = intel_pt_full_trace_check,
159 .min_kver = "4.1",
160 .setup = setup,
161 .cleanup = cleanup,
162 .needs_root = 1,
163 };
164
165 #else
166 TST_TEST_TCONF("missing aux_* fields in struct perf_event_mmap_page");
167 #endif /* HAVE_STRUCT_PERF_EVENT_MMAP_PAGE_AUX_HEAD */
168