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
pt_cpu_errata(struct pt_errata * errata,const struct pt_cpu * cpu)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
pt_config_from_user(struct pt_config * config,const struct pt_config * uconfig)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. */
pt_filter_addr_ncfg(void)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
pt_filter_addr_cfg(const struct pt_conf_addr_filter * filter,uint8_t n)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
pt_filter_addr_a(const struct pt_conf_addr_filter * filter,uint8_t n)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
pt_filter_addr_b(const struct pt_conf_addr_filter * filter,uint8_t n)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
pt_filter_check_cfg_filter(const struct pt_conf_addr_filter * filter,uint64_t addr)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
pt_filter_check_cfg_stop(const struct pt_conf_addr_filter * filter,uint64_t addr)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
pt_filter_addr_check(const struct pt_conf_addr_filter * filter,uint64_t addr)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