xref: /freebsd/contrib/processor-trace/libipt/src/pt_config.c (revision 8881d206f4e68b564c2c5f50fc717086fc3e827a)
1 /*
2  * Copyright (c) 2013-2019, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *  * Redistributions of source code must retain the above copyright notice,
8  *    this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright notice,
10  *    this list of conditions and the following disclaimer in the documentation
11  *    and/or other materials provided with the distribution.
12  *  * Neither the name of Intel Corporation nor the names of its contributors
13  *    may be used to endorse or promote products derived from this software
14  *    without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "pt_config.h"
30 #include "pt_opcodes.h"
31 
32 #include "intel-pt.h"
33 
34 #include <string.h>
35 #include <stddef.h>
36 
37 
38 int pt_cpu_errata(struct pt_errata *errata, const struct pt_cpu *cpu)
39 {
40 	if (!errata || !cpu)
41 		return -pte_invalid;
42 
43 	memset(errata, 0, sizeof(*errata));
44 
45 	/* We don't know about others. */
46 	if (cpu->vendor != pcv_intel)
47 		return -pte_bad_cpu;
48 
49 	switch (cpu->family) {
50 	case 0x6:
51 		switch (cpu->model) {
52 		case 0x3d:
53 		case 0x47:
54 		case 0x4f:
55 		case 0x56:
56 			errata->bdm70 = 1;
57 			errata->bdm64 = 1;
58 			return 0;
59 
60 		case 0x4e:
61 		case 0x5e:
62 		case 0x8e:
63 		case 0x9e:
64 			errata->bdm70 = 1;
65 			errata->skd007 = 1;
66 			errata->skd022 = 1;
67 			errata->skd010 = 1;
68 			errata->skl014 = 1;
69 			errata->skl168 = 1;
70 			return 0;
71 
72 		case 0x55:
73 		case 0x66:
74 		case 0x7d:
75 		case 0x7e:
76 			errata->bdm70 = 1;
77 			errata->skl014 = 1;
78 			errata->skd022 = 1;
79 			return 0;
80 
81 		case 0x5c:
82 		case 0x5f:
83 			errata->apl12 = 1;
84 			errata->apl11 = 1;
85 			return 0;
86 
87 		case 0x7a:
88 		case 0x86:
89 			errata->apl11 = 1;
90 			return 0;
91 		}
92 		break;
93 	}
94 
95 	return -pte_bad_cpu;
96 }
97 
98 int pt_config_from_user(struct pt_config *config,
99 			const struct pt_config *uconfig)
100 {
101 	uint8_t *begin, *end;
102 	size_t size;
103 
104 	if (!config)
105 		return -pte_internal;
106 
107 	if (!uconfig)
108 		return -pte_invalid;
109 
110 	size = uconfig->size;
111 	if (size < offsetof(struct pt_config, decode))
112 		return -pte_bad_config;
113 
114 	begin = uconfig->begin;
115 	end = uconfig->end;
116 
117 	if (!begin || !end || end < begin)
118 		return -pte_bad_config;
119 
120 	/* Ignore fields in the user's configuration we don't know; zero out
121 	 * fields the user didn't know about.
122 	 */
123 	if (sizeof(*config) <= size)
124 		size = sizeof(*config);
125 	else
126 		memset(((uint8_t *) config) + size, 0, sizeof(*config) - size);
127 
128 	/* Copy (portions of) the user's configuration. */
129 	memcpy(config, uconfig, size);
130 
131 	/* We copied user's size - fix it. */
132 	config->size = size;
133 
134 	return 0;
135 }
136 
137 /* The maximum number of filter addresses that fit into the configuration. */
138 static inline size_t pt_filter_addr_ncfg(void)
139 {
140 	return (sizeof(struct pt_conf_addr_filter) -
141 		offsetof(struct pt_conf_addr_filter, addr0_a)) /
142 		(2 * sizeof(uint64_t));
143 }
144 
145 uint32_t pt_filter_addr_cfg(const struct pt_conf_addr_filter *filter, uint8_t n)
146 {
147 	if (!filter)
148 		return 0u;
149 
150 	if (pt_filter_addr_ncfg() <= n)
151 		return 0u;
152 
153 	return (filter->config.addr_cfg >> (4 * n)) & 0xf;
154 }
155 
156 uint64_t pt_filter_addr_a(const struct pt_conf_addr_filter *filter, uint8_t n)
157 {
158 	const uint64_t *addr;
159 
160 	if (!filter)
161 		return 0ull;
162 
163 	if (pt_filter_addr_ncfg() <= n)
164 		return 0ull;
165 
166 	addr = &filter->addr0_a;
167 	return addr[2 * n];
168 }
169 
170 uint64_t pt_filter_addr_b(const struct pt_conf_addr_filter *filter, uint8_t n)
171 {
172 	const uint64_t *addr;
173 
174 	if (!filter)
175 		return 0ull;
176 
177 	if (pt_filter_addr_ncfg() <= n)
178 		return 0ull;
179 
180 	addr = &filter->addr0_a;
181 	return addr[(2 * n) + 1];
182 }
183 
184 static int pt_filter_check_cfg_filter(const struct pt_conf_addr_filter *filter,
185 				      uint64_t addr)
186 {
187 	uint8_t n;
188 
189 	if (!filter)
190 		return -pte_internal;
191 
192 	for (n = 0; n < pt_filter_addr_ncfg(); ++n) {
193 		uint64_t addr_a, addr_b;
194 		uint32_t addr_cfg;
195 
196 		addr_cfg = pt_filter_addr_cfg(filter, n);
197 		if (addr_cfg != pt_addr_cfg_filter)
198 			continue;
199 
200 		addr_a = pt_filter_addr_a(filter, n);
201 		addr_b = pt_filter_addr_b(filter, n);
202 
203 		/* Note that both A and B are inclusive. */
204 		if ((addr_a <= addr) && (addr <= addr_b))
205 			return 1;
206 	}
207 
208 	/* No filter hit.  If we have at least one FilterEn filter, this means
209 	 * that tracing is disabled; otherwise, tracing is enabled.
210 	 */
211 	for (n = 0; n < pt_filter_addr_ncfg(); ++n) {
212 		uint32_t addr_cfg;
213 
214 		addr_cfg = pt_filter_addr_cfg(filter, n);
215 		if (addr_cfg == pt_addr_cfg_filter)
216 			return 0;
217 	}
218 
219 	return 1;
220 }
221 
222 static int pt_filter_check_cfg_stop(const struct pt_conf_addr_filter *filter,
223 				    uint64_t addr)
224 {
225 	uint8_t n;
226 
227 	if (!filter)
228 		return -pte_internal;
229 
230 	for (n = 0; n < pt_filter_addr_ncfg(); ++n) {
231 		uint64_t addr_a, addr_b;
232 		uint32_t addr_cfg;
233 
234 		addr_cfg = pt_filter_addr_cfg(filter, n);
235 		if (addr_cfg != pt_addr_cfg_stop)
236 			continue;
237 
238 		addr_a = pt_filter_addr_a(filter, n);
239 		addr_b = pt_filter_addr_b(filter, n);
240 
241 		/* Note that both A and B are inclusive. */
242 		if ((addr_a <= addr) && (addr <= addr_b))
243 			return 0;
244 	}
245 
246 	return 1;
247 }
248 
249 int pt_filter_addr_check(const struct pt_conf_addr_filter *filter,
250 			 uint64_t addr)
251 {
252 	int status;
253 
254 	status = pt_filter_check_cfg_stop(filter, addr);
255 	if (status <= 0)
256 		return status;
257 
258 	return pt_filter_check_cfg_filter(filter, addr);
259 }
260