]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/processor-trace/libipt/src/pt_packet.c
Import Intel Processor Trace decoder library from
[FreeBSD/FreeBSD.git] / contrib / processor-trace / libipt / src / pt_packet.c
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_packet.h"
30 #include "pt_opcodes.h"
31
32 #include "intel-pt.h"
33
34 #include <limits.h>
35
36
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }