xref: /freebsd/contrib/processor-trace/libipt/src/pt_packet.c (revision 85f87cf491bec6f90948a85b10f5523ea24db9e3)
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_packet.h"
30 #include "pt_opcodes.h"
31 
32 #include "intel-pt.h"
33 
34 #include <limits.h>
35 
36 
pt_pkt_read_value(const uint8_t * pos,int size)37 static uint64_t pt_pkt_read_value(const uint8_t *pos, int size)
38 {
39 	uint64_t val;
40 	int idx;
41 
42 	for (val = 0, idx = 0; idx < size; ++idx) {
43 		uint64_t byte = *pos++;
44 
45 		byte <<= (idx * 8);
46 		val |= byte;
47 	}
48 
49 	return val;
50 }
51 
pt_pkt_read_unknown(struct pt_packet * packet,const uint8_t * pos,const struct pt_config * config)52 int pt_pkt_read_unknown(struct pt_packet *packet, const uint8_t *pos,
53 			const struct pt_config *config)
54 {
55 	int (*decode)(struct pt_packet_unknown *, const struct pt_config *,
56 		      const uint8_t *, void *);
57 	int size;
58 
59 	if (!packet || !pos || !config)
60 		return -pte_internal;
61 
62 	decode = config->decode.callback;
63 	if (!decode)
64 		return -pte_bad_opc;
65 
66 	/* Fill in some default values. */
67 	packet->payload.unknown.packet = pos;
68 	packet->payload.unknown.priv = NULL;
69 
70 	/* We accept a size of zero to allow the callback to modify the
71 	 * trace buffer and resume normal decoding.
72 	 */
73 	size = (*decode)(&packet->payload.unknown, config, pos,
74 			 config->decode.context);
75 	if (size < 0)
76 		return size;
77 
78 	if (size > UCHAR_MAX)
79 		return -pte_invalid;
80 
81 	packet->type = ppt_unknown;
82 	packet->size = (uint8_t) size;
83 
84 	if (config->end < pos + size)
85 		return -pte_eos;
86 
87 	return size;
88 }
89 
pt_pkt_read_psb(const uint8_t * pos,const struct pt_config * config)90 int pt_pkt_read_psb(const uint8_t *pos, const struct pt_config *config)
91 {
92 	int count;
93 
94 	if (!pos || !config)
95 		return -pte_internal;
96 
97 	if (config->end < pos + ptps_psb)
98 		return -pte_eos;
99 
100 	pos += pt_opcs_psb;
101 
102 	for (count = 0; count < pt_psb_repeat_count; ++count) {
103 		if (*pos++ != pt_psb_hi)
104 			return -pte_bad_packet;
105 		if (*pos++ != pt_psb_lo)
106 			return -pte_bad_packet;
107 	}
108 
109 	return ptps_psb;
110 }
111 
pt_pkt_ip_size(enum pt_ip_compression ipc)112 static int pt_pkt_ip_size(enum pt_ip_compression ipc)
113 {
114 	switch (ipc) {
115 	case pt_ipc_suppressed:
116 		return 0;
117 
118 	case pt_ipc_update_16:
119 		return 2;
120 
121 	case pt_ipc_update_32:
122 		return 4;
123 
124 	case pt_ipc_update_48:
125 	case pt_ipc_sext_48:
126 		return 6;
127 
128 	case pt_ipc_full:
129 		return 8;
130 	}
131 
132 	return -pte_bad_packet;
133 }
134 
pt_pkt_read_ip(struct pt_packet_ip * packet,const uint8_t * pos,const struct pt_config * config)135 int pt_pkt_read_ip(struct pt_packet_ip *packet, const uint8_t *pos,
136 		   const struct pt_config *config)
137 {
138 	uint64_t ip;
139 	uint8_t ipc;
140 	int ipsize;
141 
142 	if (!packet || !pos || !config)
143 		return -pte_internal;
144 
145 	ipc = (*pos++ >> pt_opm_ipc_shr) & pt_opm_ipc_shr_mask;
146 
147 	ip = 0ull;
148 	ipsize = pt_pkt_ip_size((enum pt_ip_compression) ipc);
149 	if (ipsize < 0)
150 		return ipsize;
151 
152 	if (config->end < pos + ipsize)
153 		return -pte_eos;
154 
155 	if (ipsize)
156 		ip = pt_pkt_read_value(pos, ipsize);
157 
158 	packet->ipc = (enum pt_ip_compression) ipc;
159 	packet->ip = ip;
160 
161 	return ipsize + 1;
162 }
163 
pt_pkt_tnt_bit_size(uint64_t payload)164 static uint8_t pt_pkt_tnt_bit_size(uint64_t payload)
165 {
166 	uint8_t size;
167 
168 	/* The payload bit-size is the bit-index of the payload's stop-bit,
169 	 * which itself is not part of the payload proper.
170 	 */
171 	for (size = 0; ; size += 1) {
172 		payload >>= 1;
173 		if (!payload)
174 			break;
175 	}
176 
177 	return size;
178 }
179 
pt_pkt_read_tnt(struct pt_packet_tnt * packet,uint64_t payload)180 static int pt_pkt_read_tnt(struct pt_packet_tnt *packet, uint64_t payload)
181 {
182 	uint8_t bit_size;
183 
184 	if (!packet)
185 		return -pte_internal;
186 
187 	bit_size = pt_pkt_tnt_bit_size(payload);
188 	if (!bit_size)
189 		return -pte_bad_packet;
190 
191 	/* Remove the stop bit from the payload. */
192 	payload &= ~(1ull << bit_size);
193 
194 	packet->payload = payload;
195 	packet->bit_size = bit_size;
196 
197 	return 0;
198 }
199 
pt_pkt_read_tnt_8(struct pt_packet_tnt * packet,const uint8_t * pos,const struct pt_config * config)200 int pt_pkt_read_tnt_8(struct pt_packet_tnt *packet, const uint8_t *pos,
201 		      const struct pt_config *config)
202 {
203 	int errcode;
204 
205 	(void) config;
206 
207 	if (!pos)
208 		return -pte_internal;
209 
210 	errcode = pt_pkt_read_tnt(packet, pos[0] >> pt_opm_tnt_8_shr);
211 	if (errcode < 0)
212 		return errcode;
213 
214 	return ptps_tnt_8;
215 }
216 
pt_pkt_read_tnt_64(struct pt_packet_tnt * packet,const uint8_t * pos,const struct pt_config * config)217 int pt_pkt_read_tnt_64(struct pt_packet_tnt *packet, const uint8_t *pos,
218 		       const struct pt_config *config)
219 {
220 	uint64_t payload;
221 	int errcode;
222 
223 	if (!pos || !config)
224 		return -pte_internal;
225 
226 	if (config->end < pos + ptps_tnt_64)
227 		return -pte_eos;
228 
229 	payload = pt_pkt_read_value(pos + pt_opcs_tnt_64, pt_pl_tnt_64_size);
230 
231 	errcode = pt_pkt_read_tnt(packet, payload);
232 	if (errcode < 0)
233 		return errcode;
234 
235 	return ptps_tnt_64;
236 }
237 
pt_pkt_read_pip(struct pt_packet_pip * packet,const uint8_t * pos,const struct pt_config * config)238 int pt_pkt_read_pip(struct pt_packet_pip *packet, const uint8_t *pos,
239 		    const struct pt_config *config)
240 {
241 	uint64_t payload;
242 
243 	if (!packet || !pos || !config)
244 		return -pte_internal;
245 
246 	if (config->end < pos + ptps_pip)
247 		return -pte_eos;
248 
249 	/* Read the payload. */
250 	payload = pt_pkt_read_value(pos + pt_opcs_pip, pt_pl_pip_size);
251 
252 	/* Extract the non-root information from the payload. */
253 	packet->nr = payload & pt_pl_pip_nr;
254 
255 	/* Create the cr3 value. */
256 	payload  >>= pt_pl_pip_shr;
257 	payload  <<= pt_pl_pip_shl;
258 	packet->cr3 = payload;
259 
260 	return ptps_pip;
261 }
262 
pt_pkt_read_mode_exec(struct pt_packet_mode_exec * packet,uint8_t mode)263 static int pt_pkt_read_mode_exec(struct pt_packet_mode_exec *packet,
264 				 uint8_t mode)
265 {
266 	if (!packet)
267 		return -pte_internal;
268 
269 	packet->csl = (mode & pt_mob_exec_csl) != 0;
270 	packet->csd = (mode & pt_mob_exec_csd) != 0;
271 
272 	return ptps_mode;
273 }
274 
pt_pkt_read_mode_tsx(struct pt_packet_mode_tsx * packet,uint8_t mode)275 static int pt_pkt_read_mode_tsx(struct pt_packet_mode_tsx *packet,
276 				uint8_t mode)
277 {
278 	if (!packet)
279 		return -pte_internal;
280 
281 	packet->intx = (mode & pt_mob_tsx_intx) != 0;
282 	packet->abrt = (mode & pt_mob_tsx_abrt) != 0;
283 
284 	return ptps_mode;
285 }
286 
pt_pkt_read_mode(struct pt_packet_mode * packet,const uint8_t * pos,const struct pt_config * config)287 int pt_pkt_read_mode(struct pt_packet_mode *packet, const uint8_t *pos,
288 		     const struct pt_config *config)
289 {
290 	uint8_t payload, mode, leaf;
291 
292 	if (!packet || !pos || !config)
293 		return -pte_internal;
294 
295 	if (config->end < pos + ptps_mode)
296 		return -pte_eos;
297 
298 	payload = pos[pt_opcs_mode];
299 	leaf = payload & pt_mom_leaf;
300 	mode = payload & pt_mom_bits;
301 
302 	packet->leaf = (enum pt_mode_leaf) leaf;
303 	switch (leaf) {
304 	default:
305 		return -pte_bad_packet;
306 
307 	case pt_mol_exec:
308 		return pt_pkt_read_mode_exec(&packet->bits.exec, mode);
309 
310 	case pt_mol_tsx:
311 		return pt_pkt_read_mode_tsx(&packet->bits.tsx, mode);
312 	}
313 }
314 
pt_pkt_read_tsc(struct pt_packet_tsc * packet,const uint8_t * pos,const struct pt_config * config)315 int pt_pkt_read_tsc(struct pt_packet_tsc *packet, const uint8_t *pos,
316 		    const struct pt_config *config)
317 {
318 	if (!packet || !pos || !config)
319 		return -pte_internal;
320 
321 	if (config->end < pos + ptps_tsc)
322 		return -pte_eos;
323 
324 	packet->tsc = pt_pkt_read_value(pos + pt_opcs_tsc, pt_pl_tsc_size);
325 
326 	return ptps_tsc;
327 }
328 
pt_pkt_read_cbr(struct pt_packet_cbr * packet,const uint8_t * pos,const struct pt_config * config)329 int pt_pkt_read_cbr(struct pt_packet_cbr *packet, const uint8_t *pos,
330 		    const struct pt_config *config)
331 {
332 	if (!packet || !pos || !config)
333 		return -pte_internal;
334 
335 	if (config->end < pos + ptps_cbr)
336 		return -pte_eos;
337 
338 	packet->ratio = pos[2];
339 
340 	return ptps_cbr;
341 }
342 
pt_pkt_read_tma(struct pt_packet_tma * packet,const uint8_t * pos,const struct pt_config * config)343 int pt_pkt_read_tma(struct pt_packet_tma *packet, const uint8_t *pos,
344 		    const struct pt_config *config)
345 {
346 	uint16_t ctc, fc;
347 
348 	if (!packet || !pos || !config)
349 		return -pte_internal;
350 
351 	if (config->end < pos + ptps_tma)
352 		return -pte_eos;
353 
354 	ctc = pos[pt_pl_tma_ctc_0];
355 	ctc |= pos[pt_pl_tma_ctc_1] << 8;
356 
357 	fc = pos[pt_pl_tma_fc_0];
358 	fc |= pos[pt_pl_tma_fc_1] << 8;
359 
360 	if (fc & ~pt_pl_tma_fc_mask)
361 		return -pte_bad_packet;
362 
363 	packet->ctc = ctc;
364 	packet->fc = fc;
365 
366 	return ptps_tma;
367 }
368 
pt_pkt_read_mtc(struct pt_packet_mtc * packet,const uint8_t * pos,const struct pt_config * config)369 int pt_pkt_read_mtc(struct pt_packet_mtc *packet, const uint8_t *pos,
370 		    const struct pt_config *config)
371 {
372 	if (!packet || !pos || !config)
373 		return -pte_internal;
374 
375 	if (config->end < pos + ptps_mtc)
376 		return -pte_eos;
377 
378 	packet->ctc = pos[pt_opcs_mtc];
379 
380 	return ptps_mtc;
381 }
382 
pt_pkt_read_cyc(struct pt_packet_cyc * packet,const uint8_t * pos,const struct pt_config * config)383 int pt_pkt_read_cyc(struct pt_packet_cyc *packet, const uint8_t *pos,
384 		    const struct pt_config *config)
385 {
386 	const uint8_t *begin, *end;
387 	uint64_t value;
388 	uint8_t cyc, ext, shl;
389 
390 	if (!packet || !pos || !config)
391 		return -pte_internal;
392 
393 	begin = pos;
394 	end = config->end;
395 
396 	/* The first byte contains the opcode and part of the payload.
397 	 * We already checked that this first byte is within bounds.
398 	 */
399 	cyc = *pos++;
400 
401 	ext = cyc & pt_opm_cyc_ext;
402 	cyc >>= pt_opm_cyc_shr;
403 
404 	value = cyc;
405 	shl = (8 - pt_opm_cyc_shr);
406 
407 	while (ext) {
408 		uint64_t bits;
409 
410 		if (end <= pos)
411 			return -pte_eos;
412 
413 		bits = *pos++;
414 		ext = bits & pt_opm_cycx_ext;
415 
416 		bits >>= pt_opm_cycx_shr;
417 		bits <<= shl;
418 
419 		shl += (8 - pt_opm_cycx_shr);
420 		if (sizeof(value) * 8 < shl)
421 			return -pte_bad_packet;
422 
423 		value |= bits;
424 	}
425 
426 	packet->value = value;
427 
428 	return (int) (pos - begin);
429 }
430 
pt_pkt_read_vmcs(struct pt_packet_vmcs * packet,const uint8_t * pos,const struct pt_config * config)431 int pt_pkt_read_vmcs(struct pt_packet_vmcs *packet, const uint8_t *pos,
432 		     const struct pt_config *config)
433 {
434 	uint64_t payload;
435 
436 	if (!packet || !pos || !config)
437 		return -pte_internal;
438 
439 	if (config->end < pos + ptps_vmcs)
440 		return -pte_eos;
441 
442 	payload = pt_pkt_read_value(pos + pt_opcs_vmcs, pt_pl_vmcs_size);
443 
444 	packet->base = payload << pt_pl_vmcs_shl;
445 
446 	return ptps_vmcs;
447 }
448 
pt_pkt_read_mnt(struct pt_packet_mnt * packet,const uint8_t * pos,const struct pt_config * config)449 int pt_pkt_read_mnt(struct pt_packet_mnt *packet, const uint8_t *pos,
450 		    const struct pt_config *config)
451 {
452 	if (!packet || !pos || !config)
453 		return -pte_internal;
454 
455 	if (config->end < pos + ptps_mnt)
456 		return -pte_eos;
457 
458 	packet->payload = pt_pkt_read_value(pos + pt_opcs_mnt, pt_pl_mnt_size);
459 
460 	return ptps_mnt;
461 }
462 
pt_pkt_read_exstop(struct pt_packet_exstop * packet,const uint8_t * pos,const struct pt_config * config)463 int pt_pkt_read_exstop(struct pt_packet_exstop *packet, const uint8_t *pos,
464 		       const struct pt_config *config)
465 {
466 	if (!packet || !pos || !config)
467 		return -pte_internal;
468 
469 	if (config->end < pos + ptps_exstop)
470 		return -pte_eos;
471 
472 	packet->ip = pos[1] & pt_pl_exstop_ip_mask ? 1 : 0;
473 
474 	return ptps_exstop;
475 }
476 
pt_pkt_read_mwait(struct pt_packet_mwait * packet,const uint8_t * pos,const struct pt_config * config)477 int pt_pkt_read_mwait(struct pt_packet_mwait *packet, const uint8_t *pos,
478 		      const struct pt_config *config)
479 {
480 	if (!packet || !pos || !config)
481 		return -pte_internal;
482 
483 	if (config->end < pos + ptps_mwait)
484 		return -pte_eos;
485 
486 	packet->hints = (uint32_t) pt_pkt_read_value(pos + pt_opcs_mwait,
487 						     pt_pl_mwait_hints_size);
488 	packet->ext = (uint32_t) pt_pkt_read_value(pos + pt_opcs_mwait +
489 						   pt_pl_mwait_hints_size,
490 						   pt_pl_mwait_ext_size);
491 	return ptps_mwait;
492 }
493 
pt_pkt_read_pwre(struct pt_packet_pwre * packet,const uint8_t * pos,const struct pt_config * config)494 int pt_pkt_read_pwre(struct pt_packet_pwre *packet, const uint8_t *pos,
495 		     const struct pt_config *config)
496 {
497 	uint64_t payload;
498 
499 	if (!packet || !pos || !config)
500 		return -pte_internal;
501 
502 	if (config->end < pos + ptps_pwre)
503 		return -pte_eos;
504 
505 	payload = pt_pkt_read_value(pos + pt_opcs_pwre, pt_pl_pwre_size);
506 
507 	memset(packet, 0, sizeof(*packet));
508 	packet->state = (uint8_t) ((payload & pt_pl_pwre_state_mask) >>
509 				   pt_pl_pwre_state_shr);
510 	packet->sub_state = (uint8_t) ((payload & pt_pl_pwre_sub_state_mask) >>
511 				       pt_pl_pwre_sub_state_shr);
512 	if (payload & pt_pl_pwre_hw_mask)
513 		packet->hw = 1;
514 
515 	return ptps_pwre;
516 }
517 
pt_pkt_read_pwrx(struct pt_packet_pwrx * packet,const uint8_t * pos,const struct pt_config * config)518 int pt_pkt_read_pwrx(struct pt_packet_pwrx *packet, const uint8_t *pos,
519 		     const struct pt_config *config)
520 {
521 	uint64_t payload;
522 
523 	if (!packet || !pos || !config)
524 		return -pte_internal;
525 
526 	if (config->end < pos + ptps_pwrx)
527 		return -pte_eos;
528 
529 	payload = pt_pkt_read_value(pos + pt_opcs_pwrx, pt_pl_pwrx_size);
530 
531 	memset(packet, 0, sizeof(*packet));
532 	packet->last = (uint8_t) ((payload & pt_pl_pwrx_last_mask) >>
533 				  pt_pl_pwrx_last_shr);
534 	packet->deepest = (uint8_t) ((payload & pt_pl_pwrx_deepest_mask) >>
535 				     pt_pl_pwrx_deepest_shr);
536 	if (payload & pt_pl_pwrx_wr_int)
537 		packet->interrupt = 1;
538 	if (payload & pt_pl_pwrx_wr_store)
539 		packet->store = 1;
540 	if (payload & pt_pl_pwrx_wr_hw)
541 		packet->autonomous = 1;
542 
543 	return ptps_pwrx;
544 }
545 
pt_pkt_read_ptw(struct pt_packet_ptw * packet,const uint8_t * pos,const struct pt_config * config)546 int pt_pkt_read_ptw(struct pt_packet_ptw *packet, const uint8_t *pos,
547 		    const struct pt_config *config)
548 {
549 	uint8_t opc, plc;
550 	int size;
551 
552 	if (!packet || !pos || !config)
553 		return -pte_internal;
554 
555 	/* Skip the ext opcode. */
556 	pos++;
557 
558 	opc = *pos++;
559 	plc = (opc >> pt_opm_ptw_pb_shr) & pt_opm_ptw_pb_shr_mask;
560 
561 	size = pt_ptw_size(plc);
562 	if (size < 0)
563 		return size;
564 
565 	if (config->end < pos + size)
566 		return -pte_eos;
567 
568 	packet->payload = pt_pkt_read_value(pos, size);
569 	packet->plc = plc;
570 	packet->ip = opc & pt_opm_ptw_ip ? 1 : 0;
571 
572 	return pt_opcs_ptw + size;
573 }
574