From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit f9f16dfbe76e category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
The perf tool searches a memory event name under the folder '/sys/devices/cpu/events/', this leads to the limitation for the selection of a memory profiling event which must be under this folder.
Thus it's impossible to use any other event as memory event which is not under this specific folder, e.g. Arm SPE hardware event is not located in '/sys/devices/cpu/events/' so it cannot be enabled for memory profiling.
This patch changes to search folder from '/sys/devices/cpu/events/' to '/sys/devices', so it give flexibility to find events which can be used for memory profiling.
Signed-off-by: Leo Yan leo.yan@linaro.org Acked-by: Jiri Olsa jolsa@redhat.com Link: https://lore.kernel.org/r/20201106094853.21082-2-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/mem-events.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/tools/perf/util/mem-events.c b/tools/perf/util/mem-events.c index ea0af0bc4314..35c8d175a9d2 100644 --- a/tools/perf/util/mem-events.c +++ b/tools/perf/util/mem-events.c @@ -18,8 +18,8 @@ unsigned int perf_mem_events__loads_ldlat = 30; #define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = { - E("ldlat-loads", "cpu/mem-loads,ldlat=%u/P", "mem-loads"), - E("ldlat-stores", "cpu/mem-stores/P", "mem-stores"), + E("ldlat-loads", "cpu/mem-loads,ldlat=%u/P", "cpu/events/mem-loads"), + E("ldlat-stores", "cpu/mem-stores/P", "cpu/events/mem-stores"), }; #undef E
@@ -93,7 +93,7 @@ int perf_mem_events__init(void) struct perf_mem_event *e = &perf_mem_events[j]; struct stat st;
- scnprintf(path, PATH_MAX, "%s/devices/cpu/events/%s", + scnprintf(path, PATH_MAX, "%s/devices/%s", mnt, e->sysfs_name);
if (!stat(path, &st))
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit eaf6aaeec5fa category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
Different architectures might use different event or different event parameters for memory profiling, this patch introduces a weak perf_mem_events__ptr() function which allows to return back a architecture specific memory event.
Since the variable 'perf_mem_events' can be only accessed by the perf_mem_events__ptr() function, mark the variable as 'static', this allows the architectures to define its own memory event array.
Signed-off-by: Leo Yan leo.yan@linaro.org Acked-by: Jiri Olsa jolsa@redhat.com Link: https://lore.kernel.org/r/20201106094853.21082-3-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/builtin-c2c.c | 18 ++++++++++++------ tools/perf/builtin-mem.c | 21 ++++++++++++++------- tools/perf/util/mem-events.c | 26 +++++++++++++++++++------- tools/perf/util/mem-events.h | 2 +- 4 files changed, 46 insertions(+), 21 deletions(-)
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index d5bea5d3cd51..4d1a08e38233 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -2867,6 +2867,7 @@ static int perf_c2c__record(int argc, const char **argv) int ret; bool all_user = false, all_kernel = false; bool event_set = false; + struct perf_mem_event *e; struct option options[] = { OPT_CALLBACK('e', "event", &event_set, "event", "event selector. Use 'perf c2c record -e list' to list available events", @@ -2894,11 +2895,15 @@ static int perf_c2c__record(int argc, const char **argv) rec_argv[i++] = "record";
if (!event_set) { - perf_mem_events[PERF_MEM_EVENTS__LOAD].record = true; - perf_mem_events[PERF_MEM_EVENTS__STORE].record = true; + e = perf_mem_events__ptr(PERF_MEM_EVENTS__LOAD); + e->record = true; + + e = perf_mem_events__ptr(PERF_MEM_EVENTS__STORE); + e->record = true; }
- if (perf_mem_events[PERF_MEM_EVENTS__LOAD].record) + e = perf_mem_events__ptr(PERF_MEM_EVENTS__LOAD); + if (e->record) rec_argv[i++] = "-W";
rec_argv[i++] = "-d"; @@ -2906,12 +2911,13 @@ static int perf_c2c__record(int argc, const char **argv) rec_argv[i++] = "--sample-cpu";
for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) { - if (!perf_mem_events[j].record) + e = perf_mem_events__ptr(j); + if (!e->record) continue;
- if (!perf_mem_events[j].supported) { + if (!e->supported) { pr_err("failed: event '%s' not supported\n", - perf_mem_events[j].name); + perf_mem_events__name(j)); free(rec_argv); return -1; } diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index 3523279af6af..9a7df8d01296 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c @@ -64,6 +64,7 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem) const char **rec_argv; int ret; bool all_user = false, all_kernel = false; + struct perf_mem_event *e; struct option options[] = { OPT_CALLBACK('e', "event", &mem, "event", "event selector. use 'perf mem record -e list' to list available events", @@ -86,13 +87,18 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)
rec_argv[i++] = "record";
- if (mem->operation & MEM_OPERATION_LOAD) - perf_mem_events[PERF_MEM_EVENTS__LOAD].record = true; + if (mem->operation & MEM_OPERATION_LOAD) { + e = perf_mem_events__ptr(PERF_MEM_EVENTS__LOAD); + e->record = true; + }
- if (mem->operation & MEM_OPERATION_STORE) - perf_mem_events[PERF_MEM_EVENTS__STORE].record = true; + if (mem->operation & MEM_OPERATION_STORE) { + e = perf_mem_events__ptr(PERF_MEM_EVENTS__STORE); + e->record = true; + }
- if (perf_mem_events[PERF_MEM_EVENTS__LOAD].record) + e = perf_mem_events__ptr(PERF_MEM_EVENTS__LOAD); + if (e->record) rec_argv[i++] = "-W";
rec_argv[i++] = "-d"; @@ -101,10 +107,11 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem) rec_argv[i++] = "--phys-data";
for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) { - if (!perf_mem_events[j].record) + e = perf_mem_events__ptr(j); + if (!e->record) continue;
- if (!perf_mem_events[j].supported) { + if (!e->supported) { pr_err("failed: event '%s' not supported\n", perf_mem_events__name(j)); free(rec_argv); diff --git a/tools/perf/util/mem-events.c b/tools/perf/util/mem-events.c index 35c8d175a9d2..7a5a0d699e27 100644 --- a/tools/perf/util/mem-events.c +++ b/tools/perf/util/mem-events.c @@ -17,7 +17,7 @@ unsigned int perf_mem_events__loads_ldlat = 30;
#define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
-struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = { +static struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = { E("ldlat-loads", "cpu/mem-loads,ldlat=%u/P", "cpu/events/mem-loads"), E("ldlat-stores", "cpu/mem-stores/P", "cpu/events/mem-stores"), }; @@ -28,19 +28,31 @@ struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = { static char mem_loads_name[100]; static bool mem_loads_name__init;
+struct perf_mem_event * __weak perf_mem_events__ptr(int i) +{ + if (i >= PERF_MEM_EVENTS__MAX) + return NULL; + + return &perf_mem_events[i]; +} + char * __weak perf_mem_events__name(int i) { + struct perf_mem_event *e = perf_mem_events__ptr(i); + + if (!e) + return NULL; + if (i == PERF_MEM_EVENTS__LOAD) { if (!mem_loads_name__init) { mem_loads_name__init = true; scnprintf(mem_loads_name, sizeof(mem_loads_name), - perf_mem_events[i].name, - perf_mem_events__loads_ldlat); + e->name, perf_mem_events__loads_ldlat); } return mem_loads_name; }
- return (char *)perf_mem_events[i].name; + return (char *)e->name; }
int perf_mem_events__parse(const char *str) @@ -61,7 +73,7 @@ int perf_mem_events__parse(const char *str)
while (tok) { for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) { - struct perf_mem_event *e = &perf_mem_events[j]; + struct perf_mem_event *e = perf_mem_events__ptr(j);
if (strstr(e->tag, tok)) e->record = found = true; @@ -90,7 +102,7 @@ int perf_mem_events__init(void)
for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) { char path[PATH_MAX]; - struct perf_mem_event *e = &perf_mem_events[j]; + struct perf_mem_event *e = perf_mem_events__ptr(j); struct stat st;
scnprintf(path, PATH_MAX, "%s/devices/%s", @@ -108,7 +120,7 @@ void perf_mem_events__list(void) int j;
for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) { - struct perf_mem_event *e = &perf_mem_events[j]; + struct perf_mem_event *e = perf_mem_events__ptr(j);
fprintf(stderr, "%-13s%-*s%s\n", e->tag, diff --git a/tools/perf/util/mem-events.h b/tools/perf/util/mem-events.h index 904dad34f7f7..726a9c8103e4 100644 --- a/tools/perf/util/mem-events.h +++ b/tools/perf/util/mem-events.h @@ -31,13 +31,13 @@ enum { PERF_MEM_EVENTS__MAX, };
-extern struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX]; extern unsigned int perf_mem_events__loads_ldlat;
int perf_mem_events__parse(const char *str); int perf_mem_events__init(void);
char *perf_mem_events__name(int i); +struct perf_mem_event *perf_mem_events__ptr(int i);
void perf_mem_events__list(void);
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit 4ba2452cd88f category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
On the architectures with perf memory profiling, two types of hardware events have been supported: load and store; if want to profile memory for both load and store operations, the tool will use these two events at the same time, the usage is:
# perf mem record -t load,store -- uname
But this cannot be applied for AUX tracing event, the same PMU event can be used to only trace memory load, or only memory store, or trace for both memory load and store.
This patch introduces a new event PERF_MEM_EVENTS__LOAD_STORE, which is used to support the event which can record both memory load and store operations.
When user specifies memory operation type as 'load,store', or doesn't set type so use 'load,store' as default, if the arch supports the event PERF_MEM_EVENTS__LOAD_STORE, the tool will convert the required operations to this single event; otherwise, if the arch doesn't support PERF_MEM_EVENTS__LOAD_STORE, the tool rolls back to enable both events PERF_MEM_EVENTS__LOAD and PERF_MEM_EVENTS__STORE, which keeps the same behaviour with before.
Signed-off-by: Leo Yan leo.yan@linaro.org Acked-by: Jiri Olsa jolsa@redhat.com Link: https://lore.kernel.org/r/20201106094853.21082-4-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/builtin-mem.c | 24 ++++++++++++++++++------ tools/perf/util/mem-events.c | 13 ++++++++++++- tools/perf/util/mem-events.h | 1 + 3 files changed, 31 insertions(+), 7 deletions(-)
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index 9a7df8d01296..21ebe0f47e64 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c @@ -87,14 +87,26 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)
rec_argv[i++] = "record";
- if (mem->operation & MEM_OPERATION_LOAD) { - e = perf_mem_events__ptr(PERF_MEM_EVENTS__LOAD); - e->record = true; - } + e = perf_mem_events__ptr(PERF_MEM_EVENTS__LOAD_STORE);
- if (mem->operation & MEM_OPERATION_STORE) { - e = perf_mem_events__ptr(PERF_MEM_EVENTS__STORE); + /* + * The load and store operations are required, use the event + * PERF_MEM_EVENTS__LOAD_STORE if it is supported. + */ + if (e->tag && + (mem->operation & MEM_OPERATION_LOAD) && + (mem->operation & MEM_OPERATION_STORE)) { e->record = true; + } else { + if (mem->operation & MEM_OPERATION_LOAD) { + e = perf_mem_events__ptr(PERF_MEM_EVENTS__LOAD); + e->record = true; + } + + if (mem->operation & MEM_OPERATION_STORE) { + e = perf_mem_events__ptr(PERF_MEM_EVENTS__STORE); + e->record = true; + } }
e = perf_mem_events__ptr(PERF_MEM_EVENTS__LOAD); diff --git a/tools/perf/util/mem-events.c b/tools/perf/util/mem-events.c index 7a5a0d699e27..19007e463b8a 100644 --- a/tools/perf/util/mem-events.c +++ b/tools/perf/util/mem-events.c @@ -20,6 +20,7 @@ unsigned int perf_mem_events__loads_ldlat = 30; static struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = { E("ldlat-loads", "cpu/mem-loads,ldlat=%u/P", "cpu/events/mem-loads"), E("ldlat-stores", "cpu/mem-stores/P", "cpu/events/mem-stores"), + E(NULL, NULL, NULL), }; #undef E
@@ -75,6 +76,9 @@ int perf_mem_events__parse(const char *str) for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) { struct perf_mem_event *e = perf_mem_events__ptr(j);
+ if (!e->tag) + continue; + if (strstr(e->tag, tok)) e->record = found = true; } @@ -105,6 +109,13 @@ int perf_mem_events__init(void) struct perf_mem_event *e = perf_mem_events__ptr(j); struct stat st;
+ /* + * If the event entry isn't valid, skip initialization + * and "e->supported" will keep false. + */ + if (!e->tag) + continue; + scnprintf(path, PATH_MAX, "%s/devices/%s", mnt, e->sysfs_name);
@@ -123,7 +134,7 @@ void perf_mem_events__list(void) struct perf_mem_event *e = perf_mem_events__ptr(j);
fprintf(stderr, "%-13s%-*s%s\n", - e->tag, + e->tag ?: "", verbose > 0 ? 25 : 0, verbose > 0 ? perf_mem_events__name(j) : "", e->supported ? ": available" : ""); diff --git a/tools/perf/util/mem-events.h b/tools/perf/util/mem-events.h index 726a9c8103e4..5ef178278909 100644 --- a/tools/perf/util/mem-events.h +++ b/tools/perf/util/mem-events.h @@ -28,6 +28,7 @@ struct mem_info { enum { PERF_MEM_EVENTS__LOAD, PERF_MEM_EVENTS__STORE, + PERF_MEM_EVENTS__LOAD_STORE, PERF_MEM_EVENTS__MAX, };
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit 8b8173b45a7a category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
When user doesn't specify event name, perf c2c tool enables both the load and store events, and this leads to failure for opening the duplicate PMU device for AUX trace.
After the memory event PERF_MEM_EVENTS__LOAD_STORE is introduced, when the user doesn't specify event name, this patch converts the required operation to PERF_MEM_EVENTS__LOAD_STORE if the arch supports it. Otherwise, the tool still rolls back to enable events PERF_MEM_EVENTS__LOAD and PERF_MEM_EVENTS__STORE.
Signed-off-by: Leo Yan leo.yan@linaro.org Acked-by: Jiri Olsa jolsa@redhat.com Link: https://lore.kernel.org/r/20201106094853.21082-5-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/builtin-c2c.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 4d1a08e38233..98ae33eac6cc 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -2895,11 +2895,20 @@ static int perf_c2c__record(int argc, const char **argv) rec_argv[i++] = "record";
if (!event_set) { - e = perf_mem_events__ptr(PERF_MEM_EVENTS__LOAD); - e->record = true; + e = perf_mem_events__ptr(PERF_MEM_EVENTS__LOAD_STORE); + /* + * The load and store operations are required, use the event + * PERF_MEM_EVENTS__LOAD_STORE if it is supported. + */ + if (e->tag) { + e->record = true; + } else { + e = perf_mem_events__ptr(PERF_MEM_EVENTS__LOAD); + e->record = true;
- e = perf_mem_events__ptr(PERF_MEM_EVENTS__STORE); - e->record = true; + e = perf_mem_events__ptr(PERF_MEM_EVENTS__STORE); + e->record = true; + } }
e = perf_mem_events__ptr(PERF_MEM_EVENTS__LOAD);
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit 436cce00710a category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
It's needless to initialize memory events for reporting, this patch moves memory event initialization for only recording. Furthermore, the change allows to parse perf data on cross platforms, e.g. perf tool can report result properly even the machine doesn't support the memory events.
Signed-off-by: Leo Yan leo.yan@linaro.org Acked-by: Ian Rogers irogers@google.com Acked-by: Jiri Olsa jolsa@redhat.com Link: https://lore.kernel.org/r/20201106094853.21082-6-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/builtin-mem.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index 21ebe0f47e64..72ce4b8fbb0f 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c @@ -77,6 +77,11 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem) OPT_END() };
+ if (perf_mem_events__init()) { + pr_err("failed: memory events not supported\n"); + return -1; + } + argc = parse_options(argc, argv, options, record_mem_usage, PARSE_OPT_KEEP_UNKNOWN);
@@ -441,11 +446,6 @@ int cmd_mem(int argc, const char **argv) NULL };
- if (perf_mem_events__init()) { - pr_err("failed: memory events not supported\n"); - return -1; - } - argc = parse_options_subcommand(argc, argv, mem_options, mem_subcommands, mem_usage, PARSE_OPT_KEEP_UNKNOWN);
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit 014a771c7867 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
This patch is to add itrace option '-M' to synthesize memory event.
Signed-off-by: Leo Yan leo.yan@linaro.org Acked-by: Jiri Olsa jolsa@redhat.com Link: https://lore.kernel.org/r/20201106094853.21082-7-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/Documentation/itrace.txt | 1 + tools/perf/util/auxtrace.c | 4 ++++ tools/perf/util/auxtrace.h | 2 ++ 3 files changed, 7 insertions(+)
diff --git a/tools/perf/Documentation/itrace.txt b/tools/perf/Documentation/itrace.txt index d3740c8f399b..079cdfabb352 100644 --- a/tools/perf/Documentation/itrace.txt +++ b/tools/perf/Documentation/itrace.txt @@ -11,6 +11,7 @@ d create a debug log f synthesize first level cache events m synthesize last level cache events + M synthesize memory events t synthesize TLB events a synthesize remote access events g synthesize a call chain (use with i or x) diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index d3c15b53495d..1ee9207f3d96 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -1329,6 +1329,7 @@ void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts, synth_opts->flc = true; synth_opts->llc = true; synth_opts->tlb = true; + synth_opts->mem = true; synth_opts->remote_access = true;
if (no_sample) { @@ -1550,6 +1551,9 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str, case 'a': synth_opts->remote_access = true; break; + case 'M': + synth_opts->mem = true; + break; case 'q': synth_opts->quick += 1; break; diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index 951d2d14cf24..7e5c9e1552bd 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h @@ -88,6 +88,7 @@ enum itrace_period_type { * @llc: whether to synthesize last level cache events * @tlb: whether to synthesize TLB events * @remote_access: whether to synthesize remote access events + * @mem: whether to synthesize memory events * @callchain_sz: maximum callchain size * @last_branch_sz: branch context size * @period: 'instructions' events period @@ -126,6 +127,7 @@ struct itrace_synth_opts { bool llc; bool tlb; bool remote_access; + bool mem; unsigned int callchain_sz; unsigned int last_branch_sz; unsigned long long period;
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit 13e5df1e3f1b category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
The 'perf mem' tool doesn't support AUX trace data so it cannot receive the hardware tracing data.
On arm64, although it doesn't support PMU events for memory load and store, ARM SPE is a good candidate for memory profiling, the hardware tracer can record memory accessing operations with affiliated information (e.g. physical address and virtual address for accessing, cache levels, TLB walking, latency, etc).
To allow "perf mem" tool to support AUX trace, this patch adds the AUX callbacks for session structure; make itrace memory event as default for "perf mem", this tells the AUX trace decoder to synthesize memory samples.
Signed-off-by: Leo Yan leo.yan@linaro.org Acked-by: Jiri Olsa jolsa@redhat.com Link: https://lore.kernel.org/r/20201106094853.21082-8-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/builtin-mem.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index 72ce4b8fbb0f..fdfbff7592f4 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c @@ -7,6 +7,7 @@ #include "perf.h"
#include <subcmd/parse-options.h> +#include "util/auxtrace.h" #include "util/trace-event.h" #include "util/tool.h" #include "util/session.h" @@ -255,6 +256,12 @@ static int process_sample_event(struct perf_tool *tool,
static int report_raw_events(struct perf_mem *mem) { + struct itrace_synth_opts itrace_synth_opts = { + .set = true, + .mem = true, /* Only enable memory event */ + .default_no_sample = true, + }; + struct perf_data data = { .path = input_name, .mode = PERF_DATA_MODE_READ, @@ -267,6 +274,8 @@ static int report_raw_events(struct perf_mem *mem) if (IS_ERR(session)) return PTR_ERR(session);
+ session->itrace_synth_opts = &itrace_synth_opts; + if (mem->cpu_list) { ret = perf_session__cpu_bitmap(session, mem->cpu_list, mem->cpu_bitmap); @@ -410,8 +419,12 @@ int cmd_mem(int argc, const char **argv) .comm = perf_event__process_comm, .lost = perf_event__process_lost, .fork = perf_event__process_fork, + .attr = perf_event__process_attr, .build_id = perf_event__process_build_id, .namespaces = perf_event__process_namespaces, + .auxtrace_info = perf_event__process_auxtrace_info, + .auxtrace = perf_event__process_auxtrace, + .auxtrace_error = perf_event__process_auxtrace_error, .ordered_events = true, }, .input_name = "perf.data",
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit c825f7885178 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
This patch adds the AUX callbacks in session structure, so support AUX trace for "perf c2c" tool; make itrace memory event as default for "perf c2c", this tells the AUX trace decoder to synthesize samples and can be used for statistics.
Signed-off-by: Leo Yan leo.yan@linaro.org Acked-by: Jiri Olsa jolsa@redhat.com Link: https://lore.kernel.org/r/20201106094853.21082-9-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/builtin-c2c.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 98ae33eac6cc..c5babeaa3b38 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -369,6 +369,10 @@ static struct perf_c2c c2c = { .exit = perf_event__process_exit, .fork = perf_event__process_fork, .lost = perf_event__process_lost, + .attr = perf_event__process_attr, + .auxtrace_info = perf_event__process_auxtrace_info, + .auxtrace = perf_event__process_auxtrace, + .auxtrace_error = perf_event__process_auxtrace_error, .ordered_events = true, .ordering_requires_timestamps = true, }, @@ -2678,6 +2682,12 @@ static int setup_coalesce(const char *coalesce, bool no_source)
static int perf_c2c__report(int argc, const char **argv) { + struct itrace_synth_opts itrace_synth_opts = { + .set = true, + .mem = true, /* Only enable memory event */ + .default_no_sample = true, + }; + struct perf_session *session; struct ui_progress prog; struct perf_data data = { @@ -2757,6 +2767,8 @@ static int perf_c2c__report(int argc, const char **argv) goto out; }
+ session->itrace_synth_opts = &itrace_synth_opts; + err = setup_nodes(session); if (err) { pr_err("Failed setup nodes\n");
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit 40714c58630a category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
This patch adds ARM SPE events for perf memory profiling:
'spe-load': event for only recording memory load ops; 'spe-store': event for only recording memory store ops; 'spe-ldst': event for recording memory load and store ops.
Signed-off-by: Leo Yan leo.yan@linaro.org Acked-by: Jiri Olsa jolsa@redhat.com Link: https://lore.kernel.org/r/20201106094853.21082-10-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/arch/arm64/util/Build | 2 +- tools/perf/arch/arm64/util/mem-events.c | 37 +++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tools/perf/arch/arm64/util/mem-events.c
diff --git a/tools/perf/arch/arm64/util/Build b/tools/perf/arch/arm64/util/Build index 8d2b9bcfffca..ead2f2275eee 100644 --- a/tools/perf/arch/arm64/util/Build +++ b/tools/perf/arch/arm64/util/Build @@ -10,4 +10,4 @@ perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o perf-$(CONFIG_AUXTRACE) += ../../arm/util/pmu.o \ ../../arm/util/auxtrace.o \ ../../arm/util/cs-etm.o \ - arm-spe.o + arm-spe.o mem-events.o diff --git a/tools/perf/arch/arm64/util/mem-events.c b/tools/perf/arch/arm64/util/mem-events.c new file mode 100644 index 000000000000..2a2497372671 --- /dev/null +++ b/tools/perf/arch/arm64/util/mem-events.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "map_symbol.h" +#include "mem-events.h" + +#define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s } + +static struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = { + E("spe-load", "arm_spe_0/ts_enable=1,load_filter=1,store_filter=0,min_latency=%u/", "arm_spe_0"), + E("spe-store", "arm_spe_0/ts_enable=1,load_filter=0,store_filter=1/", "arm_spe_0"), + E("spe-ldst", "arm_spe_0/ts_enable=1,load_filter=1,store_filter=1,min_latency=%u/", "arm_spe_0"), +}; + +static char mem_ev_name[100]; + +struct perf_mem_event *perf_mem_events__ptr(int i) +{ + if (i >= PERF_MEM_EVENTS__MAX) + return NULL; + + return &perf_mem_events[i]; +} + +char *perf_mem_events__name(int i) +{ + struct perf_mem_event *e = perf_mem_events__ptr(i); + + if (i >= PERF_MEM_EVENTS__MAX) + return NULL; + + if (i == PERF_MEM_EVENTS__LOAD || i == PERF_MEM_EVENTS__LOAD_STORE) + scnprintf(mem_ev_name, sizeof(mem_ev_name), + e->name, perf_mem_events__loads_ldlat); + else /* PERF_MEM_EVENTS__STORE */ + scnprintf(mem_ev_name, sizeof(mem_ev_name), e->name); + + return mem_ev_name; +}
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit c185f1cde466 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
Include header linux/bitops.h, directly use its BIT() macro and remove the self defined macros.
Committer notes:
Use BIT_ULL() instead of BIT to build on 32-bit arches as mentioned in review by Andre Przywara andre.przywara@arm.com. I noticed the build failure when crossbuilding to arm32 from x86_64.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: Andre Przywara andre.przywara@arm.com Link: https://lore.kernel.org/r/20201111071149.815-2-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe-decoder/arm-spe-decoder.c | 5 +---- tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c | 7 +++---- 2 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c index 93e063f22be5..cc18a1e8c212 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c @@ -12,6 +12,7 @@ #include <string.h> #include <stdint.h> #include <stdlib.h> +#include <linux/bitops.h> #include <linux/compiler.h> #include <linux/zalloc.h>
@@ -21,10 +22,6 @@
#include "arm-spe-decoder.h"
-#ifndef BIT -#define BIT(n) (1UL << (n)) -#endif - static u64 arm_spe_calc_ip(int index, u64 payload) { u8 *addr = (u8 *)&payload; diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index b94001b756c7..5f65a3a70c57 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -8,13 +8,12 @@ #include <string.h> #include <endian.h> #include <byteswap.h> +#include <linux/bitops.h>
#include "arm-spe-pkt-decoder.h"
-#define BIT(n) (1ULL << (n)) - -#define NS_FLAG BIT(63) -#define EL_FLAG (BIT(62) | BIT(61)) +#define NS_FLAG BIT_ULL(63) +#define EL_FLAG (BIT_ULL(62) | BIT_ULL(61))
#define SPE_HEADER0_PAD 0x0 #define SPE_HEADER0_END 0x1
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit 903b659436b7 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
Fix a typo: s/iff/if.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: Andre Przywara andre.przywara@arm.com Link: https://lore.kernel.org/r/20201111071149.815-3-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index 5f65a3a70c57..12a96585da94 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -142,7 +142,7 @@ static int arm_spe_get_events(const unsigned char *buf, size_t len,
/* we use index to identify Events with a less number of * comparisons in arm_spe_pkt_desc(): E.g., the LLC-ACCESS, - * LLC-REFILL, and REMOTE-ACCESS events are identified iff + * LLC-REFILL, and REMOTE-ACCESS events are identified if * index > 1. */ packet->index = ret - 1;
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit b2ded2e2e276 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
This patch defines macro to extract "sz" field from header, and renames the function payloadlen() to arm_spe_payload_len().
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: Andre Przywara andre.przywara@arm.com Link: https://lore.kernel.org/r/20201111071149.815-4-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- .../util/arm-spe-decoder/arm-spe-pkt-decoder.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index 12a96585da94..a8eb7be189ec 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -69,22 +69,22 @@ const char *arm_spe_pkt_name(enum arm_spe_pkt_type type) return arm_spe_packet_name[type]; }
-/* return ARM SPE payload size from its encoding, - * which is in bits 5:4 of the byte. - * 00 : byte - * 01 : halfword (2) - * 10 : word (4) - * 11 : doubleword (8) +/* + * Extracts the field "sz" from header bits and converts to bytes: + * 00 : byte (1) + * 01 : halfword (2) + * 10 : word (4) + * 11 : doubleword (8) */ -static int payloadlen(unsigned char byte) +static unsigned int arm_spe_payload_len(unsigned char hdr) { - return 1 << ((byte & 0x30) >> 4); + return 1U << ((hdr & GENMASK_ULL(5, 4)) >> 4); }
static int arm_spe_get_payload(const unsigned char *buf, size_t len, struct arm_spe_pkt *packet) { - size_t payload_len = payloadlen(buf[0]); + size_t payload_len = arm_spe_payload_len(buf[0]);
if (len < 1 + payload_len) return ARM_SPE_NEED_MORE_BYTES;
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit b65577baf482 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
In function arm_spe_get_events(), the event packet's 'index' is assigned as payload length, but the flow is not directive: it firstly gets the packet length from the return value of arm_spe_get_payload(), the value includes header length (1) and payload length:
int ret = arm_spe_get_payload(buf, len, packet);
and then reduces header length from packet length, so finally get the payload length:
packet->index = ret - 1;
To simplify the code, this patch directly assigns payload length to event packet's index; and at the end it calls arm_spe_get_payload() to return the payload value.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: Andre Przywara andre.przywara@arm.com Link: https://lore.kernel.org/r/20201111071149.815-5-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index a8eb7be189ec..57904da89db1 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -136,8 +136,6 @@ static int arm_spe_get_timestamp(const unsigned char *buf, size_t len, static int arm_spe_get_events(const unsigned char *buf, size_t len, struct arm_spe_pkt *packet) { - int ret = arm_spe_get_payload(buf, len, packet); - packet->type = ARM_SPE_EVENTS;
/* we use index to identify Events with a less number of @@ -145,9 +143,9 @@ static int arm_spe_get_events(const unsigned char *buf, size_t len, * LLC-REFILL, and REMOTE-ACCESS events are identified if * index > 1. */ - packet->index = ret - 1; + packet->index = arm_spe_payload_len(buf[0]);
- return ret; + return arm_spe_get_payload(buf, len, packet); }
static int arm_spe_get_data_source(const unsigned char *buf, size_t len,
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit 0a04244cabc5 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
When processing address packet and counter packet, if the packet contains extended header, it misses to account the extra one byte for header length calculation, thus returns the wrong packet length.
To correct the packet length calculation, one possible fixing is simply to plus extra 1 for extended header, but will spread some duplicate code in the flows for processing address packet and counter packet. Alternatively, we can refine the function arm_spe_get_payload() to not only support short header and allow it to support extended header, and rely on it for the packet length calculation.
So this patch refactors function arm_spe_get_payload() with a new argument 'ext_hdr' for support extended header; the packet processing flows can invoke this function to unify the packet length calculation.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: Andre Przywara andre.przywara@arm.com Link: https://lore.kernel.org/r/20201111071149.815-6-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- .../arm-spe-decoder/arm-spe-pkt-decoder.c | 34 +++++++------------ 1 file changed, 12 insertions(+), 22 deletions(-)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index 57904da89db1..671a4763fb47 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -82,14 +82,15 @@ static unsigned int arm_spe_payload_len(unsigned char hdr) }
static int arm_spe_get_payload(const unsigned char *buf, size_t len, + unsigned char ext_hdr, struct arm_spe_pkt *packet) { - size_t payload_len = arm_spe_payload_len(buf[0]); + size_t payload_len = arm_spe_payload_len(buf[ext_hdr]);
- if (len < 1 + payload_len) + if (len < 1 + ext_hdr + payload_len) return ARM_SPE_NEED_MORE_BYTES;
- buf++; + buf += 1 + ext_hdr;
switch (payload_len) { case 1: packet->payload = *(uint8_t *)buf; break; @@ -99,7 +100,7 @@ static int arm_spe_get_payload(const unsigned char *buf, size_t len, default: return ARM_SPE_BAD_PACKET; }
- return 1 + payload_len; + return 1 + ext_hdr + payload_len; }
static int arm_spe_get_pad(struct arm_spe_pkt *packet) @@ -130,7 +131,7 @@ static int arm_spe_get_timestamp(const unsigned char *buf, size_t len, struct arm_spe_pkt *packet) { packet->type = ARM_SPE_TIMESTAMP; - return arm_spe_get_payload(buf, len, packet); + return arm_spe_get_payload(buf, len, 0, packet); }
static int arm_spe_get_events(const unsigned char *buf, size_t len, @@ -145,14 +146,14 @@ static int arm_spe_get_events(const unsigned char *buf, size_t len, */ packet->index = arm_spe_payload_len(buf[0]);
- return arm_spe_get_payload(buf, len, packet); + return arm_spe_get_payload(buf, len, 0, packet); }
static int arm_spe_get_data_source(const unsigned char *buf, size_t len, struct arm_spe_pkt *packet) { packet->type = ARM_SPE_DATA_SOURCE; - return arm_spe_get_payload(buf, len, packet); + return arm_spe_get_payload(buf, len, 0, packet); }
static int arm_spe_get_context(const unsigned char *buf, size_t len, @@ -160,8 +161,7 @@ static int arm_spe_get_context(const unsigned char *buf, size_t len, { packet->type = ARM_SPE_CONTEXT; packet->index = buf[0] & 0x3; - - return arm_spe_get_payload(buf, len, packet); + return arm_spe_get_payload(buf, len, 0, packet); }
static int arm_spe_get_op_type(const unsigned char *buf, size_t len, @@ -169,41 +169,31 @@ static int arm_spe_get_op_type(const unsigned char *buf, size_t len, { packet->type = ARM_SPE_OP_TYPE; packet->index = buf[0] & 0x3; - return arm_spe_get_payload(buf, len, packet); + return arm_spe_get_payload(buf, len, 0, packet); }
static int arm_spe_get_counter(const unsigned char *buf, size_t len, const unsigned char ext_hdr, struct arm_spe_pkt *packet) { - if (len < 2) - return ARM_SPE_NEED_MORE_BYTES; - packet->type = ARM_SPE_COUNTER; if (ext_hdr) packet->index = ((buf[0] & 0x3) << 3) | (buf[1] & 0x7); else packet->index = buf[0] & 0x7;
- packet->payload = le16_to_cpu(*(uint16_t *)(buf + 1)); - - return 1 + ext_hdr + 2; + return arm_spe_get_payload(buf, len, ext_hdr, packet); }
static int arm_spe_get_addr(const unsigned char *buf, size_t len, const unsigned char ext_hdr, struct arm_spe_pkt *packet) { - if (len < 8) - return ARM_SPE_NEED_MORE_BYTES; - packet->type = ARM_SPE_ADDRESS; if (ext_hdr) packet->index = ((buf[0] & 0x3) << 3) | (buf[1] & 0x7); else packet->index = buf[0] & 0x7;
- memcpy_le64(&packet->payload, buf + 1, 8); - - return 1 + ext_hdr + 8; + return arm_spe_get_payload(buf, len, ext_hdr, packet); }
static int arm_spe_do_get_packet(const unsigned char *buf, size_t len,
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit 75eeaddd57f4 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
When outputs strings to the decoding buffer with function snprintf(), SPE decoder needs to detects if any error returns from snprintf() and if so needs to directly bail out. If snprintf() returns success, it needs to update buffer pointer and reduce the buffer length so can continue to output the next string into the consequent memory space.
This complex logics are spreading in the function arm_spe_pkt_desc() so there has many duplicate codes for handling error detecting, increment buffer pointer and decrement buffer size.
To avoid the duplicate code, this patch introduces a new helper function arm_spe_pkt_out_string() which is used to wrap up the complex logics, and it's used by the caller arm_spe_pkt_desc(). This patch moves the variable 'blen' as the function's local variable so allows to remove the unnecessary braces and improve the readability.
This patch simplifies the return value for arm_spe_pkt_desc(): '0' means success and other values mean an error has occurred. To realize this, it relies on arm_spe_pkt_out_string()'s parameter 'err', the 'err' is a cumulative value, returns its final value if printing buffer is called for one time or multiple times. Finally, the error is handled in a central place, rather than directly bailing out in switch-cases, it returns error at the end of arm_spe_pkt_desc().
This patch changes the caller arm_spe_dump() to respect the updated return value semantics of arm_spe_pkt_desc().
Suggested-by: Dave Martin Dave.Martin@arm.com Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: Andre Przywara andre.przywara@arm.com Reviewed-by: Dave Martin Dave.Martin@arm.com Acked-by: Will Deacon will@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: Ingo Molnar mingo@redhat.com Cc: James Clark james.clark@arm.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Wei Li liwei391@huawei.com Link: https://lore.kernel.org/r/20201119152441.6972-2-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- .../arm-spe-decoder/arm-spe-pkt-decoder.c | 302 +++++++++--------- tools/perf/util/arm-spe.c | 2 +- 2 files changed, 151 insertions(+), 153 deletions(-)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index 671a4763fb47..fbededc1bcd4 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -9,6 +9,7 @@ #include <endian.h> #include <byteswap.h> #include <linux/bitops.h> +#include <stdarg.h>
#include "arm-spe-pkt-decoder.h"
@@ -258,192 +259,189 @@ int arm_spe_get_packet(const unsigned char *buf, size_t len, return ret; }
+static int arm_spe_pkt_out_string(int *err, char **buf_p, size_t *blen, + const char *fmt, ...) +{ + va_list ap; + int ret; + + /* Bail out if any error occurred */ + if (err && *err) + return *err; + + va_start(ap, fmt); + ret = vsnprintf(*buf_p, *blen, fmt, ap); + va_end(ap); + + if (ret < 0) { + if (err && !*err) + *err = ret; + + /* + * A return value of *blen or more means that the output was + * truncated and the buffer is overrun. + */ + } else if ((size_t)ret >= *blen) { + (*buf_p)[*blen - 1] = '\0'; + + /* + * Set *err to 'ret' to avoid overflow if tries to + * fill this buffer sequentially. + */ + if (err && !*err) + *err = ret; + } else { + *buf_p += ret; + *blen -= ret; + } + + return ret; +} + int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf, size_t buf_len) { - int ret, ns, el, idx = packet->index; + int ns, el, idx = packet->index; unsigned long long payload = packet->payload; const char *name = arm_spe_pkt_name(packet->type); + char *buf_orig = buf; + size_t blen = buf_len; + int err = 0;
switch (packet->type) { case ARM_SPE_BAD: case ARM_SPE_PAD: case ARM_SPE_END: - return snprintf(buf, buf_len, "%s", name); - case ARM_SPE_EVENTS: { - size_t blen = buf_len; - - ret = 0; - ret = snprintf(buf, buf_len, "EV"); - buf += ret; - blen -= ret; - if (payload & 0x1) { - ret = snprintf(buf, buf_len, " EXCEPTION-GEN"); - buf += ret; - blen -= ret; - } - if (payload & 0x2) { - ret = snprintf(buf, buf_len, " RETIRED"); - buf += ret; - blen -= ret; - } - if (payload & 0x4) { - ret = snprintf(buf, buf_len, " L1D-ACCESS"); - buf += ret; - blen -= ret; - } - if (payload & 0x8) { - ret = snprintf(buf, buf_len, " L1D-REFILL"); - buf += ret; - blen -= ret; - } - if (payload & 0x10) { - ret = snprintf(buf, buf_len, " TLB-ACCESS"); - buf += ret; - blen -= ret; - } - if (payload & 0x20) { - ret = snprintf(buf, buf_len, " TLB-REFILL"); - buf += ret; - blen -= ret; - } - if (payload & 0x40) { - ret = snprintf(buf, buf_len, " NOT-TAKEN"); - buf += ret; - blen -= ret; - } - if (payload & 0x80) { - ret = snprintf(buf, buf_len, " MISPRED"); - buf += ret; - blen -= ret; - } + arm_spe_pkt_out_string(&err, &buf, &blen, "%s", name); + break; + case ARM_SPE_EVENTS: + arm_spe_pkt_out_string(&err, &buf, &blen, "EV"); + + if (payload & 0x1) + arm_spe_pkt_out_string(&err, &buf, &blen, " EXCEPTION-GEN"); + if (payload & 0x2) + arm_spe_pkt_out_string(&err, &buf, &blen, " RETIRED"); + if (payload & 0x4) + arm_spe_pkt_out_string(&err, &buf, &blen, " L1D-ACCESS"); + if (payload & 0x8) + arm_spe_pkt_out_string(&err, &buf, &blen, " L1D-REFILL"); + if (payload & 0x10) + arm_spe_pkt_out_string(&err, &buf, &blen, " TLB-ACCESS"); + if (payload & 0x20) + arm_spe_pkt_out_string(&err, &buf, &blen, " TLB-REFILL"); + if (payload & 0x40) + arm_spe_pkt_out_string(&err, &buf, &blen, " NOT-TAKEN"); + if (payload & 0x80) + arm_spe_pkt_out_string(&err, &buf, &blen, " MISPRED"); if (idx > 1) { - if (payload & 0x100) { - ret = snprintf(buf, buf_len, " LLC-ACCESS"); - buf += ret; - blen -= ret; - } - if (payload & 0x200) { - ret = snprintf(buf, buf_len, " LLC-REFILL"); - buf += ret; - blen -= ret; - } - if (payload & 0x400) { - ret = snprintf(buf, buf_len, " REMOTE-ACCESS"); - buf += ret; - blen -= ret; - } + if (payload & 0x100) + arm_spe_pkt_out_string(&err, &buf, &blen, " LLC-ACCESS"); + if (payload & 0x200) + arm_spe_pkt_out_string(&err, &buf, &blen, " LLC-REFILL"); + if (payload & 0x400) + arm_spe_pkt_out_string(&err, &buf, &blen, " REMOTE-ACCESS"); } - if (ret < 0) - return ret; - blen -= ret; - return buf_len - blen; - } + break; case ARM_SPE_OP_TYPE: switch (idx) { - case 0: return snprintf(buf, buf_len, "%s", payload & 0x1 ? - "COND-SELECT" : "INSN-OTHER"); - case 1: { - size_t blen = buf_len; + case 0: + arm_spe_pkt_out_string(&err, &buf, &blen, + payload & 0x1 ? "COND-SELECT" : "INSN-OTHER"); + break; + case 1: + arm_spe_pkt_out_string(&err, &buf, &blen, + payload & 0x1 ? "ST" : "LD");
- if (payload & 0x1) - ret = snprintf(buf, buf_len, "ST"); - else - ret = snprintf(buf, buf_len, "LD"); - buf += ret; - blen -= ret; if (payload & 0x2) { - if (payload & 0x4) { - ret = snprintf(buf, buf_len, " AT"); - buf += ret; - blen -= ret; - } - if (payload & 0x8) { - ret = snprintf(buf, buf_len, " EXCL"); - buf += ret; - blen -= ret; - } - if (payload & 0x10) { - ret = snprintf(buf, buf_len, " AR"); - buf += ret; - blen -= ret; - } + if (payload & 0x4) + arm_spe_pkt_out_string(&err, &buf, &blen, " AT"); + if (payload & 0x8) + arm_spe_pkt_out_string(&err, &buf, &blen, " EXCL"); + if (payload & 0x10) + arm_spe_pkt_out_string(&err, &buf, &blen, " AR"); } else if (payload & 0x4) { - ret = snprintf(buf, buf_len, " SIMD-FP"); - buf += ret; - blen -= ret; - } - if (ret < 0) - return ret; - blen -= ret; - return buf_len - blen; - } - case 2: { - size_t blen = buf_len; - - ret = snprintf(buf, buf_len, "B"); - buf += ret; - blen -= ret; - if (payload & 0x1) { - ret = snprintf(buf, buf_len, " COND"); - buf += ret; - blen -= ret; - } - if (payload & 0x2) { - ret = snprintf(buf, buf_len, " IND"); - buf += ret; - blen -= ret; - } - if (ret < 0) - return ret; - blen -= ret; - return buf_len - blen; + arm_spe_pkt_out_string(&err, &buf, &blen, " SIMD-FP"); } - default: return 0; + break; + case 2: + arm_spe_pkt_out_string(&err, &buf, &blen, "B"); + + if (payload & 0x1) + arm_spe_pkt_out_string(&err, &buf, &blen, " COND"); + if (payload & 0x2) + arm_spe_pkt_out_string(&err, &buf, &blen, " IND"); + + break; + default: + /* Unknown index */ + err = -1; + break; } + break; case ARM_SPE_DATA_SOURCE: case ARM_SPE_TIMESTAMP: - return snprintf(buf, buf_len, "%s %lld", name, payload); + arm_spe_pkt_out_string(&err, &buf, &blen, "%s %lld", name, payload); + break; case ARM_SPE_ADDRESS: switch (idx) { case 0: - case 1: ns = !!(packet->payload & NS_FLAG); + case 1: + ns = !!(packet->payload & NS_FLAG); el = (packet->payload & EL_FLAG) >> 61; payload &= ~(0xffULL << 56); - return snprintf(buf, buf_len, "%s 0x%llx el%d ns=%d", + arm_spe_pkt_out_string(&err, &buf, &blen, + "%s 0x%llx el%d ns=%d", (idx == 1) ? "TGT" : "PC", payload, el, ns); - case 2: return snprintf(buf, buf_len, "VA 0x%llx", payload); - case 3: ns = !!(packet->payload & NS_FLAG); + break; + case 2: + arm_spe_pkt_out_string(&err, &buf, &blen, + "VA 0x%llx", payload); + break; + case 3: + ns = !!(packet->payload & NS_FLAG); payload &= ~(0xffULL << 56); - return snprintf(buf, buf_len, "PA 0x%llx ns=%d", - payload, ns); - default: return 0; + arm_spe_pkt_out_string(&err, &buf, &blen, + "PA 0x%llx ns=%d", payload, ns); + break; + default: + /* Unknown index */ + err = -1; + break; } + break; case ARM_SPE_CONTEXT: - return snprintf(buf, buf_len, "%s 0x%lx el%d", name, - (unsigned long)payload, idx + 1); - case ARM_SPE_COUNTER: { - size_t blen = buf_len; - - ret = snprintf(buf, buf_len, "%s %d ", name, - (unsigned short)payload); - buf += ret; - blen -= ret; + arm_spe_pkt_out_string(&err, &buf, &blen, "%s 0x%lx el%d", + name, (unsigned long)payload, idx + 1); + break; + case ARM_SPE_COUNTER: + arm_spe_pkt_out_string(&err, &buf, &blen, "%s %d ", name, + (unsigned short)payload); switch (idx) { - case 0: ret = snprintf(buf, buf_len, "TOT"); break; - case 1: ret = snprintf(buf, buf_len, "ISSUE"); break; - case 2: ret = snprintf(buf, buf_len, "XLAT"); break; - default: ret = 0; + case 0: + arm_spe_pkt_out_string(&err, &buf, &blen, "TOT"); + break; + case 1: + arm_spe_pkt_out_string(&err, &buf, &blen, "ISSUE"); + break; + case 2: + arm_spe_pkt_out_string(&err, &buf, &blen, "XLAT"); + break; + default: + break; } - if (ret < 0) - return ret; - blen -= ret; - return buf_len - blen; - } + break; default: + /* Unknown packet type */ + err = -1; break; }
- return snprintf(buf, buf_len, "%s 0x%llx (%d)", - name, payload, packet->index); + /* Output raw data if detect any error */ + if (err) { + err = 0; + arm_spe_pkt_out_string(&err, &buf_orig, &buf_len, "%s 0x%llx (%d)", + name, payload, packet->index); + } + + return err; } diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index 3882a5360ada..8901a1656a41 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -113,7 +113,7 @@ static void arm_spe_dump(struct arm_spe *spe __maybe_unused, if (ret > 0) { ret = arm_spe_pkt_desc(&packet, desc, ARM_SPE_PKT_DESC_MAX); - if (ret > 0) + if (!ret) color_fprintf(stdout, color, " %s\n", desc); } else { color_fprintf(stdout, color, " Bad packet!\n");
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit 11695142e25e category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
The packet header parsing uses the hard coded values and it uses nested if-else statements.
To improve the readability, this patch refactors the macros for packet header format so it removes the hard coded values. Furthermore, based on the new mask macros it reduces the nested if-else statements and changes to use the flat conditions checking, this is directive and can easily map to the descriptions in ARMv8-a architecture reference manual (ARM DDI 0487E.a), chapter 'D10.1.5 Statistical Profiling Extension protocol packet headers'.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: Andre Przywara andre.przywara@arm.com Acked-by: Will Deacon will@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: Dave Martin Dave.Martin@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: James Clark james.clark@arm.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Wei Li liwei391@huawei.com Link: https://lore.kernel.org/r/20201119152441.6972-3-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- .../arm-spe-decoder/arm-spe-pkt-decoder.c | 92 +++++++++---------- .../arm-spe-decoder/arm-spe-pkt-decoder.h | 20 ++++ 2 files changed, 61 insertions(+), 51 deletions(-)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index fbededc1bcd4..a769fe5a4496 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -16,28 +16,6 @@ #define NS_FLAG BIT_ULL(63) #define EL_FLAG (BIT_ULL(62) | BIT_ULL(61))
-#define SPE_HEADER0_PAD 0x0 -#define SPE_HEADER0_END 0x1 -#define SPE_HEADER0_ADDRESS 0x30 /* address packet (short) */ -#define SPE_HEADER0_ADDRESS_MASK 0x38 -#define SPE_HEADER0_COUNTER 0x18 /* counter packet (short) */ -#define SPE_HEADER0_COUNTER_MASK 0x38 -#define SPE_HEADER0_TIMESTAMP 0x71 -#define SPE_HEADER0_TIMESTAMP 0x71 -#define SPE_HEADER0_EVENTS 0x2 -#define SPE_HEADER0_EVENTS_MASK 0xf -#define SPE_HEADER0_SOURCE 0x3 -#define SPE_HEADER0_SOURCE_MASK 0xf -#define SPE_HEADER0_CONTEXT 0x24 -#define SPE_HEADER0_CONTEXT_MASK 0x3c -#define SPE_HEADER0_OP_TYPE 0x8 -#define SPE_HEADER0_OP_TYPE_MASK 0x3c -#define SPE_HEADER1_ALIGNMENT 0x0 -#define SPE_HEADER1_ADDRESS 0xb0 /* address packet (extended) */ -#define SPE_HEADER1_ADDRESS_MASK 0xf8 -#define SPE_HEADER1_COUNTER 0x98 /* counter packet (extended) */ -#define SPE_HEADER1_COUNTER_MASK 0xf8 - #if __BYTE_ORDER == __BIG_ENDIAN #define le16_to_cpu bswap_16 #define le32_to_cpu bswap_32 @@ -200,46 +178,58 @@ static int arm_spe_get_addr(const unsigned char *buf, size_t len, static int arm_spe_do_get_packet(const unsigned char *buf, size_t len, struct arm_spe_pkt *packet) { - unsigned int byte; + unsigned int hdr; + unsigned char ext_hdr = 0;
memset(packet, 0, sizeof(struct arm_spe_pkt));
if (!len) return ARM_SPE_NEED_MORE_BYTES;
- byte = buf[0]; - if (byte == SPE_HEADER0_PAD) + hdr = buf[0]; + + if (hdr == SPE_HEADER0_PAD) return arm_spe_get_pad(packet); - else if (byte == SPE_HEADER0_END) /* no timestamp at end of record */ + + if (hdr == SPE_HEADER0_END) /* no timestamp at end of record */ return arm_spe_get_end(packet); - else if (byte & 0xc0 /* 0y11xxxxxx */) { - if (byte & 0x80) { - if ((byte & SPE_HEADER0_ADDRESS_MASK) == SPE_HEADER0_ADDRESS) - return arm_spe_get_addr(buf, len, 0, packet); - if ((byte & SPE_HEADER0_COUNTER_MASK) == SPE_HEADER0_COUNTER) - return arm_spe_get_counter(buf, len, 0, packet); - } else - if (byte == SPE_HEADER0_TIMESTAMP) - return arm_spe_get_timestamp(buf, len, packet); - else if ((byte & SPE_HEADER0_EVENTS_MASK) == SPE_HEADER0_EVENTS) - return arm_spe_get_events(buf, len, packet); - else if ((byte & SPE_HEADER0_SOURCE_MASK) == SPE_HEADER0_SOURCE) - return arm_spe_get_data_source(buf, len, packet); - else if ((byte & SPE_HEADER0_CONTEXT_MASK) == SPE_HEADER0_CONTEXT) - return arm_spe_get_context(buf, len, packet); - else if ((byte & SPE_HEADER0_OP_TYPE_MASK) == SPE_HEADER0_OP_TYPE) - return arm_spe_get_op_type(buf, len, packet); - } else if ((byte & 0xe0) == 0x20 /* 0y001xxxxx */) { - /* 16-bit header */ - byte = buf[1]; - if (byte == SPE_HEADER1_ALIGNMENT) + + if (hdr == SPE_HEADER0_TIMESTAMP) + return arm_spe_get_timestamp(buf, len, packet); + + if ((hdr & SPE_HEADER0_MASK1) == SPE_HEADER0_EVENTS) + return arm_spe_get_events(buf, len, packet); + + if ((hdr & SPE_HEADER0_MASK1) == SPE_HEADER0_SOURCE) + return arm_spe_get_data_source(buf, len, packet); + + if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_CONTEXT) + return arm_spe_get_context(buf, len, packet); + + if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_OP_TYPE) + return arm_spe_get_op_type(buf, len, packet); + + if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_EXTENDED) { + /* 16-bit extended format header */ + ext_hdr = 1; + + hdr = buf[1]; + if (hdr == SPE_HEADER1_ALIGNMENT) return arm_spe_get_alignment(buf, len, packet); - else if ((byte & SPE_HEADER1_ADDRESS_MASK) == SPE_HEADER1_ADDRESS) - return arm_spe_get_addr(buf, len, 1, packet); - else if ((byte & SPE_HEADER1_COUNTER_MASK) == SPE_HEADER1_COUNTER) - return arm_spe_get_counter(buf, len, 1, packet); }
+ /* + * The short format header's byte 0 or the extended format header's + * byte 1 has been assigned to 'hdr', which uses the same encoding for + * address packet and counter packet, so don't need to distinguish if + * it's short format or extended format and handle in once. + */ + if ((hdr & SPE_HEADER0_MASK3) == SPE_HEADER0_ADDRESS) + return arm_spe_get_addr(buf, len, ext_hdr, packet); + + if ((hdr & SPE_HEADER0_MASK3) == SPE_HEADER0_COUNTER) + return arm_spe_get_counter(buf, len, ext_hdr, packet); + return ARM_SPE_BAD_PACKET; }
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h index 4c870521b8eb..129f43405eb1 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h @@ -36,6 +36,26 @@ struct arm_spe_pkt { uint64_t payload; };
+/* Short header (HEADER0) and extended header (HEADER1) */ +#define SPE_HEADER0_PAD 0x0 +#define SPE_HEADER0_END 0x1 +#define SPE_HEADER0_TIMESTAMP 0x71 +/* Mask for event & data source */ +#define SPE_HEADER0_MASK1 (GENMASK_ULL(7, 6) | GENMASK_ULL(3, 0)) +#define SPE_HEADER0_EVENTS 0x42 +#define SPE_HEADER0_SOURCE 0x43 +/* Mask for context & operation */ +#define SPE_HEADER0_MASK2 GENMASK_ULL(7, 2) +#define SPE_HEADER0_CONTEXT 0x64 +#define SPE_HEADER0_OP_TYPE 0x48 +/* Mask for extended format */ +#define SPE_HEADER0_EXTENDED 0x20 +/* Mask for address & counter */ +#define SPE_HEADER0_MASK3 GENMASK_ULL(7, 3) +#define SPE_HEADER0_ADDRESS 0xb0 +#define SPE_HEADER0_COUNTER 0x98 +#define SPE_HEADER1_ALIGNMENT 0x0 + #define SPE_ADDR_PKT_HDR_INDEX_INS (0x0) #define SPE_ADDR_PKT_HDR_INDEX_BRANCH (0x1) #define SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT (0x2)
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit ab2aa439e4aa category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
This patch moves out the address parsing code from arm_spe_pkt_desc() and uses the new introduced function arm_spe_pkt_desc_addr() to process address packet.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: Andre Przywara andre.przywara@arm.com Acked-by: Will Deacon will@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: Dave Martin Dave.Martin@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: James Clark james.clark@arm.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Wei Li liwei391@huawei.com Link: https://lore.kernel.org/r/20201119152441.6972-4-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- .../arm-spe-decoder/arm-spe-pkt-decoder.c | 64 +++++++++++-------- 1 file changed, 38 insertions(+), 26 deletions(-)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index a769fe5a4496..b16d68b40bbd 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -288,10 +288,46 @@ static int arm_spe_pkt_out_string(int *err, char **buf_p, size_t *blen, return ret; }
+static int arm_spe_pkt_desc_addr(const struct arm_spe_pkt *packet, + char *buf, size_t buf_len) +{ + int ns, el, idx = packet->index; + u64 payload = packet->payload; + int err = 0; + + switch (idx) { + case 0: + case 1: + ns = !!(packet->payload & NS_FLAG); + el = (packet->payload & EL_FLAG) >> 61; + payload &= ~(0xffULL << 56); + arm_spe_pkt_out_string(&err, &buf, &buf_len, + "%s 0x%llx el%d ns=%d", + (idx == 1) ? "TGT" : "PC", payload, el, ns); + break; + case 2: + arm_spe_pkt_out_string(&err, &buf, &buf_len, + "VA 0x%llx", payload); + break; + case 3: + ns = !!(packet->payload & NS_FLAG); + payload &= ~(0xffULL << 56); + arm_spe_pkt_out_string(&err, &buf, &buf_len, + "PA 0x%llx ns=%d", payload, ns); + break; + default: + /* Unknown index */ + err = -1; + break; + } + + return err; +} + int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf, size_t buf_len) { - int ns, el, idx = packet->index; + int idx = packet->index; unsigned long long payload = packet->payload; const char *name = arm_spe_pkt_name(packet->type); char *buf_orig = buf; @@ -373,31 +409,7 @@ int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf, arm_spe_pkt_out_string(&err, &buf, &blen, "%s %lld", name, payload); break; case ARM_SPE_ADDRESS: - switch (idx) { - case 0: - case 1: - ns = !!(packet->payload & NS_FLAG); - el = (packet->payload & EL_FLAG) >> 61; - payload &= ~(0xffULL << 56); - arm_spe_pkt_out_string(&err, &buf, &blen, - "%s 0x%llx el%d ns=%d", - (idx == 1) ? "TGT" : "PC", payload, el, ns); - break; - case 2: - arm_spe_pkt_out_string(&err, &buf, &blen, - "VA 0x%llx", payload); - break; - case 3: - ns = !!(packet->payload & NS_FLAG); - payload &= ~(0xffULL << 56); - arm_spe_pkt_out_string(&err, &buf, &blen, - "PA 0x%llx ns=%d", payload, ns); - break; - default: - /* Unknown index */ - err = -1; - break; - } + err = arm_spe_pkt_desc_addr(packet, buf, buf_len); break; case ARM_SPE_CONTEXT: arm_spe_pkt_out_string(&err, &buf, &blen, "%s 0x%lx el%d",
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit 09935ca7b64c category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
This patch is to refactor address packet handling, it defines macros for address packet's header and payload, these macros are used by decoder and the dump flow.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: Andre Przywara andre.przywara@arm.com Acked-by: Will Deacon will@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: Dave Martin Dave.Martin@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: James Clark james.clark@arm.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Wei Li liwei391@huawei.com Link: https://lore.kernel.org/r/20201119152441.6972-5-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- .../util/arm-spe-decoder/arm-spe-decoder.c | 29 ++++++++------- .../arm-spe-decoder/arm-spe-pkt-decoder.c | 26 +++++++------- .../arm-spe-decoder/arm-spe-pkt-decoder.h | 35 ++++++++++++------- 3 files changed, 48 insertions(+), 42 deletions(-)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c index cc18a1e8c212..776b3e6628bb 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c @@ -24,36 +24,35 @@
static u64 arm_spe_calc_ip(int index, u64 payload) { - u8 *addr = (u8 *)&payload; - int ns, el; + u64 ns, el;
/* Instruction virtual address or Branch target address */ if (index == SPE_ADDR_PKT_HDR_INDEX_INS || index == SPE_ADDR_PKT_HDR_INDEX_BRANCH) { - ns = addr[7] & SPE_ADDR_PKT_NS; - el = (addr[7] & SPE_ADDR_PKT_EL_MASK) >> SPE_ADDR_PKT_EL_OFFSET; + ns = SPE_ADDR_PKT_GET_NS(payload); + el = SPE_ADDR_PKT_GET_EL(payload); + + /* Clean highest byte */ + payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
/* Fill highest byte for EL1 or EL2 (VHE) mode */ if (ns && (el == SPE_ADDR_PKT_EL1 || el == SPE_ADDR_PKT_EL2)) - addr[7] = 0xff; - /* Clean highest byte for other cases */ - else - addr[7] = 0x0; + payload |= 0xffULL << SPE_ADDR_PKT_ADDR_BYTE7_SHIFT;
/* Data access virtual address */ } else if (index == SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT) {
+ /* Clean tags */ + payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload); + /* Fill highest byte if bits [48..55] is 0xff */ - if (addr[6] == 0xff) - addr[7] = 0xff; - /* Otherwise, cleanup tags */ - else - addr[7] = 0x0; + if (SPE_ADDR_PKT_ADDR_GET_BYTE_6(payload) == 0xffULL) + payload |= 0xffULL << SPE_ADDR_PKT_ADDR_BYTE7_SHIFT;
/* Data access physical address */ } else if (index == SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS) { - /* Cleanup byte 7 */ - addr[7] = 0x0; + /* Clean highest byte */ + payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload); } else { pr_err("unsupported address packet index: 0x%x\n", index); } diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index b16d68b40bbd..d37c4008adbc 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -13,9 +13,6 @@
#include "arm-spe-pkt-decoder.h"
-#define NS_FLAG BIT_ULL(63) -#define EL_FLAG (BIT_ULL(62) | BIT_ULL(61)) - #if __BYTE_ORDER == __BIG_ENDIAN #define le16_to_cpu bswap_16 #define le32_to_cpu bswap_32 @@ -167,10 +164,11 @@ static int arm_spe_get_addr(const unsigned char *buf, size_t len, const unsigned char ext_hdr, struct arm_spe_pkt *packet) { packet->type = ARM_SPE_ADDRESS; + if (ext_hdr) - packet->index = ((buf[0] & 0x3) << 3) | (buf[1] & 0x7); + packet->index = SPE_HDR_EXTENDED_INDEX(buf[0], buf[1]); else - packet->index = buf[0] & 0x7; + packet->index = SPE_HDR_SHORT_INDEX(buf[0]);
return arm_spe_get_payload(buf, len, ext_hdr, packet); } @@ -296,22 +294,22 @@ static int arm_spe_pkt_desc_addr(const struct arm_spe_pkt *packet, int err = 0;
switch (idx) { - case 0: - case 1: - ns = !!(packet->payload & NS_FLAG); - el = (packet->payload & EL_FLAG) >> 61; - payload &= ~(0xffULL << 56); + case SPE_ADDR_PKT_HDR_INDEX_INS: + case SPE_ADDR_PKT_HDR_INDEX_BRANCH: + ns = !!SPE_ADDR_PKT_GET_NS(payload); + el = SPE_ADDR_PKT_GET_EL(payload); + payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload); arm_spe_pkt_out_string(&err, &buf, &buf_len, "%s 0x%llx el%d ns=%d", (idx == 1) ? "TGT" : "PC", payload, el, ns); break; - case 2: + case SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT: arm_spe_pkt_out_string(&err, &buf, &buf_len, "VA 0x%llx", payload); break; - case 3: - ns = !!(packet->payload & NS_FLAG); - payload &= ~(0xffULL << 56); + case SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS: + ns = !!SPE_ADDR_PKT_GET_NS(payload); + payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload); arm_spe_pkt_out_string(&err, &buf, &buf_len, "PA 0x%llx ns=%d", payload, ns); break; diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h index 129f43405eb1..f97d6840be3a 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h @@ -56,19 +56,28 @@ struct arm_spe_pkt { #define SPE_HEADER0_COUNTER 0x98 #define SPE_HEADER1_ALIGNMENT 0x0
-#define SPE_ADDR_PKT_HDR_INDEX_INS (0x0) -#define SPE_ADDR_PKT_HDR_INDEX_BRANCH (0x1) -#define SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT (0x2) -#define SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS (0x3) - -#define SPE_ADDR_PKT_NS BIT(7) -#define SPE_ADDR_PKT_CH BIT(6) -#define SPE_ADDR_PKT_EL_OFFSET (5) -#define SPE_ADDR_PKT_EL_MASK (0x3 << SPE_ADDR_PKT_EL_OFFSET) -#define SPE_ADDR_PKT_EL0 (0) -#define SPE_ADDR_PKT_EL1 (1) -#define SPE_ADDR_PKT_EL2 (2) -#define SPE_ADDR_PKT_EL3 (3) +#define SPE_HDR_SHORT_INDEX(h) ((h) & GENMASK_ULL(2, 0)) +#define SPE_HDR_EXTENDED_INDEX(h0, h1) (((h0) & GENMASK_ULL(1, 0)) << 3 | \ + SPE_HDR_SHORT_INDEX(h1)) + +/* Address packet header */ +#define SPE_ADDR_PKT_HDR_INDEX_INS 0x0 +#define SPE_ADDR_PKT_HDR_INDEX_BRANCH 0x1 +#define SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT 0x2 +#define SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS 0x3 + +/* Address packet payload */ +#define SPE_ADDR_PKT_ADDR_BYTE7_SHIFT 56 +#define SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(v) ((v) & GENMASK_ULL(55, 0)) +#define SPE_ADDR_PKT_ADDR_GET_BYTE_6(v) (((v) & GENMASK_ULL(55, 48)) >> 48) + +#define SPE_ADDR_PKT_GET_NS(v) (((v) & BIT_ULL(63)) >> 63) +#define SPE_ADDR_PKT_GET_EL(v) (((v) & GENMASK_ULL(62, 61)) >> 61) + +#define SPE_ADDR_PKT_EL0 0 +#define SPE_ADDR_PKT_EL1 1 +#define SPE_ADDR_PKT_EL2 2 +#define SPE_ADDR_PKT_EL3 3
const char *arm_spe_pkt_name(enum arm_spe_pkt_type);
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit 5513ddaf103c category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
To establish a valid address from the address packet payload and finally the address value can be used for parsing data symbol in DSO, current code uses 0xff to replace the tag in the top byte of data virtual address.
So far the code only fixups top byte for the memory layouts with 4KB pages, it misses to support memory layouts with 64KB pages.
This patch adds the conditions for checking bits [55:52] are 0xf, if detects the pattern it will fill 0xff into the top byte of the address, also adds comment to explain the fixing up.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: Andre Przywara andre.przywara@arm.com Acked-by: Will Deacon will@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: Dave Martin Dave.Martin@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: James Clark james.clark@arm.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Wei Li liwei391@huawei.com Link: https://lore.kernel.org/r/20201119152441.6972-6-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- .../util/arm-spe-decoder/arm-spe-decoder.c | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c index 776b3e6628bb..cac2ef79c025 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c @@ -24,7 +24,7 @@
static u64 arm_spe_calc_ip(int index, u64 payload) { - u64 ns, el; + u64 ns, el, val;
/* Instruction virtual address or Branch target address */ if (index == SPE_ADDR_PKT_HDR_INDEX_INS || @@ -45,8 +45,22 @@ static u64 arm_spe_calc_ip(int index, u64 payload) /* Clean tags */ payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
- /* Fill highest byte if bits [48..55] is 0xff */ - if (SPE_ADDR_PKT_ADDR_GET_BYTE_6(payload) == 0xffULL) + /* + * Armv8 ARM (ARM DDI 0487F.c), chapter "D10.2.1 Address packet" + * defines the data virtual address payload format, the top byte + * (bits [63:56]) is assigned as top-byte tag; so we only can + * retrieve address value from bits [55:0]. + * + * According to Documentation/arm64/memory.rst, if detects the + * specific pattern in bits [55:52] of payload which falls in + * the kernel space, should fixup the top byte and this allows + * perf tool to parse DSO symbol for data address correctly. + * + * For this reason, if detects the bits [55:52] is 0xf, will + * fill 0xff into the top byte. + */ + val = SPE_ADDR_PKT_ADDR_GET_BYTE_6(payload); + if ((val & 0xf0ULL) == 0xf0ULL) payload |= 0xffULL << SPE_ADDR_PKT_ADDR_BYTE7_SHIFT;
/* Data access physical address */
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit 6550149e801a category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
Minor refactoring to use macro for index mask.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: Andre Przywara andre.przywara@arm.com Acked-by: Will Deacon will@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: Dave Martin Dave.Martin@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: James Clark james.clark@arm.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Wei Li liwei391@huawei.com Link: https://lore.kernel.org/r/20201119152441.6972-7-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c | 2 +- tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index d37c4008adbc..978f5551b82c 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -136,7 +136,7 @@ static int arm_spe_get_context(const unsigned char *buf, size_t len, struct arm_spe_pkt *packet) { packet->type = ARM_SPE_CONTEXT; - packet->index = buf[0] & 0x3; + packet->index = SPE_CTX_PKT_HDR_INDEX(buf[0]); return arm_spe_get_payload(buf, len, 0, packet); }
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h index f97d6840be3a..9bc876bffd35 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h @@ -79,6 +79,9 @@ struct arm_spe_pkt { #define SPE_ADDR_PKT_EL2 2 #define SPE_ADDR_PKT_EL3 3
+/* Context packet header */ +#define SPE_CTX_PKT_HDR_INDEX(h) ((h) & GENMASK_ULL(1, 0)) + const char *arm_spe_pkt_name(enum arm_spe_pkt_type);
int arm_spe_get_packet(const unsigned char *buf, size_t len,
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit c52cfe987213 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
This patch moves out the counter packet parsing code from arm_spe_pkt_desc() to the new function arm_spe_pkt_desc_counter().
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: Andre Przywara andre.przywara@arm.com Acked-by: Will Deacon will@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: Dave Martin Dave.Martin@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: James Clark james.clark@arm.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Wei Li liwei391@huawei.com Link: https://lore.kernel.org/r/20201119152441.6972-8-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- .../arm-spe-decoder/arm-spe-pkt-decoder.c | 43 ++++++++++++------- 1 file changed, 28 insertions(+), 15 deletions(-)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index 978f5551b82c..397ade5ffdeb 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -322,6 +322,33 @@ static int arm_spe_pkt_desc_addr(const struct arm_spe_pkt *packet, return err; }
+static int arm_spe_pkt_desc_counter(const struct arm_spe_pkt *packet, + char *buf, size_t buf_len) +{ + u64 payload = packet->payload; + const char *name = arm_spe_pkt_name(packet->type); + int err = 0; + + arm_spe_pkt_out_string(&err, &buf, &buf_len, "%s %d ", name, + (unsigned short)payload); + + switch (packet->index) { + case 0: + arm_spe_pkt_out_string(&err, &buf, &buf_len, "TOT"); + break; + case 1: + arm_spe_pkt_out_string(&err, &buf, &buf_len, "ISSUE"); + break; + case 2: + arm_spe_pkt_out_string(&err, &buf, &buf_len, "XLAT"); + break; + default: + break; + } + + return err; +} + int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf, size_t buf_len) { @@ -414,21 +441,7 @@ int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf, name, (unsigned long)payload, idx + 1); break; case ARM_SPE_COUNTER: - arm_spe_pkt_out_string(&err, &buf, &blen, "%s %d ", name, - (unsigned short)payload); - switch (idx) { - case 0: - arm_spe_pkt_out_string(&err, &buf, &blen, "TOT"); - break; - case 1: - arm_spe_pkt_out_string(&err, &buf, &blen, "ISSUE"); - break; - case 2: - arm_spe_pkt_out_string(&err, &buf, &blen, "XLAT"); - break; - default: - break; - } + err = arm_spe_pkt_desc_counter(packet, buf, buf_len); break; default: /* Unknown packet type */
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit d158aa408f22 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
This patch defines macros for counter packet header, and uses macros to replace hard code values in functions arm_spe_get_counter() and arm_spe_pkt_desc().
In the function arm_spe_get_counter(), adds a new line for more readable.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: Andre Przywara andre.przywara@arm.com Acked-by: Will Deacon will@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: Dave Martin Dave.Martin@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: James Clark james.clark@arm.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Wei Li liwei391@huawei.com Link: https://lore.kernel.org/r/20201119152441.6972-9-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c | 11 ++++++----- tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h | 5 +++++ 2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index 397ade5ffdeb..52f4339b1f0c 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -152,10 +152,11 @@ static int arm_spe_get_counter(const unsigned char *buf, size_t len, const unsigned char ext_hdr, struct arm_spe_pkt *packet) { packet->type = ARM_SPE_COUNTER; + if (ext_hdr) - packet->index = ((buf[0] & 0x3) << 3) | (buf[1] & 0x7); + packet->index = SPE_HDR_EXTENDED_INDEX(buf[0], buf[1]); else - packet->index = buf[0] & 0x7; + packet->index = SPE_HDR_SHORT_INDEX(buf[0]);
return arm_spe_get_payload(buf, len, ext_hdr, packet); } @@ -333,13 +334,13 @@ static int arm_spe_pkt_desc_counter(const struct arm_spe_pkt *packet, (unsigned short)payload);
switch (packet->index) { - case 0: + case SPE_CNT_PKT_HDR_INDEX_TOTAL_LAT: arm_spe_pkt_out_string(&err, &buf, &buf_len, "TOT"); break; - case 1: + case SPE_CNT_PKT_HDR_INDEX_ISSUE_LAT: arm_spe_pkt_out_string(&err, &buf, &buf_len, "ISSUE"); break; - case 2: + case SPE_CNT_PKT_HDR_INDEX_TRANS_LAT: arm_spe_pkt_out_string(&err, &buf, &buf_len, "XLAT"); break; default: diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h index 9bc876bffd35..7d8e34e35f05 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h @@ -82,6 +82,11 @@ struct arm_spe_pkt { /* Context packet header */ #define SPE_CTX_PKT_HDR_INDEX(h) ((h) & GENMASK_ULL(1, 0))
+/* Counter packet header */ +#define SPE_CNT_PKT_HDR_INDEX_TOTAL_LAT 0x0 +#define SPE_CNT_PKT_HDR_INDEX_ISSUE_LAT 0x1 +#define SPE_CNT_PKT_HDR_INDEX_TRANS_LAT 0x2 + const char *arm_spe_pkt_name(enum arm_spe_pkt_type);
int arm_spe_get_packet(const unsigned char *buf, size_t len,
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit e66f6d759602 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
This patch moves out the event packet parsing from arm_spe_pkt_desc() to the new function arm_spe_pkt_desc_event().
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: Andre Przywara andre.przywara@arm.com Acked-by: Will Deacon will@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: Dave Martin Dave.Martin@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: James Clark james.clark@arm.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Wei Li liwei391@huawei.com Link: https://lore.kernel.org/r/20201119152441.6972-10-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- .../arm-spe-decoder/arm-spe-pkt-decoder.c | 63 +++++++++++-------- 1 file changed, 37 insertions(+), 26 deletions(-)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index 52f4339b1f0c..da6b9f76739c 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -287,6 +287,42 @@ static int arm_spe_pkt_out_string(int *err, char **buf_p, size_t *blen, return ret; }
+static int arm_spe_pkt_desc_event(const struct arm_spe_pkt *packet, + char *buf, size_t buf_len) +{ + u64 payload = packet->payload; + int err = 0; + + arm_spe_pkt_out_string(&err, &buf, &buf_len, "EV"); + + if (payload & 0x1) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " EXCEPTION-GEN"); + if (payload & 0x2) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " RETIRED"); + if (payload & 0x4) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " L1D-ACCESS"); + if (payload & 0x8) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " L1D-REFILL"); + if (payload & 0x10) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " TLB-ACCESS"); + if (payload & 0x20) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " TLB-REFILL"); + if (payload & 0x40) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " NOT-TAKEN"); + if (payload & 0x80) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " MISPRED"); + if (packet->index > 1) { + if (payload & 0x100) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-ACCESS"); + if (payload & 0x200) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-REFILL"); + if (payload & 0x400) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " REMOTE-ACCESS"); + } + + return err; +} + static int arm_spe_pkt_desc_addr(const struct arm_spe_pkt *packet, char *buf, size_t buf_len) { @@ -367,32 +403,7 @@ int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf, arm_spe_pkt_out_string(&err, &buf, &blen, "%s", name); break; case ARM_SPE_EVENTS: - arm_spe_pkt_out_string(&err, &buf, &blen, "EV"); - - if (payload & 0x1) - arm_spe_pkt_out_string(&err, &buf, &blen, " EXCEPTION-GEN"); - if (payload & 0x2) - arm_spe_pkt_out_string(&err, &buf, &blen, " RETIRED"); - if (payload & 0x4) - arm_spe_pkt_out_string(&err, &buf, &blen, " L1D-ACCESS"); - if (payload & 0x8) - arm_spe_pkt_out_string(&err, &buf, &blen, " L1D-REFILL"); - if (payload & 0x10) - arm_spe_pkt_out_string(&err, &buf, &blen, " TLB-ACCESS"); - if (payload & 0x20) - arm_spe_pkt_out_string(&err, &buf, &blen, " TLB-REFILL"); - if (payload & 0x40) - arm_spe_pkt_out_string(&err, &buf, &blen, " NOT-TAKEN"); - if (payload & 0x80) - arm_spe_pkt_out_string(&err, &buf, &blen, " MISPRED"); - if (idx > 1) { - if (payload & 0x100) - arm_spe_pkt_out_string(&err, &buf, &blen, " LLC-ACCESS"); - if (payload & 0x200) - arm_spe_pkt_out_string(&err, &buf, &blen, " LLC-REFILL"); - if (payload & 0x400) - arm_spe_pkt_out_string(&err, &buf, &blen, " REMOTE-ACCESS"); - } + err = arm_spe_pkt_desc_event(packet, buf, buf_len); break; case ARM_SPE_OP_TYPE: switch (idx) {
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit 889d1a675fcf category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
Move the enums of event types to arm-spe-pkt-decoder.h, thus function arm_spe_pkt_desc_event() can use them for bitmasks.
Suggested-by: Andre Przywara andre.przywara@arm.com Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: Andre Przywara andre.przywara@arm.com Acked-by: Will Deacon will@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: Dave Martin Dave.Martin@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: James Clark james.clark@arm.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Wei Li liwei391@huawei.com Link: https://lore.kernel.org/r/20201119152441.6972-11-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- .../util/arm-spe-decoder/arm-spe-decoder.h | 17 -------------- .../arm-spe-decoder/arm-spe-pkt-decoder.c | 22 +++++++++---------- .../arm-spe-decoder/arm-spe-pkt-decoder.h | 18 +++++++++++++++ 3 files changed, 29 insertions(+), 28 deletions(-)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h index a5111a8d4360..24727b8ca7ff 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h +++ b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h @@ -13,23 +13,6 @@
#include "arm-spe-pkt-decoder.h"
-enum arm_spe_events { - EV_EXCEPTION_GEN = 0, - EV_RETIRED = 1, - EV_L1D_ACCESS = 2, - EV_L1D_REFILL = 3, - EV_TLB_ACCESS = 4, - EV_TLB_WALK = 5, - EV_NOT_TAKEN = 6, - EV_MISPRED = 7, - EV_LLC_ACCESS = 8, - EV_LLC_MISS = 9, - EV_REMOTE_ACCESS = 10, - EV_ALIGNMENT = 11, - EV_PARTIAL_PREDICATE = 17, - EV_EMPTY_PREDICATE = 18, -}; - enum arm_spe_sample_type { ARM_SPE_L1D_ACCESS = 1 << 0, ARM_SPE_L1D_MISS = 1 << 1, diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index da6b9f76739c..3f30b2937715 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -295,28 +295,28 @@ static int arm_spe_pkt_desc_event(const struct arm_spe_pkt *packet,
arm_spe_pkt_out_string(&err, &buf, &buf_len, "EV");
- if (payload & 0x1) + if (payload & BIT(EV_EXCEPTION_GEN)) arm_spe_pkt_out_string(&err, &buf, &buf_len, " EXCEPTION-GEN"); - if (payload & 0x2) + if (payload & BIT(EV_RETIRED)) arm_spe_pkt_out_string(&err, &buf, &buf_len, " RETIRED"); - if (payload & 0x4) + if (payload & BIT(EV_L1D_ACCESS)) arm_spe_pkt_out_string(&err, &buf, &buf_len, " L1D-ACCESS"); - if (payload & 0x8) + if (payload & BIT(EV_L1D_REFILL)) arm_spe_pkt_out_string(&err, &buf, &buf_len, " L1D-REFILL"); - if (payload & 0x10) + if (payload & BIT(EV_TLB_ACCESS)) arm_spe_pkt_out_string(&err, &buf, &buf_len, " TLB-ACCESS"); - if (payload & 0x20) + if (payload & BIT(EV_TLB_WALK)) arm_spe_pkt_out_string(&err, &buf, &buf_len, " TLB-REFILL"); - if (payload & 0x40) + if (payload & BIT(EV_NOT_TAKEN)) arm_spe_pkt_out_string(&err, &buf, &buf_len, " NOT-TAKEN"); - if (payload & 0x80) + if (payload & BIT(EV_MISPRED)) arm_spe_pkt_out_string(&err, &buf, &buf_len, " MISPRED"); if (packet->index > 1) { - if (payload & 0x100) + if (payload & BIT(EV_LLC_ACCESS)) arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-ACCESS"); - if (payload & 0x200) + if (payload & BIT(EV_LLC_MISS)) arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-REFILL"); - if (payload & 0x400) + if (payload & BIT(EV_REMOTE_ACCESS)) arm_spe_pkt_out_string(&err, &buf, &buf_len, " REMOTE-ACCESS"); }
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h index 7d8e34e35f05..42ed4e61ede2 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h @@ -87,6 +87,24 @@ struct arm_spe_pkt { #define SPE_CNT_PKT_HDR_INDEX_ISSUE_LAT 0x1 #define SPE_CNT_PKT_HDR_INDEX_TRANS_LAT 0x2
+/* Event packet payload */ +enum arm_spe_events { + EV_EXCEPTION_GEN = 0, + EV_RETIRED = 1, + EV_L1D_ACCESS = 2, + EV_L1D_REFILL = 3, + EV_TLB_ACCESS = 4, + EV_TLB_WALK = 5, + EV_NOT_TAKEN = 6, + EV_MISPRED = 7, + EV_LLC_ACCESS = 8, + EV_LLC_MISS = 9, + EV_REMOTE_ACCESS = 10, + EV_ALIGNMENT = 11, + EV_PARTIAL_PREDICATE = 17, + EV_EMPTY_PREDICATE = 18, +}; + const char *arm_spe_pkt_name(enum arm_spe_pkt_type);
int arm_spe_get_packet(const unsigned char *buf, size_t len,
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit 4d0f4ca273aa category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
In the Armv8 ARM (ARM DDI 0487F.c), chapter "D10.2.6 Events packet", it describes the event bit is valid with specific payload requirement. For example, the Last Level cache access event, the bit is defined as:
E[8], byte 1 bit [0], when SZ == 0b01 , when SZ == 0b10 , or when SZ == 0b11
It requires the payload size is at least 2 bytes, when byte 1 (start counting from 0) is valid, E[8] (bit 0 in byte 1) can be used for LLC access event type. For safety, the code checks the condition for payload size firstly, if meet the requirement for payload size, then continue to parse event type.
If review function arm_spe_get_payload(), it has used cast, so any bytes beyond the valid size have been set to zeros.
For this reason, we don't need to check payload size anymore afterwards when parse events, thus this patch removes payload size conditions.
Suggested-by: Andre Przywara andre.przywara@arm.com Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: Andre Przywara andre.przywara@arm.com Acked-by: Will Deacon will@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: Dave Martin Dave.Martin@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: James Clark james.clark@arm.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Wei Li liwei391@huawei.com Link: https://lore.kernel.org/r/20201119152441.6972-12-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe-decoder/arm-spe-decoder.c | 9 +++------ .../util/arm-spe-decoder/arm-spe-pkt-decoder.c | 14 ++++++-------- 2 files changed, 9 insertions(+), 14 deletions(-)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c index cac2ef79c025..90d575cee1b9 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c @@ -192,16 +192,13 @@ static int arm_spe_read_record(struct arm_spe_decoder *decoder) if (payload & BIT(EV_TLB_ACCESS)) decoder->record.type |= ARM_SPE_TLB_ACCESS;
- if ((idx == 2 || idx == 4 || idx == 8) && - (payload & BIT(EV_LLC_MISS))) + if (payload & BIT(EV_LLC_MISS)) decoder->record.type |= ARM_SPE_LLC_MISS;
- if ((idx == 2 || idx == 4 || idx == 8) && - (payload & BIT(EV_LLC_ACCESS))) + if (payload & BIT(EV_LLC_ACCESS)) decoder->record.type |= ARM_SPE_LLC_ACCESS;
- if ((idx == 2 || idx == 4 || idx == 8) && - (payload & BIT(EV_REMOTE_ACCESS))) + if (payload & BIT(EV_REMOTE_ACCESS)) decoder->record.type |= ARM_SPE_REMOTE_ACCESS;
if (payload & BIT(EV_MISPRED)) diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index 3f30b2937715..88bcf7e5be76 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -311,14 +311,12 @@ static int arm_spe_pkt_desc_event(const struct arm_spe_pkt *packet, arm_spe_pkt_out_string(&err, &buf, &buf_len, " NOT-TAKEN"); if (payload & BIT(EV_MISPRED)) arm_spe_pkt_out_string(&err, &buf, &buf_len, " MISPRED"); - if (packet->index > 1) { - if (payload & BIT(EV_LLC_ACCESS)) - arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-ACCESS"); - if (payload & BIT(EV_LLC_MISS)) - arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-REFILL"); - if (payload & BIT(EV_REMOTE_ACCESS)) - arm_spe_pkt_out_string(&err, &buf, &buf_len, " REMOTE-ACCESS"); - } + if (payload & BIT(EV_LLC_ACCESS)) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-ACCESS"); + if (payload & BIT(EV_LLC_MISS)) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-REFILL"); + if (payload & BIT(EV_REMOTE_ACCESS)) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " REMOTE-ACCESS");
return err; }
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit 7488ffc4d981 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
The operation type packet is complex and contains subclass; the parsing flow causes deep indentation; for more readable, this patch introduces a new function arm_spe_pkt_desc_op_type() which is used for operation type parsing.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: Andre Przywara andre.przywara@arm.com Acked-by: Will Deacon will@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: Dave Martin Dave.Martin@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: James Clark james.clark@arm.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Wei Li liwei391@huawei.com Link: https://lore.kernel.org/r/20201119152441.6972-13-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- .../arm-spe-decoder/arm-spe-pkt-decoder.c | 79 +++++++++++-------- 1 file changed, 45 insertions(+), 34 deletions(-)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index 88bcf7e5be76..d6c060f119b4 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -321,6 +321,50 @@ static int arm_spe_pkt_desc_event(const struct arm_spe_pkt *packet, return err; }
+static int arm_spe_pkt_desc_op_type(const struct arm_spe_pkt *packet, + char *buf, size_t buf_len) +{ + u64 payload = packet->payload; + int err = 0; + + switch (packet->index) { + case 0: + arm_spe_pkt_out_string(&err, &buf, &buf_len, + payload & 0x1 ? "COND-SELECT" : "INSN-OTHER"); + break; + case 1: + arm_spe_pkt_out_string(&err, &buf, &buf_len, + payload & 0x1 ? "ST" : "LD"); + + if (payload & 0x2) { + if (payload & 0x4) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " AT"); + if (payload & 0x8) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " EXCL"); + if (payload & 0x10) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " AR"); + } else if (payload & 0x4) { + arm_spe_pkt_out_string(&err, &buf, &buf_len, " SIMD-FP"); + } + break; + case 2: + arm_spe_pkt_out_string(&err, &buf, &buf_len, "B"); + + if (payload & 0x1) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " COND"); + if (payload & 0x2) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " IND"); + + break; + default: + /* Unknown index */ + err = -1; + break; + } + + return err; +} + static int arm_spe_pkt_desc_addr(const struct arm_spe_pkt *packet, char *buf, size_t buf_len) { @@ -404,40 +448,7 @@ int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf, err = arm_spe_pkt_desc_event(packet, buf, buf_len); break; case ARM_SPE_OP_TYPE: - switch (idx) { - case 0: - arm_spe_pkt_out_string(&err, &buf, &blen, - payload & 0x1 ? "COND-SELECT" : "INSN-OTHER"); - break; - case 1: - arm_spe_pkt_out_string(&err, &buf, &blen, - payload & 0x1 ? "ST" : "LD"); - - if (payload & 0x2) { - if (payload & 0x4) - arm_spe_pkt_out_string(&err, &buf, &blen, " AT"); - if (payload & 0x8) - arm_spe_pkt_out_string(&err, &buf, &blen, " EXCL"); - if (payload & 0x10) - arm_spe_pkt_out_string(&err, &buf, &blen, " AR"); - } else if (payload & 0x4) { - arm_spe_pkt_out_string(&err, &buf, &blen, " SIMD-FP"); - } - break; - case 2: - arm_spe_pkt_out_string(&err, &buf, &blen, "B"); - - if (payload & 0x1) - arm_spe_pkt_out_string(&err, &buf, &blen, " COND"); - if (payload & 0x2) - arm_spe_pkt_out_string(&err, &buf, &blen, " IND"); - - break; - default: - /* Unknown index */ - err = -1; - break; - } + err = arm_spe_pkt_desc_op_type(packet, buf, buf_len); break; case ARM_SPE_DATA_SOURCE: case ARM_SPE_TIMESTAMP:
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit e771218f32f9 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
Defines macros for operation packet header and formats (support sub classes for 'other', 'branch', 'load and store', etc). Uses these macros for operation packet decoding and dumping.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: Andre Przywara andre.przywara@arm.com Acked-by: Will Deacon will@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: Dave Martin Dave.Martin@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: James Clark james.clark@arm.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Wei Li liwei391@huawei.com Link: https://lore.kernel.org/r/20201119152441.6972-14-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- .../arm-spe-decoder/arm-spe-pkt-decoder.c | 26 ++++++++++--------- .../arm-spe-decoder/arm-spe-pkt-decoder.h | 23 ++++++++++++++++ 2 files changed, 37 insertions(+), 12 deletions(-)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index d6c060f119b4..1d1354a0eef4 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -144,7 +144,7 @@ static int arm_spe_get_op_type(const unsigned char *buf, size_t len, struct arm_spe_pkt *packet) { packet->type = ARM_SPE_OP_TYPE; - packet->index = buf[0] & 0x3; + packet->index = SPE_OP_PKT_HDR_CLASS(buf[0]); return arm_spe_get_payload(buf, len, 0, packet); }
@@ -328,31 +328,33 @@ static int arm_spe_pkt_desc_op_type(const struct arm_spe_pkt *packet, int err = 0;
switch (packet->index) { - case 0: + case SPE_OP_PKT_HDR_CLASS_OTHER: arm_spe_pkt_out_string(&err, &buf, &buf_len, - payload & 0x1 ? "COND-SELECT" : "INSN-OTHER"); + payload & SPE_OP_PKT_COND ? "COND-SELECT" : "INSN-OTHER"); break; - case 1: + case SPE_OP_PKT_HDR_CLASS_LD_ST_ATOMIC: arm_spe_pkt_out_string(&err, &buf, &buf_len, payload & 0x1 ? "ST" : "LD");
- if (payload & 0x2) { - if (payload & 0x4) + if (SPE_OP_PKT_IS_LDST_ATOMIC(payload)) { + if (payload & SPE_OP_PKT_AT) arm_spe_pkt_out_string(&err, &buf, &buf_len, " AT"); - if (payload & 0x8) + if (payload & SPE_OP_PKT_EXCL) arm_spe_pkt_out_string(&err, &buf, &buf_len, " EXCL"); - if (payload & 0x10) + if (payload & SPE_OP_PKT_AR) arm_spe_pkt_out_string(&err, &buf, &buf_len, " AR"); - } else if (payload & 0x4) { + } else if (SPE_OP_PKT_LDST_SUBCLASS_GET(payload) == + SPE_OP_PKT_LDST_SUBCLASS_SIMD_FP) { arm_spe_pkt_out_string(&err, &buf, &buf_len, " SIMD-FP"); } break; - case 2: + case SPE_OP_PKT_HDR_CLASS_BR_ERET: arm_spe_pkt_out_string(&err, &buf, &buf_len, "B");
- if (payload & 0x1) + if (payload & SPE_OP_PKT_COND) arm_spe_pkt_out_string(&err, &buf, &buf_len, " COND"); - if (payload & 0x2) + + if (SPE_OP_PKT_IS_INDIRECT_BRANCH(payload)) arm_spe_pkt_out_string(&err, &buf, &buf_len, " IND");
break; diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h index 42ed4e61ede2..7032fc141ad4 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h @@ -105,6 +105,29 @@ enum arm_spe_events { EV_EMPTY_PREDICATE = 18, };
+/* Operation packet header */ +#define SPE_OP_PKT_HDR_CLASS(h) ((h) & GENMASK_ULL(1, 0)) +#define SPE_OP_PKT_HDR_CLASS_OTHER 0x0 +#define SPE_OP_PKT_HDR_CLASS_LD_ST_ATOMIC 0x1 +#define SPE_OP_PKT_HDR_CLASS_BR_ERET 0x2 + +#define SPE_OP_PKT_COND BIT(0) + +#define SPE_OP_PKT_LDST_SUBCLASS_GET(v) ((v) & GENMASK_ULL(7, 1)) +#define SPE_OP_PKT_LDST_SUBCLASS_GP_REG 0x0 +#define SPE_OP_PKT_LDST_SUBCLASS_SIMD_FP 0x4 +#define SPE_OP_PKT_LDST_SUBCLASS_UNSPEC_REG 0x10 +#define SPE_OP_PKT_LDST_SUBCLASS_NV_SYSREG 0x30 + +#define SPE_OP_PKT_IS_LDST_ATOMIC(v) (((v) & (GENMASK_ULL(7, 5) | BIT(1))) == 0x2) + +#define SPE_OP_PKT_AR BIT(4) +#define SPE_OP_PKT_EXCL BIT(3) +#define SPE_OP_PKT_AT BIT(2) +#define SPE_OP_PKT_ST BIT(0) + +#define SPE_OP_PKT_IS_INDIRECT_BRANCH(v) (((v) & GENMASK_ULL(7, 1)) == 0x2) + const char *arm_spe_pkt_name(enum arm_spe_pkt_type);
int arm_spe_get_packet(const unsigned char *buf, size_t len,
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.11-rc1 commit 3d829724b16c category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
For the operation type packet payload with load/store class, it misses to support these sub classes:
- A load/store targeting the general-purpose registers; - A load/store targeting unspecified registers; - The ARMv8.4 nested virtualisation extension can redirect system register accesses to a memory page controlled by the hypervisor. The SPE profiling feature in newer implementations can tag those memory accesses accordingly.
Add the bit pattern describing load/store sub classes, so that the perf tool can decode it properly.
Inspired by Andre Przywara, refined the commit log and code for more clear description.
Co-developed-by: Andre Przywara andre.przywara@arm.com Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: Andre Przywara andre.przywara@arm.com Acked-by: Will Deacon will@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: Dave Martin Dave.Martin@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: James Clark james.clark@arm.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Wei Li liwei391@huawei.com Link: https://lore.kernel.org/r/20201119152441.6972-15-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- .../util/arm-spe-decoder/arm-spe-pkt-decoder.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index 1d1354a0eef4..84d661aab54f 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -343,9 +343,23 @@ static int arm_spe_pkt_desc_op_type(const struct arm_spe_pkt *packet, arm_spe_pkt_out_string(&err, &buf, &buf_len, " EXCL"); if (payload & SPE_OP_PKT_AR) arm_spe_pkt_out_string(&err, &buf, &buf_len, " AR"); - } else if (SPE_OP_PKT_LDST_SUBCLASS_GET(payload) == - SPE_OP_PKT_LDST_SUBCLASS_SIMD_FP) { + } + + switch (SPE_OP_PKT_LDST_SUBCLASS_GET(payload)) { + case SPE_OP_PKT_LDST_SUBCLASS_SIMD_FP: arm_spe_pkt_out_string(&err, &buf, &buf_len, " SIMD-FP"); + break; + case SPE_OP_PKT_LDST_SUBCLASS_GP_REG: + arm_spe_pkt_out_string(&err, &buf, &buf_len, " GP-REG"); + break; + case SPE_OP_PKT_LDST_SUBCLASS_UNSPEC_REG: + arm_spe_pkt_out_string(&err, &buf, &buf_len, " UNSPEC-REG"); + break; + case SPE_OP_PKT_LDST_SUBCLASS_NV_SYSREG: + arm_spe_pkt_out_string(&err, &buf, &buf_len, " NV-SYSREG"); + break; + default: + break; } break; case SPE_OP_PKT_HDR_CLASS_BR_ERET:
From: Andre Przywara andre.przywara@arm.com
mainline inclusion from mainline-v5.11-rc1 commit 3601e605501d category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
When SPE records a physical address, it can additionally tag the event with information from the Memory Tagging architecture extension.
Decode the two additional fields in the SPE event payload.
[leoy: Refined patch to use predefined macros]
Signed-off-by: Andre Przywara andre.przywara@arm.com Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: Dave Martin Dave.Martin@arm.com Acked-by: Will Deacon will@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: Ingo Molnar mingo@redhat.com Cc: James Clark james.clark@arm.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Wei Li liwei391@huawei.com Link: https://lore.kernel.org/r/20201119152441.6972-16-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c | 6 +++++- tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index 84d661aab54f..57c01ce27915 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -385,6 +385,7 @@ static int arm_spe_pkt_desc_addr(const struct arm_spe_pkt *packet, char *buf, size_t buf_len) { int ns, el, idx = packet->index; + int ch, pat; u64 payload = packet->payload; int err = 0;
@@ -404,9 +405,12 @@ static int arm_spe_pkt_desc_addr(const struct arm_spe_pkt *packet, break; case SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS: ns = !!SPE_ADDR_PKT_GET_NS(payload); + ch = !!SPE_ADDR_PKT_GET_CH(payload); + pat = SPE_ADDR_PKT_GET_PAT(payload); payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload); arm_spe_pkt_out_string(&err, &buf, &buf_len, - "PA 0x%llx ns=%d", payload, ns); + "PA 0x%llx ns=%d ch=%d pat=%x", + payload, ns, ch, pat); break; default: /* Unknown index */ diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h index 7032fc141ad4..1ad14885c2a1 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h @@ -73,6 +73,8 @@ struct arm_spe_pkt {
#define SPE_ADDR_PKT_GET_NS(v) (((v) & BIT_ULL(63)) >> 63) #define SPE_ADDR_PKT_GET_EL(v) (((v) & GENMASK_ULL(62, 61)) >> 61) +#define SPE_ADDR_PKT_GET_CH(v) (((v) & BIT_ULL(62)) >> 62) +#define SPE_ADDR_PKT_GET_PAT(v) (((v) & GENMASK_ULL(59, 56)) >> 56)
#define SPE_ADDR_PKT_EL0 0 #define SPE_ADDR_PKT_EL1 1
From: Wei Li liwei391@huawei.com
mainline inclusion from mainline-v5.11-rc1 commit 05e91e7fe26c category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
This patch is to support Armv8.3 extension for SPE, it adds alignment field in the Events packet and it supports the Scalable Vector Extension (SVE) for Operation packet and Events packet with two additions:
- The vector length for SVE operations in the Operation Type packet; - The incomplete predicate and empty predicate fields in the Events packet.
Signed-off-by: Wei Li liwei391@huawei.com Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: Andre Przywara andre.przywara@arm.com Acked-by: Will Deacon will@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: Dave Martin Dave.Martin@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: James Clark james.clark@arm.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Link: https://lore.kernel.org/r/20201119152441.6972-17-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- .../arm-spe-decoder/arm-spe-pkt-decoder.c | 36 +++++++++++++++++-- .../arm-spe-decoder/arm-spe-pkt-decoder.h | 16 +++++++++ 2 files changed, 50 insertions(+), 2 deletions(-)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index 57c01ce27915..f3ac9d40cebf 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -317,6 +317,12 @@ static int arm_spe_pkt_desc_event(const struct arm_spe_pkt *packet, arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-REFILL"); if (payload & BIT(EV_REMOTE_ACCESS)) arm_spe_pkt_out_string(&err, &buf, &buf_len, " REMOTE-ACCESS"); + if (payload & BIT(EV_ALIGNMENT)) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " ALIGNMENT"); + if (payload & BIT(EV_PARTIAL_PREDICATE)) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " SVE-PARTIAL-PRED"); + if (payload & BIT(EV_EMPTY_PREDICATE)) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " SVE-EMPTY-PRED");
return err; } @@ -329,8 +335,23 @@ static int arm_spe_pkt_desc_op_type(const struct arm_spe_pkt *packet,
switch (packet->index) { case SPE_OP_PKT_HDR_CLASS_OTHER: - arm_spe_pkt_out_string(&err, &buf, &buf_len, - payload & SPE_OP_PKT_COND ? "COND-SELECT" : "INSN-OTHER"); + if (SPE_OP_PKT_IS_OTHER_SVE_OP(payload)) { + arm_spe_pkt_out_string(&err, &buf, &buf_len, "SVE-OTHER"); + + /* SVE effective vector length */ + arm_spe_pkt_out_string(&err, &buf, &buf_len, " EVLEN %d", + SPE_OP_PKG_SVE_EVL(payload)); + + if (payload & SPE_OP_PKT_SVE_FP) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " FP"); + if (payload & SPE_OP_PKT_SVE_PRED) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " PRED"); + } else { + arm_spe_pkt_out_string(&err, &buf, &buf_len, "OTHER"); + arm_spe_pkt_out_string(&err, &buf, &buf_len, " %s", + payload & SPE_OP_PKT_COND ? + "COND-SELECT" : "INSN-OTHER"); + } break; case SPE_OP_PKT_HDR_CLASS_LD_ST_ATOMIC: arm_spe_pkt_out_string(&err, &buf, &buf_len, @@ -361,6 +382,17 @@ static int arm_spe_pkt_desc_op_type(const struct arm_spe_pkt *packet, default: break; } + + if (SPE_OP_PKT_IS_LDST_SVE(payload)) { + /* SVE effective vector length */ + arm_spe_pkt_out_string(&err, &buf, &buf_len, " EVLEN %d", + SPE_OP_PKG_SVE_EVL(payload)); + + if (payload & SPE_OP_PKT_SVE_PRED) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " PRED"); + if (payload & SPE_OP_PKT_SVE_SG) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " SG"); + } break; case SPE_OP_PKT_HDR_CLASS_BR_ERET: arm_spe_pkt_out_string(&err, &buf, &buf_len, "B"); diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h index 1ad14885c2a1..9b970e7bf1e2 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h @@ -113,6 +113,8 @@ enum arm_spe_events { #define SPE_OP_PKT_HDR_CLASS_LD_ST_ATOMIC 0x1 #define SPE_OP_PKT_HDR_CLASS_BR_ERET 0x2
+#define SPE_OP_PKT_IS_OTHER_SVE_OP(v) (((v) & (BIT(7) | BIT(3) | BIT(0))) == 0x8) + #define SPE_OP_PKT_COND BIT(0)
#define SPE_OP_PKT_LDST_SUBCLASS_GET(v) ((v) & GENMASK_ULL(7, 1)) @@ -128,6 +130,20 @@ enum arm_spe_events { #define SPE_OP_PKT_AT BIT(2) #define SPE_OP_PKT_ST BIT(0)
+#define SPE_OP_PKT_IS_LDST_SVE(v) (((v) & (BIT(3) | BIT(1))) == 0x8) + +#define SPE_OP_PKT_SVE_SG BIT(7) +/* + * SVE effective vector length (EVL) is stored in byte 0 bits [6:4]; + * the length is rounded up to a power of two and use 32 as one step, + * so EVL calculation is: + * + * 32 * (2 ^ bits [6:4]) = 32 << (bits [6:4]) + */ +#define SPE_OP_PKG_SVE_EVL(v) (32 << (((v) & GENMASK_ULL(6, 4)) >> 4)) +#define SPE_OP_PKT_SVE_PRED BIT(2) +#define SPE_OP_PKT_SVE_FP BIT(1) + #define SPE_OP_PKT_IS_INDIRECT_BRANCH(v) (((v) & GENMASK_ULL(7, 1)) == 0x2)
const char *arm_spe_pkt_name(enum arm_spe_pkt_type);
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.12-rc1 commit 1834436e340c category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
For shared cache line statistics, 'perf c2c' relies on HITM. We can use more general naming rather than only binding to HITM, so replace "hitm_stats" with "shared_clines_stats" in structure perf_c2c, and rename function resort_hitm_cb() to resort_shared_cl_cb().
Signed-off-by: Leo Yan leo.yan@linaro.org Acked-by: Jiri Olsa jolsa@redhat.com Acked-by: Namhyung Kim namhyung@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: David Ahern dsahern@gmail.com Cc: Don Zickus dzickus@redhat.com Cc: Ingo Molnar mingo@redhat.com Cc: Joe Mario jmario@redhat.com Cc: Joe Perches joe@perches.com Cc: Mark Rutland mark.rutland@arm.com Cc: Peter Zijlstra peterz@infradead.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Link: https://lore.kernel.org/r/20210114154646.209024-2-leo.yan@linaro.org Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/builtin-c2c.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index c5babeaa3b38..2d0c71300dbf 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -97,8 +97,8 @@ struct perf_c2c { bool symbol_full; bool stitch_lbr;
- /* HITM shared clines stats */ - struct c2c_stats hitm_stats; + /* Shared cache line stats */ + struct c2c_stats shared_clines_stats; int shared_clines;
int display; @@ -1961,7 +1961,7 @@ static int resort_cl_cb(struct hist_entry *he, void *arg __maybe_unused) { struct c2c_hist_entry *c2c_he; struct c2c_hists *c2c_hists; - bool display = he__display(he, &c2c.hitm_stats); + bool display = he__display(he, &c2c.shared_clines_stats);
c2c_he = container_of(he, struct c2c_hist_entry, he); c2c_hists = c2c_he->hists; @@ -2048,14 +2048,14 @@ static int setup_nodes(struct perf_session *session)
#define HAS_HITMS(__h) ((__h)->stats.lcl_hitm || (__h)->stats.rmt_hitm)
-static int resort_hitm_cb(struct hist_entry *he, void *arg __maybe_unused) +static int resort_shared_cl_cb(struct hist_entry *he, void *arg __maybe_unused) { struct c2c_hist_entry *c2c_he; c2c_he = container_of(he, struct c2c_hist_entry, he);
if (HAS_HITMS(c2c_he)) { c2c.shared_clines++; - c2c_add_stats(&c2c.hitm_stats, &c2c_he->stats); + c2c_add_stats(&c2c.shared_clines_stats, &c2c_he->stats); }
return 0; @@ -2126,7 +2126,7 @@ static void print_c2c__display_stats(FILE *out)
static void print_shared_cacheline_info(FILE *out) { - struct c2c_stats *stats = &c2c.hitm_stats; + struct c2c_stats *stats = &c2c.shared_clines_stats; int hitm_cnt = stats->lcl_hitm + stats->rmt_hitm;
fprintf(out, "=================================================\n"); @@ -2827,7 +2827,7 @@ static int perf_c2c__report(int argc, const char **argv) ui_progress__init(&prog, c2c.hists.hists.nr_entries, "Sorting...");
hists__collapse_resort(&c2c.hists.hists, NULL); - hists__output_resort_cb(&c2c.hists.hists, &prog, resort_hitm_cb); + hists__output_resort_cb(&c2c.hists.hists, &prog, resort_shared_cl_cb); hists__iterate_cb(&c2c.hists.hists, resort_cl_cb);
ui_progress__finish();
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.12-rc1 commit 2290e1d6193b category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
This patch has no functionality changes but refactors hist entry validation for cache line resorting.
It renames function "valid_hitm_or_store()" to "is_valid_hist_entry()", changes return type from integer type to bool type. In the function, it uses switch-case instead of ternary operators, which is easier to extend for more display types.
Signed-off-by: Leo Yan leo.yan@linaro.org Acked-by: Jiri Olsa jolsa@redhat.com Acked-by: Namhyung Kim namhyung@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: David Ahern dsahern@gmail.com Cc: Don Zickus dzickus@redhat.com Cc: Ingo Molnar mingo@redhat.com Cc: Joe Mario jmario@redhat.com Cc: Joe Perches joe@perches.com Cc: Mark Rutland mark.rutland@arm.com Cc: Peter Zijlstra peterz@infradead.org Link: https://lore.kernel.org/r/20210114154646.209024-3-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/builtin-c2c.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-)
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 2d0c71300dbf..bc2ee84298ff 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -1888,16 +1888,32 @@ static bool he__display(struct hist_entry *he, struct c2c_stats *stats) return he->filtered == 0; }
-static inline int valid_hitm_or_store(struct hist_entry *he) +static inline bool is_valid_hist_entry(struct hist_entry *he) { struct c2c_hist_entry *c2c_he; - bool has_hitm; + bool has_record = false;
c2c_he = container_of(he, struct c2c_hist_entry, he); - has_hitm = c2c.display == DISPLAY_TOT ? c2c_he->stats.tot_hitm : - c2c.display == DISPLAY_LCL ? c2c_he->stats.lcl_hitm : - c2c_he->stats.rmt_hitm; - return has_hitm || c2c_he->stats.store; + + /* It's a valid entry if contains stores */ + if (c2c_he->stats.store) + return true; + + switch (c2c.display) { + case DISPLAY_LCL: + has_record = !!c2c_he->stats.lcl_hitm; + break; + case DISPLAY_RMT: + has_record = !!c2c_he->stats.rmt_hitm; + break; + case DISPLAY_TOT: + has_record = !!c2c_he->stats.tot_hitm; + break; + default: + break; + } + + return has_record; }
static void set_node_width(struct c2c_hist_entry *c2c_he, int len) @@ -1951,7 +1967,7 @@ static int filter_cb(struct hist_entry *he, void *arg __maybe_unused)
calc_width(c2c_he);
- if (!valid_hitm_or_store(he)) + if (!is_valid_hist_entry(he)) he->filtered = HIST_FILTER__C2C;
return 0;
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.12-rc1 commit 69a95bfdf95b category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
When sorting on the respective metrics (lcl_hitm, rmt_hitm, tot_hitm), the FILTER_HITM macro is used to filter out the cache line entries if its overhead is less than 1%.
This patch introduces a static function filter_display() to replace that macro and refines its parameters with a more flexible way, rather than passing field name, it changes to pass the cache line's statistic and sum value.
Signed-off-by: Leo Yan leo.yan@linaro.org Acked-by: Namhyung Kim namhyung@kernel.org Acked-by: Jiri Olsa jolsa@redhat.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: David Ahern dsahern@gmail.com Cc: Don Zickus dzickus@redhat.com Cc: Ingo Molnar mingo@redhat.com Cc: Joe Mario jmario@redhat.com Cc: Joe Perches joe@perches.com Cc: Mark Rutland mark.rutland@arm.com Cc: Peter Zijlstra peterz@infradead.org Link: https://lore.kernel.org/r/20210114154646.209024-4-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/builtin-c2c.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index bc2ee84298ff..7aaccea00883 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -1851,40 +1851,40 @@ static int c2c_hists__reinit(struct c2c_hists *c2c_hists,
#define DISPLAY_LINE_LIMIT 0.001
+static u8 filter_display(u32 val, u32 sum) +{ + if (sum == 0 || ((double)val / sum) < DISPLAY_LINE_LIMIT) + return HIST_FILTER__C2C; + + return 0; +} + static bool he__display(struct hist_entry *he, struct c2c_stats *stats) { struct c2c_hist_entry *c2c_he; - double ld_dist;
if (c2c.show_all) return true;
c2c_he = container_of(he, struct c2c_hist_entry, he);
-#define FILTER_HITM(__h) \ - if (stats->__h) { \ - ld_dist = ((double)c2c_he->stats.__h / stats->__h); \ - if (ld_dist < DISPLAY_LINE_LIMIT) \ - he->filtered = HIST_FILTER__C2C; \ - } else { \ - he->filtered = HIST_FILTER__C2C; \ - } - switch (c2c.display) { case DISPLAY_LCL: - FILTER_HITM(lcl_hitm); + he->filtered = filter_display(c2c_he->stats.lcl_hitm, + stats->lcl_hitm); break; case DISPLAY_RMT: - FILTER_HITM(rmt_hitm); + he->filtered = filter_display(c2c_he->stats.rmt_hitm, + stats->rmt_hitm); break; case DISPLAY_TOT: - FILTER_HITM(tot_hitm); + he->filtered = filter_display(c2c_he->stats.tot_hitm, + stats->tot_hitm); + break; default: break; }
-#undef FILTER_HITM - return he->filtered == 0; }
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.12-rc1 commit 111c14159117 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
For percent() its arguments are defined as integers; this is not consistent with its consumers which pass u32 arguments.
Thus this patch makes argument type as u32 for percent().
Signed-off-by: Leo Yan leo.yan@linaro.org Acked-by: Namhyung Kim namhyung@kernel.org Acked-by: Jiri Olsa jolsa@redhat.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: David Ahern dsahern@gmail.com Cc: Don Zickus dzickus@redhat.com Cc: Ingo Molnar mingo@redhat.com Cc: Joe Mario jmario@redhat.com Cc: Joe Perches joe@perches.com Cc: Mark Rutland mark.rutland@arm.com Cc: Peter Zijlstra peterz@infradead.org Link: https://lore.kernel.org/r/20210114154646.209024-5-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/builtin-c2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 7aaccea00883..7702f9599162 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -876,7 +876,7 @@ static struct c2c_stats *total_stats(struct hist_entry *he) return &hists->stats; }
-static double percent(int st, int tot) +static double percent(u32 st, u32 tot) { return tot ? 100. * (double) st / (double) tot : 0; }
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.12-rc1 commit f3d0a551db13 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
The macro DISPLAY_HITM() is used to calculate HITM percentage introduced by every node and it's shown for the node info.
This patch introduces the static function display_metrics() to replace the macro, and the parameters are refined for passing the metric's statistic and sum value.
Signed-off-by: Leo Yan leo.yan@linaro.org Acked-by: Namhyung Kim namhyung@kernel.org Acked-by: Jiri Olsa jolsa@redhat.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: David Ahern dsahern@gmail.com Cc: Don Zickus dzickus@redhat.com Cc: Ingo Molnar mingo@redhat.com Cc: Joe Mario jmario@redhat.com Cc: Joe Perches joe@perches.com Cc: Mark Rutland mark.rutland@arm.com Cc: Peter Zijlstra peterz@infradead.org Link: https://lore.kernel.org/r/20210114154646.209024-6-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/builtin-c2c.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-)
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 7702f9599162..62213bef7b98 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -1048,6 +1048,19 @@ empty_cmp(struct perf_hpp_fmt *fmt __maybe_unused, return 0; }
+static int display_metrics(struct perf_hpp *hpp, u32 val, u32 sum) +{ + int ret; + + if (sum != 0) + ret = scnprintf(hpp->buf, hpp->size, "%5.1f%% ", + percent(val, sum)); + else + ret = scnprintf(hpp->buf, hpp->size, "%6s ", "n/a"); + + return ret; +} + static int node_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp, struct hist_entry *he) @@ -1091,29 +1104,23 @@ node_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp, ret = scnprintf(hpp->buf, hpp->size, "%2d{%2d ", node, num); advance_hpp(hpp, ret);
- #define DISPLAY_HITM(__h) \ - if (c2c_he->stats.__h> 0) { \ - ret = scnprintf(hpp->buf, hpp->size, "%5.1f%% ", \ - percent(stats->__h, c2c_he->stats.__h));\ - } else { \ - ret = scnprintf(hpp->buf, hpp->size, "%6s ", "n/a"); \ - } - switch (c2c.display) { case DISPLAY_RMT: - DISPLAY_HITM(rmt_hitm); + ret = display_metrics(hpp, stats->rmt_hitm, + c2c_he->stats.rmt_hitm); break; case DISPLAY_LCL: - DISPLAY_HITM(lcl_hitm); + ret = display_metrics(hpp, stats->lcl_hitm, + c2c_he->stats.lcl_hitm); break; case DISPLAY_TOT: - DISPLAY_HITM(tot_hitm); + ret = display_metrics(hpp, stats->tot_hitm, + c2c_he->stats.tot_hitm); + break; default: break; }
- #undef DISPLAY_HITM - advance_hpp(hpp, ret);
if (c2c_he->stats.store > 0) {
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.12-rc1 commit 0998d9604892 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
This patch adds several local variables:
"cl_output": pointer for outputting single cache line metrics; "output_str": pointer for outputting cache line metrics; "sort_str": pointer to the sorting metrics.
This can improve readability for the code and it's more flexible when later extend to different strings for the output metrics.
Signed-off-by: Leo Yan leo.yan@linaro.org Acked-by: Jiri Olsa jolsa@redhat.com Acked-by: Namhyung Kim namhyung@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: David Ahern dsahern@gmail.com Cc: Don Zickus dzickus@redhat.com Cc: Ingo Molnar mingo@redhat.com Cc: Joe Mario jmario@redhat.com Cc: Joe Perches joe@perches.com Cc: Mark Rutland mark.rutland@arm.com Cc: Peter Zijlstra peterz@infradead.org Link: https://lore.kernel.org/r/20210114154646.209024-7-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/builtin-c2c.c | 59 ++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 26 deletions(-)
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 62213bef7b98..d247f9878948 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -2199,16 +2199,17 @@ static void print_pareto(FILE *out) struct perf_hpp_list hpp_list; struct rb_node *nd; int ret; + const char *cl_output; + + cl_output = "cl_num," + "cl_rmt_hitm," + "cl_lcl_hitm," + "cl_stores_l1hit," + "cl_stores_l1miss," + "dcacheline";
perf_hpp_list__init(&hpp_list); - ret = hpp_list__parse(&hpp_list, - "cl_num," - "cl_rmt_hitm," - "cl_lcl_hitm," - "cl_stores_l1hit," - "cl_stores_l1miss," - "dcacheline", - NULL); + ret = hpp_list__parse(&hpp_list, cl_output, NULL);
if (WARN_ONCE(ret, "failed to setup sort entries\n")) return; @@ -2752,6 +2753,7 @@ static int perf_c2c__report(int argc, const char **argv) OPT_END() }; int err = 0; + const char *output_str, *sort_str = NULL;
argc = parse_options(argc, argv, options, report_c2c_usage, PARSE_OPT_STOP_AT_NON_OPTION); @@ -2828,24 +2830,29 @@ static int perf_c2c__report(int argc, const char **argv) goto out_mem2node; }
- c2c_hists__reinit(&c2c.hists, - "cl_idx," - "dcacheline," - "dcacheline_node," - "dcacheline_count," - "percent_hitm," - "tot_hitm,lcl_hitm,rmt_hitm," - "tot_recs," - "tot_loads," - "tot_stores," - "stores_l1hit,stores_l1miss," - "ld_fbhit,ld_l1hit,ld_l2hit," - "ld_lclhit,lcl_hitm," - "ld_rmthit,rmt_hitm," - "dram_lcl,dram_rmt", - c2c.display == DISPLAY_TOT ? "tot_hitm" : - c2c.display == DISPLAY_LCL ? "lcl_hitm" : "rmt_hitm" - ); + output_str = "cl_idx," + "dcacheline," + "dcacheline_node," + "dcacheline_count," + "percent_hitm," + "tot_hitm,lcl_hitm,rmt_hitm," + "tot_recs," + "tot_loads," + "tot_stores," + "stores_l1hit,stores_l1miss," + "ld_fbhit,ld_l1hit,ld_l2hit," + "ld_lclhit,lcl_hitm," + "ld_rmthit,rmt_hitm," + "dram_lcl,dram_rmt"; + + if (c2c.display == DISPLAY_TOT) + sort_str = "tot_hitm"; + else if (c2c.display == DISPLAY_RMT) + sort_str = "rmt_hitm"; + else if (c2c.display == DISPLAY_LCL) + sort_str = "lcl_hitm"; + + c2c_hists__reinit(&c2c.hists, output_str, sort_str);
ui_progress__init(&prog, c2c.hists.hists.nr_entries, "Sorting...");
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.12-rc1 commit 845d3a65c335 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
This patch is to enable sample type PERF_SAMPLE_DATA_SRC for Arm SPE in the perf data, when output the tracing data, it tells tools that it contains data source in the memory event.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: James Clark james.clark@arm.com Tested-by: James Clark james.clark@arm.com Cc: Adrian Hunter adrian.hunter@intel.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant al.grant@arm.com Cc: Andre Przywara andre.przywara@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Wei Li liwei391@huawei.com Cc: Will Deacon will@kernel.org Link: https://lore.kernel.org/r/20210211133856.2137-1-james.clark@arm.com Signed-off-by: James Clark james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index 8901a1656a41..b134516e890b 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -803,7 +803,7 @@ arm_spe_synth_events(struct arm_spe *spe, struct perf_session *session) attr.type = PERF_TYPE_HARDWARE; attr.sample_type = evsel->core.attr.sample_type & PERF_SAMPLE_MASK; attr.sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID | - PERF_SAMPLE_PERIOD; + PERF_SAMPLE_PERIOD | PERF_SAMPLE_DATA_SRC; if (spe->timeless_decoding) attr.sample_type &= ~(u64)PERF_SAMPLE_TIME; else
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.12-rc1 commit 265cfb9586d3 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
This patch is to store virtual and physical memory addresses in packet, which will be used for memory samples.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: James Clark james.clark@arm.com Tested-by: James Clark james.clark@arm.com Cc: Adrian Hunter adrian.hunter@intel.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant al.grant@arm.com Cc: Andre Przywara andre.przywara@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Wei Li liwei391@huawei.com Cc: Will Deacon will@kernel.org Link: https://lore.kernel.org/r/20210211133856.2137-2-james.clark@arm.com Signed-off-by: James Clark james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe-decoder/arm-spe-decoder.c | 4 ++++ tools/perf/util/arm-spe-decoder/arm-spe-decoder.h | 2 ++ 2 files changed, 6 insertions(+)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c index 90d575cee1b9..7aac3048b090 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c @@ -172,6 +172,10 @@ static int arm_spe_read_record(struct arm_spe_decoder *decoder) decoder->record.from_ip = ip; else if (idx == SPE_ADDR_PKT_HDR_INDEX_BRANCH) decoder->record.to_ip = ip; + else if (idx == SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT) + decoder->record.virt_addr = ip; + else if (idx == SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS) + decoder->record.phys_addr = ip; break; case ARM_SPE_COUNTER: break; diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h index 24727b8ca7ff..7b845001afe7 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h +++ b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h @@ -30,6 +30,8 @@ struct arm_spe_record { u64 from_ip; u64 to_ip; u64 timestamp; + u64 virt_addr; + u64 phys_addr; };
struct arm_spe_insn;
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.12-rc1 commit 97ae666ae036 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
This patch is to store operation type in packet structure.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: James Clark james.clark@arm.com Tested-by: James Clark james.clark@arm.com Cc: Adrian Hunter adrian.hunter@intel.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant al.grant@arm.com Cc: Andre Przywara andre.przywara@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Wei Li liwei391@huawei.com Cc: Will Deacon will@kernel.org Signed-off-by: James Clark james.clark@arm.com Link: https://lore.kernel.org/r/20210211133856.2137-3-james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe-decoder/arm-spe-decoder.c | 6 ++++++ tools/perf/util/arm-spe-decoder/arm-spe-decoder.h | 6 ++++++ 2 files changed, 12 insertions(+)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c index 7aac3048b090..32fe41835fa6 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c @@ -182,6 +182,12 @@ static int arm_spe_read_record(struct arm_spe_decoder *decoder) case ARM_SPE_CONTEXT: break; case ARM_SPE_OP_TYPE: + if (idx == SPE_OP_PKT_HDR_CLASS_LD_ST_ATOMIC) { + if (payload & 0x1) + decoder->record.op = ARM_SPE_ST; + else + decoder->record.op = ARM_SPE_LD; + } break; case ARM_SPE_EVENTS: if (payload & BIT(EV_L1D_REFILL)) diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h index 7b845001afe7..59bdb7309674 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h +++ b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h @@ -24,9 +24,15 @@ enum arm_spe_sample_type { ARM_SPE_REMOTE_ACCESS = 1 << 7, };
+enum arm_spe_op_type { + ARM_SPE_LD = 1 << 0, + ARM_SPE_ST = 1 << 1, +}; + struct arm_spe_record { enum arm_spe_sample_type type; int err; + u32 op; u64 from_ip; u64 to_ip; u64 timestamp;
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.12-rc1 commit 54f7815efef7 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
To properly handle memory and branch samples, this patch divides into two functions for generating samples: arm_spe__synth_mem_sample() is for synthesizing memory and TLB samples; arm_spe__synth_branch_sample() is to synthesize branch samples.
Arm SPE backend decoder has passed virtual and physical address through packets, the address info is stored into the synthesize samples in the function arm_spe__synth_mem_sample().
Committer notes:
Fixed this:
36 46.77 fedora:27 : FAIL clang version 5.0.2 (tags/RELEASE_502/final)
util/arm-spe.c:269:34: error: missing field 'pid' initializer [-Werror,-Wmissing-field-initializers] struct perf_sample sample = { 0 }; ^ util/arm-spe.c:288:34: error: missing field 'pid' initializer [-Werror,-Wmissing-field-initializers] struct perf_sample sample = { 0 };
By using = { .ip = 0, };
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: James Clark james.clark@arm.com Tested-by: James Clark james.clark@arm.com Cc: Adrian Hunter adrian.hunter@intel.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant al.grant@arm.com Cc: Andre Przywara andre.przywara@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Wei Li liwei391@huawei.com Cc: Will Deacon will@kernel.org Signed-off-by: James Clark james.clark@arm.com Link: https://lore.kernel.org/r/20210211133856.2137-4-james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe.c | 50 +++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 20 deletions(-)
diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index b134516e890b..de70a8f3ff36 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -235,7 +235,6 @@ static void arm_spe_prep_sample(struct arm_spe *spe, sample->cpumode = arm_spe_cpumode(spe, sample->ip); sample->pid = speq->pid; sample->tid = speq->tid; - sample->addr = record->to_ip; sample->period = 1; sample->cpu = speq->cpu;
@@ -259,11 +258,29 @@ arm_spe_deliver_synth_event(struct arm_spe *spe, return ret; }
-static int -arm_spe_synth_spe_events_sample(struct arm_spe_queue *speq, - u64 spe_events_id) +static int arm_spe__synth_mem_sample(struct arm_spe_queue *speq, + u64 spe_events_id) +{ + struct arm_spe *spe = speq->spe; + struct arm_spe_record *record = &speq->decoder->record; + union perf_event *event = speq->event_buf; + struct perf_sample sample = { .ip = 0, }; + + arm_spe_prep_sample(spe, speq, event, &sample); + + sample.id = spe_events_id; + sample.stream_id = spe_events_id; + sample.addr = record->virt_addr; + sample.phys_addr = record->phys_addr; + + return arm_spe_deliver_synth_event(spe, speq, event, &sample); +} + +static int arm_spe__synth_branch_sample(struct arm_spe_queue *speq, + u64 spe_events_id) { struct arm_spe *spe = speq->spe; + struct arm_spe_record *record = &speq->decoder->record; union perf_event *event = speq->event_buf; struct perf_sample sample = { .ip = 0, };
@@ -271,6 +288,7 @@ arm_spe_synth_spe_events_sample(struct arm_spe_queue *speq,
sample.id = spe_events_id; sample.stream_id = spe_events_id; + sample.addr = record->to_ip;
return arm_spe_deliver_synth_event(spe, speq, event, &sample); } @@ -283,15 +301,13 @@ static int arm_spe_sample(struct arm_spe_queue *speq)
if (spe->sample_flc) { if (record->type & ARM_SPE_L1D_MISS) { - err = arm_spe_synth_spe_events_sample( - speq, spe->l1d_miss_id); + err = arm_spe__synth_mem_sample(speq, spe->l1d_miss_id); if (err) return err; }
if (record->type & ARM_SPE_L1D_ACCESS) { - err = arm_spe_synth_spe_events_sample( - speq, spe->l1d_access_id); + err = arm_spe__synth_mem_sample(speq, spe->l1d_access_id); if (err) return err; } @@ -299,15 +315,13 @@ static int arm_spe_sample(struct arm_spe_queue *speq)
if (spe->sample_llc) { if (record->type & ARM_SPE_LLC_MISS) { - err = arm_spe_synth_spe_events_sample( - speq, spe->llc_miss_id); + err = arm_spe__synth_mem_sample(speq, spe->llc_miss_id); if (err) return err; }
if (record->type & ARM_SPE_LLC_ACCESS) { - err = arm_spe_synth_spe_events_sample( - speq, spe->llc_access_id); + err = arm_spe__synth_mem_sample(speq, spe->llc_access_id); if (err) return err; } @@ -315,31 +329,27 @@ static int arm_spe_sample(struct arm_spe_queue *speq)
if (spe->sample_tlb) { if (record->type & ARM_SPE_TLB_MISS) { - err = arm_spe_synth_spe_events_sample( - speq, spe->tlb_miss_id); + err = arm_spe__synth_mem_sample(speq, spe->tlb_miss_id); if (err) return err; }
if (record->type & ARM_SPE_TLB_ACCESS) { - err = arm_spe_synth_spe_events_sample( - speq, spe->tlb_access_id); + err = arm_spe__synth_mem_sample(speq, spe->tlb_access_id); if (err) return err; } }
if (spe->sample_branch && (record->type & ARM_SPE_BRANCH_MISS)) { - err = arm_spe_synth_spe_events_sample(speq, - spe->branch_miss_id); + err = arm_spe__synth_branch_sample(speq, spe->branch_miss_id); if (err) return err; }
if (spe->sample_remote_access && (record->type & ARM_SPE_REMOTE_ACCESS)) { - err = arm_spe_synth_spe_events_sample(speq, - spe->remote_access_id); + err = arm_spe__synth_mem_sample(speq, spe->remote_access_id); if (err) return err; }
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.12-rc1 commit e55ed3423c1b category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
The memory event can deliver two benefits:
- The first benefit is the memory event can give out global view for memory accessing, rather than organizing events with scatter mode (e.g. uses separate event for L1 cache, last level cache, etc) which which can only display a event for single memory type, memory events include all memory accessing so it can display the data accessing cross memory levels in the same view;
- The second benefit is the sample generation might introduce a big overhead and need to wait for long time for Perf reporting, we can specify itrace option '--itrace=M' to filter out other events and only output memory events, this can significantly reduce the overhead caused by generating samples.
This patch is to enable memory event for Arm SPE.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: James Clark james.clark@arm.com Tested-by: James Clark james.clark@arm.com Cc: Adrian Hunter adrian.hunter@intel.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant al.grant@arm.com Cc: Andre Przywara andre.przywara@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Wei Li liwei391@huawei.com Cc: Will Deacon will@kernel.org Signed-off-by: James Clark james.clark@arm.com Link: https://lore.kernel.org/r/20210211133856.2137-5-james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index de70a8f3ff36..0ae294a58402 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -53,6 +53,7 @@ struct arm_spe { u8 sample_tlb; u8 sample_branch; u8 sample_remote_access; + u8 sample_memory;
u64 l1d_miss_id; u64 l1d_access_id; @@ -62,6 +63,7 @@ struct arm_spe { u64 tlb_access_id; u64 branch_miss_id; u64 remote_access_id; + u64 memory_id;
u64 kernel_start;
@@ -293,6 +295,18 @@ static int arm_spe__synth_branch_sample(struct arm_spe_queue *speq, return arm_spe_deliver_synth_event(spe, speq, event, &sample); }
+#define SPE_MEM_TYPE (ARM_SPE_L1D_ACCESS | ARM_SPE_L1D_MISS | \ + ARM_SPE_LLC_ACCESS | ARM_SPE_LLC_MISS | \ + ARM_SPE_REMOTE_ACCESS) + +static bool arm_spe__is_memory_event(enum arm_spe_sample_type type) +{ + if (type & SPE_MEM_TYPE) + return true; + + return false; +} + static int arm_spe_sample(struct arm_spe_queue *speq) { const struct arm_spe_record *record = &speq->decoder->record; @@ -354,6 +368,12 @@ static int arm_spe_sample(struct arm_spe_queue *speq) return err; }
+ if (spe->sample_memory && arm_spe__is_memory_event(record->type)) { + err = arm_spe__synth_mem_sample(speq, spe->memory_id); + if (err) + return err; + } + return 0; }
@@ -917,6 +937,16 @@ arm_spe_synth_events(struct arm_spe *spe, struct perf_session *session) id += 1; }
+ if (spe->synth_opts.mem) { + spe->sample_memory = true; + + err = arm_spe_synth_event(session, &attr, id); + if (err) + return err; + spe->memory_id = id; + arm_spe_set_event_name(evlist, id, "memory"); + } + return 0; }
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.12-rc1 commit a89dbc9b988f category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
The sample structure contains the field 'data_src' which is used to tell the data operation attributions, e.g. operation type is loading or storing, cache level, it's snooping or remote accessing, etc. At the end, the 'data_src' will be parsed by perf mem/c2c tools to display human readable strings.
This patch is to fill the 'data_src' field in the synthesized samples base on different types. Currently perf tool can display statistics for L1/L2/L3 caches but it doesn't support the 'last level cache'. To fit to current implementation, 'data_src' field uses L3 cache for last level cache.
Before this commit, perf mem report looks like this: # Samples: 75K of event 'l1d-miss' # Total weight : 75951 # Sort order : local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked # # Overhead Samples Local Weight Memory access Symbol Shared Object Data Symbol Data Object Snoop TLB access # ........ ....... ............ ............. ...................... ............. ...................... ........... ..... .......... # 81.56% 61945 0 N/A [.] 0x00000000000009d8 serial_c [.] 0000000000000000 [unknown] N/A N/A 18.44% 14003 0 N/A [.] 0x0000000000000828 serial_c [.] 0000000000000000 [unknown] N/A N/A
Now on a system with Arm SPE, addresses and access types are displayed:
# Samples: 75K of event 'l1d-miss' # Total weight : 75951 # Sort order : local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked # # Overhead Samples Local Weight Memory access Symbol Shared Object Data Symbol Data Object Snoop TLB access # ........ ....... ............ ............. ...................... ............. ...................... ........... ..... .......... # 0.43% 324 0 L1 miss [.] 0x00000000000009d8 serial_c [.] 0x0000ffff80794e00 anon N/A Walker hit 0.42% 322 0 L1 miss [.] 0x00000000000009d8 serial_c [.] 0x0000ffff80794580 anon N/A Walker hit
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: James Clark james.clark@arm.com Tested-by: James Clark james.clark@arm.com Cc: Adrian Hunter adrian.hunter@intel.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant al.grant@arm.com Cc: Andre Przywara andre.przywara@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Wei Li liwei391@huawei.com Cc: Will Deacon will@kernel.org Signed-off-by: James Clark james.clark@arm.com Link: https://lore.kernel.org/r/20210211133856.2137-6-james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe.c | 69 ++++++++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 9 deletions(-)
diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index 0ae294a58402..2539d4baec44 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -261,7 +261,7 @@ arm_spe_deliver_synth_event(struct arm_spe *spe, }
static int arm_spe__synth_mem_sample(struct arm_spe_queue *speq, - u64 spe_events_id) + u64 spe_events_id, u64 data_src) { struct arm_spe *spe = speq->spe; struct arm_spe_record *record = &speq->decoder->record; @@ -274,6 +274,7 @@ static int arm_spe__synth_mem_sample(struct arm_spe_queue *speq, sample.stream_id = spe_events_id; sample.addr = record->virt_addr; sample.phys_addr = record->phys_addr; + sample.data_src = data_src;
return arm_spe_deliver_synth_event(spe, speq, event, &sample); } @@ -307,21 +308,66 @@ static bool arm_spe__is_memory_event(enum arm_spe_sample_type type) return false; }
+static u64 arm_spe__synth_data_source(const struct arm_spe_record *record) +{ + union perf_mem_data_src data_src = { 0 }; + + if (record->op == ARM_SPE_LD) + data_src.mem_op = PERF_MEM_OP_LOAD; + else + data_src.mem_op = PERF_MEM_OP_STORE; + + if (record->type & (ARM_SPE_LLC_ACCESS | ARM_SPE_LLC_MISS)) { + data_src.mem_lvl = PERF_MEM_LVL_L3; + + if (record->type & ARM_SPE_LLC_MISS) + data_src.mem_lvl |= PERF_MEM_LVL_MISS; + else + data_src.mem_lvl |= PERF_MEM_LVL_HIT; + } else if (record->type & (ARM_SPE_L1D_ACCESS | ARM_SPE_L1D_MISS)) { + data_src.mem_lvl = PERF_MEM_LVL_L1; + + if (record->type & ARM_SPE_L1D_MISS) + data_src.mem_lvl |= PERF_MEM_LVL_MISS; + else + data_src.mem_lvl |= PERF_MEM_LVL_HIT; + } + + if (record->type & ARM_SPE_REMOTE_ACCESS) + data_src.mem_lvl |= PERF_MEM_LVL_REM_CCE1; + + if (record->type & (ARM_SPE_TLB_ACCESS | ARM_SPE_TLB_MISS)) { + data_src.mem_dtlb = PERF_MEM_TLB_WK; + + if (record->type & ARM_SPE_TLB_MISS) + data_src.mem_dtlb |= PERF_MEM_TLB_MISS; + else + data_src.mem_dtlb |= PERF_MEM_TLB_HIT; + } + + return data_src.val; +} + static int arm_spe_sample(struct arm_spe_queue *speq) { const struct arm_spe_record *record = &speq->decoder->record; struct arm_spe *spe = speq->spe; + u64 data_src; int err;
+ data_src = arm_spe__synth_data_source(record); + if (spe->sample_flc) { if (record->type & ARM_SPE_L1D_MISS) { - err = arm_spe__synth_mem_sample(speq, spe->l1d_miss_id); + err = arm_spe__synth_mem_sample(speq, spe->l1d_miss_id, + data_src); if (err) return err; }
if (record->type & ARM_SPE_L1D_ACCESS) { - err = arm_spe__synth_mem_sample(speq, spe->l1d_access_id); + err = arm_spe__synth_mem_sample(speq, spe->l1d_access_id, + data_src); if (err) return err; } @@ -329,13 +375,15 @@ static int arm_spe_sample(struct arm_spe_queue *speq)
if (spe->sample_llc) { if (record->type & ARM_SPE_LLC_MISS) { - err = arm_spe__synth_mem_sample(speq, spe->llc_miss_id); + err = arm_spe__synth_mem_sample(speq, spe->llc_miss_id, + data_src); if (err) return err; }
if (record->type & ARM_SPE_LLC_ACCESS) { - err = arm_spe__synth_mem_sample(speq, spe->llc_access_id); + err = arm_spe__synth_mem_sample(speq, spe->llc_access_id, + data_src); if (err) return err; } @@ -343,13 +391,15 @@ static int arm_spe_sample(struct arm_spe_queue *speq)
if (spe->sample_tlb) { if (record->type & ARM_SPE_TLB_MISS) { - err = arm_spe__synth_mem_sample(speq, spe->tlb_miss_id); + err = arm_spe__synth_mem_sample(speq, spe->tlb_miss_id, + data_src); if (err) return err; }
if (record->type & ARM_SPE_TLB_ACCESS) { - err = arm_spe__synth_mem_sample(speq, spe->tlb_access_id); + err = arm_spe__synth_mem_sample(speq, spe->tlb_access_id, + data_src); if (err) return err; } @@ -363,13 +413,14 @@ static int arm_spe_sample(struct arm_spe_queue *speq)
if (spe->sample_remote_access && (record->type & ARM_SPE_REMOTE_ACCESS)) { - err = arm_spe__synth_mem_sample(speq, spe->remote_access_id); + err = arm_spe__synth_mem_sample(speq, spe->remote_access_id, + data_src); if (err) return err; }
if (spe->sample_memory && arm_spe__is_memory_event(record->type)) { - err = arm_spe__synth_mem_sample(speq, spe->memory_id); + err = arm_spe__synth_mem_sample(speq, spe->memory_id, data_src); if (err) return err; }
From: Ian Rogers irogers@google.com
mainline inclusion from mainline-v5.12-rc7 commit 92f1e8adf7db category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
SPE extended headers are > 1 byte so ensure the buffer contains at least this before reading. This issue was detected by fuzzing.
Signed-off-by: Ian Rogers irogers@google.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Andre Przywara andre.przywara@arm.com Cc: Dave Martin dave.martin@arm.com Cc: Jiri Olsa jolsa@redhat.com Cc: Leo Yan leo.yan@linaro.org Cc: Mark Rutland mark.rutland@arm.com Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Stephane Eranian eranian@google.com Cc: Will Deacon will@kernel.org Link: http://lore.kernel.org/lkml/20210407153955.317215-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index f3ac9d40cebf..2e5eff4f8f03 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -210,8 +210,10 @@ static int arm_spe_do_get_packet(const unsigned char *buf, size_t len,
if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_EXTENDED) { /* 16-bit extended format header */ - ext_hdr = 1; + if (len == 1) + return ARM_SPE_BAD_PACKET;
+ ext_hdr = 1; hdr = buf[1]; if (hdr == SPE_HEADER1_ALIGNMENT) return arm_spe_get_alignment(buf, len, packet);
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.14-rc1 commit 2f021954952f category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
Now it's hard code to set sample flags for CPU, TIME and TID for SPE event, which is pointless.
The CPU is useful for sampling only for per-mmap case, it is used to indicate the AUX trace is associated to which CPU.
The TIME sample is not needed for AUX event, since the time for AUX event is not really used and this time is a different thing from the timestamp in Arm SPE trace, the timestamp tracing which is controlled by Arm SPE's config bit.
The TID sample is not useful for AUX event.
This patch corrects the sample flags for SPE event, it only set CPU sample bit for per-cpu mmap case.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: James Clark james.clark@arm.com Tested-by: James Clark james.clark@arm.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Will Deacon will@kernel.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20210519041546.1574961-2-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/arch/arm64/util/arm-spe.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c index e3593063b3d1..35e7c7e774c2 100644 --- a/tools/perf/arch/arm64/util/arm-spe.c +++ b/tools/perf/arch/arm64/util/arm-spe.c @@ -68,6 +68,7 @@ static int arm_spe_recording_options(struct auxtrace_record *itr, container_of(itr, struct arm_spe_recording, itr); struct perf_pmu *arm_spe_pmu = sper->arm_spe_pmu; struct evsel *evsel, *arm_spe_evsel = NULL; + struct perf_cpu_map *cpus = evlist->core.cpus; bool privileged = perf_event_paranoid_check(-1); struct evsel *tracking_evsel; int err; @@ -120,9 +121,9 @@ static int arm_spe_recording_options(struct auxtrace_record *itr, */ perf_evlist__to_front(evlist, arm_spe_evsel);
- evsel__set_sample_bit(arm_spe_evsel, CPU); - evsel__set_sample_bit(arm_spe_evsel, TIME); - evsel__set_sample_bit(arm_spe_evsel, TID); + /* In the case of per-cpu mmaps, sample CPU for AUX event. */ + if (!perf_cpu_map__empty(cpus)) + evsel__set_sample_bit(arm_spe_evsel, CPU);
/* Add dummy event to keep tracking */ err = parse_events(evlist, "dummy:u", NULL);
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.14-rc1 commit e582badf1706 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
The dummy event is mainly used for mmap, the TIME sample is only needed for per-cpu case so that the perf tool can rely on the correct timing for parsing symbols. And the CPU sample is useless for mmap.
The BRANCH_STACK sample bit will be always reset for the dummy event in the function evsel__config(), so don't need to repeatedly reset it for Arm SPE specific.
So this patch only enables TIME sample for per-cpu mmap.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: James Clark james.clark@arm.com Tested-by: James Clark james.clark@arm.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Will Deacon will@kernel.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20210519041546.1574961-3-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/arch/arm64/util/arm-spe.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c index 35e7c7e774c2..119d8d7656b9 100644 --- a/tools/perf/arch/arm64/util/arm-spe.c +++ b/tools/perf/arch/arm64/util/arm-spe.c @@ -135,9 +135,10 @@ static int arm_spe_recording_options(struct auxtrace_record *itr,
tracking_evsel->core.attr.freq = 0; tracking_evsel->core.attr.sample_period = 1; - evsel__set_sample_bit(tracking_evsel, TIME); - evsel__set_sample_bit(tracking_evsel, CPU); - evsel__reset_sample_bit(tracking_evsel, BRANCH_STACK); + + /* In per-cpu case, always need the time of mmap events etc */ + if (!perf_cpu_map__empty(cpus)) + evsel__set_sample_bit(tracking_evsel, TIME);
return 0; }
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.14-rc1 commit f99237e46432 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
For per-cpu mmap, it should enable timestamp tracing for Arm SPE; this is helpful for samples correlation.
To automatically enable the timestamp, a helper arm_spe_set_timestamp() is introduced for setting "ts_enable" format bit.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: James Clark james.clark@arm.com Tested-by: James Clark james.clark@arm.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: linux-arm-kernel@lists.infradead.org Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Will Deacon will@kernel.org Link: https://lore.kernel.org/r/20210519041546.1574961-4-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/arch/arm64/util/arm-spe.c | 33 ++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-)
diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c index 119d8d7656b9..a11e7aa5a654 100644 --- a/tools/perf/arch/arm64/util/arm-spe.c +++ b/tools/perf/arch/arm64/util/arm-spe.c @@ -14,6 +14,7 @@ #include "../../../util/cpumap.h" #include "../../../util/event.h" #include "../../../util/evsel.h" +#include "../../../util/evsel_config.h" #include "../../../util/evlist.h" #include "../../../util/session.h" #include <internal/lib.h> // page_size @@ -32,6 +33,29 @@ struct arm_spe_recording { struct evlist *evlist; };
+static void arm_spe_set_timestamp(struct auxtrace_record *itr, + struct evsel *evsel) +{ + struct arm_spe_recording *ptr; + struct perf_pmu *arm_spe_pmu; + struct evsel_config_term *term = evsel__get_config_term(evsel, CFG_CHG); + u64 user_bits = 0, bit; + + ptr = container_of(itr, struct arm_spe_recording, itr); + arm_spe_pmu = ptr->arm_spe_pmu; + + if (term) + user_bits = term->val.cfg_chg; + + bit = perf_pmu__format_bits(&arm_spe_pmu->format, "ts_enable"); + + /* Skip if user has set it */ + if (bit & user_bits) + return; + + evsel->core.attr.config |= bit; +} + static size_t arm_spe_info_priv_size(struct auxtrace_record *itr __maybe_unused, struct evlist *evlist __maybe_unused) @@ -121,9 +145,14 @@ static int arm_spe_recording_options(struct auxtrace_record *itr, */ perf_evlist__to_front(evlist, arm_spe_evsel);
- /* In the case of per-cpu mmaps, sample CPU for AUX event. */ - if (!perf_cpu_map__empty(cpus)) + /* + * In the case of per-cpu mmaps, sample CPU for AUX event; + * also enable the timestamp tracing for samples correlation. + */ + if (!perf_cpu_map__empty(cpus)) { evsel__set_sample_bit(arm_spe_evsel, CPU); + arm_spe_set_timestamp(itr, arm_spe_evsel); + }
/* Add dummy event to keep tracking */ err = parse_events(evlist, "dummy:u", NULL);
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.14-rc1 commit afe360a8c35e category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
The option "opts->full_auxtrace" is checked at the earlier place, if it is false the function will directly bail out. So remove the redundant checking for "opts->full_auxtrace".
Suggested-by: James Clark james.clark@arm.com Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: James Clark james.clark@arm.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: Ingo Molnar mingo@redhat.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Will Deacon will@kernel.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20210519041546.1574961-5-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/arch/arm64/util/arm-spe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c index a11e7aa5a654..02fe1345b85c 100644 --- a/tools/perf/arch/arm64/util/arm-spe.c +++ b/tools/perf/arch/arm64/util/arm-spe.c @@ -116,7 +116,7 @@ static int arm_spe_recording_options(struct auxtrace_record *itr, return 0;
/* We are in full trace mode but '-m,xyz' wasn't specified */ - if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) { + if (!opts->auxtrace_mmap_pages) { if (privileged) { opts->auxtrace_mmap_pages = MiB(4) / page_size; } else {
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.14-rc1 commit c210c3069636 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
During the recording phase, "perf record" tool synthesizes event PERF_RECORD_TIME_CONV for the hardware clock parameters and saves the event into the data file.
Afterwards, when processing the data file, the event TIME_CONV will be processed at the very early time and is stored into session context.
This patch extracts these parameters from the session context and saves into the structure "spe->tc" with the type perf_tsc_conversion, so that the parameters are ready for conversion between clock counter and time stamp.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: James Clark james.clark@arm.com Tested-by: James Clark james.clark@arm.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Dave Martin Dave.Martin@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Will Deacon will@kernel.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20210519071939.1598923-2-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index 2539d4baec44..d2ae5a5c13ee 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -26,6 +26,7 @@ #include "symbol.h" #include "thread.h" #include "thread-stack.h" +#include "tsc.h" #include "tool.h" #include "util/synthetic-events.h"
@@ -45,6 +46,8 @@ struct arm_spe { struct machine *machine; u32 pmu_type;
+ struct perf_tsc_conversion tc; + u8 timeless_decoding; u8 data_queued;
@@ -1006,6 +1009,7 @@ int arm_spe_process_auxtrace_info(union perf_event *event, { struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; size_t min_sz = sizeof(u64) * ARM_SPE_AUXTRACE_PRIV_MAX; + struct perf_record_time_conv *tc = &session->time_conv; struct arm_spe *spe; int err;
@@ -1027,6 +1031,28 @@ int arm_spe_process_auxtrace_info(union perf_event *event, spe->pmu_type = auxtrace_info->priv[ARM_SPE_PMU_TYPE];
spe->timeless_decoding = arm_spe__is_timeless_decoding(spe); + + /* + * The synthesized event PERF_RECORD_TIME_CONV has been handled ahead + * and the parameters for hardware clock are stored in the session + * context. Passes these parameters to the struct perf_tsc_conversion + * in "spe->tc", which is used for later conversion between clock + * counter and timestamp. + * + * For backward compatibility, copies the fields starting from + * "time_cycles" only if they are contained in the event. + */ + spe->tc.time_shift = tc->time_shift; + spe->tc.time_mult = tc->time_mult; + spe->tc.time_zero = tc->time_zero; + + if (event_contains(*tc, time_cycles)) { + spe->tc.time_cycles = tc->time_cycles; + spe->tc.time_mask = tc->time_mask; + spe->tc.cap_user_time_zero = tc->cap_user_time_zero; + spe->tc.cap_user_time_short = tc->cap_user_time_short; + } + spe->auxtrace.process_event = arm_spe_process_event; spe->auxtrace.process_auxtrace_event = arm_spe_process_auxtrace_event; spe->auxtrace.flush_events = arm_spe_flush;
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.14-rc1 commit 630519014c7b category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
When handle a perf event, Arm SPE decoder needs to decide if this perf event is earlier or later than the samples from Arm SPE trace data; to do comparision, it needs to use the same unit for the time.
This patch converts the event kernel time to arch timer's counter value, thus it can be used to compare with counter value contained in Arm SPE Timestamp packet.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: James Clark james.clark@arm.com Tested-by: James Clark james.clark@arm.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Dave Martin Dave.Martin@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Will Deacon will@kernel.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20210519071939.1598923-3-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index d2ae5a5c13ee..ff8b52e6d475 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -669,7 +669,7 @@ static int arm_spe_process_event(struct perf_session *session, }
if (sample->time && (sample->time != (u64) -1)) - timestamp = sample->time; + timestamp = perf_time_to_tsc(sample->time, &spe->tc); else timestamp = 0;
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.14-rc1 commit 85498f756f01 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
In current code, it assigns the arch timer counter to the synthesized samples Arm SPE trace, thus the samples don't contain the kernel time but only contain the raw counter value.
To fix the issue, this patch converts the timer counter to kernel time and assigns it to sample timestamp.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: James Clark james.clark@arm.com Tested-by: James Clark james.clark@arm.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Dave Martin Dave.Martin@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Will Deacon will@kernel.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20210519071939.1598923-4-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index ff8b52e6d475..da379328442c 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -234,7 +234,7 @@ static void arm_spe_prep_sample(struct arm_spe *spe, struct arm_spe_record *record = &speq->decoder->record;
if (!spe->timeless_decoding) - sample->time = speq->timestamp; + sample->time = tsc_to_perf_time(record->timestamp, &spe->tc);
sample->ip = record->from_ip; sample->cpumode = arm_spe_cpumode(spe, sample->ip);
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.14-rc1 commit afb5e9e47faf category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
It's possible that record in Arm SPE trace is later than perf event and vice versa. This asks to correlate the perf events and Arm SPE synthesized events to be processed in the manner of correct timing.
To achieve the time ordering, this patch reverses the flow, it firstly calls arm_spe_sample() and then calls arm_spe_decode(). By comparing the timestamp value and detect the perf event is coming earlier than Arm SPE trace data, it bails out from the decoding loop, the last record is pushed into auxtrace stack and is deferred to generate sample. To track the timestamp, everytime it updates timestamp for the latest record.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: James Clark james.clark@arm.com Tested-by: James Clark james.clark@arm.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Dave Martin Dave.Martin@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Will Deacon will@kernel.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20210519071939.1598923-5-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe.c | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-)
diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index da379328442c..5c5b438584c4 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -434,12 +434,36 @@ static int arm_spe_sample(struct arm_spe_queue *speq) static int arm_spe_run_decoder(struct arm_spe_queue *speq, u64 *timestamp) { struct arm_spe *spe = speq->spe; + struct arm_spe_record *record; int ret;
if (!spe->kernel_start) spe->kernel_start = machine__kernel_start(spe->machine);
while (1) { + /* + * The usual logic is firstly to decode the packets, and then + * based the record to synthesize sample; but here the flow is + * reversed: it calls arm_spe_sample() for synthesizing samples + * prior to arm_spe_decode(). + * + * Two reasons for this code logic: + * 1. Firstly, when setup queue in arm_spe__setup_queue(), it + * has decoded trace data and generated a record, but the record + * is left to generate sample until run to here, so it's correct + * to synthesize sample for the left record. + * 2. After decoding trace data, it needs to compare the record + * timestamp with the coming perf event, if the record timestamp + * is later than the perf event, it needs bail out and pushs the + * record into auxtrace heap, thus the record can be deferred to + * synthesize sample until run to here at the next time; so this + * can correlate samples between Arm SPE trace data and other + * perf events with correct time ordering. + */ + ret = arm_spe_sample(speq); + if (ret) + return ret; + ret = arm_spe_decode(speq->decoder); if (!ret) { pr_debug("No data or all data has been processed.\n"); @@ -453,10 +477,17 @@ static int arm_spe_run_decoder(struct arm_spe_queue *speq, u64 *timestamp) if (ret < 0) continue;
- ret = arm_spe_sample(speq); - if (ret) - return ret; + record = &speq->decoder->record;
+ /* Update timestamp for the last record */ + if (record->timestamp > speq->timestamp) + speq->timestamp = record->timestamp; + + /* + * If the timestamp of the queue is later than timestamp of the + * coming perf event, bail out so can allow the perf event to + * be processed ahead. + */ if (!spe->timeless_decoding && speq->timestamp >= *timestamp) { *timestamp = speq->timestamp; return 0;
From: Leo Yan leo.yan@linaro.org
mainline inclusion from mainline-v5.14-rc1 commit 8941ba502f74 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
When decode Arm SPE trace, it waits for PERF_RECORD_EXIT event (the last perf event) for processing trace data, which is needless and even might cause logic error, e.g. it might fail to correlate perf events with Arm SPE events correctly.
So this patch removes the condition checking for PERF_RECORD_EXIT event.
Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: James Clark james.clark@arm.com Tested-by: James Clark james.clark@arm.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Al Grant Al.Grant@arm.com Cc: Dave Martin Dave.Martin@arm.com Cc: Ingo Molnar mingo@redhat.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: linux-arm-kernel@lists.infradead.org Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Will Deacon will@kernel.org Link: https://lore.kernel.org/r/20210519071939.1598923-6-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index 5c5b438584c4..58b7069c5a5f 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -717,11 +717,7 @@ static int arm_spe_process_event(struct perf_session *session, sample->time); } } else if (timestamp) { - if (event->header.type == PERF_RECORD_EXIT) { - err = arm_spe_process_queues(spe, timestamp); - if (err) - return err; - } + err = arm_spe_process_queues(spe, timestamp); }
return err;
From: German Gomez german.gomez@arm.com
mainline inclusion from mainline-v5.16-rc1 commit 0901b5602872 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
This patch enables support for snapshot mode of arm_spe events, including the implementation of the necessary callbacks (excluding find_snapshot, which is to be included in a followup commit).
Reviewed-by: James Clark james.clark@arm.com Reviewed-by: Leo Yan leo.yan@linaro.org Signed-off-by: German Gomez german.gomez@arm.com Acked-by: Namhyung Kim namhyung@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Will Deacon will@kernel.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20211109163009.92072-2-german.gomez@arm.com Tested-by: Leo Yan leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/arch/arm64/util/arm-spe.c | 130 +++++++++++++++++++++++++++ 1 file changed, 130 insertions(+)
diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c index 02fe1345b85c..1e545237391b 100644 --- a/tools/perf/arch/arm64/util/arm-spe.c +++ b/tools/perf/arch/arm64/util/arm-spe.c @@ -84,6 +84,55 @@ static int arm_spe_info_fill(struct auxtrace_record *itr, return 0; }
+static void +arm_spe_snapshot_resolve_auxtrace_defaults(struct record_opts *opts, + bool privileged) +{ + /* + * The default snapshot size is the auxtrace mmap size. If neither auxtrace mmap size nor + * snapshot size is specified, then the default is 4MiB for privileged users, 128KiB for + * unprivileged users. + * + * The default auxtrace mmap size is 4MiB/page_size for privileged users, 128KiB for + * unprivileged users. If an unprivileged user does not specify mmap pages, the mmap pages + * will be reduced from the default 512KiB/page_size to 256KiB/page_size, otherwise the + * user is likely to get an error as they exceed their mlock limmit. + */ + + /* + * No size were given to '-S' or '-m,', so go with the default + */ + if (!opts->auxtrace_snapshot_size && !opts->auxtrace_mmap_pages) { + if (privileged) { + opts->auxtrace_mmap_pages = MiB(4) / page_size; + } else { + opts->auxtrace_mmap_pages = KiB(128) / page_size; + if (opts->mmap_pages == UINT_MAX) + opts->mmap_pages = KiB(256) / page_size; + } + } else if (!opts->auxtrace_mmap_pages && !privileged && opts->mmap_pages == UINT_MAX) { + opts->mmap_pages = KiB(256) / page_size; + } + + /* + * '-m,xyz' was specified but no snapshot size, so make the snapshot size as big as the + * auxtrace mmap area. + */ + if (!opts->auxtrace_snapshot_size) + opts->auxtrace_snapshot_size = opts->auxtrace_mmap_pages * (size_t)page_size; + + /* + * '-Sxyz' was specified but no auxtrace mmap area, so make the auxtrace mmap area big + * enough to fit the requested snapshot size. + */ + if (!opts->auxtrace_mmap_pages) { + size_t sz = opts->auxtrace_snapshot_size; + + sz = round_up(sz, page_size) / page_size; + opts->auxtrace_mmap_pages = roundup_pow_of_two(sz); + } +} + static int arm_spe_recording_options(struct auxtrace_record *itr, struct evlist *evlist, struct record_opts *opts) @@ -115,6 +164,36 @@ static int arm_spe_recording_options(struct auxtrace_record *itr, if (!opts->full_auxtrace) return 0;
+ /* + * we are in snapshot mode. + */ + if (opts->auxtrace_snapshot_mode) { + /* + * Command arguments '-Sxyz' and/or '-m,xyz' are missing, so fill those in with + * default values. + */ + if (!opts->auxtrace_snapshot_size || !opts->auxtrace_mmap_pages) + arm_spe_snapshot_resolve_auxtrace_defaults(opts, privileged); + + /* + * Snapshot size can't be bigger than the auxtrace area. + */ + if (opts->auxtrace_snapshot_size > opts->auxtrace_mmap_pages * (size_t)page_size) { + pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n", + opts->auxtrace_snapshot_size, + opts->auxtrace_mmap_pages * (size_t)page_size); + return -EINVAL; + } + + /* + * Something went wrong somewhere - this shouldn't happen. + */ + if (!opts->auxtrace_snapshot_size || !opts->auxtrace_mmap_pages) { + pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n"); + return -EINVAL; + } + } + /* We are in full trace mode but '-m,xyz' wasn't specified */ if (!opts->auxtrace_mmap_pages) { if (privileged) { @@ -138,6 +217,9 @@ static int arm_spe_recording_options(struct auxtrace_record *itr, } }
+ if (opts->auxtrace_snapshot_mode) + pr_debug2("%sx snapshot size: %zu\n", ARM_SPE_PMU_NAME, + opts->auxtrace_snapshot_size);
/* * To obtain the auxtrace buffer file descriptor, the auxtrace event @@ -172,6 +254,51 @@ static int arm_spe_recording_options(struct auxtrace_record *itr, return 0; }
+static int arm_spe_parse_snapshot_options(struct auxtrace_record *itr __maybe_unused, + struct record_opts *opts, + const char *str) +{ + unsigned long long snapshot_size = 0; + char *endptr; + + if (str) { + snapshot_size = strtoull(str, &endptr, 0); + if (*endptr || snapshot_size > SIZE_MAX) + return -1; + } + + opts->auxtrace_snapshot_mode = true; + opts->auxtrace_snapshot_size = snapshot_size; + + return 0; +} + +static int arm_spe_snapshot_start(struct auxtrace_record *itr) +{ + struct arm_spe_recording *ptr = + container_of(itr, struct arm_spe_recording, itr); + struct evsel *evsel; + + evlist__for_each_entry(ptr->evlist, evsel) { + if (evsel->core.attr.type == ptr->arm_spe_pmu->type) + return evsel__disable(evsel); + } + return -EINVAL; +} + +static int arm_spe_snapshot_finish(struct auxtrace_record *itr) +{ + struct arm_spe_recording *ptr = + container_of(itr, struct arm_spe_recording, itr); + struct evsel *evsel; + + evlist__for_each_entry(ptr->evlist, evsel) { + if (evsel->core.attr.type == ptr->arm_spe_pmu->type) + return evsel__enable(evsel); + } + return -EINVAL; +} + static u64 arm_spe_reference(struct auxtrace_record *itr __maybe_unused) { struct timespec ts; @@ -207,6 +334,9 @@ struct auxtrace_record *arm_spe_recording_init(int *err,
sper->arm_spe_pmu = arm_spe_pmu; sper->itr.pmu = arm_spe_pmu; + sper->itr.snapshot_start = arm_spe_snapshot_start; + sper->itr.snapshot_finish = arm_spe_snapshot_finish; + sper->itr.parse_snapshot_options = arm_spe_parse_snapshot_options; sper->itr.recording_options = arm_spe_recording_options; sper->itr.info_priv_size = arm_spe_info_priv_size; sper->itr.info_fill = arm_spe_info_fill;
From: German Gomez german.gomez@arm.com
mainline inclusion from mainline-v5.16-rc1 commit 6b1b208bef5b category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
Shell script test_arm_spe.sh has been added to test the recording of SPE tracing events in snapshot mode.
Reviewed-by: Leo Yan leo.yan@linaro.org Signed-off-by: German Gomez german.gomez@arm.com Acked-by: Namhyung Kim namhyung@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Will Deacon will@kernel.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20211109163009.92072-4-german.gomez@arm.com Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/tests/shell/test_arm_spe.sh | 89 ++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100755 tools/perf/tests/shell/test_arm_spe.sh
diff --git a/tools/perf/tests/shell/test_arm_spe.sh b/tools/perf/tests/shell/test_arm_spe.sh new file mode 100755 index 000000000000..e59044edc406 --- /dev/null +++ b/tools/perf/tests/shell/test_arm_spe.sh @@ -0,0 +1,89 @@ +#!/bin/sh +# Check Arm SPE trace data recording and synthesized samples + +# Uses the 'perf record' to record trace data of Arm SPE events; +# then verify if any SPE event samples are generated by SPE with +# 'perf script' and 'perf report' commands. + +# SPDX-License-Identifier: GPL-2.0 +# German Gomez german.gomez@arm.com, 2021 + +skip_if_no_arm_spe_event() { + perf list | egrep -q 'arm_spe_[0-9]+//' && return 0 + + # arm_spe event doesn't exist + return 2 +} + +skip_if_no_arm_spe_event || exit 2 + +perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) +glb_err=0 + +cleanup_files() +{ + rm -f ${perfdata} + exit $glb_err +} + +trap cleanup_files exit term int + +arm_spe_report() { + if [ $2 != 0 ]; then + echo "$1: FAIL" + glb_err=$2 + else + echo "$1: PASS" + fi +} + +perf_script_samples() { + echo "Looking at perf.data file for dumping samples:" + + # from arm-spe.c/arm_spe_synth_events() + events="(ld1-miss|ld1-access|llc-miss|lld-access|tlb-miss|tlb-access|branch-miss|remote-access|memory)" + + # Below is an example of the samples dumping: + # dd 3048 [002] 1 l1d-access: ffffaa64999c __GI___libc_write+0x3c (/lib/aarch64-linux-gnu/libc-2.27.so) + # dd 3048 [002] 1 tlb-access: ffffaa64999c __GI___libc_write+0x3c (/lib/aarch64-linux-gnu/libc-2.27.so) + # dd 3048 [002] 1 memory: ffffaa64999c __GI___libc_write+0x3c (/lib/aarch64-linux-gnu/libc-2.27.so) + perf script -F,-time -i ${perfdata} 2>&1 | \ + egrep " +$1 +[0-9]+ .* +${events}:(.*:)? +" > /dev/null 2>&1 +} + +perf_report_samples() { + echo "Looking at perf.data file for reporting samples:" + + # Below is an example of the samples reporting: + # 73.04% 73.04% dd libc-2.27.so [.] _dl_addr + # 7.71% 7.71% dd libc-2.27.so [.] getenv + # 2.59% 2.59% dd ld-2.27.so [.] strcmp + perf report --stdio -i ${perfdata} 2>&1 | \ + egrep " +[0-9]+.[0-9]+% +[0-9]+.[0-9]+% +$1 " > /dev/null 2>&1 +} + +arm_spe_snapshot_test() { + echo "Recording trace with snapshot mode $perfdata" + perf record -o ${perfdata} -e arm_spe// -S \ + -- dd if=/dev/zero of=/dev/null > /dev/null 2>&1 & + PERFPID=$! + + # Wait for perf program + sleep 1 + + # Send signal to snapshot trace data + kill -USR2 $PERFPID + + # Stop perf program + kill $PERFPID + wait $PERFPID + + perf_script_samples dd && + perf_report_samples dd + + err=$? + arm_spe_report "SPE snapshot testing" $err +} + +arm_spe_snapshot_test +exit $glb_err
From: German Gomez german.gomez@arm.com
mainline inclusion from mainline-v5.16-rc1 commit 56c31cdff7c2 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
The head pointer of the AUX buffer managed by the arm_spe_pmu.c driver is not monotonically increasing, therefore the find_snapshot callback is needed in order to find the trace data within the AUX buffer and avoid wasting space in the perf.data file.
The pointer is assumed to have wrapped if the buffer contains non-zero data at the end. If it has wrapped, the entire contents of the AUX buffer are stored in the perf.data file. Otherwise only the data up to the head pointer is stored.
Reviewed-by: James Clark james.clark@arm.com Reviewed-by: Leo Yan leo.yan@linaro.org Signed-off-by: German Gomez german.gomez@arm.com Acked-by: Namhyung Kim namhyung@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Will Deacon will@kernel.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20211109163009.92072-3-german.gomez@arm.com Tested-by: Leo Yan leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/arch/arm64/util/arm-spe.c | 145 +++++++++++++++++++++++++++ 1 file changed, 145 insertions(+)
diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c index 1e545237391b..23e72d50565f 100644 --- a/tools/perf/arch/arm64/util/arm-spe.c +++ b/tools/perf/arch/arm64/util/arm-spe.c @@ -23,6 +23,7 @@ #include "../../../util/auxtrace.h" #include "../../../util/record.h" #include "../../../util/arm-spe.h" +#include <tools/libc_compat.h> // reallocarray
#define KiB(x) ((x) * 1024) #define MiB(x) ((x) * 1024 * 1024) @@ -31,6 +32,8 @@ struct arm_spe_recording { struct auxtrace_record itr; struct perf_pmu *arm_spe_pmu; struct evlist *evlist; + int wrapped_cnt; + bool *wrapped; };
static void arm_spe_set_timestamp(struct auxtrace_record *itr, @@ -299,6 +302,146 @@ static int arm_spe_snapshot_finish(struct auxtrace_record *itr) return -EINVAL; }
+static int arm_spe_alloc_wrapped_array(struct arm_spe_recording *ptr, int idx) +{ + bool *wrapped; + int cnt = ptr->wrapped_cnt, new_cnt, i; + + /* + * No need to allocate, so return early. + */ + if (idx < cnt) + return 0; + + /* + * Make ptr->wrapped as big as idx. + */ + new_cnt = idx + 1; + + /* + * Free'ed in arm_spe_recording_free(). + */ + wrapped = reallocarray(ptr->wrapped, new_cnt, sizeof(bool)); + if (!wrapped) + return -ENOMEM; + + /* + * init new allocated values. + */ + for (i = cnt; i < new_cnt; i++) + wrapped[i] = false; + + ptr->wrapped_cnt = new_cnt; + ptr->wrapped = wrapped; + + return 0; +} + +static bool arm_spe_buffer_has_wrapped(unsigned char *buffer, + size_t buffer_size, u64 head) +{ + u64 i, watermark; + u64 *buf = (u64 *)buffer; + size_t buf_size = buffer_size; + + /* + * Defensively handle the case where head might be continually increasing - if its value is + * equal or greater than the size of the ring buffer, then we can safely determine it has + * wrapped around. Otherwise, continue to detect if head might have wrapped. + */ + if (head >= buffer_size) + return true; + + /* + * We want to look the very last 512 byte (chosen arbitrarily) in the ring buffer. + */ + watermark = buf_size - 512; + + /* + * The value of head is somewhere within the size of the ring buffer. This can be that there + * hasn't been enough data to fill the ring buffer yet or the trace time was so long that + * head has numerically wrapped around. To find we need to check if we have data at the + * very end of the ring buffer. We can reliably do this because mmap'ed pages are zeroed + * out and there is a fresh mapping with every new session. + */ + + /* + * head is less than 512 byte from the end of the ring buffer. + */ + if (head > watermark) + watermark = head; + + /* + * Speed things up by using 64 bit transactions (see "u64 *buf" above) + */ + watermark /= sizeof(u64); + buf_size /= sizeof(u64); + + /* + * If we find trace data at the end of the ring buffer, head has been there and has + * numerically wrapped around at least once. + */ + for (i = watermark; i < buf_size; i++) + if (buf[i]) + return true; + + return false; +} + +static int arm_spe_find_snapshot(struct auxtrace_record *itr, int idx, + struct auxtrace_mmap *mm, unsigned char *data, + u64 *head, u64 *old) +{ + int err; + bool wrapped; + struct arm_spe_recording *ptr = + container_of(itr, struct arm_spe_recording, itr); + + /* + * Allocate memory to keep track of wrapping if this is the first + * time we deal with this *mm. + */ + if (idx >= ptr->wrapped_cnt) { + err = arm_spe_alloc_wrapped_array(ptr, idx); + if (err) + return err; + } + + /* + * Check to see if *head has wrapped around. If it hasn't only the + * amount of data between *head and *old is snapshot'ed to avoid + * bloating the perf.data file with zeros. But as soon as *head has + * wrapped around the entire size of the AUX ring buffer it taken. + */ + wrapped = ptr->wrapped[idx]; + if (!wrapped && arm_spe_buffer_has_wrapped(data, mm->len, *head)) { + wrapped = true; + ptr->wrapped[idx] = true; + } + + pr_debug3("%s: mmap index %d old head %zu new head %zu size %zu\n", + __func__, idx, (size_t)*old, (size_t)*head, mm->len); + + /* + * No wrap has occurred, we can just use *head and *old. + */ + if (!wrapped) + return 0; + + /* + * *head has wrapped around - adjust *head and *old to pickup the + * entire content of the AUX buffer. + */ + if (*head >= mm->len) { + *old = *head - mm->len; + } else { + *head += mm->len; + *old = *head - mm->len; + } + + return 0; +} + static u64 arm_spe_reference(struct auxtrace_record *itr __maybe_unused) { struct timespec ts; @@ -313,6 +456,7 @@ static void arm_spe_recording_free(struct auxtrace_record *itr) struct arm_spe_recording *sper = container_of(itr, struct arm_spe_recording, itr);
+ free(sper->wrapped); free(sper); }
@@ -336,6 +480,7 @@ struct auxtrace_record *arm_spe_recording_init(int *err, sper->itr.pmu = arm_spe_pmu; sper->itr.snapshot_start = arm_spe_snapshot_start; sper->itr.snapshot_finish = arm_spe_snapshot_finish; + sper->itr.find_snapshot = arm_spe_find_snapshot; sper->itr.parse_snapshot_options = arm_spe_parse_snapshot_options; sper->itr.recording_options = arm_spe_recording_options; sper->itr.info_priv_size = arm_spe_info_priv_size;
From: Andrew Kilroy andrew.kilroy@arm.com
mainline inclusion from mainline-v5.16-rc1 commit 09e9afac8cea category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
Since the size is already printed earlier in hex, print the same data using the same format, in hex.
Reviewed-by: James Clark james.clark@arm.com Reviewed-by: Leo Yan leo.yan@linaro.org Signed-off-by: Andrew Kilroy andrew.kilroy@arm.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Mike Leach mike.leach@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Will Deacon will@kernel.org Cc: coresight@lists.linaro.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20211109142153.56546-3-german.gomez@arm.com Signed-off-by: German Gomez german.gomez@arm.com Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index 58b7069c5a5f..2196291976d9 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -100,7 +100,7 @@ static void arm_spe_dump(struct arm_spe *spe __maybe_unused, const char *color = PERF_COLOR_BLUE;
color_fprintf(stdout, color, - ". ... ARM SPE data: size %zu bytes\n", + ". ... ARM SPE data: size %#zx bytes\n", len);
while (len) {
From: Namhyung Kim namhyung@kernel.org
mainline inclusion from mainline-v5.16-rc1 commit 9dc9855f18ba category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
When perf report synthesize events from ARM SPE data, it refers to current cpu, pid and tid in the machine. But there's no place to set them in the ARM SPE decoder. I'm seeing all pid/tid is set to -1 and user symbols are not resolved in the output.
# perf record -a -e arm_spe_0/ts_enable=1/ sleep 1
# perf report -q | head 8.77% 8.77% :-1 [kernel.kallsyms] [k] format_decode 7.02% 7.02% :-1 [kernel.kallsyms] [k] seq_printf 7.02% 7.02% :-1 [unknown] [.] 0x0000ffff9f687c34 5.26% 5.26% :-1 [kernel.kallsyms] [k] vsnprintf 3.51% 3.51% :-1 [kernel.kallsyms] [k] string 3.51% 3.51% :-1 [unknown] [.] 0x0000ffff9f66ae20 3.51% 3.51% :-1 [unknown] [.] 0x0000ffff9f670b3c 3.51% 3.51% :-1 [unknown] [.] 0x0000ffff9f67c040 1.75% 1.75% :-1 [kernel.kallsyms] [k] ___cache_free 1.75% 1.75% :-1 [kernel.kallsyms] [k] __count_memcg_events
Like Intel PT, add context switch records to track task info. As ARM SPE support was added later than PERF_RECORD_SWITCH_CPU_WIDE, I think we can safely set the attr.context_switch bit and use it.
Reviewed-by: Leo Yan leo.yan@linaro.org Signed-off-by: German Gomez german.gomez@arm.com Signed-off-by: Namhyung Kim namhyung@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Will Deacon will@kernel.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20211111133625.193568-2-german.gomez@arm.com Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/arch/arm64/util/arm-spe.c | 6 +++++- tools/perf/util/arm-spe.c | 25 +++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c index 23e72d50565f..2bbfd5625b27 100644 --- a/tools/perf/arch/arm64/util/arm-spe.c +++ b/tools/perf/arch/arm64/util/arm-spe.c @@ -251,8 +251,12 @@ static int arm_spe_recording_options(struct auxtrace_record *itr, tracking_evsel->core.attr.sample_period = 1;
/* In per-cpu case, always need the time of mmap events etc */ - if (!perf_cpu_map__empty(cpus)) + if (!perf_cpu_map__empty(cpus)) { evsel__set_sample_bit(tracking_evsel, TIME); + evsel__set_sample_bit(tracking_evsel, CPU); + /* also track task context switch */ + tracking_evsel->core.attr.context_switch = 1; + }
return 0; } diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index 2196291976d9..9e3a6c54801d 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -681,6 +681,25 @@ static int arm_spe_process_timeless_queues(struct arm_spe *spe, pid_t tid, return 0; }
+static int arm_spe_context_switch(struct arm_spe *spe, union perf_event *event, + struct perf_sample *sample) +{ + pid_t pid, tid; + int cpu; + + if (!(event->header.misc & PERF_RECORD_MISC_SWITCH_OUT)) + return 0; + + pid = event->context_switch.next_prev_pid; + tid = event->context_switch.next_prev_tid; + cpu = sample->cpu; + + if (tid == -1) + pr_warning("context_switch event has no tid\n"); + + return machine__set_current_tid(spe->machine, cpu, pid, tid); +} + static int arm_spe_process_event(struct perf_session *session, union perf_event *event, struct perf_sample *sample, @@ -718,6 +737,12 @@ static int arm_spe_process_event(struct perf_session *session, } } else if (timestamp) { err = arm_spe_process_queues(spe, timestamp); + if (err) + return err; + + if (event->header.type == PERF_RECORD_SWITCH_CPU_WIDE || + event->header.type == PERF_RECORD_SWITCH) + err = arm_spe_context_switch(spe, event, sample); }
return err;
From: German Gomez german.gomez@arm.com
mainline inclusion from mainline-v5.16-rc1 commit 455c988225c7 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
Update 'perf record' docs and ARM SPE recording options so that they are consistent. This includes supporting the --no-switch-events flag in ARM SPE as well.
Reviewed-by: Leo Yan leo.yan@linaro.org Signed-off-by: German Gomez german.gomez@arm.com Acked-by: Namhyung Kim namhyung@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Will Deacon will@kernel.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20211111133625.193568-3-german.gomez@arm.com Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/Documentation/perf-record.txt | 2 +- tools/perf/arch/arm64/util/arm-spe.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 768888b9326a..fa5d203142f2 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -463,7 +463,7 @@ This option sets the time out limit. The default value is 500 ms.
--switch-events:: Record context switch events i.e. events of type PERF_RECORD_SWITCH or -PERF_RECORD_SWITCH_CPU_WIDE. In some cases (e.g. Intel PT or CoreSight) +PERF_RECORD_SWITCH_CPU_WIDE. In some cases (e.g. Intel PT, CoreSight or Arm SPE) switch events will be enabled automatically, which can be suppressed by by the option --no-switch-events.
diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c index 2bbfd5625b27..f3aa09647606 100644 --- a/tools/perf/arch/arm64/util/arm-spe.c +++ b/tools/perf/arch/arm64/util/arm-spe.c @@ -254,8 +254,10 @@ static int arm_spe_recording_options(struct auxtrace_record *itr, if (!perf_cpu_map__empty(cpus)) { evsel__set_sample_bit(tracking_evsel, TIME); evsel__set_sample_bit(tracking_evsel, CPU); + /* also track task context switch */ - tracking_evsel->core.attr.context_switch = 1; + if (!record_opts__no_switch_events(opts)) + tracking_evsel->core.attr.context_switch = 1; }
return 0;
From: German Gomez german.gomez@arm.com
mainline inclusion from mainline-v5.16-rc1 commit 169de64f5dc2 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
This patch is to save context ID in record, this will be used to set TID for samples.
Reviewed-by: Leo Yan leo.yan@linaro.org Signed-off-by: German Gomez german.gomez@arm.com Acked-by: Namhyung Kim namhyung@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Will Deacon will@kernel.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20211111133625.193568-4-german.gomez@arm.com Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe-decoder/arm-spe-decoder.c | 2 ++ tools/perf/util/arm-spe-decoder/arm-spe-decoder.h | 1 + 2 files changed, 3 insertions(+)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c index 32fe41835fa6..3fc528c9270c 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c @@ -151,6 +151,7 @@ static int arm_spe_read_record(struct arm_spe_decoder *decoder) u64 payload, ip;
memset(&decoder->record, 0x0, sizeof(decoder->record)); + decoder->record.context_id = (u64)-1;
while (1) { err = arm_spe_get_next_packet(decoder); @@ -180,6 +181,7 @@ static int arm_spe_read_record(struct arm_spe_decoder *decoder) case ARM_SPE_COUNTER: break; case ARM_SPE_CONTEXT: + decoder->record.context_id = payload; break; case ARM_SPE_OP_TYPE: if (idx == SPE_OP_PKT_HDR_CLASS_LD_ST_ATOMIC) { diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h index 59bdb7309674..46a8556a9e95 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h +++ b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h @@ -38,6 +38,7 @@ struct arm_spe_record { u64 timestamp; u64 virt_addr; u64 phys_addr; + u64 context_id; };
struct arm_spe_insn;
From: German Gomez german.gomez@arm.com
mainline inclusion from mainline-v5.16-rc1 commit 27d113cfe892 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
If ARM SPE traces contains CONTEXT packets with TID info, use these values for tracking the TID of samples. Otherwise fall back to using context switch events and display a message warning to the user of possible timing inaccuracies [1].
[1] https://lore.kernel.org/lkml/f877cfa6-9b25-6445-3806-ca44a4042eaf@arm.com/
Signed-off-by: German Gomez german.gomez@arm.com Acked-by: Namhyung Kim namhyung@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Leo Yan leo.yan@linaro.org Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Will Deacon will@kernel.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20211111133625.193568-5-german.gomez@arm.com Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe.c | 99 +++++++++++++++++++++++++++------------ 1 file changed, 70 insertions(+), 29 deletions(-)
diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index 9e3a6c54801d..4748bcfe61de 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -71,6 +71,7 @@ struct arm_spe { u64 kernel_start;
unsigned long num_events; + u8 use_ctx_pkt_for_pid; };
struct arm_spe_queue { @@ -226,6 +227,44 @@ static inline u8 arm_spe_cpumode(struct arm_spe *spe, u64 ip) PERF_RECORD_MISC_USER; }
+static void arm_spe_set_pid_tid_cpu(struct arm_spe *spe, + struct auxtrace_queue *queue) +{ + struct arm_spe_queue *speq = queue->priv; + pid_t tid; + + tid = machine__get_current_tid(spe->machine, speq->cpu); + if (tid != -1) { + speq->tid = tid; + thread__zput(speq->thread); + } else + speq->tid = queue->tid; + + if ((!speq->thread) && (speq->tid != -1)) { + speq->thread = machine__find_thread(spe->machine, -1, + speq->tid); + } + + if (speq->thread) { + speq->pid = speq->thread->pid_; + if (queue->cpu == -1) + speq->cpu = speq->thread->cpu; + } +} + +static int arm_spe_set_tid(struct arm_spe_queue *speq, pid_t tid) +{ + struct arm_spe *spe = speq->spe; + int err = machine__set_current_tid(spe->machine, speq->cpu, -1, tid); + + if (err) + return err; + + arm_spe_set_pid_tid_cpu(spe, &spe->queues.queue_array[speq->queue_nr]); + + return 0; +} + static void arm_spe_prep_sample(struct arm_spe *spe, struct arm_spe_queue *speq, union perf_event *event, @@ -460,6 +499,19 @@ static int arm_spe_run_decoder(struct arm_spe_queue *speq, u64 *timestamp) * can correlate samples between Arm SPE trace data and other * perf events with correct time ordering. */ + + /* + * Update pid/tid info. + */ + record = &speq->decoder->record; + if (!spe->timeless_decoding && record->context_id != (u64)-1) { + ret = arm_spe_set_tid(speq, record->context_id); + if (ret) + return ret; + + spe->use_ctx_pkt_for_pid = true; + } + ret = arm_spe_sample(speq); if (ret) return ret; @@ -586,31 +638,6 @@ static bool arm_spe__is_timeless_decoding(struct arm_spe *spe) return timeless_decoding; }
-static void arm_spe_set_pid_tid_cpu(struct arm_spe *spe, - struct auxtrace_queue *queue) -{ - struct arm_spe_queue *speq = queue->priv; - pid_t tid; - - tid = machine__get_current_tid(spe->machine, speq->cpu); - if (tid != -1) { - speq->tid = tid; - thread__zput(speq->thread); - } else - speq->tid = queue->tid; - - if ((!speq->thread) && (speq->tid != -1)) { - speq->thread = machine__find_thread(spe->machine, -1, - speq->tid); - } - - if (speq->thread) { - speq->pid = speq->thread->pid_; - if (queue->cpu == -1) - speq->cpu = speq->thread->cpu; - } -} - static int arm_spe_process_queues(struct arm_spe *spe, u64 timestamp) { unsigned int queue_nr; @@ -641,7 +668,12 @@ static int arm_spe_process_queues(struct arm_spe *spe, u64 timestamp) ts = timestamp; }
- arm_spe_set_pid_tid_cpu(spe, queue); + /* + * A previous context-switch event has set pid/tid in the machine's context, so + * here we need to update the pid/tid in the thread and SPE queue. + */ + if (!spe->use_ctx_pkt_for_pid) + arm_spe_set_pid_tid_cpu(spe, queue);
ret = arm_spe_run_decoder(speq, &ts); if (ret < 0) { @@ -740,8 +772,9 @@ static int arm_spe_process_event(struct perf_session *session, if (err) return err;
- if (event->header.type == PERF_RECORD_SWITCH_CPU_WIDE || - event->header.type == PERF_RECORD_SWITCH) + if (!spe->use_ctx_pkt_for_pid && + (event->header.type == PERF_RECORD_SWITCH_CPU_WIDE || + event->header.type == PERF_RECORD_SWITCH)) err = arm_spe_context_switch(spe, event, sample); }
@@ -808,7 +841,15 @@ static int arm_spe_flush(struct perf_session *session __maybe_unused, return arm_spe_process_timeless_queues(spe, -1, MAX_TIMESTAMP - 1);
- return arm_spe_process_queues(spe, MAX_TIMESTAMP); + ret = arm_spe_process_queues(spe, MAX_TIMESTAMP); + if (ret) + return ret; + + if (!spe->use_ctx_pkt_for_pid) + ui__warning("Arm SPE CONTEXT packets not found in the traces.\n" + "Matching of TIDs to SPE events could be inaccurate.\n"); + + return 0; }
static void arm_spe_free_queue(void *priv)
From: Arnaldo Carvalho de Melo acme@redhat.com
mainline inclusion from mainline-v5.16-rc2 commit 70f9c9b2df1d category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
As it is being used in tools/perf/arch/arm64/util/arm-spe.c and the COMPAT_NEED_REALLOCARRAY was only being set when CORESIGHT=1 is set.
Fixes: 56c31cdff7c2a640 ("perf arm-spe: Implement find_snapshot callback") Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: German Gomez german.gomez@arm.com Cc: James Clark james.clark@arm.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Leo Yan leo.yan@linaro.org Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Will Deacon will@kernel.org Link: https://lore.kernel.org/all/YZT63mIc7iY01er3@kernel.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/Makefile.config | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 014b959575ca..0acefa560df4 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -985,6 +985,9 @@ ifndef NO_AUXTRACE ifndef NO_AUXTRACE $(call detected,CONFIG_AUXTRACE) CFLAGS += -DHAVE_AUXTRACE_SUPPORT + ifeq ($(feature-reallocarray), 0) + CFLAGS += -DCOMPAT_NEED_REALLOCARRAY + endif endif endif
From: German Gomez german.gomez@arm.com
mainline inclusion from mainline-v5.16-rc2 commit 9e1a8d9f6832 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4NGPV CVE: NA
-------------------------------------------------
'perf inject' is currently not working for Arm SPE. When you try to run 'perf inject' and 'perf report' with a perf.data file that contains SPE traces, the tool reports a "Bad address" error:
# ./perf record -e arm_spe_0/ts_enable=1,store_filter=1,branch_filter=1,load_filter=1/ -a -- sleep 1 # ./perf inject -i perf.data -o perf.inject.data --itrace # ./perf report -i perf.inject.data --stdio
0x42c00 [0x8]: failed to process type: 9 [Bad address] Error: failed to process sample
As far as I know, the issue was first spotted in [1], but 'perf inject' was not yet injecting the samples. This patch does something similar to what cs_etm does for injecting the samples [2], but for SPE.
[1] https://patchwork.kernel.org/project/linux-arm-kernel/cover/20210412091006.4... [2] https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/pe...
Reviewed-by: James Clark james.clark@arm.com Signed-off-by: German Gomez german.gomez@arm.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Jiri Olsa jolsa@redhat.com Cc: John Garry john.garry@huawei.com Cc: Leo Yan leo.yan@linaro.org Cc: Mark Rutland mark.rutland@arm.com Cc: Mathieu Poirier mathieu.poirier@linaro.org Cc: Namhyung Kim namhyung@kernel.org Cc: Will Deacon will@kernel.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20211105104130.28186-2-german.gomez@arm.com Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Wei Li liwei391@huawei.com Reviewed-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- tools/perf/util/arm-spe.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index 4748bcfe61de..fccac06b573a 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -51,6 +51,7 @@ struct arm_spe { u8 timeless_decoding; u8 data_queued;
+ u64 sample_type; u8 sample_flc; u8 sample_llc; u8 sample_tlb; @@ -287,6 +288,12 @@ static void arm_spe_prep_sample(struct arm_spe *spe, event->sample.header.size = sizeof(struct perf_event_header); }
+static int arm_spe__inject_event(union perf_event *event, struct perf_sample *sample, u64 type) +{ + event->header.size = perf_event__sample_event_size(sample, type, 0); + return perf_event__synthesize_sample(event, type, 0, sample); +} + static inline int arm_spe_deliver_synth_event(struct arm_spe *spe, struct arm_spe_queue *speq __maybe_unused, @@ -295,6 +302,12 @@ arm_spe_deliver_synth_event(struct arm_spe *spe, { int ret;
+ if (spe->synth_opts.inject) { + ret = arm_spe__inject_event(event, sample, spe->sample_type); + if (ret) + return ret; + } + ret = perf_session__deliver_synth_event(spe->session, event, sample); if (ret) pr_err("ARM SPE: failed to deliver event, error %d\n", ret); @@ -986,6 +999,8 @@ arm_spe_synth_events(struct arm_spe *spe, struct perf_session *session) else attr.sample_type |= PERF_SAMPLE_TIME;
+ spe->sample_type = attr.sample_type; + attr.exclude_user = evsel->core.attr.exclude_user; attr.exclude_kernel = evsel->core.attr.exclude_kernel; attr.exclude_hv = evsel->core.attr.exclude_hv;
From: Chen Wandun chenwandun@huawei.com
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4OF4N
------------------------------------------
Function setup_psi_v1 is called before cgroup_v1_psi_init. Cgroup psi will be enable for a short time between the two functions, when passing parameter psi_v1=0 in kernel boot cmdline, that'is not unexpected behavior.
So the setting of psi_v1_disabled should be run in advance.
Fixes: f9a7d23ac0a0 ("psi: introduce psi_v1 boot parameter") Reported-by: Yang Yingliang yangyingliang@huawei.com Signed-off-by: Chen Wandun chenwandun@huawei.com Reviewed-by: Kefeng Wang wangkefeng.wang@huawei.com Reviewed-by: Kefeng Wang wangkefeng.wang@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- kernel/sched/cpuacct.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/kernel/sched/cpuacct.c b/kernel/sched/cpuacct.c index 60a95eb67d9b..e51c1f524b8c 100644 --- a/kernel/sched/cpuacct.c +++ b/kernel/sched/cpuacct.c @@ -380,16 +380,20 @@ struct cgroup_subsys cpuacct_cgrp_subsys = { static bool psi_v1_enable; static int __init setup_psi_v1(char *str) { - return kstrtobool(str, &psi_v1_enable) == 0; + int ret; + + ret = kstrtobool(str, &psi_v1_enable); + if (!psi_v1_enable) + static_branch_enable(&psi_v1_disabled); + + return ret == 0; } __setup("psi_v1=", setup_psi_v1);
static int __init cgroup_v1_psi_init(void) { - if (!psi_v1_enable) { - static_branch_enable(&psi_v1_disabled); + if (!psi_v1_enable) return 0; - }
cgroup_add_legacy_cftypes(&cpuacct_cgrp_subsys, cgroup_v1_psi_files); return 0;
From: Joseph Qi joseph.qi@linux.alibaba.com
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4OF4N
------------------------------------------
Fix the build error if CONFIG_CGROUP_CPUACCT is not enabled.
Fixes: a885e3f9e457 ("psi: support psi under cgroup v1") Signed-off-by: Joseph Qi joseph.qi@linux.alibaba.com Reviewed-by: Xunlei Pang xlpang@linux.alibaba.com Signed-off-by: Chen Wandun chenwandun@huawei.com Reviewed-by: Kefeng Wang wangkefeng.wang@huawei.com Reviewed-by: Kefeng Wang wangkefeng.wang@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- kernel/sched/psi.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/kernel/sched/psi.c b/kernel/sched/psi.c index 9f363830e40d..ddbd3d79b988 100644 --- a/kernel/sched/psi.c +++ b/kernel/sched/psi.c @@ -756,7 +756,11 @@ static struct psi_group *iterate_groups(struct task_struct *task, void **iter) if (static_branch_likely(&psi_v1_disabled)) cgroup = task->cgroups->dfl_cgrp; else +#ifdef CONFIG_CGROUP_CPUACCT cgroup = task_cgroup(task, cpuacct_cgrp_id); +#else + cgroup = NULL; +#endif } else if (*iter == &psi_system) return NULL; else
From: Xunlei Pang xlpang@linux.alibaba.com
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4OF4N
------------------------------------------
task_css() should be protected by rcu. In my environment if not protected by rcu qemu may fail to start.
Fixes: a885e3f9e457 ("psi: support psi under cgroup v1") Reported-by: Yang Yingliang yangyingliang@huawei.com Acked-by: Michael Wang yun.wany@linux.alibaba.com Signed-off-by: Xunlei Pang xlpang@linux.alibaba.com Signed-off-by: Yihao Wu wuyihao@linux.alibaba.com Acked-by: Yang Shi yang.shi@linux.alibaba.com Signed-off-by: Chen Wandun chenwandun@huawei.com Reviewed-by: Kefeng Wang wangkefeng.wang@huawei.com Reviewed-by: Kefeng Wang wangkefeng.wang@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- kernel/sched/psi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/kernel/sched/psi.c b/kernel/sched/psi.c index ddbd3d79b988..360f13382069 100644 --- a/kernel/sched/psi.c +++ b/kernel/sched/psi.c @@ -755,12 +755,15 @@ static struct psi_group *iterate_groups(struct task_struct *task, void **iter) if (!*iter) { if (static_branch_likely(&psi_v1_disabled)) cgroup = task->cgroups->dfl_cgrp; - else + else { #ifdef CONFIG_CGROUP_CPUACCT + rcu_read_lock(); cgroup = task_cgroup(task, cpuacct_cgrp_id); + rcu_read_unlock(); #else cgroup = NULL; #endif + } } else if (*iter == &psi_system) return NULL; else
From: Yuan Can yuancan@huawei.com
ascend inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4K2U5 CVE: NA
-------------------------------------------------------
Add suspend and resume support for smmuv3. The smmu is stopped when suspending and started when resuming.
Signed-off-by: Yuan Can yuancan@huawei.com Reviewed-by: Hanjun Guo guohanjun@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 97 ++++++++++++++++++--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 2 + 2 files changed, 89 insertions(+), 10 deletions(-)
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index 5a7e141d39cc..0702408997c9 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -4732,6 +4732,13 @@ static void arm_smmu_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg) doorbell = (((u64)msg->address_hi) << 32) | msg->address_lo; doorbell &= MSI_CFG0_ADDR_MASK;
+#ifdef CONFIG_PM_SLEEP + /* Saves the msg (base addr of msi irq) and restores it during resume */ + desc->msg.address_lo = msg->address_lo; + desc->msg.address_hi = msg->address_hi; + desc->msg.data = msg->data; +#endif + writeq_relaxed(doorbell, smmu->base + cfg[0]); writel_relaxed(msg->data, smmu->base + cfg[1]); writel_relaxed(ARM_SMMU_MEMATTR_DEVICE_nGnRE, smmu->base + cfg[2]); @@ -4787,11 +4794,51 @@ static void arm_smmu_setup_msis(struct arm_smmu_device *smmu) devm_add_action(dev, arm_smmu_free_msis, dev); }
-static void arm_smmu_setup_unique_irqs(struct arm_smmu_device *smmu) +#ifdef CONFIG_PM_SLEEP +static void arm_smmu_resume_msis(struct arm_smmu_device *smmu) +{ + struct msi_desc *desc; + struct device *dev = smmu->dev; + + for_each_msi_entry(desc, dev) { + switch (desc->platform.msi_index) { + case EVTQ_MSI_INDEX: + case GERROR_MSI_INDEX: + case PRIQ_MSI_INDEX: { + phys_addr_t *cfg = arm_smmu_msi_cfg[desc->platform.msi_index]; + struct msi_msg *msg = &desc->msg; + phys_addr_t doorbell = (((u64)msg->address_hi) << 32) | msg->address_lo; + + doorbell &= MSI_CFG0_ADDR_MASK; + writeq_relaxed(doorbell, smmu->base + cfg[0]); + writel_relaxed(msg->data, smmu->base + cfg[1]); + writel_relaxed(ARM_SMMU_MEMATTR_DEVICE_nGnRE, + smmu->base + cfg[2]); + break; + } + default: + continue; + + } + } +} +#else +static void arm_smmu_resume_msis(struct arm_smmu_device *smmu) +{ +} +#endif + +static void arm_smmu_setup_unique_irqs(struct arm_smmu_device *smmu, bool resume) { int irq, ret;
- arm_smmu_setup_msis(smmu); + if (!resume) + arm_smmu_setup_msis(smmu); + else { + /* The irq doesn't need to be re-requested during resume */ + arm_smmu_resume_msis(smmu); + return; + }
/* Request interrupt lines */ irq = smmu->evtq.q.irq; @@ -4833,7 +4880,7 @@ static void arm_smmu_setup_unique_irqs(struct arm_smmu_device *smmu) } }
-static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu) +static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu, bool resume) { int ret, irq; u32 irqen_flags = IRQ_CTRL_EVTQ_IRQEN | IRQ_CTRL_GERROR_IRQEN; @@ -4860,7 +4907,7 @@ static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu) if (ret < 0) dev_warn(smmu->dev, "failed to enable combined irq\n"); } else - arm_smmu_setup_unique_irqs(smmu); + arm_smmu_setup_unique_irqs(smmu, resume);
if (smmu->features & ARM_SMMU_FEAT_PRI) irqen_flags |= IRQ_CTRL_PRIQ_IRQEN; @@ -4885,7 +4932,7 @@ static int arm_smmu_device_disable(struct arm_smmu_device *smmu) return ret; }
-static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass) +static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool resume) { int i; int ret; @@ -5019,7 +5066,7 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass) } }
- ret = arm_smmu_setup_irqs(smmu); + ret = arm_smmu_setup_irqs(smmu, resume); if (ret) { dev_err(smmu->dev, "failed to setup irqs\n"); return ret; @@ -5029,7 +5076,7 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass) enables &= ~(CR0_EVTQEN | CR0_PRIQEN);
/* Enable the SMMU interface, or ensure bypass */ - if (!bypass || disable_bypass) { + if (!smmu->bypass || disable_bypass) { enables |= CR0_SMMUEN; } else { ret = arm_smmu_update_gbpa(smmu, 0, GBPA_ABORT); @@ -5645,6 +5692,26 @@ static void __iomem *arm_smmu_ioremap(struct device *dev, resource_size_t start, return devm_ioremap_resource(dev, &res); }
+#ifdef CONFIG_PM_SLEEP +static int arm_smmu_suspend(struct device *dev) +{ + /* + * The smmu is powered off and related registers are automatically + * cleared when suspend. No need to do anything. + */ + return 0; +} + +static int arm_smmu_resume(struct device *dev) +{ + struct arm_smmu_device *smmu = dev_get_drvdata(dev); + + arm_smmu_device_reset(smmu, true); + + return 0; +} +#endif + static int arm_smmu_device_probe(struct platform_device *pdev) { int irq, ret; @@ -5652,7 +5719,6 @@ static int arm_smmu_device_probe(struct platform_device *pdev) resource_size_t ioaddr; struct arm_smmu_device *smmu; struct device *dev = &pdev->dev; - bool bypass;
smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL); if (!smmu) { @@ -5670,7 +5736,7 @@ static int arm_smmu_device_probe(struct platform_device *pdev) }
/* Set bypass mode according to firmware probing result */ - bypass = !!ret; + smmu->bypass = !!ret;
/* Base address */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -5729,7 +5795,7 @@ static int arm_smmu_device_probe(struct platform_device *pdev) platform_set_drvdata(pdev, smmu);
/* Reset the device */ - ret = arm_smmu_device_reset(smmu, bypass); + ret = arm_smmu_device_reset(smmu, false); if (ret) return ret;
@@ -5776,6 +5842,16 @@ static const struct of_device_id arm_smmu_of_match[] = { }; MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
+#ifdef CONFIG_PM_SLEEP +static const struct dev_pm_ops arm_smmu_pm_ops = { + .suspend = arm_smmu_suspend, + .resume = arm_smmu_resume, +}; +#define ARM_SMMU_PM_OPS (&arm_smmu_pm_ops) +#else +#define ARM_SMMU_PM_OPS NULL +#endif + static void arm_smmu_driver_unregister(struct platform_driver *drv) { arm_smmu_sva_notifier_synchronize(); @@ -5787,6 +5863,7 @@ static struct platform_driver arm_smmu_driver = { .name = "arm-smmu-v3", .of_match_table = arm_smmu_of_match, .suppress_bind_attrs = true, + .pm = ARM_SMMU_PM_OPS, }, .probe = arm_smmu_device_probe, .remove = arm_smmu_device_remove, diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h index 0be76a9c15c0..1dd49bed58df 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h @@ -761,6 +761,8 @@ struct arm_smmu_device {
unsigned int mpam_partid_max; unsigned int mpam_pmg_max; + + bool bypass; };
struct arm_smmu_stream {
From: Xiongfeng Wang wangxiongfeng2@huawei.com
hulk inclusion category: bugfix bugzilla: 16100,20881,https://gitee.com/openeuler/kernel/issues/I4OG3O?from=project-issue CVE: NA
-------------------------------------------------
When I run a stress test about pcie hotplug and removing operations by sysfs, I got a hange task, and the following call trace is printed.
INFO: task irq/746-pciehp:41551 blocked for more than 120 seconds. Tainted: P W OE 4.19.25- "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. irq/746-pciehp D 0 41551 2 0x00000228 Call trace: __switch_to+0x94/0xe8 __schedule+0x270/0x8b0 schedule+0x2c/0x88 schedule_preempt_disabled+0x14/0x20 __mutex_lock.isra.1+0x1fc/0x540 __mutex_lock_slowpath+0x24/0x30 mutex_lock+0x80/0xa8 pci_lock_rescan_remove+0x20/0x28 pciehp_configure_device+0x30/0x140 pciehp_handle_presence_or_link_change+0x35c/0x4b0 pciehp_ist+0x1cc/0x1d0 irq_thread_fn+0x30/0x80 irq_thread+0x128/0x200 kthread+0x134/0x138 ret_from_fork+0x10/0x18 INFO: task bash:6424 blocked for more than 120 seconds. Tainted: P W OE 4.19.25- "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. bash D 0 6424 2231 0x00000200 Call trace: __switch_to+0x94/0xe8 __schedule+0x270/0x8b0 schedule+0x2c/0x88 schedule_timeout+0x224/0x448 wait_for_common+0x198/0x2a0 wait_for_completion+0x28/0x38 kthread_stop+0x60/0x190 __free_irq+0x1c0/0x348 free_irq+0x40/0x88 pcie_shutdown_notification+0x54/0x80 pciehp_remove+0x30/0x50 pcie_port_remove_service+0x3c/0x58 device_release_driver_internal+0x1b4/0x250 device_release_driver+0x28/0x38 bus_remove_device+0xd4/0x160 device_del+0x128/0x348 device_unregister+0x24/0x78 remove_iter+0x48/0x58 device_for_each_child+0x6c/0xb8 pcie_port_device_remove+0x2c/0x48 pcie_portdrv_remove+0x5c/0x68 pci_device_remove+0x48/0xd8 device_release_driver_internal+0x1b4/0x250 device_release_driver+0x28/0x38 pci_stop_bus_device+0x84/0xb8 pci_stop_and_remove_bus_device_locked+0x24/0x40 remove_store+0xa4/0xb8 dev_attr_store+0x44/0x60 sysfs_kf_write+0x58/0x80 kernfs_fop_write+0xe8/0x1f0 __vfs_write+0x60/0x190 vfs_write+0xac/0x1c0 ksys_write+0x6c/0xd8 __arm64_sys_write+0x24/0x30 el0_svc_common+0xa0/0x180 el0_svc_handler+0x38/0x78 el0_svc+0x8/0xc
When we remove a slot by sysfs. 'pci_stop_and_remove_bus_device_locked()' will be called. This function will get the global mutex lock 'pci_rescan_remove_lock', and remove the slot. If the irq thread 'pciehp_ist' is still running, we will wait until it exits.
If a pciehp interrupt happens immediately after we remove the slot by sysfs, but before we free the pciehp irq in 'pci_stop_and_remove_bus_device_locked()'. 'pciehp_ist' will hung because the global mutex lock 'pci_rescan_remove_lock' is held by the sysfs operation. But the sysfs operation is waiting for the pciehp irq thread 'pciehp_ist' ends. Then a hung task occurs.
So this two kinds of operation, removing through attention buttion and removing through /sys/devices/pci***/remove, should not be excuted at the same time. This patch add a global variable to mark that one of these operations is under processing. When this variable is set, if another operation is requested, it will be rejected.
We use a global variable 'slot_being_removed_rescaned' to mark whether a slot is being removed or rescaned. This will cause a slot hotplug operation is delayed if another slot is being remove or rescaned. But if these two slots are under different root ports, they should not influence each other. This patch make the flag 'slot_being_removed_rescanned' per root port so that one slot hotplug operation doesn't influence slots below another root port.
We record the root port in struct pci_dev when the pci device is initialized and added into the system instead of using 'pcie_find_root_port()' to find the root port when we need it. Because iterating the pci tree needs the protection of 'pci_lock_rescan_remove()'. This will make the problem more complexed because the lock is very coarse-grained. We don't need to worry about 'use-after-free' because child pci devices are always removed before the root port device is removed.
Signed-off-by: Xiongfeng Wang wangxiongfeng2@huawei.com Reviewed-by: Hanjun Guo guohanjun@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com Signed-off-by: Jialin Zhang zhangjialin11@huawei.com Reviewed-by: Xiongfeng Wang wangxiongfeng2@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/pci/hotplug/pciehp.h | 5 ++ drivers/pci/hotplug/pciehp_ctrl.c | 40 ++++++++++++++++ drivers/pci/hotplug/pciehp_hpc.c | 76 +++++++++++++++++++++++++++---- drivers/pci/pci-sysfs.c | 22 +++++++++ drivers/pci/probe.c | 5 ++ include/linux/pci.h | 7 +++ include/linux/workqueue.h | 2 + 7 files changed, 147 insertions(+), 10 deletions(-)
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 4fd200d8b0a9..5b17becc17c8 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -191,6 +191,11 @@ static inline const char *slot_name(struct controller *ctrl) return hotplug_slot_name(&ctrl->hotplug_slot); }
+static inline struct pci_dev *ctrl_dev(struct controller *ctrl) +{ + return ctrl->pcie->port; +} + static inline struct controller *to_ctrl(struct hotplug_slot *hotplug_slot) { return container_of(hotplug_slot, struct controller, hotplug_slot); diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 529c34808440..c0f621cfef2e 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -143,6 +143,8 @@ void pciehp_queue_pushbutton_work(struct work_struct *work) { struct controller *ctrl = container_of(work, struct controller, button_work.work); + int events = ctrl->button_work.data; + struct pci_dev *rpdev = ctrl_dev(ctrl)->rpdev;
mutex_lock(&ctrl->state_lock); switch (ctrl->state) { @@ -153,6 +155,15 @@ void pciehp_queue_pushbutton_work(struct work_struct *work) pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC); break; default: + if (events) { + atomic_or(events, &ctrl->pending_events); + if (!pciehp_poll_mode) + irq_wake_thread(ctrl->pcie->irq, ctrl); + } else { + if (rpdev) + clear_bit(0, + &rpdev->slot_being_removed_rescanned); + } break; } mutex_unlock(&ctrl->state_lock); @@ -160,6 +171,8 @@ void pciehp_queue_pushbutton_work(struct work_struct *work)
void pciehp_handle_button_press(struct controller *ctrl) { + struct pci_dev *rpdev = ctrl_dev(ctrl)->rpdev; + mutex_lock(&ctrl->state_lock); switch (ctrl->state) { case OFF_STATE: @@ -176,6 +189,7 @@ void pciehp_handle_button_press(struct controller *ctrl) /* blink power indicator and turn off attention */ pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK, PCI_EXP_SLTCTL_ATTN_IND_OFF); + ctrl->button_work.data = 0; schedule_delayed_work(&ctrl->button_work, 5 * HZ); break; case BLINKINGOFF_STATE: @@ -198,10 +212,14 @@ void pciehp_handle_button_press(struct controller *ctrl) } ctrl_info(ctrl, "Slot(%s): Action canceled due to button press\n", slot_name(ctrl)); + if (rpdev) + clear_bit(0, &rpdev->slot_being_removed_rescanned); break; default: ctrl_err(ctrl, "Slot(%s): Ignoring invalid state %#x\n", slot_name(ctrl), ctrl->state); + if (rpdev) + clear_bit(0, &rpdev->slot_being_removed_rescanned); break; } mutex_unlock(&ctrl->state_lock); @@ -209,6 +227,8 @@ void pciehp_handle_button_press(struct controller *ctrl)
void pciehp_handle_disable_request(struct controller *ctrl) { + struct pci_dev *rpdev = ctrl_dev(ctrl)->rpdev; + mutex_lock(&ctrl->state_lock); switch (ctrl->state) { case BLINKINGON_STATE: @@ -220,11 +240,14 @@ void pciehp_handle_disable_request(struct controller *ctrl) mutex_unlock(&ctrl->state_lock);
ctrl->request_result = pciehp_disable_slot(ctrl, SAFE_REMOVAL); + if (rpdev) + clear_bit(0, &rpdev->slot_being_removed_rescanned); }
void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events) { int present, link_active; + struct pci_dev *rpdev = ctrl_dev(ctrl)->rpdev;
/* * If the slot is on and presence or link has changed, turn it off. @@ -257,6 +280,8 @@ void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events) link_active = pciehp_check_link_active(ctrl); if (present <= 0 && link_active <= 0) { mutex_unlock(&ctrl->state_lock); + if (rpdev) + clear_bit(0, &rpdev->slot_being_removed_rescanned); return; }
@@ -279,6 +304,8 @@ void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events) mutex_unlock(&ctrl->state_lock); break; } + if (rpdev) + clear_bit(0, &rpdev->slot_being_removed_rescanned); }
static int __pciehp_enable_slot(struct controller *ctrl) @@ -399,6 +426,14 @@ int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot) int pciehp_sysfs_disable_slot(struct hotplug_slot *hotplug_slot) { struct controller *ctrl = to_ctrl(hotplug_slot); + struct pci_dev *rpdev = ctrl_dev(ctrl)->rpdev; + + if (rpdev && test_and_set_bit(0, + &rpdev->slot_being_removed_rescanned)) { + ctrl_info(ctrl, "Slot(%s): Slot is being removed or rescanned, please try later!\n", + slot_name(ctrl)); + return -EINVAL; + }
mutex_lock(&ctrl->state_lock); switch (ctrl->state) { @@ -409,6 +444,8 @@ int pciehp_sysfs_disable_slot(struct hotplug_slot *hotplug_slot) wait_event(ctrl->requester, !atomic_read(&ctrl->pending_events) && !ctrl->ist_running); + if (rpdev) + clear_bit(0, &rpdev->slot_being_removed_rescanned); return ctrl->request_result; case POWEROFF_STATE: ctrl_info(ctrl, "Slot(%s): Already in powering off state\n", @@ -427,5 +464,8 @@ int pciehp_sysfs_disable_slot(struct hotplug_slot *hotplug_slot) } mutex_unlock(&ctrl->state_lock);
+ if (rpdev) + clear_bit(0, &rpdev->slot_being_removed_rescanned); + return -ENODEV; } diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 9d06939736c0..b0a132265a39 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -45,11 +45,6 @@ static const struct dmi_system_id inband_presence_disabled_dmi_table[] = { {} };
-static inline struct pci_dev *ctrl_dev(struct controller *ctrl) -{ - return ctrl->pcie->port; -} - static irqreturn_t pciehp_isr(int irq, void *dev_id); static irqreturn_t pciehp_ist(int irq, void *dev_id); static int pciehp_poll(void *data); @@ -696,6 +691,7 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id) { struct controller *ctrl = (struct controller *)dev_id; struct pci_dev *pdev = ctrl_dev(ctrl); + struct pci_dev *rpdev = pdev->rpdev; irqreturn_t ret; u32 events;
@@ -721,7 +717,18 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id) if (events & PCI_EXP_SLTSTA_ABP) { ctrl_info(ctrl, "Slot(%s): Attention button pressed\n", slot_name(ctrl)); - pciehp_handle_button_press(ctrl); + if (!rpdev || (rpdev && !test_and_set_bit(0, + &rpdev->slot_being_removed_rescanned))) + pciehp_handle_button_press(ctrl); + else { + if (ctrl->state == BLINKINGOFF_STATE || + ctrl->state == BLINKINGON_STATE) + pciehp_handle_button_press(ctrl); + else + ctrl_info(ctrl, "Slot(%s): Slot operation failed because a remove or" + " rescan operation is under processing, please try later!\n", + slot_name(ctrl)); + } }
/* Check Power Fault Detected */ @@ -747,10 +754,59 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id) * or Data Link Layer State Changed events. */ down_read(&ctrl->reset_lock); - if (events & DISABLE_SLOT) - pciehp_handle_disable_request(ctrl); - else if (events & (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC)) - pciehp_handle_presence_or_link_change(ctrl, events); + if (events & DISABLE_SLOT) { + if (!rpdev || (rpdev && !test_and_set_bit(0, + &rpdev->slot_being_removed_rescanned))) + pciehp_handle_disable_request(ctrl); + else { + if (ctrl->state == BLINKINGOFF_STATE || + ctrl->state == BLINKINGON_STATE) + pciehp_handle_disable_request(ctrl); + else { + ctrl_info(ctrl, "Slot(%s): DISABLE_SLOT event in remove or rescan process!\n", + slot_name(ctrl)); + /* + * we use the work_struct private data to store + * the event type + */ + ctrl->button_work.data = DISABLE_SLOT; + /* + * If 'work.timer' is pending, schedule the work will + * cause BUG_ON(). + */ + if (!timer_pending(&ctrl->button_work.timer)) + schedule_delayed_work(&ctrl->button_work, 3 * HZ); + else + ctrl_info(ctrl, "Slot(%s): Didn't schedule delayed_work because timer is pending!\n", + slot_name(ctrl)); + } + } + } else if (events & (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC)) { + if (!rpdev || (rpdev && !test_and_set_bit(0, + &rpdev->slot_being_removed_rescanned))) + pciehp_handle_presence_or_link_change(ctrl, events); + else { + if (ctrl->state == BLINKINGOFF_STATE || + ctrl->state == BLINKINGON_STATE) + pciehp_handle_presence_or_link_change(ctrl, + events); + else { + /* + * When we are removing or rescanning through + * sysfs, suprise link down/up happens. So we + * will handle this event 3 seconds later. + */ + ctrl_info(ctrl, "Slot(%s): Surprise link down/up in remove or rescan process!\n", + slot_name(ctrl)); + ctrl->button_work.data = events & (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC); + if (!timer_pending(&ctrl->button_work.timer)) + schedule_delayed_work(&ctrl->button_work, 3 * HZ); + else + ctrl_info(ctrl, "Slot(%s): Didn't schedule delayed_work because timer is pending!\n", + slot_name(ctrl)); + } + } + } up_read(&ctrl->reset_lock);
ret = IRQ_HANDLED; diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index d15c881e2e7e..8b8776189e81 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -454,12 +454,34 @@ static ssize_t remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long val; + struct pci_dev *rpdev = to_pci_dev(dev)->rpdev;
if (kstrtoul(buf, 0, &val) < 0) return -EINVAL;
+ if (rpdev && test_and_set_bit(0, + &rpdev->slot_being_removed_rescanned)) { + pr_info("Slot is being removed or rescanned, please try later!\n"); + return -EINVAL; + } + + /* + * if 'dev' is root port itself, 'pci_stop_and_remove_bus_device()' may + * free the 'rpdev', but we need to clear + * 'rpdev->slot_being_removed_rescanned' in the end. So get 'rpdev' to + * avoid possible 'use-after-free'. + */ + if (rpdev) + pci_dev_get(rpdev); + if (val && device_remove_file_self(dev, attr)) pci_stop_and_remove_bus_device_locked(to_pci_dev(dev)); + + if (rpdev) { + clear_bit(0, &rpdev->slot_being_removed_rescanned); + pci_dev_put(rpdev); + } + return count; } static DEVICE_ATTR_IGNORE_LOCKDEP(remove, 0220, NULL, diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 0187fe60b7d8..6a54bdcd5631 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2513,6 +2513,11 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) /* Set up MSI IRQ domain */ pci_set_msi_domain(dev);
+ if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) + dev->rpdev = dev; + else + dev->rpdev = pcie_find_root_port(dev); + /* Notifier could use PCI capabilities */ dev->match_driver = false; ret = device_add(&dev->dev); diff --git a/include/linux/pci.h b/include/linux/pci.h index 774cf41565a5..7d4e52256e3a 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -503,6 +503,12 @@ struct pci_dev { char *driver_override; /* Driver name to force a match */
unsigned long priv_flags; /* Private flags for the PCI driver */ + /* + * This flag is only set on root ports. When a slot below a root port + * is being removed or rescanned, this flag is set. + */ + unsigned long slot_being_removed_rescanned; + struct pci_dev *rpdev; /* root port pci_dev */ };
static inline struct pci_dev *pci_physfn(struct pci_dev *dev) @@ -989,6 +995,7 @@ extern struct bus_type pci_bus_type; /* Do NOT directly access these two variables, unless you are arch-specific PCI * code, or PCI core code. */ extern struct list_head pci_root_buses; /* List of all known PCI buses */ + /* Some device drivers need know if PCI is initiated */ int no_pci_devices(void);
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 0c35ad697a7b..a48e8ea06d74 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -119,6 +119,8 @@ struct delayed_work { /* target workqueue and CPU ->timer uses to queue ->work */ struct workqueue_struct *wq; int cpu; + /* delayed_work private data, only used in pciehp now */ + unsigned long data; };
struct rcu_work {
From: Xiongfeng Wang wangxiongfeng2@huawei.com
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4OG3O?from=project-issue CVE: NA
------------------------------------
When I do some aer-inject and sysfs remove stress tests, I got the following use-after-free Calltrace:
================================================================== BUG: KASAN: use-after-free in pci_stop_bus_device+0x174/0x178 Read of size 8 at addr fffffc3e2e402218 by task bash/26311
CPU: 38 PID: 26311 Comm: bash Tainted: G W 4.19.105+ #82 Hardware name: Huawei TaiShan 2280 V2/BC82AMDC, BIOS 2280-V2 CS V5.B161.01 06/10/2021 Call trace: dump_backtrace+0x0/0x360 show_stack+0x24/0x30 dump_stack+0x130/0x164 print_address_description+0x68/0x278 kasan_report+0x204/0x330 __asan_report_load8_noabort+0x30/0x40 pci_stop_bus_device+0x174/0x178 pci_stop_and_remove_bus_device_locked+0x24/0x40 remove_store+0x1c8/0x1e0 dev_attr_store+0x60/0x80 sysfs_kf_write+0x104/0x170 kernfs_fop_write+0x23c/0x430 __vfs_write+0xec/0x4e0 vfs_write+0x12c/0x3d0 ksys_write+0xe8/0x208 __arm64_sys_write+0x70/0xa0 el0_svc_common+0x10c/0x450 el0_svc_handler+0x50/0xc0 el0_svc+0x10/0x14
Allocated by task 684: kasan_kmalloc+0xe0/0x190 kmem_cache_alloc_trace+0x110/0x240 pci_alloc_dev+0x4c/0x110 pci_scan_single_device+0x100/0x218 pci_scan_slot+0x8c/0x2d8 pci_scan_child_bus_extend+0x90/0x628 pci_scan_child_bus+0x24/0x30 pci_scan_bridge_extend+0x3b8/0xb28 pci_scan_child_bus_extend+0x350/0x628 pci_rescan_bus+0x24/0x48 pcie_do_fatal_recovery+0x390/0x4b0 handle_error_source+0x124/0x158 aer_isr+0x5a0/0x800 process_one_work+0x598/0x1250 worker_thread+0x384/0xf08 kthread+0x2a4/0x320 ret_from_fork+0x10/0x18
Freed by task 685: __kasan_slab_free+0x120/0x228 kasan_slab_free+0x10/0x18 kfree+0x88/0x218 pci_release_dev+0xb4/0xd8 device_release+0x6c/0x1c0 kobject_put+0x12c/0x400 put_device+0x24/0x30 pci_dev_put+0x24/0x30 handle_error_source+0x12c/0x158 aer_isr+0x5a0/0x800 process_one_work+0x598/0x1250 worker_thread+0x384/0xf08 kthread+0x2a4/0x320 ret_from_fork+0x10/0x18
The buggy address belongs to the object at fffffc3e2e402200 which belongs to the cache kmalloc-4096 of size 4096 The buggy address is located 24 bytes inside of 4096-byte region [fffffc3e2e402200, fffffc3e2e403200) The buggy address belongs to the page: page:ffff7ff0f8b90000 count:1 mapcount:0 mapping:ffffdc365f016e00 index:0x0 compound_mapcount: 0 flags: 0x6ffffe0000008100(slab|head) raw: 6ffffe0000008100 ffff7f70d83aae00 0000000300000003 ffffdc365f016e00 raw: 0000000000000000 0000000080070007 00000001ffffffff 0000000000000000 page dumped because: kasan: bad access detected
Memory state around the buggy address: fffffc3e2e402100: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fffffc3e2e402180: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
fffffc3e2e402200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^ fffffc3e2e402280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fffffc3e2e402300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ==================================================================
It is caused by the following race condition:
CPU0 CPU1 remove_store() aer_isr() device_remove_file_self() handle_error_source() pci_stop_and_remove_bus_device_locked pcie_do_fatal_recovery() (blocked) pci_lock_rescan_remove() #CPU1 acquire the lock pci_stop_and_remove_bus_device() pci_unlock_rescan_remove() #CPU1 release the lock pci_lock_rescan_remove() #CPU0 acquire the lock pci_dev_put() #free pci_dev pci_stop_and_remove_bus_device() pci_stop_bus_device() #use-after-free pci_unlock_rescan_remove()
An AER interrupt is triggered on CPU1. CPU1 starts to process it. A work 'aer_isr()' is scheduled on CPU1. It calling into pcie_do_fatal_recovery(), and aquire lock 'pci_rescan_remove_lock'. Before it removes the sysfs corresponding to the error pci device, a sysfs remove operation is executed on CPU0. CPU0 use device_remove_file_self() to remove the sysfs directory and wait for the lock to be released. After CPU1 finish pci_stop_and_remove_bus_device(), it release the lock and free the 'pci_dev' in pci_dev_put(). CPU0 acquire the lock and access the 'pci_dev'. Then a use-after-free is triggered.
To fix this issue, we increase the reference count in remove_store() before remove the device and decrease the reference count in the end.
Signed-off-by: Xiongfeng Wang wangxiongfeng2@huawei.com Reviewed-by: Hanjun Guo guohanjun@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com Signed-off-by: Jialin Zhang zhangjialin11@huawei.com Reviewed-by: Xiongfeng Wang wangxiongfeng2@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/pci/pci-sysfs.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 8b8776189e81..d012fbe7a113 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -454,7 +454,8 @@ static ssize_t remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long val; - struct pci_dev *rpdev = to_pci_dev(dev)->rpdev; + struct pci_dev *pdev = to_pci_dev(dev); + struct pci_dev *rpdev = pdev->rpdev;
if (kstrtoul(buf, 0, &val) < 0) return -EINVAL; @@ -474,8 +475,12 @@ static ssize_t remove_store(struct device *dev, struct device_attribute *attr, if (rpdev) pci_dev_get(rpdev);
- if (val && device_remove_file_self(dev, attr)) - pci_stop_and_remove_bus_device_locked(to_pci_dev(dev)); + if (val) { + pci_dev_get(pdev); + if (device_remove_file_self(dev, attr)) + pci_stop_and_remove_bus_device_locked(pdev); + pci_dev_put(pdev); + }
if (rpdev) { clear_bit(0, &rpdev->slot_being_removed_rescanned);
From: Xiongfeng Wang xiongfeng.wang@linaro.org
euler inclusion category: bugfix bugzilla: 4390,https://gitee.com/openeuler/kernel/issues/I4OG3O?from=project-issue CVE: NA
----------------------------------------
This patch add check for the offset of MSI-X Table. If it is out of range of the BAR space BIR selects, we just fail this MSI-X mapping.
Signed-off-by: Xiongfeng Wang xiongfeng.wang@linaro.org Reviewed-by: Hanjun Guo guohanjun@huawei.com Signed-off-by: Mao Wenan maowenan@huawei.com Signed-off-by: Hui Wang john.wanghui@huawei.com
Signed-off-by: Zhang Xiaoxu zhangxiaoxu5@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com Reviewed-by: Xiongfeng Wang wangxiongfeng2@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com Signed-off-by: Jialin Zhang zhangjialin11@huawei.com Reviewed-by: Xiongfeng Wang wangxiongfeng2@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/pci/msi.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index db7475dc601f..294b16cde9e7 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -711,6 +711,12 @@ static void __iomem *msix_map_region(struct pci_dev *dev, unsigned nr_entries) return NULL;
table_offset &= PCI_MSIX_TABLE_OFFSET; + if (table_offset >= pci_resource_len(dev, bir)) { + dev_err(&dev->dev, + "MSI-X Table offset is out of range of BAR:%d!\n", + bir); + return NULL; + } phys_addr = pci_resource_start(dev, bir) + table_offset;
return ioremap(phys_addr, nr_entries * PCI_MSIX_ENTRY_SIZE);
From: Xiongfeng Wang wangxiongfeng2@huawei.com
hulk inclusion category: bugfix bugzilla: 4390,https://gitee.com/openeuler/kernel/issues/I4OG3O?from=project-issue CVE: NA -------------------
We use 'bir' as the index of array resource[DEVICE_COUNT_RESOURCE]. Wrong 'bir' will cause access out of range. This patch add a check for 'bir'.
Signed-off-by: Xiongfeng Wang wangxiongfeng2@huawei.com Reviewed-by: Yang Yingliang yangyingliang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com Signed-off-by: Jialin Zhang zhangjialin11@huawei.com Reviewed-by: Xiongfeng Wang wangxiongfeng2@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/pci/msi.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 294b16cde9e7..b165a88c8f85 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -706,6 +706,11 @@ static void __iomem *msix_map_region(struct pci_dev *dev, unsigned nr_entries) pci_read_config_dword(dev, dev->msix_cap + PCI_MSIX_TABLE, &table_offset); bir = (u8)(table_offset & PCI_MSIX_TABLE_BIR); + if (bir >= DEVICE_COUNT_RESOURCE) { + dev_err(&dev->dev, "MSI-X Table BIR is out of range !\n"); + return NULL; + } + flags = pci_resource_flags(dev, bir); if (!flags || (flags & IORESOURCE_UNSET)) return NULL;
From: Xiongfeng Wang wangxiongfeng2@huawei.com
hulk inclusion category: bugfix bugzilla: 20702,https://gitee.com/openeuler/kernel/issues/I4OG3O?from=project-issue CVE: NA ---------------------------
When I inject a PCIE Fatal error into a mellanox netdevice, 'dmesg' shows the device is recovered successfully, but 'lspci' didn't show the device. I checked the configuration space of the slot where the netdevice is inserted and found out the bit 'PCI_BRIDGE_CTL_BUS_RESET' is set. Later, I found out it is because this bit is saved in 'saved_config_space' of 'struct pci_dev' when 'pci_pm_runtime_suspend()' is called. And 'PCI_BRIDGE_CTL_BUS_RESET' is set every time we restore the configuration sapce.
This patch avoid saving the bit 'PCI_BRIDGE_CTL_BUS_RESET' when we save the configuration space of a bridge.
Signed-off-by: Xiongfeng Wang wangxiongfeng2@huawei.com Reviewed-by: Hanjun Guo guohanjun@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com Signed-off-by: Jialin Zhang zhangjialin11@huawei.com Reviewed-by: Xiongfeng Wang wangxiongfeng2@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/pci/pci.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 0d7109018a91..666fcc4c37a0 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1553,6 +1553,9 @@ int pci_save_state(struct pci_dev *dev) pci_dbg(dev, "saving config space at offset %#x (reading %#x)\n", i * 4, dev->saved_config_space[i]); } + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) + dev->saved_config_space[PCI_BRIDGE_CONTROL / 4] &= + ~(PCI_BRIDGE_CTL_BUS_RESET << 16); dev->state_saved = true;
i = pci_save_pcie_state(dev);