1 /*
2 * Copyright (c) 2013-2018, 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 errata->bdm70 = 1;
63 errata->skd007 = 1;
64 errata->skd022 = 1;
65 errata->skd010 = 1;
66 errata->skl014 = 1;
67 return 0;
68
69 case 0x8e:
70 case 0x9e:
71 errata->bdm70 = 1;
72 errata->skl014 = 1;
73 errata->skd022 = 1;
74 errata->skd010 = 1;
75 errata->skd007 = 1;
76 return 0;
77
78 case 0x5c:
79 case 0x5f:
80 errata->apl12 = 1;
81 errata->apl11 = 1;
82 return 0;
83 }
84 break;
85 }
86
87 return -pte_bad_cpu;
88 }
89
pt_config_from_user(struct pt_config * config,const struct pt_config * uconfig)90 int pt_config_from_user(struct pt_config *config,
91 const struct pt_config *uconfig)
92 {
93 uint8_t *begin, *end;
94 size_t size;
95
96 if (!config)
97 return -pte_internal;
98
99 if (!uconfig)
100 return -pte_invalid;
101
102 size = uconfig->size;
103 if (size < offsetof(struct pt_config, decode))
104 return -pte_bad_config;
105
106 begin = uconfig->begin;
107 end = uconfig->end;
108
109 if (!begin || !end || end < begin)
110 return -pte_bad_config;
111
112 /* Ignore fields in the user's configuration we don't know; zero out
113 * fields the user didn't know about.
114 */
115 if (sizeof(*config) <= size)
116 size = sizeof(*config);
117 else
118 memset(((uint8_t *) config) + size, 0, sizeof(*config) - size);
119
120 /* Copy (portions of) the user's configuration. */
121 memcpy(config, uconfig, size);
122
123 /* We copied user's size - fix it. */
124 config->size = size;
125
126 return 0;
127 }
128
129 /* The maximum number of filter addresses that fit into the configuration. */
pt_filter_addr_ncfg(void)130 static inline size_t pt_filter_addr_ncfg(void)
131 {
132 return (sizeof(struct pt_conf_addr_filter) -
133 offsetof(struct pt_conf_addr_filter, addr0_a)) /
134 (2 * sizeof(uint64_t));
135 }
136
pt_filter_addr_cfg(const struct pt_conf_addr_filter * filter,uint8_t n)137 uint32_t pt_filter_addr_cfg(const struct pt_conf_addr_filter *filter, uint8_t n)
138 {
139 if (!filter)
140 return 0u;
141
142 if (pt_filter_addr_ncfg() <= n)
143 return 0u;
144
145 return (filter->config.addr_cfg >> (4 * n)) & 0xf;
146 }
147
pt_filter_addr_a(const struct pt_conf_addr_filter * filter,uint8_t n)148 uint64_t pt_filter_addr_a(const struct pt_conf_addr_filter *filter, uint8_t n)
149 {
150 const uint64_t *addr;
151
152 if (!filter)
153 return 0ull;
154
155 if (pt_filter_addr_ncfg() <= n)
156 return 0ull;
157
158 addr = &filter->addr0_a;
159 return addr[2 * n];
160 }
161
pt_filter_addr_b(const struct pt_conf_addr_filter * filter,uint8_t n)162 uint64_t pt_filter_addr_b(const struct pt_conf_addr_filter *filter, uint8_t n)
163 {
164 const uint64_t *addr;
165
166 if (!filter)
167 return 0ull;
168
169 if (pt_filter_addr_ncfg() <= n)
170 return 0ull;
171
172 addr = &filter->addr0_a;
173 return addr[(2 * n) + 1];
174 }
175
pt_filter_check_cfg_filter(const struct pt_conf_addr_filter * filter,uint64_t addr)176 static int pt_filter_check_cfg_filter(const struct pt_conf_addr_filter *filter,
177 uint64_t addr)
178 {
179 uint8_t n;
180
181 if (!filter)
182 return -pte_internal;
183
184 for (n = 0; n < pt_filter_addr_ncfg(); ++n) {
185 uint64_t addr_a, addr_b;
186 uint32_t addr_cfg;
187
188 addr_cfg = pt_filter_addr_cfg(filter, n);
189 if (addr_cfg != pt_addr_cfg_filter)
190 continue;
191
192 addr_a = pt_filter_addr_a(filter, n);
193 addr_b = pt_filter_addr_b(filter, n);
194
195 /* Note that both A and B are inclusive. */
196 if ((addr_a <= addr) && (addr <= addr_b))
197 return 1;
198 }
199
200 /* No filter hit. If we have at least one FilterEn filter, this means
201 * that tracing is disabled; otherwise, tracing is enabled.
202 */
203 for (n = 0; n < pt_filter_addr_ncfg(); ++n) {
204 uint32_t addr_cfg;
205
206 addr_cfg = pt_filter_addr_cfg(filter, n);
207 if (addr_cfg == pt_addr_cfg_filter)
208 return 0;
209 }
210
211 return 1;
212 }
213
pt_filter_check_cfg_stop(const struct pt_conf_addr_filter * filter,uint64_t addr)214 static int pt_filter_check_cfg_stop(const struct pt_conf_addr_filter *filter,
215 uint64_t addr)
216 {
217 uint8_t n;
218
219 if (!filter)
220 return -pte_internal;
221
222 for (n = 0; n < pt_filter_addr_ncfg(); ++n) {
223 uint64_t addr_a, addr_b;
224 uint32_t addr_cfg;
225
226 addr_cfg = pt_filter_addr_cfg(filter, n);
227 if (addr_cfg != pt_addr_cfg_stop)
228 continue;
229
230 addr_a = pt_filter_addr_a(filter, n);
231 addr_b = pt_filter_addr_b(filter, n);
232
233 /* Note that both A and B are inclusive. */
234 if ((addr_a <= addr) && (addr <= addr_b))
235 return 0;
236 }
237
238 return 1;
239 }
240
pt_filter_addr_check(const struct pt_conf_addr_filter * filter,uint64_t addr)241 int pt_filter_addr_check(const struct pt_conf_addr_filter *filter,
242 uint64_t addr)
243 {
244 int status;
245
246 status = pt_filter_check_cfg_stop(filter, addr);
247 if (status <= 0)
248 return status;
249
250 return pt_filter_check_cfg_filter(filter, addr);
251 }
252