lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <CAPqJEFpSvaa9xKQ4Rtork6ma8__mmBLRCMAeZR8e_-kMW324oQ@mail.gmail.com>
Date: Fri, 6 Feb 2026 21:07:36 +0800
From: Eric Lin <eric.lin@...ive.com>
To: Anup Patel <apatel@...tanamicro.com>
Cc: Rob Herring <robh@...nel.org>, Krzysztof Kozlowski <krzk+dt@...nel.org>, 
	Conor Dooley <conor+dt@...nel.org>, Paul Walmsley <paul.walmsley@...ive.com>, 
	Palmer Dabbelt <palmer@...belt.com>, Greg KH <gregkh@...uxfoundation.org>, 
	Alexander Shishkin <alexander.shishkin@...ux.intel.com>, Ian Rogers <irogers@...gle.com>, 
	Mark Rutland <mark.rutland@....com>, devicetree@...r.kernel.org, 
	Alexandre Ghiti <alex@...ti.fr>, Atish Patra <atish.patra@...ux.dev>, 
	Peter Zijlstra <peterz@...radead.org>, Anup Patel <anup@...infault.org>, 
	Adrian Hunter <adrian.hunter@...el.com>, linux-kernel@...r.kernel.org, 
	Mayuresh Chitale <mchitale@...tanamicro.com>, Ingo Molnar <mingo@...hat.com>, 
	Jiri Olsa <jolsa@...nel.org>, Mayuresh Chitale <mchitale@...il.com>, 
	Namhyung Kim <namhyung@...nel.org>, linux-riscv@...ts.infradead.org, 
	Andrew Jones <ajones@...tanamicro.com>, Liang Kan <kan.liang@...ux.intel.com>
Subject: Re: [PATCH v2 09/12] rvtrace: Add perf driver for tracing using perf tool

Hi Anup,

On Sat, Nov 1, 2025 at 11:45 PM Anup Patel <apatel@...tanamicro.com> wrote:
>
> From: Mayuresh Chitale <mchitale@...tanamicro.com>
>
> Add perf driver for RISC-V tracing similar to ARM Coresight and Hisilicon
> PTT drivers. The driver adds 'rvtrace' event descriptor which can be used
> by the perf tool to record the RISC-V trace data.
>
> Co-developed-by: Anup Patel <apatel@...tanamicro.com>
> Signed-off-by: Anup Patel <apatel@...tanamicro.com>
> Signed-off-by: Mayuresh Chitale <mchitale@...tanamicro.com>
> ---
>  drivers/hwtracing/rvtrace/Kconfig        |   1 +
>  drivers/hwtracing/rvtrace/Makefile       |   2 +-
>  drivers/hwtracing/rvtrace/rvtrace-core.c |   8 +
>  drivers/hwtracing/rvtrace/rvtrace-perf.c | 343 +++++++++++++++++++++++
>  include/linux/rvtrace.h                  |   3 +
>  5 files changed, 356 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/hwtracing/rvtrace/rvtrace-perf.c
>
> diff --git a/drivers/hwtracing/rvtrace/Kconfig b/drivers/hwtracing/rvtrace/Kconfig
> index 0577f9acb858..ba11acf1117d 100644
> --- a/drivers/hwtracing/rvtrace/Kconfig
> +++ b/drivers/hwtracing/rvtrace/Kconfig
> @@ -4,6 +4,7 @@ menuconfig RVTRACE
>         tristate "RISC-V Trace Support"
>         depends on RISCV
>         depends on OF
> +       select PERF_EVENTS
>         default RISCV
>         help
>           This framework provides a kernel interface for the RISC-V trace
> diff --git a/drivers/hwtracing/rvtrace/Makefile b/drivers/hwtracing/rvtrace/Makefile
> index 122e575da9fb..07403f4d94e3 100644
> --- a/drivers/hwtracing/rvtrace/Makefile
> +++ b/drivers/hwtracing/rvtrace/Makefile
> @@ -1,6 +1,6 @@
>  # SPDX-License-Identifier: GPL-2.0
>
>  obj-$(CONFIG_RVTRACE) += rvtrace.o
> -rvtrace-y := rvtrace-core.o rvtrace-platform.o
> +rvtrace-y := rvtrace-core.o rvtrace-platform.o rvtrace-perf.o
>  obj-$(CONFIG_RVTRACE_ENCODER) += rvtrace-encoder.o
>  obj-$(CONFIG_RVTRACE_RAMSINK) += rvtrace-ramsink.o
> diff --git a/drivers/hwtracing/rvtrace/rvtrace-core.c b/drivers/hwtracing/rvtrace/rvtrace-core.c
> index b955e5f3b048..bbe39aaf930d 100644
> --- a/drivers/hwtracing/rvtrace/rvtrace-core.c
> +++ b/drivers/hwtracing/rvtrace/rvtrace-core.c
> @@ -777,11 +777,19 @@ static int __init rvtrace_init(void)
>                 return ret;
>         }
>
> +       ret = rvtrace_perf_init();
> +       if (ret) {
> +               platform_driver_unregister(&rvtrace_platform_driver);
> +               bus_unregister(&rvtrace_bustype);
> +               return ret;
> +       }
> +
>         return 0;
>  }
>
>  static void __exit rvtrace_exit(void)
>  {
> +       rvtrace_perf_exit();
>         platform_driver_unregister(&rvtrace_platform_driver);
>         bus_unregister(&rvtrace_bustype);
>  }
> diff --git a/drivers/hwtracing/rvtrace/rvtrace-perf.c b/drivers/hwtracing/rvtrace/rvtrace-perf.c
> new file mode 100644
> index 000000000000..2d3039f8b681
> --- /dev/null
> +++ b/drivers/hwtracing/rvtrace/rvtrace-perf.c
> @@ -0,0 +1,343 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright(C) 2025 Ventanamicro Limited. All rights reserved.
> + * Author: Mayuresh Chitale <mchitale@...anamicro.com>
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/cpumask.h>
> +#include <linux/device.h>
> +#include <linux/list.h>
> +#include <linux/mm.h>
> +#include <linux/init.h>
> +#include <linux/perf_event.h>
> +#include <linux/vmalloc.h>
> +#include <linux/percpu-defs.h>
> +#include <linux/slab.h>
> +#include <linux/stringhash.h>
> +#include <linux/types.h>
> +#include <linux/workqueue.h>
> +#include <linux/rvtrace.h>
> +
> +#define RVTRACE_PMU_NAME "rvtrace"
> +#define RVTRACE_BUF_LEN (4 * 1024 * 1024)

Currently, it seems "RVTRACE_BUF_LEN" is not used. Should we remove it?

Best regards,
Eric Lin

> +
> +static struct pmu rvtrace_pmu;
> +static DEFINE_SPINLOCK(perf_buf_lock);
> +
> +/**
> + * struct rvtrace_event_data - RISC-V trace specific perf event data
> + * @work:              Handle to free allocated memory outside IRQ context.
> + * @mask:              Hold the CPU(s) this event was set for.
> + * @aux_hwid_done:     Whether a CPU has emitted the TraceID packet or not.
> + * @path:              An array of path, each slot for one CPU.
> + * @buf:               Aux buffer / pages allocated by perf framework.
> + */
> +struct rvtrace_event_data {
> +       struct work_struct work;
> +       cpumask_t mask;
> +       cpumask_t aux_hwid_done;
> +       struct rvtrace_path * __percpu *path;
> +       struct rvtrace_perf_auxbuf buf;
> +};
> +
> +struct rvtrace_ctxt {
> +       struct perf_output_handle handle;
> +       struct rvtrace_event_data *event_data;
> +};
> +
> +static DEFINE_PER_CPU(struct rvtrace_ctxt, rvtrace_ctxt);
> +
> +static void *alloc_event_data(int cpu)
> +{
> +       struct rvtrace_event_data *event_data;
> +       cpumask_t *mask;
> +
> +       event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
> +       if (!event_data)
> +               return NULL;
> +
> +       /* Update mask as per selected CPUs */
> +       mask = &event_data->mask;
> +       if (cpu != -1)
> +               cpumask_set_cpu(cpu, mask);
> +       else
> +               cpumask_copy(mask, cpu_present_mask);
> +
> +       event_data->path = alloc_percpu(struct rvtrace_path *);
> +       return event_data;
> +}
> +
> +static void rvtrace_free_aux(void *data)
> +{
> +       struct rvtrace_event_data *event_data = data;
> +
> +       schedule_work(&event_data->work);
> +}
> +
> +static struct rvtrace_path **rvtrace_event_cpu_path_ptr(struct rvtrace_event_data *data,
> +                                                       int cpu)
> +{
> +       return per_cpu_ptr(data->path, cpu);
> +}
> +
> +static void free_event_data(struct work_struct *work)
> +{
> +       struct rvtrace_event_data *event_data;
> +       struct rvtrace_path *path;
> +       cpumask_t *mask;
> +       int cpu;
> +
> +       event_data = container_of(work, struct rvtrace_event_data, work);
> +       mask = &event_data->mask;
> +       for_each_cpu(cpu, mask) {
> +               path = *rvtrace_event_cpu_path_ptr(event_data, cpu);
> +               rvtrace_destroy_path(path);
> +       }
> +       free_percpu(event_data->path);
> +       kfree(event_data);
> +}
> +
> +static void *rvtrace_setup_aux(struct perf_event *event, void **pages,
> +                              int nr_pages, bool overwrite)
> +{
> +       struct rvtrace_event_data *event_data = NULL;
> +       struct page **pagelist;
> +       int cpu = event->cpu, i;
> +       cpumask_t *mask;
> +
> +       event_data = alloc_event_data(cpu);
> +       if (!event_data)
> +               return NULL;
> +
> +       INIT_WORK(&event_data->work, free_event_data);
> +       mask = &event_data->mask;
> +       /*
> +        * Create the path for each CPU in the mask. In case of any failure skip the CPU
> +        */
> +       for_each_cpu(cpu, mask) {
> +               struct rvtrace_component *src;
> +               struct rvtrace_path *path;
> +
> +               src = rvtrace_cpu_source(cpu);
> +               if (!src)
> +                       continue;
> +
> +               path = rvtrace_create_path(src, NULL, RVTRACE_COMPONENT_MODE_PERF);
> +               if (!path)
> +                       continue;
> +
> +               *rvtrace_event_cpu_path_ptr(event_data, cpu) = path;
> +       }
> +
> +       /* If we don't have any CPUs ready for tracing, abort */
> +       cpu = cpumask_first(&event_data->mask);
> +       if (cpu >= nr_cpu_ids)
> +               goto err;
> +
> +       pagelist = kcalloc(nr_pages, sizeof(*pagelist), GFP_KERNEL);
> +       if (!pagelist)
> +               goto err;
> +
> +       for (i = 0; i < nr_pages; i++)
> +               pagelist[i] = virt_to_page(pages[i]);
> +
> +       event_data->buf.base = vmap(pagelist, nr_pages, VM_MAP, PAGE_KERNEL);
> +       if (!event_data->buf.base) {
> +               kfree(pagelist);
> +               goto err;
> +       }
> +
> +       event_data->buf.nr_pages = nr_pages;
> +       event_data->buf.length = nr_pages * PAGE_SIZE;
> +       event_data->buf.pos = 0;
> +       return event_data;
> +err:
> +       rvtrace_free_aux(event_data);
> +       return NULL;
> +}
> +
> +static void rvtrace_event_read(struct perf_event *event)
> +{
> +}
> +
> +static void rvtrace_event_destroy(struct perf_event *event)
> +{
> +}
> +
> +static int rvtrace_event_init(struct perf_event *event)
> +{
> +       if (event->attr.type != rvtrace_pmu.type)
> +               return -EINVAL;
> +
> +       event->destroy = rvtrace_event_destroy;
> +       return 0;
> +}
> +
> +static void rvtrace_event_start(struct perf_event *event, int flags)
> +{
> +       struct rvtrace_ctxt *ctxt = this_cpu_ptr(&rvtrace_ctxt);
> +       struct perf_output_handle *handle = &ctxt->handle;
> +       struct rvtrace_event_data *event_data;
> +       int cpu = smp_processor_id();
> +       struct rvtrace_path *path;
> +
> +       if (WARN_ON(ctxt->event_data))
> +               goto fail;
> +
> +       /*
> +        * Deal with the ring buffer API and get a handle on the
> +        * session's information.
> +        */
> +       event_data = perf_aux_output_begin(handle, event);
> +       if (!event_data)
> +               goto fail;
> +
> +       if (!cpumask_test_cpu(cpu, &event_data->mask))
> +               goto out;
> +
> +       event_data->buf.pos = handle->head % event_data->buf.length;
> +       path = *rvtrace_event_cpu_path_ptr(event_data, cpu);
> +       if (!path) {
> +               pr_err("Error. Path not found\n");
> +               return;
> +       }
> +
> +       if (rvtrace_path_start(path)) {
> +               pr_err("Error. Tracing not started\n");
> +               return;
> +       }
> +
> +       /*
> +        * output cpu / trace ID in perf record, once for the lifetime
> +        * of the event.
> +        */
> +       if (!cpumask_test_cpu(cpu, &event_data->aux_hwid_done)) {
> +               cpumask_set_cpu(cpu, &event_data->aux_hwid_done);
> +               perf_report_aux_output_id(event, cpu);
> +       }
> +
> +out:
> +       /* Tell the perf core the event is alive */
> +       event->hw.state = 0;
> +       ctxt->event_data = event_data;
> +       return;
> +fail:
> +       event->hw.state = PERF_HES_STOPPED;
> +}
> +
> +static void rvtrace_event_stop(struct perf_event *event, int mode)
> +{
> +       struct rvtrace_ctxt *ctxt = this_cpu_ptr(&rvtrace_ctxt);
> +       struct perf_output_handle *handle = &ctxt->handle;
> +       struct rvtrace_event_data *event_data;
> +       int ret, cpu = smp_processor_id();
> +       struct rvtrace_path *path;
> +       size_t size;
> +
> +       if (event->hw.state == PERF_HES_STOPPED)
> +               return;
> +
> +       if (handle->event &&
> +           WARN_ON(perf_get_aux(handle) != ctxt->event_data))
> +               return;
> +
> +       event_data = ctxt->event_data;
> +       ctxt->event_data = NULL;
> +
> +       if (WARN_ON(!event_data))
> +               return;
> +
> +       if (handle->event && (mode & PERF_EF_UPDATE) && !cpumask_test_cpu(cpu, &event_data->mask)) {
> +               event->hw.state = PERF_HES_STOPPED;
> +               perf_aux_output_end(handle, 0);
> +               return;
> +       }
> +
> +       /* stop tracing */
> +       path = *rvtrace_event_cpu_path_ptr(event_data, cpu);
> +       if (!path) {
> +               pr_err("Error. Path not found\n");
> +               return;
> +       }
> +
> +       if (rvtrace_path_stop(path)) {
> +               pr_err("Error. Tracing not stopped\n");
> +               return;
> +       }
> +
> +       event->hw.state = PERF_HES_STOPPED;
> +       if (handle->event && (mode & PERF_EF_UPDATE)) {
> +               if (WARN_ON_ONCE(handle->event != event))
> +                       return;
> +               spin_lock(&perf_buf_lock);
> +               ret = rvtrace_path_copyto_auxbuf(path, &event_data->buf, &size);
> +               spin_unlock(&perf_buf_lock);
> +               WARN_ON_ONCE(ret);
> +               if (READ_ONCE(handle->event))
> +                       perf_aux_output_end(handle, size);
> +               else
> +                       WARN_ON(size);
> +       }
> +}
> +
> +static int rvtrace_event_add(struct perf_event *event, int mode)
> +{
> +       struct hw_perf_event *hwc = &event->hw;
> +       int ret = 0;
> +
> +       if (mode & PERF_EF_START) {
> +               rvtrace_event_start(event, 0);
> +               if (hwc->state & PERF_HES_STOPPED)
> +                       ret = -EINVAL;
> +       } else {
> +               hwc->state = PERF_HES_STOPPED;
> +       }
> +
> +       return ret;
> +}
> +
> +static void rvtrace_event_del(struct perf_event *event, int mode)
> +{
> +       rvtrace_event_stop(event, PERF_EF_UPDATE);
> +}
> +
> +PMU_FORMAT_ATTR(event, "config:0-0");
> +
> +static struct attribute *rvtrace_pmu_formats_attr[] = {
> +       &format_attr_event.attr,
> +       NULL,
> +};
> +
> +static struct attribute_group rvtrace_pmu_format_group = {
> +       .name = "format",
> +       .attrs = rvtrace_pmu_formats_attr,
> +};
> +
> +static const struct attribute_group *rvtrace_pmu_attr_groups[] = {
> +       &rvtrace_pmu_format_group,
> +       NULL,
> +};
> +
> +int __init rvtrace_perf_init(void)
> +{
> +       rvtrace_pmu.capabilities        = (PERF_PMU_CAP_EXCLUSIVE | PERF_PMU_CAP_ITRACE);
> +       rvtrace_pmu.attr_groups         = rvtrace_pmu_attr_groups;
> +       rvtrace_pmu.task_ctx_nr         = perf_sw_context;
> +       rvtrace_pmu.read                = rvtrace_event_read;
> +       rvtrace_pmu.event_init          = rvtrace_event_init;
> +       rvtrace_pmu.setup_aux           = rvtrace_setup_aux;
> +       rvtrace_pmu.free_aux            = rvtrace_free_aux;
> +       rvtrace_pmu.start               = rvtrace_event_start;
> +       rvtrace_pmu.stop                = rvtrace_event_stop;
> +       rvtrace_pmu.add                 = rvtrace_event_add;
> +       rvtrace_pmu.del                 = rvtrace_event_del;
> +       rvtrace_pmu.module              = THIS_MODULE;
> +
> +       return perf_pmu_register(&rvtrace_pmu, RVTRACE_PMU_NAME, -1);
> +}
> +
> +void __exit rvtrace_perf_exit(void)
> +{
> +       perf_pmu_unregister(&rvtrace_pmu);
> +}
> diff --git a/include/linux/rvtrace.h b/include/linux/rvtrace.h
> index cecf6c153ca6..d5f782ac132f 100644
> --- a/include/linux/rvtrace.h
> +++ b/include/linux/rvtrace.h
> @@ -343,4 +343,7 @@ static inline int rvtrace_comp_is_empty(struct rvtrace_component *comp)
>                                 comp->pdata->control_poll_timeout_usecs);
>  }
>
> +int rvtrace_perf_init(void);
> +void rvtrace_perf_exit(void);
> +
>  #endif
> --
> 2.43.0
>
>
> _______________________________________________
> linux-riscv mailing list
> linux-riscv@...ts.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ