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
37static 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
52int 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
90int 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
112static 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
135int 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
164static 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
180static 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
200int 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
217int 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
238int 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
263static 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
275static 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
287int 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
315int 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
329int 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
343int 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
369int 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
383int 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
431int 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
449int 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
463int 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
477int 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
494int 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
518int 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
546int 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