On 04/22/2020 10:33 PM, Al Grant wrote:
Hi, this is an incomplete patch for an issue with EL2 kernels, and I'm looking for feedback on how to complete it.
The background is that to support tracing multiple address spaces we get ETM to embed the context id in the trace, and we build with CONFIG_PID_IN_CONTEXTIDR to get the scheduler to put the thread id in CONTEXTIDR_EL1. This is a known technique, it's what context id tracing is designed for.
The problem is when the kernel is running not at EL1 (OS level) but at EL2 (hypervisor level), which is now becoming common. With HCR_EL2.E2H set, the kernel's writes to CONTEXTIDR_EL1 actually change a different physical register, CONTEXTIDR_EL2. However, ETM still traces CONTEXTIDR_EL1. So the context ids in the trace are zero, and trace cannot be reconstructed.
ETM 4.1 has an option VMIDOPT to cause CONTEXTIDR_EL2 to be output in trace, in the VMID field replacing the value of VTTBR.VMID. So we can use that, but the trace follower, collecting events from OpenCSD, needs to be aware it needs to check the VMID field not the CID field. OpenCSD doesn't need to change but perf does. TRCCONFIGR is already in the metadata, so perf consumers can check it to see what's going on.
The patch below does the kernel and userspace side but is not complete. The problem is that userspace perf creates the metadata copy of TRCCONFIGR based on its request (and fills in the other id registers by reading sysfs), but the detection of EL2/E2H happens in the kernel which adjusts TRCCONFIGR, and it's this config which is needed for decode. I see three ways round this:
- have userspace test to see if the kernel is EL2 (somehow) and adjust the
metadata to mirror what the kernel is doing
- have the kernel pass the adjusted TRCCONFIGR back so perf can put it in the
metadata
- have the perf decoder get the thread id from whichever of VMID and
CONTEXTID is available in a PE_CONTEXT element
Obviously, the last is simplest, but it's a bodge, and means that OpenCSD will see VMIDs when its TRCCONFIGR says it won't. It's kind of cleanest to get the real TRCCONFIGR somehow, but how do we do that?
We do get TRCCONFIGR in the perf records. We should simply make sure we get the uptodate value (wherever we are getting it from).
Al
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c index a128b5063f46..96488a0cfdcf 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.c +++ b/drivers/hwtracing/coresight/coresight-etm4x.c @@ -353,8 +353,32 @@ static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, }
if (attr->config & BIT(ETM_OPT_CTXTID))
/* bit[6], Context ID tracing bit */
config->cfg |= BIT(ETM4_CFG_BIT_CTXTID);
{
/*
* Enable context-id tracing. The assumption is that this
* will work with CONFIG_PID_IN_CONTEXTIDR to trace process
* id changes and support decode of multiple processes.
* But ETM's context id trace traces physical CONTEXTIDR_EL1,
* while the logical CONTEXTIDR_EL1 that is written to on
* process switch is either physical CONTEXTIDR_EL1 or
* CONTEXTIDR_EL2 depending on HCR_EL2.E2H. On principle
* we should continue to use logical CONTEXTIDR_EL1.
* In order to trace physical CONTEXTIDR_EL2, we need to
* enable VMID tracing and use the VMIDOPT flag to trace
* CONTEXTIDR_EL2 rather than VTTBR.VMID in the VMID field.
* Trace decoders will need to inspect TRCCONFIGR and use
* either the CID or the VMID field from the trace packet.
*/
if (!(is_kernel_in_hyp_mode() &&
(read_sysreg(hcr_el2) & BIT(34)) != 0)) {
The patch looks good to me. We should be careful about the register access, as we assume that the kernel is running in AArch64 mode above, which may not be necessarily true.
Suzuki