xref: /freebsd-src/contrib/processor-trace/libipt/src/pt_packet.c (revision 85f87cf491bec6f90948a85b10f5523ea24db9e3)
174fe6c29SRuslan Bukin /*
2*85f87cf4SRuslan Bukin  * Copyright (c) 2013-2019, Intel Corporation
374fe6c29SRuslan Bukin  *
474fe6c29SRuslan Bukin  * Redistribution and use in source and binary forms, with or without
574fe6c29SRuslan Bukin  * modification, are permitted provided that the following conditions are met:
674fe6c29SRuslan Bukin  *
774fe6c29SRuslan Bukin  *  * Redistributions of source code must retain the above copyright notice,
874fe6c29SRuslan Bukin  *    this list of conditions and the following disclaimer.
974fe6c29SRuslan Bukin  *  * Redistributions in binary form must reproduce the above copyright notice,
1074fe6c29SRuslan Bukin  *    this list of conditions and the following disclaimer in the documentation
1174fe6c29SRuslan Bukin  *    and/or other materials provided with the distribution.
1274fe6c29SRuslan Bukin  *  * Neither the name of Intel Corporation nor the names of its contributors
1374fe6c29SRuslan Bukin  *    may be used to endorse or promote products derived from this software
1474fe6c29SRuslan Bukin  *    without specific prior written permission.
1574fe6c29SRuslan Bukin  *
1674fe6c29SRuslan Bukin  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1774fe6c29SRuslan Bukin  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1874fe6c29SRuslan Bukin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1974fe6c29SRuslan Bukin  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2074fe6c29SRuslan Bukin  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2174fe6c29SRuslan Bukin  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2274fe6c29SRuslan Bukin  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2374fe6c29SRuslan Bukin  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2474fe6c29SRuslan Bukin  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2574fe6c29SRuslan Bukin  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2674fe6c29SRuslan Bukin  * POSSIBILITY OF SUCH DAMAGE.
2774fe6c29SRuslan Bukin  */
2874fe6c29SRuslan Bukin 
2974fe6c29SRuslan Bukin #include "pt_packet.h"
3074fe6c29SRuslan Bukin #include "pt_opcodes.h"
3174fe6c29SRuslan Bukin 
3274fe6c29SRuslan Bukin #include "intel-pt.h"
3374fe6c29SRuslan Bukin 
3474fe6c29SRuslan Bukin #include <limits.h>
3574fe6c29SRuslan Bukin 
3674fe6c29SRuslan Bukin 
pt_pkt_read_value(const uint8_t * pos,int size)3774fe6c29SRuslan Bukin static uint64_t pt_pkt_read_value(const uint8_t *pos, int size)
3874fe6c29SRuslan Bukin {
3974fe6c29SRuslan Bukin 	uint64_t val;
4074fe6c29SRuslan Bukin 	int idx;
4174fe6c29SRuslan Bukin 
4274fe6c29SRuslan Bukin 	for (val = 0, idx = 0; idx < size; ++idx) {
4374fe6c29SRuslan Bukin 		uint64_t byte = *pos++;
4474fe6c29SRuslan Bukin 
4574fe6c29SRuslan Bukin 		byte <<= (idx * 8);
4674fe6c29SRuslan Bukin 		val |= byte;
4774fe6c29SRuslan Bukin 	}
4874fe6c29SRuslan Bukin 
4974fe6c29SRuslan Bukin 	return val;
5074fe6c29SRuslan Bukin }
5174fe6c29SRuslan Bukin 
pt_pkt_read_unknown(struct pt_packet * packet,const uint8_t * pos,const struct pt_config * config)5274fe6c29SRuslan Bukin int pt_pkt_read_unknown(struct pt_packet *packet, const uint8_t *pos,
5374fe6c29SRuslan Bukin 			const struct pt_config *config)
5474fe6c29SRuslan Bukin {
5574fe6c29SRuslan Bukin 	int (*decode)(struct pt_packet_unknown *, const struct pt_config *,
5674fe6c29SRuslan Bukin 		      const uint8_t *, void *);
5774fe6c29SRuslan Bukin 	int size;
5874fe6c29SRuslan Bukin 
5974fe6c29SRuslan Bukin 	if (!packet || !pos || !config)
6074fe6c29SRuslan Bukin 		return -pte_internal;
6174fe6c29SRuslan Bukin 
6274fe6c29SRuslan Bukin 	decode = config->decode.callback;
6374fe6c29SRuslan Bukin 	if (!decode)
6474fe6c29SRuslan Bukin 		return -pte_bad_opc;
6574fe6c29SRuslan Bukin 
6674fe6c29SRuslan Bukin 	/* Fill in some default values. */
6774fe6c29SRuslan Bukin 	packet->payload.unknown.packet = pos;
6874fe6c29SRuslan Bukin 	packet->payload.unknown.priv = NULL;
6974fe6c29SRuslan Bukin 
7074fe6c29SRuslan Bukin 	/* We accept a size of zero to allow the callback to modify the
7174fe6c29SRuslan Bukin 	 * trace buffer and resume normal decoding.
7274fe6c29SRuslan Bukin 	 */
7374fe6c29SRuslan Bukin 	size = (*decode)(&packet->payload.unknown, config, pos,
7474fe6c29SRuslan Bukin 			 config->decode.context);
7574fe6c29SRuslan Bukin 	if (size < 0)
7674fe6c29SRuslan Bukin 		return size;
7774fe6c29SRuslan Bukin 
7874fe6c29SRuslan Bukin 	if (size > UCHAR_MAX)
7974fe6c29SRuslan Bukin 		return -pte_invalid;
8074fe6c29SRuslan Bukin 
8174fe6c29SRuslan Bukin 	packet->type = ppt_unknown;
8274fe6c29SRuslan Bukin 	packet->size = (uint8_t) size;
8374fe6c29SRuslan Bukin 
8474fe6c29SRuslan Bukin 	if (config->end < pos + size)
8574fe6c29SRuslan Bukin 		return -pte_eos;
8674fe6c29SRuslan Bukin 
8774fe6c29SRuslan Bukin 	return size;
8874fe6c29SRuslan Bukin }
8974fe6c29SRuslan Bukin 
pt_pkt_read_psb(const uint8_t * pos,const struct pt_config * config)9074fe6c29SRuslan Bukin int pt_pkt_read_psb(const uint8_t *pos, const struct pt_config *config)
9174fe6c29SRuslan Bukin {
9274fe6c29SRuslan Bukin 	int count;
9374fe6c29SRuslan Bukin 
9474fe6c29SRuslan Bukin 	if (!pos || !config)
9574fe6c29SRuslan Bukin 		return -pte_internal;
9674fe6c29SRuslan Bukin 
9774fe6c29SRuslan Bukin 	if (config->end < pos + ptps_psb)
9874fe6c29SRuslan Bukin 		return -pte_eos;
9974fe6c29SRuslan Bukin 
10074fe6c29SRuslan Bukin 	pos += pt_opcs_psb;
10174fe6c29SRuslan Bukin 
10274fe6c29SRuslan Bukin 	for (count = 0; count < pt_psb_repeat_count; ++count) {
10374fe6c29SRuslan Bukin 		if (*pos++ != pt_psb_hi)
10474fe6c29SRuslan Bukin 			return -pte_bad_packet;
10574fe6c29SRuslan Bukin 		if (*pos++ != pt_psb_lo)
10674fe6c29SRuslan Bukin 			return -pte_bad_packet;
10774fe6c29SRuslan Bukin 	}
10874fe6c29SRuslan Bukin 
10974fe6c29SRuslan Bukin 	return ptps_psb;
11074fe6c29SRuslan Bukin }
11174fe6c29SRuslan Bukin 
pt_pkt_ip_size(enum pt_ip_compression ipc)11274fe6c29SRuslan Bukin static int pt_pkt_ip_size(enum pt_ip_compression ipc)
11374fe6c29SRuslan Bukin {
11474fe6c29SRuslan Bukin 	switch (ipc) {
11574fe6c29SRuslan Bukin 	case pt_ipc_suppressed:
11674fe6c29SRuslan Bukin 		return 0;
11774fe6c29SRuslan Bukin 
11874fe6c29SRuslan Bukin 	case pt_ipc_update_16:
11974fe6c29SRuslan Bukin 		return 2;
12074fe6c29SRuslan Bukin 
12174fe6c29SRuslan Bukin 	case pt_ipc_update_32:
12274fe6c29SRuslan Bukin 		return 4;
12374fe6c29SRuslan Bukin 
12474fe6c29SRuslan Bukin 	case pt_ipc_update_48:
12574fe6c29SRuslan Bukin 	case pt_ipc_sext_48:
12674fe6c29SRuslan Bukin 		return 6;
12774fe6c29SRuslan Bukin 
12874fe6c29SRuslan Bukin 	case pt_ipc_full:
12974fe6c29SRuslan Bukin 		return 8;
13074fe6c29SRuslan Bukin 	}
13174fe6c29SRuslan Bukin 
13274fe6c29SRuslan Bukin 	return -pte_bad_packet;
13374fe6c29SRuslan Bukin }
13474fe6c29SRuslan Bukin 
pt_pkt_read_ip(struct pt_packet_ip * packet,const uint8_t * pos,const struct pt_config * config)13574fe6c29SRuslan Bukin int pt_pkt_read_ip(struct pt_packet_ip *packet, const uint8_t *pos,
13674fe6c29SRuslan Bukin 		   const struct pt_config *config)
13774fe6c29SRuslan Bukin {
13874fe6c29SRuslan Bukin 	uint64_t ip;
13974fe6c29SRuslan Bukin 	uint8_t ipc;
14074fe6c29SRuslan Bukin 	int ipsize;
14174fe6c29SRuslan Bukin 
14274fe6c29SRuslan Bukin 	if (!packet || !pos || !config)
14374fe6c29SRuslan Bukin 		return -pte_internal;
14474fe6c29SRuslan Bukin 
14574fe6c29SRuslan Bukin 	ipc = (*pos++ >> pt_opm_ipc_shr) & pt_opm_ipc_shr_mask;
14674fe6c29SRuslan Bukin 
14774fe6c29SRuslan Bukin 	ip = 0ull;
14874fe6c29SRuslan Bukin 	ipsize = pt_pkt_ip_size((enum pt_ip_compression) ipc);
14974fe6c29SRuslan Bukin 	if (ipsize < 0)
15074fe6c29SRuslan Bukin 		return ipsize;
15174fe6c29SRuslan Bukin 
15274fe6c29SRuslan Bukin 	if (config->end < pos + ipsize)
15374fe6c29SRuslan Bukin 		return -pte_eos;
15474fe6c29SRuslan Bukin 
15574fe6c29SRuslan Bukin 	if (ipsize)
15674fe6c29SRuslan Bukin 		ip = pt_pkt_read_value(pos, ipsize);
15774fe6c29SRuslan Bukin 
15874fe6c29SRuslan Bukin 	packet->ipc = (enum pt_ip_compression) ipc;
15974fe6c29SRuslan Bukin 	packet->ip = ip;
16074fe6c29SRuslan Bukin 
16174fe6c29SRuslan Bukin 	return ipsize + 1;
16274fe6c29SRuslan Bukin }
16374fe6c29SRuslan Bukin 
pt_pkt_tnt_bit_size(uint64_t payload)16474fe6c29SRuslan Bukin static uint8_t pt_pkt_tnt_bit_size(uint64_t payload)
16574fe6c29SRuslan Bukin {
16674fe6c29SRuslan Bukin 	uint8_t size;
16774fe6c29SRuslan Bukin 
16874fe6c29SRuslan Bukin 	/* The payload bit-size is the bit-index of the payload's stop-bit,
16974fe6c29SRuslan Bukin 	 * which itself is not part of the payload proper.
17074fe6c29SRuslan Bukin 	 */
17174fe6c29SRuslan Bukin 	for (size = 0; ; size += 1) {
17274fe6c29SRuslan Bukin 		payload >>= 1;
17374fe6c29SRuslan Bukin 		if (!payload)
17474fe6c29SRuslan Bukin 			break;
17574fe6c29SRuslan Bukin 	}
17674fe6c29SRuslan Bukin 
17774fe6c29SRuslan Bukin 	return size;
17874fe6c29SRuslan Bukin }
17974fe6c29SRuslan Bukin 
pt_pkt_read_tnt(struct pt_packet_tnt * packet,uint64_t payload)18074fe6c29SRuslan Bukin static int pt_pkt_read_tnt(struct pt_packet_tnt *packet, uint64_t payload)
18174fe6c29SRuslan Bukin {
18274fe6c29SRuslan Bukin 	uint8_t bit_size;
18374fe6c29SRuslan Bukin 
18474fe6c29SRuslan Bukin 	if (!packet)
18574fe6c29SRuslan Bukin 		return -pte_internal;
18674fe6c29SRuslan Bukin 
18774fe6c29SRuslan Bukin 	bit_size = pt_pkt_tnt_bit_size(payload);
18874fe6c29SRuslan Bukin 	if (!bit_size)
18974fe6c29SRuslan Bukin 		return -pte_bad_packet;
19074fe6c29SRuslan Bukin 
19174fe6c29SRuslan Bukin 	/* Remove the stop bit from the payload. */
19274fe6c29SRuslan Bukin 	payload &= ~(1ull << bit_size);
19374fe6c29SRuslan Bukin 
19474fe6c29SRuslan Bukin 	packet->payload = payload;
19574fe6c29SRuslan Bukin 	packet->bit_size = bit_size;
19674fe6c29SRuslan Bukin 
19774fe6c29SRuslan Bukin 	return 0;
19874fe6c29SRuslan Bukin }
19974fe6c29SRuslan Bukin 
pt_pkt_read_tnt_8(struct pt_packet_tnt * packet,const uint8_t * pos,const struct pt_config * config)20074fe6c29SRuslan Bukin int pt_pkt_read_tnt_8(struct pt_packet_tnt *packet, const uint8_t *pos,
20174fe6c29SRuslan Bukin 		      const struct pt_config *config)
20274fe6c29SRuslan Bukin {
20374fe6c29SRuslan Bukin 	int errcode;
20474fe6c29SRuslan Bukin 
20574fe6c29SRuslan Bukin 	(void) config;
20674fe6c29SRuslan Bukin 
20774fe6c29SRuslan Bukin 	if (!pos)
20874fe6c29SRuslan Bukin 		return -pte_internal;
20974fe6c29SRuslan Bukin 
21074fe6c29SRuslan Bukin 	errcode = pt_pkt_read_tnt(packet, pos[0] >> pt_opm_tnt_8_shr);
21174fe6c29SRuslan Bukin 	if (errcode < 0)
21274fe6c29SRuslan Bukin 		return errcode;
21374fe6c29SRuslan Bukin 
21474fe6c29SRuslan Bukin 	return ptps_tnt_8;
21574fe6c29SRuslan Bukin }
21674fe6c29SRuslan Bukin 
pt_pkt_read_tnt_64(struct pt_packet_tnt * packet,const uint8_t * pos,const struct pt_config * config)21774fe6c29SRuslan Bukin int pt_pkt_read_tnt_64(struct pt_packet_tnt *packet, const uint8_t *pos,
21874fe6c29SRuslan Bukin 		       const struct pt_config *config)
21974fe6c29SRuslan Bukin {
22074fe6c29SRuslan Bukin 	uint64_t payload;
22174fe6c29SRuslan Bukin 	int errcode;
22274fe6c29SRuslan Bukin 
22374fe6c29SRuslan Bukin 	if (!pos || !config)
22474fe6c29SRuslan Bukin 		return -pte_internal;
22574fe6c29SRuslan Bukin 
22674fe6c29SRuslan Bukin 	if (config->end < pos + ptps_tnt_64)
22774fe6c29SRuslan Bukin 		return -pte_eos;
22874fe6c29SRuslan Bukin 
22974fe6c29SRuslan Bukin 	payload = pt_pkt_read_value(pos + pt_opcs_tnt_64, pt_pl_tnt_64_size);
23074fe6c29SRuslan Bukin 
23174fe6c29SRuslan Bukin 	errcode = pt_pkt_read_tnt(packet, payload);
23274fe6c29SRuslan Bukin 	if (errcode < 0)
23374fe6c29SRuslan Bukin 		return errcode;
23474fe6c29SRuslan Bukin 
23574fe6c29SRuslan Bukin 	return ptps_tnt_64;
23674fe6c29SRuslan Bukin }
23774fe6c29SRuslan Bukin 
pt_pkt_read_pip(struct pt_packet_pip * packet,const uint8_t * pos,const struct pt_config * config)23874fe6c29SRuslan Bukin int pt_pkt_read_pip(struct pt_packet_pip *packet, const uint8_t *pos,
23974fe6c29SRuslan Bukin 		    const struct pt_config *config)
24074fe6c29SRuslan Bukin {
24174fe6c29SRuslan Bukin 	uint64_t payload;
24274fe6c29SRuslan Bukin 
24374fe6c29SRuslan Bukin 	if (!packet || !pos || !config)
24474fe6c29SRuslan Bukin 		return -pte_internal;
24574fe6c29SRuslan Bukin 
24674fe6c29SRuslan Bukin 	if (config->end < pos + ptps_pip)
24774fe6c29SRuslan Bukin 		return -pte_eos;
24874fe6c29SRuslan Bukin 
24974fe6c29SRuslan Bukin 	/* Read the payload. */
25074fe6c29SRuslan Bukin 	payload = pt_pkt_read_value(pos + pt_opcs_pip, pt_pl_pip_size);
25174fe6c29SRuslan Bukin 
25274fe6c29SRuslan Bukin 	/* Extract the non-root information from the payload. */
25374fe6c29SRuslan Bukin 	packet->nr = payload & pt_pl_pip_nr;
25474fe6c29SRuslan Bukin 
25574fe6c29SRuslan Bukin 	/* Create the cr3 value. */
25674fe6c29SRuslan Bukin 	payload  >>= pt_pl_pip_shr;
25774fe6c29SRuslan Bukin 	payload  <<= pt_pl_pip_shl;
25874fe6c29SRuslan Bukin 	packet->cr3 = payload;
25974fe6c29SRuslan Bukin 
26074fe6c29SRuslan Bukin 	return ptps_pip;
26174fe6c29SRuslan Bukin }
26274fe6c29SRuslan Bukin 
pt_pkt_read_mode_exec(struct pt_packet_mode_exec * packet,uint8_t mode)26374fe6c29SRuslan Bukin static int pt_pkt_read_mode_exec(struct pt_packet_mode_exec *packet,
26474fe6c29SRuslan Bukin 				 uint8_t mode)
26574fe6c29SRuslan Bukin {
26674fe6c29SRuslan Bukin 	if (!packet)
26774fe6c29SRuslan Bukin 		return -pte_internal;
26874fe6c29SRuslan Bukin 
26974fe6c29SRuslan Bukin 	packet->csl = (mode & pt_mob_exec_csl) != 0;
27074fe6c29SRuslan Bukin 	packet->csd = (mode & pt_mob_exec_csd) != 0;
27174fe6c29SRuslan Bukin 
27274fe6c29SRuslan Bukin 	return ptps_mode;
27374fe6c29SRuslan Bukin }
27474fe6c29SRuslan Bukin 
pt_pkt_read_mode_tsx(struct pt_packet_mode_tsx * packet,uint8_t mode)27574fe6c29SRuslan Bukin static int pt_pkt_read_mode_tsx(struct pt_packet_mode_tsx *packet,
27674fe6c29SRuslan Bukin 				uint8_t mode)
27774fe6c29SRuslan Bukin {
27874fe6c29SRuslan Bukin 	if (!packet)
27974fe6c29SRuslan Bukin 		return -pte_internal;
28074fe6c29SRuslan Bukin 
28174fe6c29SRuslan Bukin 	packet->intx = (mode & pt_mob_tsx_intx) != 0;
28274fe6c29SRuslan Bukin 	packet->abrt = (mode & pt_mob_tsx_abrt) != 0;
28374fe6c29SRuslan Bukin 
28474fe6c29SRuslan Bukin 	return ptps_mode;
28574fe6c29SRuslan Bukin }
28674fe6c29SRuslan Bukin 
pt_pkt_read_mode(struct pt_packet_mode * packet,const uint8_t * pos,const struct pt_config * config)28774fe6c29SRuslan Bukin int pt_pkt_read_mode(struct pt_packet_mode *packet, const uint8_t *pos,
28874fe6c29SRuslan Bukin 		     const struct pt_config *config)
28974fe6c29SRuslan Bukin {
29074fe6c29SRuslan Bukin 	uint8_t payload, mode, leaf;
29174fe6c29SRuslan Bukin 
29274fe6c29SRuslan Bukin 	if (!packet || !pos || !config)
29374fe6c29SRuslan Bukin 		return -pte_internal;
29474fe6c29SRuslan Bukin 
29574fe6c29SRuslan Bukin 	if (config->end < pos + ptps_mode)
29674fe6c29SRuslan Bukin 		return -pte_eos;
29774fe6c29SRuslan Bukin 
29874fe6c29SRuslan Bukin 	payload = pos[pt_opcs_mode];
29974fe6c29SRuslan Bukin 	leaf = payload & pt_mom_leaf;
30074fe6c29SRuslan Bukin 	mode = payload & pt_mom_bits;
30174fe6c29SRuslan Bukin 
30274fe6c29SRuslan Bukin 	packet->leaf = (enum pt_mode_leaf) leaf;
30374fe6c29SRuslan Bukin 	switch (leaf) {
30474fe6c29SRuslan Bukin 	default:
30574fe6c29SRuslan Bukin 		return -pte_bad_packet;
30674fe6c29SRuslan Bukin 
30774fe6c29SRuslan Bukin 	case pt_mol_exec:
30874fe6c29SRuslan Bukin 		return pt_pkt_read_mode_exec(&packet->bits.exec, mode);
30974fe6c29SRuslan Bukin 
31074fe6c29SRuslan Bukin 	case pt_mol_tsx:
31174fe6c29SRuslan Bukin 		return pt_pkt_read_mode_tsx(&packet->bits.tsx, mode);
31274fe6c29SRuslan Bukin 	}
31374fe6c29SRuslan Bukin }
31474fe6c29SRuslan Bukin 
pt_pkt_read_tsc(struct pt_packet_tsc * packet,const uint8_t * pos,const struct pt_config * config)31574fe6c29SRuslan Bukin int pt_pkt_read_tsc(struct pt_packet_tsc *packet, const uint8_t *pos,
31674fe6c29SRuslan Bukin 		    const struct pt_config *config)
31774fe6c29SRuslan Bukin {
31874fe6c29SRuslan Bukin 	if (!packet || !pos || !config)
31974fe6c29SRuslan Bukin 		return -pte_internal;
32074fe6c29SRuslan Bukin 
32174fe6c29SRuslan Bukin 	if (config->end < pos + ptps_tsc)
32274fe6c29SRuslan Bukin 		return -pte_eos;
32374fe6c29SRuslan Bukin 
32474fe6c29SRuslan Bukin 	packet->tsc = pt_pkt_read_value(pos + pt_opcs_tsc, pt_pl_tsc_size);
32574fe6c29SRuslan Bukin 
32674fe6c29SRuslan Bukin 	return ptps_tsc;
32774fe6c29SRuslan Bukin }
32874fe6c29SRuslan Bukin 
pt_pkt_read_cbr(struct pt_packet_cbr * packet,const uint8_t * pos,const struct pt_config * config)32974fe6c29SRuslan Bukin int pt_pkt_read_cbr(struct pt_packet_cbr *packet, const uint8_t *pos,
33074fe6c29SRuslan Bukin 		    const struct pt_config *config)
33174fe6c29SRuslan Bukin {
33274fe6c29SRuslan Bukin 	if (!packet || !pos || !config)
33374fe6c29SRuslan Bukin 		return -pte_internal;
33474fe6c29SRuslan Bukin 
33574fe6c29SRuslan Bukin 	if (config->end < pos + ptps_cbr)
33674fe6c29SRuslan Bukin 		return -pte_eos;
33774fe6c29SRuslan Bukin 
33874fe6c29SRuslan Bukin 	packet->ratio = pos[2];
33974fe6c29SRuslan Bukin 
34074fe6c29SRuslan Bukin 	return ptps_cbr;
34174fe6c29SRuslan Bukin }
34274fe6c29SRuslan Bukin 
pt_pkt_read_tma(struct pt_packet_tma * packet,const uint8_t * pos,const struct pt_config * config)34374fe6c29SRuslan Bukin int pt_pkt_read_tma(struct pt_packet_tma *packet, const uint8_t *pos,
34474fe6c29SRuslan Bukin 		    const struct pt_config *config)
34574fe6c29SRuslan Bukin {
34674fe6c29SRuslan Bukin 	uint16_t ctc, fc;
34774fe6c29SRuslan Bukin 
34874fe6c29SRuslan Bukin 	if (!packet || !pos || !config)
34974fe6c29SRuslan Bukin 		return -pte_internal;
35074fe6c29SRuslan Bukin 
35174fe6c29SRuslan Bukin 	if (config->end < pos + ptps_tma)
35274fe6c29SRuslan Bukin 		return -pte_eos;
35374fe6c29SRuslan Bukin 
35474fe6c29SRuslan Bukin 	ctc = pos[pt_pl_tma_ctc_0];
35574fe6c29SRuslan Bukin 	ctc |= pos[pt_pl_tma_ctc_1] << 8;
35674fe6c29SRuslan Bukin 
35774fe6c29SRuslan Bukin 	fc = pos[pt_pl_tma_fc_0];
35874fe6c29SRuslan Bukin 	fc |= pos[pt_pl_tma_fc_1] << 8;
35974fe6c29SRuslan Bukin 
36074fe6c29SRuslan Bukin 	if (fc & ~pt_pl_tma_fc_mask)
36174fe6c29SRuslan Bukin 		return -pte_bad_packet;
36274fe6c29SRuslan Bukin 
36374fe6c29SRuslan Bukin 	packet->ctc = ctc;
36474fe6c29SRuslan Bukin 	packet->fc = fc;
36574fe6c29SRuslan Bukin 
36674fe6c29SRuslan Bukin 	return ptps_tma;
36774fe6c29SRuslan Bukin }
36874fe6c29SRuslan Bukin 
pt_pkt_read_mtc(struct pt_packet_mtc * packet,const uint8_t * pos,const struct pt_config * config)36974fe6c29SRuslan Bukin int pt_pkt_read_mtc(struct pt_packet_mtc *packet, const uint8_t *pos,
37074fe6c29SRuslan Bukin 		    const struct pt_config *config)
37174fe6c29SRuslan Bukin {
37274fe6c29SRuslan Bukin 	if (!packet || !pos || !config)
37374fe6c29SRuslan Bukin 		return -pte_internal;
37474fe6c29SRuslan Bukin 
37574fe6c29SRuslan Bukin 	if (config->end < pos + ptps_mtc)
37674fe6c29SRuslan Bukin 		return -pte_eos;
37774fe6c29SRuslan Bukin 
37874fe6c29SRuslan Bukin 	packet->ctc = pos[pt_opcs_mtc];
37974fe6c29SRuslan Bukin 
38074fe6c29SRuslan Bukin 	return ptps_mtc;
38174fe6c29SRuslan Bukin }
38274fe6c29SRuslan Bukin 
pt_pkt_read_cyc(struct pt_packet_cyc * packet,const uint8_t * pos,const struct pt_config * config)38374fe6c29SRuslan Bukin int pt_pkt_read_cyc(struct pt_packet_cyc *packet, const uint8_t *pos,
38474fe6c29SRuslan Bukin 		    const struct pt_config *config)
38574fe6c29SRuslan Bukin {
38674fe6c29SRuslan Bukin 	const uint8_t *begin, *end;
38774fe6c29SRuslan Bukin 	uint64_t value;
38874fe6c29SRuslan Bukin 	uint8_t cyc, ext, shl;
38974fe6c29SRuslan Bukin 
39074fe6c29SRuslan Bukin 	if (!packet || !pos || !config)
39174fe6c29SRuslan Bukin 		return -pte_internal;
39274fe6c29SRuslan Bukin 
39374fe6c29SRuslan Bukin 	begin = pos;
39474fe6c29SRuslan Bukin 	end = config->end;
39574fe6c29SRuslan Bukin 
39674fe6c29SRuslan Bukin 	/* The first byte contains the opcode and part of the payload.
39774fe6c29SRuslan Bukin 	 * We already checked that this first byte is within bounds.
39874fe6c29SRuslan Bukin 	 */
39974fe6c29SRuslan Bukin 	cyc = *pos++;
40074fe6c29SRuslan Bukin 
40174fe6c29SRuslan Bukin 	ext = cyc & pt_opm_cyc_ext;
40274fe6c29SRuslan Bukin 	cyc >>= pt_opm_cyc_shr;
40374fe6c29SRuslan Bukin 
40474fe6c29SRuslan Bukin 	value = cyc;
40574fe6c29SRuslan Bukin 	shl = (8 - pt_opm_cyc_shr);
40674fe6c29SRuslan Bukin 
40774fe6c29SRuslan Bukin 	while (ext) {
40874fe6c29SRuslan Bukin 		uint64_t bits;
40974fe6c29SRuslan Bukin 
41074fe6c29SRuslan Bukin 		if (end <= pos)
41174fe6c29SRuslan Bukin 			return -pte_eos;
41274fe6c29SRuslan Bukin 
41374fe6c29SRuslan Bukin 		bits = *pos++;
41474fe6c29SRuslan Bukin 		ext = bits & pt_opm_cycx_ext;
41574fe6c29SRuslan Bukin 
41674fe6c29SRuslan Bukin 		bits >>= pt_opm_cycx_shr;
41774fe6c29SRuslan Bukin 		bits <<= shl;
41874fe6c29SRuslan Bukin 
41974fe6c29SRuslan Bukin 		shl += (8 - pt_opm_cycx_shr);
42074fe6c29SRuslan Bukin 		if (sizeof(value) * 8 < shl)
42174fe6c29SRuslan Bukin 			return -pte_bad_packet;
42274fe6c29SRuslan Bukin 
42374fe6c29SRuslan Bukin 		value |= bits;
42474fe6c29SRuslan Bukin 	}
42574fe6c29SRuslan Bukin 
42674fe6c29SRuslan Bukin 	packet->value = value;
42774fe6c29SRuslan Bukin 
42874fe6c29SRuslan Bukin 	return (int) (pos - begin);
42974fe6c29SRuslan Bukin }
43074fe6c29SRuslan Bukin 
pt_pkt_read_vmcs(struct pt_packet_vmcs * packet,const uint8_t * pos,const struct pt_config * config)43174fe6c29SRuslan Bukin int pt_pkt_read_vmcs(struct pt_packet_vmcs *packet, const uint8_t *pos,
43274fe6c29SRuslan Bukin 		     const struct pt_config *config)
43374fe6c29SRuslan Bukin {
43474fe6c29SRuslan Bukin 	uint64_t payload;
43574fe6c29SRuslan Bukin 
43674fe6c29SRuslan Bukin 	if (!packet || !pos || !config)
43774fe6c29SRuslan Bukin 		return -pte_internal;
43874fe6c29SRuslan Bukin 
43974fe6c29SRuslan Bukin 	if (config->end < pos + ptps_vmcs)
44074fe6c29SRuslan Bukin 		return -pte_eos;
44174fe6c29SRuslan Bukin 
44274fe6c29SRuslan Bukin 	payload = pt_pkt_read_value(pos + pt_opcs_vmcs, pt_pl_vmcs_size);
44374fe6c29SRuslan Bukin 
44474fe6c29SRuslan Bukin 	packet->base = payload << pt_pl_vmcs_shl;
44574fe6c29SRuslan Bukin 
44674fe6c29SRuslan Bukin 	return ptps_vmcs;
44774fe6c29SRuslan Bukin }
44874fe6c29SRuslan Bukin 
pt_pkt_read_mnt(struct pt_packet_mnt * packet,const uint8_t * pos,const struct pt_config * config)44974fe6c29SRuslan Bukin int pt_pkt_read_mnt(struct pt_packet_mnt *packet, const uint8_t *pos,
45074fe6c29SRuslan Bukin 		    const struct pt_config *config)
45174fe6c29SRuslan Bukin {
45274fe6c29SRuslan Bukin 	if (!packet || !pos || !config)
45374fe6c29SRuslan Bukin 		return -pte_internal;
45474fe6c29SRuslan Bukin 
45574fe6c29SRuslan Bukin 	if (config->end < pos + ptps_mnt)
45674fe6c29SRuslan Bukin 		return -pte_eos;
45774fe6c29SRuslan Bukin 
45874fe6c29SRuslan Bukin 	packet->payload = pt_pkt_read_value(pos + pt_opcs_mnt, pt_pl_mnt_size);
45974fe6c29SRuslan Bukin 
46074fe6c29SRuslan Bukin 	return ptps_mnt;
46174fe6c29SRuslan Bukin }
46274fe6c29SRuslan Bukin 
pt_pkt_read_exstop(struct pt_packet_exstop * packet,const uint8_t * pos,const struct pt_config * config)46374fe6c29SRuslan Bukin int pt_pkt_read_exstop(struct pt_packet_exstop *packet, const uint8_t *pos,
46474fe6c29SRuslan Bukin 		       const struct pt_config *config)
46574fe6c29SRuslan Bukin {
46674fe6c29SRuslan Bukin 	if (!packet || !pos || !config)
46774fe6c29SRuslan Bukin 		return -pte_internal;
46874fe6c29SRuslan Bukin 
46974fe6c29SRuslan Bukin 	if (config->end < pos + ptps_exstop)
47074fe6c29SRuslan Bukin 		return -pte_eos;
47174fe6c29SRuslan Bukin 
47274fe6c29SRuslan Bukin 	packet->ip = pos[1] & pt_pl_exstop_ip_mask ? 1 : 0;
47374fe6c29SRuslan Bukin 
47474fe6c29SRuslan Bukin 	return ptps_exstop;
47574fe6c29SRuslan Bukin }
47674fe6c29SRuslan Bukin 
pt_pkt_read_mwait(struct pt_packet_mwait * packet,const uint8_t * pos,const struct pt_config * config)47774fe6c29SRuslan Bukin int pt_pkt_read_mwait(struct pt_packet_mwait *packet, const uint8_t *pos,
47874fe6c29SRuslan Bukin 		      const struct pt_config *config)
47974fe6c29SRuslan Bukin {
48074fe6c29SRuslan Bukin 	if (!packet || !pos || !config)
48174fe6c29SRuslan Bukin 		return -pte_internal;
48274fe6c29SRuslan Bukin 
48374fe6c29SRuslan Bukin 	if (config->end < pos + ptps_mwait)
48474fe6c29SRuslan Bukin 		return -pte_eos;
48574fe6c29SRuslan Bukin 
48674fe6c29SRuslan Bukin 	packet->hints = (uint32_t) pt_pkt_read_value(pos + pt_opcs_mwait,
48774fe6c29SRuslan Bukin 						     pt_pl_mwait_hints_size);
48874fe6c29SRuslan Bukin 	packet->ext = (uint32_t) pt_pkt_read_value(pos + pt_opcs_mwait +
48974fe6c29SRuslan Bukin 						   pt_pl_mwait_hints_size,
49074fe6c29SRuslan Bukin 						   pt_pl_mwait_ext_size);
49174fe6c29SRuslan Bukin 	return ptps_mwait;
49274fe6c29SRuslan Bukin }
49374fe6c29SRuslan Bukin 
pt_pkt_read_pwre(struct pt_packet_pwre * packet,const uint8_t * pos,const struct pt_config * config)49474fe6c29SRuslan Bukin int pt_pkt_read_pwre(struct pt_packet_pwre *packet, const uint8_t *pos,
49574fe6c29SRuslan Bukin 		     const struct pt_config *config)
49674fe6c29SRuslan Bukin {
49774fe6c29SRuslan Bukin 	uint64_t payload;
49874fe6c29SRuslan Bukin 
49974fe6c29SRuslan Bukin 	if (!packet || !pos || !config)
50074fe6c29SRuslan Bukin 		return -pte_internal;
50174fe6c29SRuslan Bukin 
50274fe6c29SRuslan Bukin 	if (config->end < pos + ptps_pwre)
50374fe6c29SRuslan Bukin 		return -pte_eos;
50474fe6c29SRuslan Bukin 
50574fe6c29SRuslan Bukin 	payload = pt_pkt_read_value(pos + pt_opcs_pwre, pt_pl_pwre_size);
50674fe6c29SRuslan Bukin 
50774fe6c29SRuslan Bukin 	memset(packet, 0, sizeof(*packet));
50874fe6c29SRuslan Bukin 	packet->state = (uint8_t) ((payload & pt_pl_pwre_state_mask) >>
50974fe6c29SRuslan Bukin 				   pt_pl_pwre_state_shr);
51074fe6c29SRuslan Bukin 	packet->sub_state = (uint8_t) ((payload & pt_pl_pwre_sub_state_mask) >>
51174fe6c29SRuslan Bukin 				       pt_pl_pwre_sub_state_shr);
51274fe6c29SRuslan Bukin 	if (payload & pt_pl_pwre_hw_mask)
51374fe6c29SRuslan Bukin 		packet->hw = 1;
51474fe6c29SRuslan Bukin 
51574fe6c29SRuslan Bukin 	return ptps_pwre;
51674fe6c29SRuslan Bukin }
51774fe6c29SRuslan Bukin 
pt_pkt_read_pwrx(struct pt_packet_pwrx * packet,const uint8_t * pos,const struct pt_config * config)51874fe6c29SRuslan Bukin int pt_pkt_read_pwrx(struct pt_packet_pwrx *packet, const uint8_t *pos,
51974fe6c29SRuslan Bukin 		     const struct pt_config *config)
52074fe6c29SRuslan Bukin {
52174fe6c29SRuslan Bukin 	uint64_t payload;
52274fe6c29SRuslan Bukin 
52374fe6c29SRuslan Bukin 	if (!packet || !pos || !config)
52474fe6c29SRuslan Bukin 		return -pte_internal;
52574fe6c29SRuslan Bukin 
52674fe6c29SRuslan Bukin 	if (config->end < pos + ptps_pwrx)
52774fe6c29SRuslan Bukin 		return -pte_eos;
52874fe6c29SRuslan Bukin 
52974fe6c29SRuslan Bukin 	payload = pt_pkt_read_value(pos + pt_opcs_pwrx, pt_pl_pwrx_size);
53074fe6c29SRuslan Bukin 
53174fe6c29SRuslan Bukin 	memset(packet, 0, sizeof(*packet));
53274fe6c29SRuslan Bukin 	packet->last = (uint8_t) ((payload & pt_pl_pwrx_last_mask) >>
53374fe6c29SRuslan Bukin 				  pt_pl_pwrx_last_shr);
53474fe6c29SRuslan Bukin 	packet->deepest = (uint8_t) ((payload & pt_pl_pwrx_deepest_mask) >>
53574fe6c29SRuslan Bukin 				     pt_pl_pwrx_deepest_shr);
53674fe6c29SRuslan Bukin 	if (payload & pt_pl_pwrx_wr_int)
53774fe6c29SRuslan Bukin 		packet->interrupt = 1;
53874fe6c29SRuslan Bukin 	if (payload & pt_pl_pwrx_wr_store)
53974fe6c29SRuslan Bukin 		packet->store = 1;
54074fe6c29SRuslan Bukin 	if (payload & pt_pl_pwrx_wr_hw)
54174fe6c29SRuslan Bukin 		packet->autonomous = 1;
54274fe6c29SRuslan Bukin 
54374fe6c29SRuslan Bukin 	return ptps_pwrx;
54474fe6c29SRuslan Bukin }
54574fe6c29SRuslan Bukin 
pt_pkt_read_ptw(struct pt_packet_ptw * packet,const uint8_t * pos,const struct pt_config * config)54674fe6c29SRuslan Bukin int pt_pkt_read_ptw(struct pt_packet_ptw *packet, const uint8_t *pos,
54774fe6c29SRuslan Bukin 		    const struct pt_config *config)
54874fe6c29SRuslan Bukin {
54974fe6c29SRuslan Bukin 	uint8_t opc, plc;
55074fe6c29SRuslan Bukin 	int size;
55174fe6c29SRuslan Bukin 
55274fe6c29SRuslan Bukin 	if (!packet || !pos || !config)
55374fe6c29SRuslan Bukin 		return -pte_internal;
55474fe6c29SRuslan Bukin 
55574fe6c29SRuslan Bukin 	/* Skip the ext opcode. */
55674fe6c29SRuslan Bukin 	pos++;
55774fe6c29SRuslan Bukin 
55874fe6c29SRuslan Bukin 	opc = *pos++;
55974fe6c29SRuslan Bukin 	plc = (opc >> pt_opm_ptw_pb_shr) & pt_opm_ptw_pb_shr_mask;
56074fe6c29SRuslan Bukin 
56174fe6c29SRuslan Bukin 	size = pt_ptw_size(plc);
56274fe6c29SRuslan Bukin 	if (size < 0)
56374fe6c29SRuslan Bukin 		return size;
56474fe6c29SRuslan Bukin 
56574fe6c29SRuslan Bukin 	if (config->end < pos + size)
56674fe6c29SRuslan Bukin 		return -pte_eos;
56774fe6c29SRuslan Bukin 
56874fe6c29SRuslan Bukin 	packet->payload = pt_pkt_read_value(pos, size);
56974fe6c29SRuslan Bukin 	packet->plc = plc;
57074fe6c29SRuslan Bukin 	packet->ip = opc & pt_opm_ptw_ip ? 1 : 0;
57174fe6c29SRuslan Bukin 
57274fe6c29SRuslan Bukin 	return pt_opcs_ptw + size;
57374fe6c29SRuslan Bukin }
574