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
38int 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
98int 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. */
138static 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
145uint32_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
156uint64_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
170uint64_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
184static 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
222static 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
249int 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