]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/processor-trace/libipt/src/pt_time.c
Upgrade to Bzip2 version 1.0.7.
[FreeBSD/FreeBSD.git] / contrib / processor-trace / libipt / src / pt_time.c
1 /*
2  * Copyright (c) 2014-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_time.h"
30 #include "pt_opcodes.h"
31
32 #include "intel-pt.h"
33
34 #include <string.h>
35 #include <limits.h>
36
37
38 void pt_time_init(struct pt_time *time)
39 {
40         if (!time)
41                 return;
42
43         memset(time, 0, sizeof(*time));
44 }
45
46 int pt_time_query_tsc(uint64_t *tsc, uint32_t *lost_mtc,
47                       uint32_t *lost_cyc, const struct pt_time *time)
48 {
49         if (!tsc || !time)
50                 return -pte_internal;
51
52         *tsc = time->tsc;
53
54         if (lost_mtc)
55                 *lost_mtc = time->lost_mtc;
56         if (lost_cyc)
57                 *lost_cyc = time->lost_cyc;
58
59         if (!time->have_tsc)
60                 return -pte_no_time;
61
62         return 0;
63 }
64
65 int pt_time_query_cbr(uint32_t *cbr, const struct pt_time *time)
66 {
67         if (!cbr || !time)
68                 return -pte_internal;
69
70         if (!time->have_cbr)
71                 return -pte_no_cbr;
72
73         *cbr = time->cbr;
74
75         return 0;
76 }
77
78 /* Compute the distance between two CTC sources.
79  *
80  * We adjust a single wrap-around but fail if the distance is bigger than that.
81  *
82  * Returns zero on success, a negative error code otherwise.
83  */
84 static int pt_time_ctc_delta(uint32_t *ctc_delta, uint32_t ctc,
85                              uint32_t last_ctc, const struct pt_config *config)
86 {
87         if (!config || !ctc_delta)
88                 return -pte_internal;
89
90         /* Correct a single wrap-around.  If we lost enough MTCs to wrap
91          * around twice, timing will be wrong until the next TSC.
92          */
93         if (ctc < last_ctc) {
94                 ctc += 1u << (config->mtc_freq + pt_pl_mtc_bit_size);
95
96                 /* Since we only store the CTC between TMA/MTC or MTC/TMC a
97                  * single correction should suffice.
98                  */
99                 if (ctc < last_ctc)
100                         return -pte_bad_packet;
101         }
102
103         *ctc_delta = ctc - last_ctc;
104         return 0;
105 }
106
107 /* Translate CTC into the same unit as the FastCounter by multiplying with P.
108  *
109  * Returns zero on success, a negative error code otherwise.
110  */
111 static int pt_time_ctc_fc(uint64_t *fc, uint64_t ctc,
112                           const struct pt_config *config)
113 {
114         uint32_t eax, ebx;
115
116         if (!fc || !config)
117                 return -pte_internal;
118
119         eax = config->cpuid_0x15_eax;
120         ebx = config->cpuid_0x15_ebx;
121
122         /* Neither multiply nor divide by zero. */
123         if (!eax || !ebx)
124                 return -pte_bad_config;
125
126         *fc = (ctc * ebx) / eax;
127         return 0;
128 }
129
130 int pt_time_update_tsc(struct pt_time *time,
131                        const struct pt_packet_tsc *packet,
132                        const struct pt_config *config)
133 {
134         (void) config;
135
136         if (!time || !packet)
137                 return -pte_internal;
138
139         time->have_tsc = 1;
140         time->have_tma = 0;
141         time->have_mtc = 0;
142         time->tsc = time->base = packet->tsc;
143         time->ctc = 0;
144         time->fc = 0ull;
145
146         /* We got the full time; we recover from previous losses. */
147         time->lost_mtc = 0;
148         time->lost_cyc = 0;
149
150         return 0;
151 }
152
153 int pt_time_update_cbr(struct pt_time *time,
154                        const struct pt_packet_cbr *packet,
155                        const struct pt_config *config)
156 {
157         (void) config;
158
159         if (!time || !packet)
160                 return -pte_internal;
161
162         time->have_cbr = 1;
163         time->cbr = packet->ratio;
164
165         return 0;
166 }
167
168 int pt_time_update_tma(struct pt_time *time,
169                        const struct pt_packet_tma *packet,
170                        const struct pt_config *config)
171 {
172         uint32_t ctc, mtc_freq, mtc_hi, ctc_mask;
173         uint64_t fc;
174
175         if (!time || !packet || !config)
176                 return -pte_internal;
177
178         /* Without a TSC something is seriously wrong. */
179         if (!time->have_tsc)
180                 return -pte_bad_context;
181
182         /* We shouldn't have more than one TMA per TSC. */
183         if (time->have_tma)
184                 return -pte_bad_context;
185
186         /* We're ignoring MTC between TSC and TMA. */
187         if (time->have_mtc)
188                 return -pte_internal;
189
190         ctc = packet->ctc;
191         fc = packet->fc;
192
193         mtc_freq = config->mtc_freq;
194         mtc_hi = mtc_freq + pt_pl_mtc_bit_size;
195
196         /* A mask for the relevant CTC bits ignoring high-order bits that are
197          * not provided by MTC.
198          */
199         ctc_mask = (1u << mtc_hi) - 1u;
200
201         time->have_tma = 1;
202         time->base -= fc;
203         time->fc += fc;
204
205         /* If the MTC frequency is low enough that TMA provides the full CTC
206          * value, we can use the TMA as an MTC.
207          *
208          * If it isn't, we will estimate the preceding MTC based on the CTC bits
209          * the TMA provides at the next MTC.  We forget about the previous MTC
210          * in this case.
211          *
212          * If no MTC packets are dropped around TMA, we will estimate the
213          * forgotten value again at the next MTC.
214          *
215          * If MTC packets are dropped, we can't really tell where in this
216          * extended MTC period the TSC occurred.  The estimation will place it
217          * right before the next MTC.
218          */
219         if (mtc_hi <= pt_pl_tma_ctc_bit_size)
220                 time->have_mtc = 1;
221
222         /* In both cases, we store the TMA's CTC bits until the next MTC. */
223         time->ctc = time->ctc_cyc = ctc & ctc_mask;
224
225         return 0;
226 }
227
228 int pt_time_update_mtc(struct pt_time *time,
229                        const struct pt_packet_mtc *packet,
230                        const struct pt_config *config)
231 {
232         uint32_t last_ctc, ctc, ctc_delta;
233         uint64_t tsc, base;
234         uint8_t mtc_freq;
235         int errcode, have_tsc, have_tma, have_mtc;
236
237         if (!time || !packet || !config)
238                 return -pte_internal;
239
240         have_tsc = time->have_tsc;
241         have_tma = time->have_tma;
242         have_mtc = time->have_mtc;
243
244         /* We ignore MTCs between TSC and TMA to avoid apparent CTC overflows.
245          *
246          * Later MTCs will ensure that no time is lost - provided TMA provides
247          * enough bits.  If TMA doesn't provide any of the MTC bits we may place
248          * the TSC into the wrong MTC period.
249          */
250         if (have_tsc && !have_tma)
251                 return 0;
252
253         base = time->base;
254         last_ctc = time->ctc;
255         mtc_freq = config->mtc_freq;
256
257         ctc = packet->ctc << mtc_freq;
258
259         /* Store our CTC value if we have or would have reset FC. */
260         if (time->fc || time->lost_cyc || !have_mtc)
261                 time->ctc_cyc = ctc;
262
263         /* Prepare for the next packet in case we error out below. */
264         time->have_mtc = 1;
265         time->fc = 0ull;
266         time->ctc = ctc;
267
268         /* We recover from previous CYC losses. */
269         time->lost_cyc = 0;
270
271         /* Avoid a big jump when we see the first MTC with an arbitrary CTC
272          * payload.
273          */
274         if (!have_mtc) {
275                 uint32_t ctc_lo, ctc_hi;
276
277                 /* If we have not seen a TMA, we ignore this first MTC.
278                  *
279                  * We have no idea where in this MTC period tracing started.
280                  * We could lose an entire MTC period or just a tiny fraction.
281                  *
282                  * On the other hand, if we assumed a previous MTC value, we
283                  * might make just the same error.
284                  */
285                 if (!have_tma)
286                         return 0;
287
288                 /* The TMA's CTC value didn't provide enough bits - otherwise,
289                  * we would have treated the TMA as an MTC.
290                  */
291                 if (last_ctc & ~pt_pl_tma_ctc_mask)
292                         return -pte_internal;
293
294                 /* Split this MTC's CTC value into low and high parts with
295                  * respect to the bits provided by TMA.
296                  */
297                 ctc_lo = ctc & pt_pl_tma_ctc_mask;
298                 ctc_hi = ctc & ~pt_pl_tma_ctc_mask;
299
300                 /* We estimate the high-order CTC bits that are not provided by
301                  * TMA based on the CTC bits provided by this MTC.
302                  *
303                  * We assume that no MTC packets were dropped around TMA.  If
304                  * there are, we might place the TSC into the wrong MTC period
305                  * depending on how many CTC bits TMA provides and how many MTC
306                  * packets were dropped.
307                  *
308                  * Note that we may underflow which results in more bits to be
309                  * set than MTC packets may provide.  Drop those extra bits.
310                  */
311                 if (ctc_lo < last_ctc) {
312                         ctc_hi -= 1u << pt_pl_tma_ctc_bit_size;
313                         ctc_hi &= pt_pl_mtc_mask << mtc_freq;
314                 }
315
316                 last_ctc |= ctc_hi;
317         }
318
319         errcode = pt_time_ctc_delta(&ctc_delta, ctc, last_ctc, config);
320         if (errcode < 0) {
321                 time->lost_mtc += 1;
322                 return errcode;
323         }
324
325         errcode = pt_time_ctc_fc(&tsc, ctc_delta, config);
326         if (errcode < 0)
327                 return errcode;
328
329         base += tsc;
330         time->tsc = time->base = base;
331
332         return 0;
333 }
334
335 /* Adjust a CYC packet's payload spanning multiple MTC periods.
336  *
337  * CYC packets measure the Fast Counter since the last CYC(-eligible) packet.
338  * Depending on the CYC threshold, we may not get a CYC for each MTC, so a CYC
339  * period may overlap with or even span multiple MTC periods.
340  *
341  * We can't do much about the overlap case without examining all packets in
342  * the respective periods.  We leave this as expected imprecision.
343  *
344  * If we find a CYC packet to span multiple MTC packets, though, we try to
345  * approximate the portion for the current MTC period by subtracting the
346  * estimated portion for previous MTC periods using calibration information.
347  *
348  * We only consider MTC.  For the first CYC after TSC, the corresponding TMA
349  * will contain the Fast Counter at TSC.
350  *
351  * Returns zero on success, a negative error code otherwise.
352  */
353 static int pt_time_adjust_cyc(uint64_t *cyc, const struct pt_time *time,
354                               const struct pt_config *config, uint64_t fcr)
355 {
356         uint32_t last_ctc, ctc, ctc_delta;
357         uint64_t fc, total_cyc, old_cyc;
358         int errcode;
359
360         if (!time || !config || !fcr)
361                 return -pte_internal;
362
363         last_ctc = time->ctc_cyc;
364         ctc = time->ctc;
365
366         /* There is nothing to do if this is the current MTC period. */
367         if (ctc == last_ctc)
368                 return 0;
369
370         /* Calibration computes
371          *
372          *   fc  = (ctc_delta * cpuid[0x15].ebx) / cpuid[0x15].eax.
373          *   fcr = (fc << pt_tcal_fcr_shr) / cyc
374          *
375          * So cyc = (fc << pt_tcal_fcr_shr) / fcr.
376          */
377
378         errcode = pt_time_ctc_delta(&ctc_delta, ctc, last_ctc, config);
379         if (errcode < 0)
380                 return errcode;
381
382         errcode = pt_time_ctc_fc(&fc, ctc_delta, config);
383         if (errcode < 0)
384                 return errcode;
385
386         old_cyc = (fc << pt_tcal_fcr_shr) / fcr;
387         total_cyc = *cyc;
388
389         /* Make sure we don't wrap around.  If we would, attribute the entire
390          * CYC payload to any previous MTC period.
391          *
392          * We lost an unknown portion of the CYC payload for the current MTC
393          * period, but it's usually better to run too slow than too fast.
394          */
395         if (total_cyc < old_cyc)
396                 total_cyc = old_cyc;
397
398         *cyc = total_cyc - old_cyc;
399         return 0;
400 }
401
402 int pt_time_update_cyc(struct pt_time *time,
403                        const struct pt_packet_cyc *packet,
404                        const struct pt_config *config, uint64_t fcr)
405 {
406         uint64_t cyc, fc;
407
408         if (!time || !packet || !config)
409                 return -pte_internal;
410
411         if (!fcr) {
412                 time->lost_cyc += 1;
413                 return 0;
414         }
415
416         cyc = packet->value;
417         fc = time->fc;
418         if (!fc) {
419                 int errcode;
420
421                 errcode = pt_time_adjust_cyc(&cyc, time, config, fcr);
422                 if (errcode < 0)
423                         return errcode;
424         }
425
426         fc += (cyc * fcr) >> pt_tcal_fcr_shr;
427
428         time->fc = fc;
429         time->tsc = time->base + fc;
430
431         return 0;
432 }
433
434 void pt_tcal_init(struct pt_time_cal *tcal)
435 {
436         if (!tcal)
437                 return;
438
439         memset(tcal, 0, sizeof(*tcal));
440
441         tcal->min_fcr = UINT64_MAX;
442 }
443
444 static int pt_tcal_have_fcr(const struct pt_time_cal *tcal)
445 {
446         if (!tcal)
447                 return 0;
448
449         return (tcal->min_fcr <= tcal->max_fcr);
450 }
451
452 int pt_tcal_fcr(uint64_t *fcr, const struct pt_time_cal *tcal)
453 {
454         if (!fcr || !tcal)
455                 return -pte_internal;
456
457         if (!pt_tcal_have_fcr(tcal))
458                 return -pte_no_time;
459
460         *fcr = tcal->fcr;
461
462         return 0;
463 }
464
465 int pt_tcal_set_fcr(struct pt_time_cal *tcal, uint64_t fcr)
466 {
467         if (!tcal)
468                 return -pte_internal;
469
470         tcal->fcr = fcr;
471
472         if (fcr < tcal->min_fcr)
473                 tcal->min_fcr = fcr;
474
475         if (fcr > tcal->max_fcr)
476                 tcal->max_fcr = fcr;
477
478         return 0;
479 }
480
481 int pt_tcal_update_tsc(struct pt_time_cal *tcal,
482                       const struct pt_packet_tsc *packet,
483                       const struct pt_config *config)
484 {
485         (void) config;
486
487         if (!tcal || !packet)
488                 return -pte_internal;
489
490         /* A TSC outside of PSB+ may indicate loss of time.  We do not use it
491          * for calibration.  We store the TSC value for calibration at the next
492          * TSC in PSB+, though.
493          */
494         tcal->tsc = packet->tsc;
495         tcal->cyc_tsc = 0ull;
496
497         return 0;
498 }
499
500 int pt_tcal_header_tsc(struct pt_time_cal *tcal,
501                       const struct pt_packet_tsc *packet,
502                       const struct pt_config *config)
503 {
504         uint64_t tsc, last_tsc, tsc_delta, cyc, fcr;
505
506         (void) config;
507
508         if (!tcal || !packet)
509                 return -pte_internal;
510
511         last_tsc = tcal->tsc;
512         cyc = tcal->cyc_tsc;
513
514         tsc = packet->tsc;
515
516         tcal->tsc = tsc;
517         tcal->cyc_tsc = 0ull;
518
519         if (!last_tsc || !cyc)
520                 return 0;
521
522         /* Correct a single wrap-around. */
523         if (tsc < last_tsc) {
524                 tsc += 1ull << pt_pl_tsc_bit_size;
525
526                 if (tsc < last_tsc)
527                         return -pte_bad_packet;
528         }
529
530         tsc_delta = tsc - last_tsc;
531
532         /* We shift the nominator to improve rounding precision.
533          *
534          * Since we're only collecting the CYCs between two TSC, we shouldn't
535          * overflow.  Let's rather fail than overflow.
536          */
537         if (tsc_delta & ~(~0ull >> pt_tcal_fcr_shr))
538                 return -pte_internal;
539
540         fcr = (tsc_delta << pt_tcal_fcr_shr) / cyc;
541
542         return pt_tcal_set_fcr(tcal, fcr);
543 }
544
545 int pt_tcal_update_cbr(struct pt_time_cal *tcal,
546                       const struct pt_packet_cbr *packet,
547                       const struct pt_config *config)
548 {
549         /* A CBR outside of PSB+ indicates a frequency change.  Reset our
550          * calibration state.
551          */
552         pt_tcal_init(tcal);
553
554         return pt_tcal_header_cbr(tcal, packet, config);
555 }
556
557 int pt_tcal_header_cbr(struct pt_time_cal *tcal,
558                       const struct pt_packet_cbr *packet,
559                       const struct pt_config *config)
560 {
561         uint64_t cbr, p1, fcr;
562
563         if (!tcal || !packet || !config)
564                 return -pte_internal;
565
566         p1 = config->nom_freq;
567         if (!p1)
568                 return 0;
569
570         /* If we know the nominal frequency, we can use it for calibration. */
571         cbr = packet->ratio;
572
573         fcr = (p1 << pt_tcal_fcr_shr) / cbr;
574
575         return pt_tcal_set_fcr(tcal, fcr);
576 }
577
578 int pt_tcal_update_tma(struct pt_time_cal *tcal,
579                       const struct pt_packet_tma *packet,
580                       const struct pt_config *config)
581 {
582         (void) tcal;
583         (void) packet;
584         (void) config;
585
586         /* Nothing to do. */
587         return 0;
588 }
589
590 int pt_tcal_update_mtc(struct pt_time_cal *tcal,
591                       const struct pt_packet_mtc *packet,
592                       const struct pt_config *config)
593 {
594         uint32_t last_ctc, ctc, ctc_delta, have_mtc;
595         uint64_t cyc, fc, fcr;
596         int errcode;
597
598         if (!tcal || !packet || !config)
599                 return -pte_internal;
600
601         last_ctc = tcal->ctc;
602         have_mtc = tcal->have_mtc;
603         cyc = tcal->cyc_mtc;
604
605         ctc = packet->ctc << config->mtc_freq;
606
607         /* We need at least two MTC (including this). */
608         if (!have_mtc) {
609                 tcal->cyc_mtc = 0ull;
610                 tcal->ctc = ctc;
611                 tcal->have_mtc = 1;
612
613                 return 0;
614         }
615
616         /* Without any cycles, we can't calibrate.  Try again at the next
617          * MTC and distribute the cycles over the combined MTC period.
618          */
619         if (!cyc)
620                 return 0;
621
622         /* Prepare for the next packet in case we error out below. */
623         tcal->have_mtc = 1;
624         tcal->cyc_mtc = 0ull;
625         tcal->ctc = ctc;
626
627         /* Let's pretend we will fail.  We'll correct it at the end. */
628         tcal->lost_mtc += 1;
629
630         errcode = pt_time_ctc_delta(&ctc_delta, ctc, last_ctc, config);
631         if (errcode < 0)
632                 return errcode;
633
634         errcode = pt_time_ctc_fc(&fc, ctc_delta, config);
635         if (errcode < 0)
636                 return errcode;
637
638         /* We shift the nominator to improve rounding precision.
639          *
640          * Since we're only collecting the CYCs between two MTC, we shouldn't
641          * overflow.  Let's rather fail than overflow.
642          */
643         if (fc & ~(~0ull >> pt_tcal_fcr_shr))
644                 return -pte_internal;
645
646         fcr = (fc << pt_tcal_fcr_shr) / cyc;
647
648         errcode = pt_tcal_set_fcr(tcal, fcr);
649         if (errcode < 0)
650                 return errcode;
651
652         /* We updated the FCR.  This recovers from previous MTC losses. */
653         tcal->lost_mtc = 0;
654
655         return 0;
656 }
657
658 int pt_tcal_update_cyc(struct pt_time_cal *tcal,
659                       const struct pt_packet_cyc *packet,
660                       const struct pt_config *config)
661 {
662         uint64_t cyc;
663
664         (void) config;
665
666         if (!tcal || !packet)
667                 return -pte_internal;
668
669         cyc = packet->value;
670         tcal->cyc_mtc += cyc;
671         tcal->cyc_tsc += cyc;
672
673         return 0;
674 }