blob: faf01753d409844d57eaac7ab1df45619864410e [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include "x86_pt.h"
#include <cpuid.h>
#include <atomic>
#include <mutex>
#include "x86_cpuid.h"
namespace debugger_utils {
/* Trick to get a 1 of the right size */
#define ONE(x) (1 + ((x) - (x)))
#define BIT(x, bit) ((x) & (ONE(x) << (bit)))
#define BITS_SHIFT(x, high, low) (((x) >> (low)) & ((ONE(x) << ((high) - (low) + 1)) - 1))
static X86ProcessorTraceFeatures pt_features; // TODO(dje): guard annotation
static bool initialized = false; // TODO(dje): guard annotation
static std::mutex cpuid_mutex;
bool X86HaveProcessorTrace() {
const X86ProcessorTraceFeatures* ptf = X86GetProcessorTraceFeatures();
return ptf->have_pt;
}
const X86ProcessorTraceFeatures* X86GetProcessorTraceFeatures() {
std::lock_guard<std::mutex> lock(cpuid_mutex);
X86ProcessorTraceFeatures* pt = &pt_features;
if (initialized)
return pt;
memset(pt, 0, sizeof(*pt));
initialized = true;
if (!x86_feature_test(X86_FEATURE_PT))
return pt;
unsigned a, b, c, d;
unsigned max_leaf = __get_cpuid_max(0, nullptr);
pt->have_pt = true;
__cpuid_count(0x14, 0, a, b, c, d);
if (BIT(b, 2))
pt->addr_cfg_max = 2;
if (BIT(b, 1) && a >= 1) {
unsigned a1, b1, c1, d1;
__cpuid_count(0x14, 1, a1, b1, c1, d1);
pt->mtc_freq_mask = (a1 >> 16) & 0xffff;
pt->cycle_thresh_mask = b1 & 0xffff;
pt->psb_freq_mask = (b1 >> 16) & 0xffff;
pt->num_addr_ranges = a1 & 0x3;
}
pt->cr3_filtering = !!BIT(b, 0);
pt->cycle_accurate_mode = !!BIT(b, 1);
pt->ip_filtering = !!BIT(b, 2);
pt->mtc = !!BIT(b, 3);
pt->ptwrite = !!BIT(b, 4);
pt->power_events = !!BIT(b, 5);
pt->supports_filter_ranges = pt->addr_cfg_max >= 1;
pt->supports_stop_ranges = pt->addr_cfg_max >= 2;
pt->to_pa = !!BIT(c, 0);
pt->multiple_to_pa_entries = !!BIT(c, 1);
pt->single_range = !!BIT(c, 2);
pt->trace_transport_output = !!BIT(c, 3);
pt->payloads_are_lip = !!BIT(c, 31);
if (max_leaf >= 0x15) {
unsigned a1 = 0, b1 = 0, c1 = 0, d1 = 0;
__cpuid(0x15, a1, b1, c1, d1);
pt->tsc_ratio_den = a1;
pt->tsc_ratio_num = b1;
}
return pt;
}
} // namespace debugger_utils