// SPDX-License-Identifier: GPL-2.0-only
/*
* intel_pt.c: Intel Processor Trace support
* Copyright (c) 2013-2015, Intel Corporation.
*/
#include <errno.h>
#include <stdbool.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/log2.h>
#include <linux/zalloc.h>
#include <linux/err.h>
#include <cpuid.h>
#include "../../../util/session.h"
#include "../../../util/event.h"
#include "../../../util/evlist.h"
#include "../../../util/evsel.h"
#include "../../../util/evsel_config.h"
#include "../../../util/cpumap.h"
#include "../../../util/mmap.h"
#include <subcmd/parse-options.h>
#include "../../../util/parse-events.h"
#include "../../../util/pmus.h"
#include "../../../util/debug.h"
#include "../../../util/auxtrace.h"
#include "../../../util/perf_api_probe.h"
#include "../../../util/record.h"
#include "../../../util/target.h"
#include "../../../util/tsc.h"
#include <internal/lib.h> // page_size
#include "../../../util/intel-pt.h"
#include <api/fs/fs.h>
#define KiB(x) ((x) * 1024)
#define MiB(x) ((x) * 1024 * 1024)
#define KiB_MASK(x) (KiB(x) - 1)
#define MiB_MASK(x) (MiB(x) - 1)
#define INTEL_PT_PSB_PERIOD_NEAR 256
struct intel_pt_snapshot_ref {
void *ref_buf;
size_t ref_offset;
bool wrapped;
};
struct intel_pt_recording {
struct auxtrace_record itr;
struct perf_pmu *intel_pt_pmu;
int have_sched_switch;
struct evlist *evlist;
bool snapshot_mode;
bool snapshot_init_done;
size_t snapshot_size;
size_t snapshot_ref_buf_size;
int snapshot_ref_cnt;
struct intel_pt_snapshot_ref *snapshot_refs;
size_t priv_size;
};
static int intel_pt_parse_terms_with_default(const struct perf_pmu *pmu,
const char *str,
u64 *config)
{
struct parse_events_terms terms;
struct perf_event_attr attr = { .size = 0, };
int err;
parse_events_terms__init(&terms);
err = parse_events_terms(&terms, str, /*input=*/ NULL);
if (err)
goto out_free;
attr.config = *config;
err = perf_pmu__config_terms(pmu, &attr, &terms, /*zero=*/true, /*err=*/NULL);
if (err)
goto out_free;
*config = attr.config;
out_free:
parse_events_terms__exit(&terms);
return err;
}
static int intel_pt_parse_terms(const struct perf_pmu *pmu, const char *str, u64 *config)
{
*config = 0;
return intel_pt_parse_terms_with_default(pmu, str, config);
}
static u64 intel_pt_masked_bits(u64 mask, u64 bits)
{
const u64 top_bit = 1ULL << 63;
u64 res = 0;
int i;
for (i = 0; i < 64; i++) {
if (mask & top_bit) {
res <<= 1;
if (bits & top_bit)
res |= 1;
}
mask <<= 1;
bits <<= 1;
}
return res;
}
static int intel_pt_read_config(struct perf_pmu *intel_pt_pmu, const char *str,
struct evlist *evlist, u64 *res)
{
struct evsel *evsel;
u64 mask;
*res = 0;
mask = perf_pmu__format_bits(intel_pt_pmu, str);
if (!mask)
return -EINVAL;
evlist__for_each_entry(evlist, evsel) {
if (evsel->core.attr.type == intel_pt_pmu->type) {
*res = intel_pt_masked_bits(mask, evsel->core.attr.config);
return 0;
}
}
return -EINVAL;
}
static size_t intel_pt_psb_period(struct perf_pmu *intel_pt_pmu,
struct evlist *evlist)
{
u64