// 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 <cpuid.h>
#include "../../perf.h"
#include "../../util/session.h"
#include "../../util/event.h"
#include "../../util/evlist.h"
#include "../../util/evsel.h"
#include "../../util/cpumap.h"
#include <subcmd/parse-options.h>
#include "../../util/parse-events.h"
#include "../../util/pmu.h"
#include "../../util/debug.h"
#include "../../util/auxtrace.h"
#include "../../util/tsc.h"
#include "../../util/intel-pt.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 perf_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(struct list_head *formats,
const char *str,
u64 *config)
{
struct list_head *terms;
struct perf_event_attr attr = { .size = 0, };
int err;
terms = malloc(sizeof(struct list_head));
if (!terms)
return -ENOMEM;
INIT_LIST_HEAD(terms);
err = parse_events_terms(terms, str);
if (err)
goto out_free;
attr.config = *config;
err = perf_pmu__config_terms(formats, &attr, terms, true, NULL);
if (err)
goto out_free;
*config = attr.config;
out_free:
parse_events_terms__delete(terms);
return err;
}
static int intel_pt_parse_terms(struct list_head *formats, const char *str,
u64 *config)
{
*config = 0;
return intel_pt_parse_terms_with_default(formats, 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 perf_evlist *evlist, u64 *res)
{
struct perf_evsel *evsel;
u64 mask;
*res = 0;
mask = perf_pmu__format_bits(&intel_pt_pmu->format, str);
if (!mask)
return -EINVAL;
evlist__for_each_entry(evlist, evsel) {
if (evsel->attr.type == intel_pt_pmu->type) {
*res = intel_pt_masked_bits(mask, evsel->attr.config);
return 0;
}
}
return -EINVAL