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