• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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