blob: 24a81fb1262fbd3ba4c2714b711ac506e2dbe4a9 [file] [log] [blame]
Basil Eljuse4b14afb2020-09-30 13:07:23 +01001/*!
2##############################################################################
Jelle Sels83f141e2022-08-01 15:17:40 +00003# Copyright (c) 2020-2022, ARM Limited and Contributors. All rights reserved.
Basil Eljuse4b14afb2020-09-30 13:07:23 +01004#
5# SPDX-License-Identifier: BSD-3-Clause
6##############################################################################
7*/
8// Implements the trace plugin interface for the MTI interface to trace
9// source data from Arm FVP.
10
11#include "MTI/PluginInterface.h"
12#include "MTI/PluginFactory.h"
13#include "MTI/PluginInstance.h"
14#include "MTI/ModelTraceInterface.h"
Jelle Sels83f141e2022-08-01 15:17:40 +000015#include "MTI/ParameterInterface.h"
Basil Eljuse4b14afb2020-09-30 13:07:23 +010016
17#include "plugin_utils.h"
18#include "trace_sources.h"
19
20#include <errno.h>
21#include <string>
22#include <algorithm>
23#include <cstdio>
24#include <sstream>
25#include <vector>
26#include <map>
27#include <typeinfo>
28#include <typeindex>
29#include <utility>
Jelle Sels83f141e2022-08-01 15:17:40 +000030#include "SimpleCADI.h"
Basil Eljuse4b14afb2020-09-30 13:07:23 +010031
32#ifdef SG_MODEL_BUILD
33 #include "builddata.h"
34 #define PLUGIN_VERSION FULL_VERSION_STRING
35#else
36 #define PLUGIN_VERSION "unreleased"
37#endif
38
Jelle Sels83f141e2022-08-01 15:17:40 +000039enum plugin_param_t
40{
41TRACE_FILE_PREFIX,
42TRACE_MODE,
43TOTAL_PARAMETERS
44};
Basil Eljuse4b14afb2020-09-30 13:07:23 +010045using namespace eslapi;
46using namespace MTI;
47using namespace std;
48
49// Implements the plugin interface for trace coverage
Jelle Sels83f141e2022-08-01 15:17:40 +000050
51// Class used to return a static object CAInterface. CAInterface provides a
52// basis for a software model built around ’components’ and ’interfaces’.
53// A component provides concrete implementations of one or more interfaces.
54// Interfaces are identified by a string name (of type if_name_t), and an
55// integer revision (type if_rev_t). A higher revision number indicates a newer
56// revision of the same interface.
57class ThePluginFactory :public PluginFactory
58{
59public:
60 virtual CAInterface *ObtainInterface(if_name_t ifName,
61 if_rev_t minRev,
62 if_rev_t * actualRev);
63
64 virtual uint32_t GetNumberOfParameters();
65
66 virtual eslapi::CADIReturn_t
67 GetParameterInfos(eslapi::CADIParameterInfo_t *parameter_info_list);
68
69 virtual CAInterface *Instantiate(const char *instance_name,
70 uint32_t number_of_parameters,
71 eslapi::CADIParameterValue_t *parameter_values);
72
73 virtual void Release();
74
75 virtual const char *GetType() const { return "CoverageTrace"; }
76 virtual const char *GetVersion() const { return PLUGIN_VERSION; }
77};
78
79static ThePluginFactory *GetThePluginFactory();
80class CoverageTrace :
81 public ParameterInterface,
82 public PluginInstance
Basil Eljuse4b14afb2020-09-30 13:07:23 +010083{
84public:
85 virtual CAInterface * ObtainInterface(if_name_t ifName,
86 if_rev_t minRev,
87 if_rev_t * actualRev);
88
Jelle Sels83f141e2022-08-01 15:17:40 +000089 CoverageTrace(const char *instance_name, const char *trace_file_prefix,
90 int _mode);
Basil Eljuse4b14afb2020-09-30 13:07:23 +010091 ~CoverageTrace();
92
93 /** This is to associate a plugin with a simulation instance. Exactly one
94 * simulation must be registered.
95 * */
96 virtual eslapi::CADIReturn_t RegisterSimulation(eslapi::CAInterface
97 *simulation);
98
99 // This is called before the plugin .dll/.so is unloaded and should allow
100 // the plugin to do it's cleanup.
101 virtual void Release();
Jelle Sels83f141e2022-08-01 15:17:40 +0000102 void Save(void);
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100103
104 virtual const char *GetName() const;
Jelle Sels83f141e2022-08-01 15:17:40 +0000105 virtual eslapi::CADIReturn_t GetParameterInfos(uint32_t start_index,
106 uint32_t desired_num_of_params,
107 uint32_t* actual_num_of_params,
108 eslapi::CADIParameterInfo_t* params);
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100109
Jelle Sels83f141e2022-08-01 15:17:40 +0000110 virtual eslapi::CADIReturn_t GetParameterInfo(const char* parameterName,
111 eslapi::CADIParameterInfo_t* param);
112
113 virtual eslapi::CADIReturn_t GetParameterValues(uint32_t parameter_count,
114 uint32_t* actual_num_of_params_read,
115 eslapi::CADIParameterValue_t* param_values_out);
116 virtual eslapi::CADIReturn_t SetParameterValues(uint32_t parameter_count,
117 eslapi::CADIParameterValue_t* parameters,
118 eslapi::CADIFactoryErrorMessage_t* error);
119 ModeChangeTraceContext *mode_change;
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100120private:
121 std::string instance_name;
122
123 bool Error(const char *);
124
125 vector<TraceComponentContext*> trace_components;
126 std::string trace_file_prefix;
Jelle Sels83f141e2022-08-01 15:17:40 +0000127 int trace_mode;
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100128};
129
130CAInterface *CoverageTrace::ObtainInterface(if_name_t ifName,
131 if_rev_t minRev,
132 if_rev_t * actualRev)
133{
134 printf("CoverageTrace::ObtainInterface\n");
135 // If someone is asking for the matching interface
Jelle Sels83f141e2022-08-01 15:17:40 +0000136 if((strcmp(ifName,PluginInstance::IFNAME()) == 0) &&
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100137 // and the revision of this interface implementation is
Jelle Sels83f141e2022-08-01 15:17:40 +0000138 (minRev <= PluginInstance::IFREVISION()))
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100139 // at least what is being asked for
140 {
141 if (actualRev) // Make sure this is not a NULL pointer
Jelle Sels83f141e2022-08-01 15:17:40 +0000142 *actualRev = PluginInstance::IFREVISION();
143 return dynamic_cast<PluginInstance *>(this);
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100144 }
145
146 if((strcmp(ifName, CAInterface::IFNAME()) == 0) &&
147 minRev <= CAInterface::IFREVISION())
148 {
149 if (actualRev != NULL)
150 *actualRev = CAInterface::IFREVISION();
Jelle Sels83f141e2022-08-01 15:17:40 +0000151 return dynamic_cast<CAInterface *>(dynamic_cast<PluginInstance *>(this));
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100152 }
Jelle Sels83f141e2022-08-01 15:17:40 +0000153 if((strcmp(ifName, ParameterInterface::IFNAME()) == 0) &&
154 minRev <= ParameterInterface::IFREVISION())
155 {
156 if (actualRev != NULL)
157 *actualRev = ParameterInterface::IFREVISION();
158 return dynamic_cast<ParameterInterface *>(this);
159 }
160 printf("CoverageTrace::ObtainInterface Failed!\n");
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100161 return NULL;
162}
163
164
165CoverageTrace::CoverageTrace(const char *instance_name_,
Jelle Sels83f141e2022-08-01 15:17:40 +0000166 const char *trace_file_prefix_, int _mode) :
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100167 instance_name(instance_name_),
Jelle Sels83f141e2022-08-01 15:17:40 +0000168 trace_file_prefix(trace_file_prefix_),
169 trace_mode(_mode)
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100170{
171 printf("CoverageTrace::CoverageTrace\n");
172}
173
174CoverageTrace::~CoverageTrace()
175{
176 printf("CoverageTrace::~CoverageTrace\n");
177}
178
179bool
180CoverageTrace::Error(const char *msg)
181{
182 fprintf(stderr, "%s\n", msg);
183 return false;
184}
185
186// Method that registers the simulation traces events. In this case registers
187// for trace sources with the 'INST' name.
188CADIReturn_t
189CoverageTrace::RegisterSimulation(CAInterface *ca_interface)
190{
191 printf("CoverageTrace::RegisterSimulation\n");
192 if (!ca_interface) {
193 Error("Received CAInterface NULL pointer.");
194 return CADI_STATUS_IllegalArgument;
195 }
196 std::stringstream ss;
197
198 SystemTraceInterface *sys_if =
199 ca_interface->ObtainPointer<SystemTraceInterface>();
200 if (sys_if == 0) {
201 Error("Got a NULL SystemTraceInterface.");
202 return CADI_STATUS_GeneralError;
203 }
204
205 for(SystemTraceInterface::TraceComponentIndex tci=0;
206 tci < sys_if->GetNumOfTraceComponents(); ++tci) {
207 const char* tpath = sys_if->GetComponentTracePath(tci);
208 CAInterface *caif = sys_if->GetComponentTrace(tci);
209 ComponentTraceInterface *cti =
210 caif->ObtainPointer<ComponentTraceInterface>();
Jelle Sels83f141e2022-08-01 15:17:40 +0000211 InstructionTraceContext *inst_cont = NULL;
212 MTI::EventClass * event = NULL;
213
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100214 if (cti == 0) {
215 Error("Could not get TraceInterface for component.");
216 continue;
217 }
218
219 if (cti->GetTraceSource("INST") != 0) {
220 TraceComponentContext *trace_component = new
221 TraceComponentContext(tpath);
222
223 // To register a new trace source the arguments are the
224 // name of the trace source followed by a vector of
225 // pairs of (field name,field type).
Jelle Sels83f141e2022-08-01 15:17:40 +0000226 inst_cont = new InstructionTraceContext(
227 "INST",
228 { {"PC", u32},
229 {"SIZE", u32}}
230 );
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100231 inst_cont->nb_insts = 0;
Jelle Sels83f141e2022-08-01 15:17:40 +0000232 event = inst_cont->CreateEvent(&cti, inst_cont->Callback);
233 event->UnregisterCallback(inst_cont->Callback, inst_cont);
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100234 trace_component->AddTraceSource(inst_cont);
235 trace_components.push_back(trace_component);
236 }
Jelle Sels83f141e2022-08-01 15:17:40 +0000237 if (cti->GetTraceSource("MODE_CHANGE") != 0) {
238 MTI::EventClass * mode_event = NULL;
239 if(!event) {
240 Error("Could not set mode_change event");
241 continue;
242 }
243 // To register a new trace source the arguments are the
244 // name of the trace source followed by a vector of
245 // pairs of (field name,field type).
246 this->mode_change = new ModeChangeTraceContext(
247 "MODE_CHANGE",
248 { {"MODE", u8},
249 {"NON_SECURE", u8}
250 }
251 );
252 mode_event = this->mode_change->CreateEvent(&cti, this->mode_change->Callback);
253 this->mode_change->event = event;
254 this->mode_change->itc = inst_cont;
255 this->mode_change->mode_mask = trace_mode;
256 mode_event->RegisterCallback(this->mode_change->Callback, mode_change);
257 }
258
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100259 }
260
261 return CADI_STATUS_OK;
262}
263
264// This is called before the plugin .dll/.so is unloaded and should allow the
265// plugin to do it's cleanup.
266void
267CoverageTrace::Release()
268{
Jelle Sels83f141e2022-08-01 15:17:40 +0000269 printf("CoverageTrace::Release\n");
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100270 // We can dump our data now
Jelle Sels83f141e2022-08-01 15:17:40 +0000271 this->Save();
272}
273
274void
275CoverageTrace::Save(void)
276{
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100277 int error = 0;
278 char* fname;
279 int ret;
280 std::vector<TraceComponentContext*>::iterator tcc;
281 for (tcc = trace_components.begin(); tcc < trace_components.end(); ++tcc) {
282 TraceComponentContext *tcont = *tcc;
283 // Print some overall stats
284 InstructionTraceContext* rtc = (InstructionTraceContext*)
285 tcont->trace_sources["INST"];
286 printf("Trace path: %s\n", tcont->trace_path.c_str());
287
288 // Construct a trace file name
289 int status = asprintf(&fname, "%s-%s.log",
290 this->trace_file_prefix.c_str(),
291 tcont->trace_path.c_str());
Jelle Sels83f141e2022-08-01 15:17:40 +0000292 if ( status == -1)
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100293 {
294 printf("Error in asprintf: %d\n", status);
295 printf("Error description is : %s\n", strerror(errno));
296 }
297
298 // Open it
299 FILE* fp = fopen(fname, "w");
300 if (fp == NULL) {
301 fprintf(stderr, "Can't open file %s for writing.\n", fname);
302 error = 1;
303 break;
304 }
305
306 InstStatMap::iterator map_it;
307 // Dump the detailed stats
308 for (map_it = rtc->stats.begin(); map_it != rtc->stats.end();
309 ++map_it) {
Saul Romero6387ccf2022-09-09 09:14:55 +0000310 fprintf(fp, "%08x %lu %lu\n", (unsigned int)map_it->first,
311 (unsigned long)map_it->second.cnt,
312 (unsigned long)map_it->second.size);
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100313 }
314
315 // Close the file
316 ret = fclose(fp);
317 if (ret != 0) {
318 fprintf(stderr, "Failed to close %s: %s.", fname, strerror(errno));
319 error = 1;
320 break;
321 }
322
323 free(fname);
324 }
Jelle Sels83f141e2022-08-01 15:17:40 +0000325 printf("Everything saved\n");
326 if (error != 0)
327 delete this;
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100328}
329
330const char *
331CoverageTrace::GetName() const
332{
333 printf("CoverageTrace::GetName\n");
334 return instance_name.c_str();
335}
336
Jelle Sels83f141e2022-08-01 15:17:40 +0000337CADIReturn_t CoverageTrace::GetParameterInfos(uint32_t start_index,
338 uint32_t desired_num_of_params,
339 uint32_t* actual_num_of_params,
340 CADIParameterInfo_t* params)
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100341{
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100342
Jelle Sels83f141e2022-08-01 15:17:40 +0000343 *actual_num_of_params = GetThePluginFactory()->GetNumberOfParameters();
344 return GetThePluginFactory()->GetParameterInfos(params);
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100345
Jelle Sels83f141e2022-08-01 15:17:40 +0000346}
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100347
Jelle Sels83f141e2022-08-01 15:17:40 +0000348CADIReturn_t CoverageTrace::GetParameterInfo(const char* parameterName,
349 CADIParameterInfo_t* param)
350{
351 uint32_t num_of_params = GetThePluginFactory()->GetNumberOfParameters();
352 CADIParameterInfo_t* plugin_parameters = NULL;
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100353
Jelle Sels83f141e2022-08-01 15:17:40 +0000354 GetThePluginFactory()->GetParameterInfos(plugin_parameters);
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100355
Jelle Sels83f141e2022-08-01 15:17:40 +0000356 if (param == nullptr)
357 {
358 return CADI_STATUS_IllegalArgument;
359 }
360
361 printf("Reading parameter info %s \n", parameterName);
362 for (uint32_t i = 0; i < num_of_params; ++i)
363 {
364 if (strcmp(plugin_parameters[i].name, parameterName) == 0)
365 {
366 *param = plugin_parameters[i];
367 return CADI_STATUS_OK;
368 }
369 }
370 *param = plugin_parameters[0];
371 return CADI_STATUS_OK;
372
373}
374
375CADIReturn_t CoverageTrace::GetParameterValues(uint32_t parameter_count,
376 uint32_t* actual_num_of_params_read,
377 CADIParameterValue_t *param_values_out)
378{
379 if (param_values_out == nullptr || actual_num_of_params_read == nullptr)
380 {
381 return CADI_STATUS_IllegalArgument;
382 }
383
384 *actual_num_of_params_read = 0;
385 for (uint32_t i = 0; i < parameter_count; ++i)
386 {
387 CADIParameterValue_t &param_value = param_values_out[i];
388
389 switch (param_value.parameterID)
390 {
391 case TRACE_FILE_PREFIX:
392 strncpy(param_value.stringValue,
393 this->trace_file_prefix.c_str(),
394 sizeof(param_value.stringValue));
395 break;
396
397 case TRACE_MODE:
398 param_value.intValue = this->mode_change->mode_mask;
399 break;
400 default: // unknown ID
401
402 *actual_num_of_params_read = i;
403 return CADI_STATUS_IllegalArgument;
404 }
405 }
406
407 *actual_num_of_params_read = parameter_count;
408 return CADI_STATUS_OK;
409}
410
411CADIReturn_t CoverageTrace::SetParameterValues(uint32_t parameter_count,
412 CADIParameterValue_t* parameters,
413 CADIFactoryErrorMessage_t* error)
414{
415 for (uint32_t i = 0; i < parameter_count; ++i)
416 {
417 CADIParameterValue_t &parameter = parameters[i];
418 switch(parameter.parameterID)
419 {
420 case TRACE_FILE_PREFIX:
421 this->trace_file_prefix = parameter.stringValue;
422 this->Save();
423 break;
424 case TRACE_MODE:
425 this->mode_change->mode_mask = parameter.intValue;
426 break;
427 default:
428 ;
429 break;
430 }
431 }
432 return CADI_STATUS_OK;
433}
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100434
435// Allows a client to obtain a reference to any of the interfaces that the
436// component implements. The client specifies the id and revision of the
437// interface that it wants to request. The component can return NULL if it
438// doesn’t implement that interface, or only implements a lower revision.
439// The client in this case is the Arm FVP model.
440CAInterface *ThePluginFactory::ObtainInterface(if_name_t ifName,
441 if_rev_t minRev,
442 if_rev_t * actualRev)
443{
444 printf("ThePluginFactory::ObtainInterface\n");
445 // If someone is asking for the matching interface
446 if((strcmp(ifName,IFNAME()) == 0) &&
447 // and the revision of this interface implementation is
448 (minRev <= IFREVISION()))
449 // at least what is being asked for
450 {
451 if (actualRev) // Make sure this is not a NULL pointer
452 *actualRev = IFREVISION();
453 return static_cast<ThePluginFactory *>(this);
454 }
455
456 if((strcmp(ifName, CAInterface::IFNAME()) == 0) &&
457 minRev <= CAInterface::IFREVISION())
458 {
459 if (actualRev) // Make sure this is not a NULL pointer
460 *actualRev = CAInterface::IFREVISION();
461 return static_cast<CAInterface *>(this);
462 }
463 return NULL;
464}
465
466uint32_t ThePluginFactory::GetNumberOfParameters()
467{
468 printf("ThePluginFactory::GetNumberOfParameters\n");
Jelle Sels83f141e2022-08-01 15:17:40 +0000469 return TOTAL_PARAMETERS;
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100470}
471
472eslapi::CADIReturn_t
473ThePluginFactory::GetParameterInfos(
474eslapi::CADIParameterInfo_t *parameter_info_list)
475{
476 printf("ThePluginFactory::GetParameterInfos\n");
Jelle Sels83f141e2022-08-01 15:17:40 +0000477 parameter_info_list[0] = CADIParameterInfo_t(
478 TRACE_FILE_PREFIX, "trace-file-prefix", CADI_PARAM_STRING,
479 "Prefix of the trace files.", true, 0, 0, 0, "covtrace");
480 parameter_info_list[1] = CADIParameterInfo_t(
481 TRACE_MODE, "trace-mode", CADI_PARAM_INT,
482 "Selects which modes to trace.", true, 0, 0xffffffff, 0xffffffff, 0);
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100483 return CADI_STATUS_OK;
484}
485
486// Method that creates a new instance of the trace plugin
487CAInterface *ThePluginFactory::Instantiate(const char *instance_name,
488 uint32_t param_nb,
489 eslapi::CADIParameterValue_t *values)
490{
491 printf("ThePluginFactory::Instantiate\n");
492 const char *trace_file_prefix = 0;
Jelle Sels83f141e2022-08-01 15:17:40 +0000493 int mode_value = 0xffffffff;
494
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100495 printf("CoverageTrace: number of params: %d\n", param_nb);
496 for (uint32_t i = 0; i < param_nb; ++i) {
Jelle Sels83f141e2022-08-01 15:17:40 +0000497 if (values[i].parameterID == TRACE_FILE_PREFIX) {
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100498 trace_file_prefix = values[i].stringValue;
Jelle Sels83f141e2022-08-01 15:17:40 +0000499 } else if (values[i].parameterID == TRACE_MODE) {
500 mode_value = values[i].intValue;
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100501 } else {
502 printf("\tCoverageTrace: got unexpected param %d\n",
503 values[i].parameterID);
504 }
505 }
Jelle Sels83f141e2022-08-01 15:17:40 +0000506 return (PluginInstance*)new CoverageTrace(instance_name, trace_file_prefix,
507 mode_value);
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100508}
509
510void ThePluginFactory::Release()
511{
512 printf("ThePluginFactory::Release\n");
513}
514
515static ThePluginFactory factory_instance;
516
517// Entry point for the instantiation of the plugin.
518// Returns a pointer to an static object to create the interface for the
519// plugin.
520CAInterface *GetCAInterface()
521{
522 printf("********->GetCAInterface\n");
523 return &factory_instance;
524}
Jelle Sels83f141e2022-08-01 15:17:40 +0000525static ThePluginFactory *GetThePluginFactory()
526{
527 return &factory_instance;
528}
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100529
530// End of file CoverageTrace.cpp