]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
coresight: Pass guest TRFCR value to KVM
authorJames Clark <james.clark@arm.com>
Mon, 6 Jan 2025 14:24:42 +0000 (14:24 +0000)
committerMarc Zyngier <maz@kernel.org>
Sun, 12 Jan 2025 12:50:11 +0000 (12:50 +0000)
Currently the userspace and kernel filters for guests are never set, so
no trace will be generated for them. Add support for tracing guests by
passing the desired TRFCR value to KVM so it can be applied to the
guest.

By writing either E1TRE or E0TRE, filtering on either guest kernel or
guest userspace is also supported. And if both E1TRE and E0TRE are
cleared when exclude_guest is set, that option is supported too. This
change also brings exclude_host support which is difficult to add as a
separate commit without excess churn and resulting in no trace at all.

cpu_prohibit_trace() gets moved to TRBE because the ETM driver doesn't
need the read, it already has the base TRFCR value. TRBE only needs
the read to disable it and then restore.

Testing
=======

The addresses were counted with the following:

  $ perf report -D | grep -Eo 'EL2|EL1|EL0' | sort | uniq -c

Guest kernel only:

  $ perf record -e cs_etm//Gk -a -- true
    535 EL1
      1 EL2

Guest user only (only 5 addresses because the guest runs slowly in the
model):

  $ perf record -e cs_etm//Gu -a -- true
    5 EL0

Host kernel only:

  $  perf record -e cs_etm//Hk -a -- true
   3501 EL2

Host userspace only:

  $  perf record -e cs_etm//Hu -a -- true
    408 EL0
      1 EL2

Signed-off-by: James Clark <james.clark@arm.com>
Link: https://lore.kernel.org/r/20250106142446.628923-8-james.clark@linaro.org
Signed-off-by: Marc Zyngier <maz@kernel.org>
drivers/hwtracing/coresight/coresight-etm4x-core.c
drivers/hwtracing/coresight/coresight-etm4x.h
drivers/hwtracing/coresight/coresight-priv.h
drivers/hwtracing/coresight/coresight-self-hosted-trace.h
drivers/hwtracing/coresight/coresight-trbe.c

index dd8c74f893dbdfe1a35d811ef2dc476b81ce07ae..fbc4aa37852793b3eeb4638c93ef0000664145d6 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/acpi.h>
 #include <linux/bitops.h>
 #include <linux/kernel.h>
+#include <linux/kvm_host.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/types.h>
@@ -268,10 +269,28 @@ struct etm4_enable_arg {
  */
 static void etm4x_prohibit_trace(struct etmv4_drvdata *drvdata)
 {
+       u64 trfcr;
+
        /* If the CPU doesn't support FEAT_TRF, nothing to do */
        if (!drvdata->trfcr)
                return;
-       cpu_prohibit_trace();
+
+       trfcr = drvdata->trfcr & ~(TRFCR_ELx_ExTRE | TRFCR_ELx_E0TRE);
+
+       write_trfcr(trfcr);
+       kvm_tracing_set_el1_configuration(trfcr);
+}
+
+static u64 etm4x_get_kern_user_filter(struct etmv4_drvdata *drvdata)
+{
+       u64 trfcr = drvdata->trfcr;
+
+       if (drvdata->config.mode & ETM_MODE_EXCL_KERN)
+               trfcr &= ~TRFCR_ELx_ExTRE;
+       if (drvdata->config.mode & ETM_MODE_EXCL_USER)
+               trfcr &= ~TRFCR_ELx_E0TRE;
+
+       return trfcr;
 }
 
 /*
@@ -286,18 +305,28 @@ static void etm4x_prohibit_trace(struct etmv4_drvdata *drvdata)
  */
 static void etm4x_allow_trace(struct etmv4_drvdata *drvdata)
 {
-       u64 trfcr = drvdata->trfcr;
+       u64 trfcr, guest_trfcr;
 
        /* If the CPU doesn't support FEAT_TRF, nothing to do */
-       if (!trfcr)
+       if (!drvdata->trfcr)
                return;
 
-       if (drvdata->config.mode & ETM_MODE_EXCL_KERN)
-               trfcr &= ~TRFCR_ELx_ExTRE;
-       if (drvdata->config.mode & ETM_MODE_EXCL_USER)
-               trfcr &= ~TRFCR_ELx_E0TRE;
+       if (drvdata->config.mode & ETM_MODE_EXCL_HOST)
+               trfcr = drvdata->trfcr & ~(TRFCR_ELx_ExTRE | TRFCR_ELx_E0TRE);
+       else
+               trfcr = etm4x_get_kern_user_filter(drvdata);
 
        write_trfcr(trfcr);
+
+       /* Set filters for guests and pass to KVM */
+       if (drvdata->config.mode & ETM_MODE_EXCL_GUEST)
+               guest_trfcr = drvdata->trfcr & ~(TRFCR_ELx_ExTRE | TRFCR_ELx_E0TRE);
+       else
+               guest_trfcr = etm4x_get_kern_user_filter(drvdata);
+
+       /* TRFCR_EL1 doesn't have CX so mask it out. */
+       guest_trfcr &= ~TRFCR_EL2_CX;
+       kvm_tracing_set_el1_configuration(guest_trfcr);
 }
 
 #ifdef CONFIG_ETM4X_IMPDEF_FEATURE
@@ -655,6 +684,12 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
        if (attr->exclude_user)
                config->mode = ETM_MODE_EXCL_USER;
 
+       if (attr->exclude_host)
+               config->mode |= ETM_MODE_EXCL_HOST;
+
+       if (attr->exclude_guest)
+               config->mode |= ETM_MODE_EXCL_GUEST;
+
        /* Always start from the default config */
        etm4_set_default_config(config);
 
index 9e9165f62e81fe5a87d35b4e30bc23f93cb211ec..1119762b5cece8fd4d5aea81b67ec1ec24f8a5fd 100644 (file)
@@ -817,7 +817,7 @@ enum etm_impdef_type {
  * @s_ex_level: Secure ELs where tracing is supported.
  */
 struct etmv4_config {
-       u32                             mode;
+       u64                             mode;
        u32                             pe_sel;
        u32                             cfg;
        u32                             eventctrl0;
index 05f891ca6b5c9d71bdf36585328f7cfd292b3d36..76403530f33e0c50184cede7aaf1929471890188 100644 (file)
@@ -42,6 +42,9 @@ extern const struct device_type coresight_dev_type[];
 
 #define ETM_MODE_EXCL_KERN     BIT(30)
 #define ETM_MODE_EXCL_USER     BIT(31)
+#define ETM_MODE_EXCL_HOST     BIT(32)
+#define ETM_MODE_EXCL_GUEST    BIT(33)
+
 struct cs_pair_attribute {
        struct device_attribute attr;
        u32 lo_off;
index 53840a2c41f2c7051e7d4acabd895f6934275ce7..303d71911870f3d7c53b0a3eb7dbf1389ec315fd 100644 (file)
@@ -21,13 +21,4 @@ static inline void write_trfcr(u64 val)
        isb();
 }
 
-static inline u64 cpu_prohibit_trace(void)
-{
-       u64 trfcr = read_trfcr();
-
-       /* Prohibit tracing at EL0 & the kernel EL */
-       write_trfcr(trfcr & ~(TRFCR_ELx_ExTRE | TRFCR_ELx_E0TRE));
-       /* Return the original value of the TRFCR */
-       return trfcr;
-}
 #endif /*  __CORESIGHT_SELF_HOSTED_TRACE_H */
index a728802d2206928f7e6792d1d3b3b5ff73a71930..d6eb0d525a4d6b4b5e75f9491fe32012b00d845c 100644 (file)
@@ -1113,6 +1113,16 @@ static bool is_perf_trbe(struct perf_output_handle *handle)
        return true;
 }
 
+static u64 cpu_prohibit_trace(void)
+{
+       u64 trfcr = read_trfcr();
+
+       /* Prohibit tracing at EL0 & the kernel EL */
+       write_trfcr(trfcr & ~(TRFCR_ELx_ExTRE | TRFCR_ELx_E0TRE));
+       /* Return the original value of the TRFCR */
+       return trfcr;
+}
+
 static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
 {
        struct perf_output_handle **handle_ptr = dev;