1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/trace_processor/importers/ftrace/pkvm_hyp_cpu_tracker.h"
18
19 #include "perfetto/base/logging.h"
20 #include "perfetto/ext/base/string_utils.h"
21 #include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h"
22 #include "protos/perfetto/trace/ftrace/hyp.pbzero.h"
23 #include "src/trace_processor/importers/common/slice_tracker.h"
24 #include "src/trace_processor/importers/common/track_tracker.h"
25
26 namespace perfetto::trace_processor {
27 namespace {
28
GetTrackName(uint32_t cpu)29 TrackTracker::LegacyCharArrayName GetTrackName(uint32_t cpu) {
30 return TrackTracker::LegacyCharArrayName{
31 base::StackString<255>("pkVM Hypervisor CPU %u", cpu)};
32 }
33
34 } // namespace
35
PkvmHypervisorCpuTracker(TraceProcessorContext * context)36 PkvmHypervisorCpuTracker::PkvmHypervisorCpuTracker(
37 TraceProcessorContext* context)
38 : context_(context),
39 category_(context->storage->InternString("pkvm_hyp")),
40 slice_name_(context->storage->InternString("hyp")),
41 hyp_enter_reason_(context->storage->InternString("hyp_enter_reason")) {}
42
43 // static
IsPkvmHypervisorEvent(uint32_t event_id)44 bool PkvmHypervisorCpuTracker::IsPkvmHypervisorEvent(uint32_t event_id) {
45 using protos::pbzero::FtraceEvent;
46 switch (event_id) {
47 case FtraceEvent::kHypEnterFieldNumber:
48 case FtraceEvent::kHypExitFieldNumber:
49 case FtraceEvent::kHostHcallFieldNumber:
50 case FtraceEvent::kHostMemAbortFieldNumber:
51 case FtraceEvent::kHostSmcFieldNumber:
52 return true;
53 default:
54 return false;
55 }
56 }
57
ParseHypEvent(uint32_t cpu,int64_t timestamp,uint32_t event_id,protozero::ConstBytes blob)58 void PkvmHypervisorCpuTracker::ParseHypEvent(uint32_t cpu,
59 int64_t timestamp,
60 uint32_t event_id,
61 protozero::ConstBytes blob) {
62 using protos::pbzero::FtraceEvent;
63 switch (event_id) {
64 case FtraceEvent::kHypEnterFieldNumber:
65 ParseHypEnter(cpu, timestamp);
66 break;
67 case FtraceEvent::kHypExitFieldNumber:
68 ParseHypExit(cpu, timestamp);
69 break;
70 case FtraceEvent::kHostHcallFieldNumber:
71 ParseHostHcall(cpu, blob);
72 break;
73 case FtraceEvent::kHostMemAbortFieldNumber:
74 ParseHostMemAbort(cpu, blob);
75 break;
76 case FtraceEvent::kHostSmcFieldNumber:
77 ParseHostSmc(cpu, blob);
78 break;
79 // TODO(b/249050813): add remaining hypervisor events
80 default:
81 PERFETTO_FATAL("Not a hypervisor event %d", event_id);
82 }
83 }
84
ParseHypEnter(uint32_t cpu,int64_t timestamp)85 void PkvmHypervisorCpuTracker::ParseHypEnter(uint32_t cpu, int64_t timestamp) {
86 // TODO(b/249050813): handle bad events (e.g. 2 hyp_enter in a row)
87 TrackId track_id = context_->track_tracker->InternCpuTrack(
88 tracks::pkvm_hypervisor, cpu, GetTrackName(cpu));
89 context_->slice_tracker->Begin(timestamp, track_id, category_, slice_name_);
90 }
91
ParseHypExit(uint32_t cpu,int64_t timestamp)92 void PkvmHypervisorCpuTracker::ParseHypExit(uint32_t cpu, int64_t timestamp) {
93 // TODO(b/249050813): handle bad events (e.g. 2 hyp_exit in a row)
94 TrackId track_id = context_->track_tracker->InternCpuTrack(
95 tracks::pkvm_hypervisor, cpu, GetTrackName(cpu));
96 context_->slice_tracker->End(timestamp, track_id);
97 }
98
ParseHostHcall(uint32_t cpu,protozero::ConstBytes blob)99 void PkvmHypervisorCpuTracker::ParseHostHcall(uint32_t cpu,
100 protozero::ConstBytes blob) {
101 protos::pbzero::HostHcallFtraceEvent::Decoder evt(blob.data, blob.size);
102 TrackId track_id = context_->track_tracker->InternCpuTrack(
103 tracks::pkvm_hypervisor, cpu, GetTrackName(cpu));
104
105 auto args_inserter = [this, &evt](ArgsTracker::BoundInserter* inserter) {
106 StringId host_hcall = context_->storage->InternString("host_hcall");
107 StringId id = context_->storage->InternString("id");
108 StringId invalid = context_->storage->InternString("invalid");
109 inserter->AddArg(hyp_enter_reason_, Variadic::String(host_hcall));
110 inserter->AddArg(id, Variadic::UnsignedInteger(evt.id()));
111 inserter->AddArg(invalid, Variadic::UnsignedInteger(evt.invalid()));
112 };
113 context_->slice_tracker->AddArgs(track_id, category_, slice_name_,
114 args_inserter);
115 }
116
ParseHostSmc(uint32_t cpu,protozero::ConstBytes blob)117 void PkvmHypervisorCpuTracker::ParseHostSmc(uint32_t cpu,
118 protozero::ConstBytes blob) {
119 protos::pbzero::HostSmcFtraceEvent::Decoder evt(blob.data, blob.size);
120 TrackId track_id = context_->track_tracker->InternCpuTrack(
121 tracks::pkvm_hypervisor, cpu, GetTrackName(cpu));
122
123 auto args_inserter = [this, &evt](ArgsTracker::BoundInserter* inserter) {
124 StringId host_smc = context_->storage->InternString("host_smc");
125 StringId id = context_->storage->InternString("id");
126 StringId forwarded = context_->storage->InternString("forwarded");
127 inserter->AddArg(hyp_enter_reason_, Variadic::String(host_smc));
128 inserter->AddArg(id, Variadic::UnsignedInteger(evt.id()));
129 inserter->AddArg(forwarded, Variadic::UnsignedInteger(evt.forwarded()));
130 };
131 context_->slice_tracker->AddArgs(track_id, category_, slice_name_,
132 args_inserter);
133 }
134
ParseHostMemAbort(uint32_t cpu,protozero::ConstBytes blob)135 void PkvmHypervisorCpuTracker::ParseHostMemAbort(uint32_t cpu,
136 protozero::ConstBytes blob) {
137 protos::pbzero::HostMemAbortFtraceEvent::Decoder evt(blob.data, blob.size);
138 TrackId track_id = context_->track_tracker->InternCpuTrack(
139 tracks::pkvm_hypervisor, cpu, GetTrackName(cpu));
140
141 auto args_inserter = [this, &evt](ArgsTracker::BoundInserter* inserter) {
142 StringId host_mem_abort = context_->storage->InternString("host_mem_abort");
143 StringId esr = context_->storage->InternString("esr");
144 StringId addr = context_->storage->InternString("addr");
145 inserter->AddArg(hyp_enter_reason_, Variadic::String(host_mem_abort));
146 inserter->AddArg(esr, Variadic::UnsignedInteger(evt.esr()));
147 inserter->AddArg(addr, Variadic::UnsignedInteger(evt.addr()));
148 };
149 context_->slice_tracker->AddArgs(track_id, category_, slice_name_,
150 args_inserter);
151 }
152
153 } // namespace perfetto::trace_processor
154