blob: d2b13fdc954d66b2c71b310127e9bd3790a5d247 [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 Romero07127e42022-09-08 16:16:11 +0000310 fprintf(fp, "%08x %lu %lu\n", map_it->first, map_it->second.cnt,
311 map_it->second.size);
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100312 }
313
314 // Close the file
315 ret = fclose(fp);
316 if (ret != 0) {
317 fprintf(stderr, "Failed to close %s: %s.", fname, strerror(errno));
318 error = 1;
319 break;
320 }
321
322 free(fname);
323 }
Jelle Sels83f141e2022-08-01 15:17:40 +0000324 printf("Everything saved\n");
325 if (error != 0)
326 delete this;
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100327}
328
329const char *
330CoverageTrace::GetName() const
331{
332 printf("CoverageTrace::GetName\n");
333 return instance_name.c_str();
334}
335
Jelle Sels83f141e2022-08-01 15:17:40 +0000336CADIReturn_t CoverageTrace::GetParameterInfos(uint32_t start_index,
337 uint32_t desired_num_of_params,
338 uint32_t* actual_num_of_params,
339 CADIParameterInfo_t* params)
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100340{
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100341
Jelle Sels83f141e2022-08-01 15:17:40 +0000342 *actual_num_of_params = GetThePluginFactory()->GetNumberOfParameters();
343 return GetThePluginFactory()->GetParameterInfos(params);
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100344
Jelle Sels83f141e2022-08-01 15:17:40 +0000345}
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100346
Jelle Sels83f141e2022-08-01 15:17:40 +0000347CADIReturn_t CoverageTrace::GetParameterInfo(const char* parameterName,
348 CADIParameterInfo_t* param)
349{
350 uint32_t num_of_params = GetThePluginFactory()->GetNumberOfParameters();
351 CADIParameterInfo_t* plugin_parameters = NULL;
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100352
Jelle Sels83f141e2022-08-01 15:17:40 +0000353 GetThePluginFactory()->GetParameterInfos(plugin_parameters);
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100354
Jelle Sels83f141e2022-08-01 15:17:40 +0000355 if (param == nullptr)
356 {
357 return CADI_STATUS_IllegalArgument;
358 }
359
360 printf("Reading parameter info %s \n", parameterName);
361 for (uint32_t i = 0; i < num_of_params; ++i)
362 {
363 if (strcmp(plugin_parameters[i].name, parameterName) == 0)
364 {
365 *param = plugin_parameters[i];
366 return CADI_STATUS_OK;
367 }
368 }
369 *param = plugin_parameters[0];
370 return CADI_STATUS_OK;
371
372}
373
374CADIReturn_t CoverageTrace::GetParameterValues(uint32_t parameter_count,
375 uint32_t* actual_num_of_params_read,
376 CADIParameterValue_t *param_values_out)
377{
378 if (param_values_out == nullptr || actual_num_of_params_read == nullptr)
379 {
380 return CADI_STATUS_IllegalArgument;
381 }
382
383 *actual_num_of_params_read = 0;
384 for (uint32_t i = 0; i < parameter_count; ++i)
385 {
386 CADIParameterValue_t &param_value = param_values_out[i];
387
388 switch (param_value.parameterID)
389 {
390 case TRACE_FILE_PREFIX:
391 strncpy(param_value.stringValue,
392 this->trace_file_prefix.c_str(),
393 sizeof(param_value.stringValue));
394 break;
395
396 case TRACE_MODE:
397 param_value.intValue = this->mode_change->mode_mask;
398 break;
399 default: // unknown ID
400
401 *actual_num_of_params_read = i;
402 return CADI_STATUS_IllegalArgument;
403 }
404 }
405
406 *actual_num_of_params_read = parameter_count;
407 return CADI_STATUS_OK;
408}
409
410CADIReturn_t CoverageTrace::SetParameterValues(uint32_t parameter_count,
411 CADIParameterValue_t* parameters,
412 CADIFactoryErrorMessage_t* error)
413{
414 for (uint32_t i = 0; i < parameter_count; ++i)
415 {
416 CADIParameterValue_t &parameter = parameters[i];
417 switch(parameter.parameterID)
418 {
419 case TRACE_FILE_PREFIX:
420 this->trace_file_prefix = parameter.stringValue;
421 this->Save();
422 break;
423 case TRACE_MODE:
424 this->mode_change->mode_mask = parameter.intValue;
425 break;
426 default:
427 ;
428 break;
429 }
430 }
431 return CADI_STATUS_OK;
432}
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100433
434// Allows a client to obtain a reference to any of the interfaces that the
435// component implements. The client specifies the id and revision of the
436// interface that it wants to request. The component can return NULL if it
437// doesn’t implement that interface, or only implements a lower revision.
438// The client in this case is the Arm FVP model.
439CAInterface *ThePluginFactory::ObtainInterface(if_name_t ifName,
440 if_rev_t minRev,
441 if_rev_t * actualRev)
442{
443 printf("ThePluginFactory::ObtainInterface\n");
444 // If someone is asking for the matching interface
445 if((strcmp(ifName,IFNAME()) == 0) &&
446 // and the revision of this interface implementation is
447 (minRev <= IFREVISION()))
448 // at least what is being asked for
449 {
450 if (actualRev) // Make sure this is not a NULL pointer
451 *actualRev = IFREVISION();
452 return static_cast<ThePluginFactory *>(this);
453 }
454
455 if((strcmp(ifName, CAInterface::IFNAME()) == 0) &&
456 minRev <= CAInterface::IFREVISION())
457 {
458 if (actualRev) // Make sure this is not a NULL pointer
459 *actualRev = CAInterface::IFREVISION();
460 return static_cast<CAInterface *>(this);
461 }
462 return NULL;
463}
464
465uint32_t ThePluginFactory::GetNumberOfParameters()
466{
467 printf("ThePluginFactory::GetNumberOfParameters\n");
Jelle Sels83f141e2022-08-01 15:17:40 +0000468 return TOTAL_PARAMETERS;
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100469}
470
471eslapi::CADIReturn_t
472ThePluginFactory::GetParameterInfos(
473eslapi::CADIParameterInfo_t *parameter_info_list)
474{
475 printf("ThePluginFactory::GetParameterInfos\n");
Jelle Sels83f141e2022-08-01 15:17:40 +0000476 parameter_info_list[0] = CADIParameterInfo_t(
477 TRACE_FILE_PREFIX, "trace-file-prefix", CADI_PARAM_STRING,
478 "Prefix of the trace files.", true, 0, 0, 0, "covtrace");
479 parameter_info_list[1] = CADIParameterInfo_t(
480 TRACE_MODE, "trace-mode", CADI_PARAM_INT,
481 "Selects which modes to trace.", true, 0, 0xffffffff, 0xffffffff, 0);
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100482 return CADI_STATUS_OK;
483}
484
485// Method that creates a new instance of the trace plugin
486CAInterface *ThePluginFactory::Instantiate(const char *instance_name,
487 uint32_t param_nb,
488 eslapi::CADIParameterValue_t *values)
489{
490 printf("ThePluginFactory::Instantiate\n");
491 const char *trace_file_prefix = 0;
Jelle Sels83f141e2022-08-01 15:17:40 +0000492 int mode_value = 0xffffffff;
493
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100494 printf("CoverageTrace: number of params: %d\n", param_nb);
495 for (uint32_t i = 0; i < param_nb; ++i) {
Jelle Sels83f141e2022-08-01 15:17:40 +0000496 if (values[i].parameterID == TRACE_FILE_PREFIX) {
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100497 trace_file_prefix = values[i].stringValue;
Jelle Sels83f141e2022-08-01 15:17:40 +0000498 } else if (values[i].parameterID == TRACE_MODE) {
499 mode_value = values[i].intValue;
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100500 } else {
501 printf("\tCoverageTrace: got unexpected param %d\n",
502 values[i].parameterID);
503 }
504 }
Jelle Sels83f141e2022-08-01 15:17:40 +0000505 return (PluginInstance*)new CoverageTrace(instance_name, trace_file_prefix,
506 mode_value);
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100507}
508
509void ThePluginFactory::Release()
510{
511 printf("ThePluginFactory::Release\n");
512}
513
514static ThePluginFactory factory_instance;
515
516// Entry point for the instantiation of the plugin.
517// Returns a pointer to an static object to create the interface for the
518// plugin.
519CAInterface *GetCAInterface()
520{
521 printf("********->GetCAInterface\n");
522 return &factory_instance;
523}
Jelle Sels83f141e2022-08-01 15:17:40 +0000524static ThePluginFactory *GetThePluginFactory()
525{
526 return &factory_instance;
527}
Basil Eljuse4b14afb2020-09-30 13:07:23 +0100528
529// End of file CoverageTrace.cpp