coverage-reporting: Add OP-TEE SPMC coverage support
diff --git a/coverage-tool/coverage-plugin/coverage_trace.cc b/coverage-tool/coverage-plugin/coverage_trace.cc
index 4dc72ee..d2b13fd 100644
--- a/coverage-tool/coverage-plugin/coverage_trace.cc
+++ b/coverage-tool/coverage-plugin/coverage_trace.cc
@@ -1,6 +1,6 @@
/*!
##############################################################################
-# Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
##############################################################################
@@ -12,6 +12,7 @@
#include "MTI/PluginFactory.h"
#include "MTI/PluginInstance.h"
#include "MTI/ModelTraceInterface.h"
+#include "MTI/ParameterInterface.h"
#include "plugin_utils.h"
#include "trace_sources.h"
@@ -26,6 +27,7 @@
#include <typeinfo>
#include <typeindex>
#include <utility>
+#include "SimpleCADI.h"
#ifdef SG_MODEL_BUILD
#include "builddata.h"
@@ -34,19 +36,58 @@
#define PLUGIN_VERSION "unreleased"
#endif
+enum plugin_param_t
+{
+TRACE_FILE_PREFIX,
+TRACE_MODE,
+TOTAL_PARAMETERS
+};
using namespace eslapi;
using namespace MTI;
using namespace std;
// Implements the plugin interface for trace coverage
-class CoverageTrace :public PluginInstance
+
+// Class used to return a static object CAInterface. CAInterface provides a
+// basis for a software model built around ’components’ and ’interfaces’.
+// A component provides concrete implementations of one or more interfaces.
+// Interfaces are identified by a string name (of type if_name_t), and an
+// integer revision (type if_rev_t). A higher revision number indicates a newer
+// revision of the same interface.
+class ThePluginFactory :public PluginFactory
+{
+public:
+ virtual CAInterface *ObtainInterface(if_name_t ifName,
+ if_rev_t minRev,
+ if_rev_t * actualRev);
+
+ virtual uint32_t GetNumberOfParameters();
+
+ virtual eslapi::CADIReturn_t
+ GetParameterInfos(eslapi::CADIParameterInfo_t *parameter_info_list);
+
+ virtual CAInterface *Instantiate(const char *instance_name,
+ uint32_t number_of_parameters,
+ eslapi::CADIParameterValue_t *parameter_values);
+
+ virtual void Release();
+
+ virtual const char *GetType() const { return "CoverageTrace"; }
+ virtual const char *GetVersion() const { return PLUGIN_VERSION; }
+};
+
+static ThePluginFactory *GetThePluginFactory();
+class CoverageTrace :
+ public ParameterInterface,
+ public PluginInstance
{
public:
virtual CAInterface * ObtainInterface(if_name_t ifName,
if_rev_t minRev,
if_rev_t * actualRev);
- CoverageTrace(const char *instance_name, const char *trace_file_prefix);
+ CoverageTrace(const char *instance_name, const char *trace_file_prefix,
+ int _mode);
~CoverageTrace();
/** This is to associate a plugin with a simulation instance. Exactly one
@@ -58,9 +99,24 @@
// This is called before the plugin .dll/.so is unloaded and should allow
// the plugin to do it's cleanup.
virtual void Release();
+ void Save(void);
virtual const char *GetName() const;
+ virtual eslapi::CADIReturn_t GetParameterInfos(uint32_t start_index,
+ uint32_t desired_num_of_params,
+ uint32_t* actual_num_of_params,
+ eslapi::CADIParameterInfo_t* params);
+ virtual eslapi::CADIReturn_t GetParameterInfo(const char* parameterName,
+ eslapi::CADIParameterInfo_t* param);
+
+ virtual eslapi::CADIReturn_t GetParameterValues(uint32_t parameter_count,
+ uint32_t* actual_num_of_params_read,
+ eslapi::CADIParameterValue_t* param_values_out);
+ virtual eslapi::CADIReturn_t SetParameterValues(uint32_t parameter_count,
+ eslapi::CADIParameterValue_t* parameters,
+ eslapi::CADIFactoryErrorMessage_t* error);
+ ModeChangeTraceContext *mode_change;
private:
std::string instance_name;
@@ -68,6 +124,7 @@
vector<TraceComponentContext*> trace_components;
std::string trace_file_prefix;
+ int trace_mode;
};
CAInterface *CoverageTrace::ObtainInterface(if_name_t ifName,
@@ -76,14 +133,14 @@
{
printf("CoverageTrace::ObtainInterface\n");
// If someone is asking for the matching interface
- if((strcmp(ifName,IFNAME()) == 0) &&
+ if((strcmp(ifName,PluginInstance::IFNAME()) == 0) &&
// and the revision of this interface implementation is
- (minRev <= IFREVISION()))
+ (minRev <= PluginInstance::IFREVISION()))
// at least what is being asked for
{
if (actualRev) // Make sure this is not a NULL pointer
- *actualRev = IFREVISION();
- return this;
+ *actualRev = PluginInstance::IFREVISION();
+ return dynamic_cast<PluginInstance *>(this);
}
if((strcmp(ifName, CAInterface::IFNAME()) == 0) &&
@@ -91,16 +148,25 @@
{
if (actualRev != NULL)
*actualRev = CAInterface::IFREVISION();
- return this;// Dynamic_cast<TracePluginInterface *>(this);
+ return dynamic_cast<CAInterface *>(dynamic_cast<PluginInstance *>(this));
}
+ if((strcmp(ifName, ParameterInterface::IFNAME()) == 0) &&
+ minRev <= ParameterInterface::IFREVISION())
+ {
+ if (actualRev != NULL)
+ *actualRev = ParameterInterface::IFREVISION();
+ return dynamic_cast<ParameterInterface *>(this);
+ }
+ printf("CoverageTrace::ObtainInterface Failed!\n");
return NULL;
}
CoverageTrace::CoverageTrace(const char *instance_name_,
- const char *trace_file_prefix_) :
+ const char *trace_file_prefix_, int _mode) :
instance_name(instance_name_),
- trace_file_prefix(trace_file_prefix_)
+ trace_file_prefix(trace_file_prefix_),
+ trace_mode(_mode)
{
printf("CoverageTrace::CoverageTrace\n");
}
@@ -142,6 +208,9 @@
CAInterface *caif = sys_if->GetComponentTrace(tci);
ComponentTraceInterface *cti =
caif->ObtainPointer<ComponentTraceInterface>();
+ InstructionTraceContext *inst_cont = NULL;
+ MTI::EventClass * event = NULL;
+
if (cti == 0) {
Error("Could not get TraceInterface for component.");
continue;
@@ -154,16 +223,39 @@
// To register a new trace source the arguments are the
// name of the trace source followed by a vector of
// pairs of (field name,field type).
- InstructionTraceContext *inst_cont = new InstructionTraceContext(
- "INST",
- { {"PC", u32},
- {"SIZE", u32}}
- );
+ inst_cont = new InstructionTraceContext(
+ "INST",
+ { {"PC", u32},
+ {"SIZE", u32}}
+ );
inst_cont->nb_insts = 0;
- inst_cont->CreateEvent(&cti, inst_cont->Callback);
+ event = inst_cont->CreateEvent(&cti, inst_cont->Callback);
+ event->UnregisterCallback(inst_cont->Callback, inst_cont);
trace_component->AddTraceSource(inst_cont);
trace_components.push_back(trace_component);
}
+ if (cti->GetTraceSource("MODE_CHANGE") != 0) {
+ MTI::EventClass * mode_event = NULL;
+ if(!event) {
+ Error("Could not set mode_change event");
+ continue;
+ }
+ // To register a new trace source the arguments are the
+ // name of the trace source followed by a vector of
+ // pairs of (field name,field type).
+ this->mode_change = new ModeChangeTraceContext(
+ "MODE_CHANGE",
+ { {"MODE", u8},
+ {"NON_SECURE", u8}
+ }
+ );
+ mode_event = this->mode_change->CreateEvent(&cti, this->mode_change->Callback);
+ this->mode_change->event = event;
+ this->mode_change->itc = inst_cont;
+ this->mode_change->mode_mask = trace_mode;
+ mode_event->RegisterCallback(this->mode_change->Callback, mode_change);
+ }
+
}
return CADI_STATUS_OK;
@@ -174,8 +266,14 @@
void
CoverageTrace::Release()
{
- printf("CoverageTrace::Release\n");
+ printf("CoverageTrace::Release\n");
// We can dump our data now
+ this->Save();
+}
+
+void
+CoverageTrace::Save(void)
+{
int error = 0;
char* fname;
int ret;
@@ -191,7 +289,7 @@
int status = asprintf(&fname, "%s-%s.log",
this->trace_file_prefix.c_str(),
tcont->trace_path.c_str());
- if ( status != 0)
+ if ( status == -1)
{
printf("Error in asprintf: %d\n", status);
printf("Error description is : %s\n", strerror(errno));
@@ -223,8 +321,9 @@
free(fname);
}
-if (error != 0)
- delete this;
+ printf("Everything saved\n");
+ if (error != 0)
+ delete this;
}
const char *
@@ -234,33 +333,103 @@
return instance_name.c_str();
}
-// Class used to return a static object CAInterface. CAInterface provides a
-// basis for a software model built around ’components’ and ’interfaces’.
-// A component provides concrete implementations of one or more interfaces.
-// Interfaces are identified by a string name (of type if_name_t), and an
-// integer revision (type if_rev_t). A higher revision number indicates a newer
-// revision of the same interface.
-class ThePluginFactory :public PluginFactory
+CADIReturn_t CoverageTrace::GetParameterInfos(uint32_t start_index,
+ uint32_t desired_num_of_params,
+ uint32_t* actual_num_of_params,
+ CADIParameterInfo_t* params)
{
-public:
- virtual CAInterface *ObtainInterface(if_name_t ifName,
- if_rev_t minRev,
- if_rev_t * actualRev);
- virtual uint32_t GetNumberOfParameters();
+ *actual_num_of_params = GetThePluginFactory()->GetNumberOfParameters();
+ return GetThePluginFactory()->GetParameterInfos(params);
- virtual eslapi::CADIReturn_t
- GetParameterInfos(eslapi::CADIParameterInfo_t *parameter_info_list);
+}
- virtual CAInterface *Instantiate(const char *instance_name,
- uint32_t number_of_parameters,
- eslapi::CADIParameterValue_t *parameter_values);
+CADIReturn_t CoverageTrace::GetParameterInfo(const char* parameterName,
+ CADIParameterInfo_t* param)
+{
+ uint32_t num_of_params = GetThePluginFactory()->GetNumberOfParameters();
+ CADIParameterInfo_t* plugin_parameters = NULL;
- virtual void Release();
+ GetThePluginFactory()->GetParameterInfos(plugin_parameters);
- virtual const char *GetType() const { return "CoverageTrace"; }
- virtual const char *GetVersion() const { return PLUGIN_VERSION; }
-};
+ if (param == nullptr)
+ {
+ return CADI_STATUS_IllegalArgument;
+ }
+
+ printf("Reading parameter info %s \n", parameterName);
+ for (uint32_t i = 0; i < num_of_params; ++i)
+ {
+ if (strcmp(plugin_parameters[i].name, parameterName) == 0)
+ {
+ *param = plugin_parameters[i];
+ return CADI_STATUS_OK;
+ }
+ }
+ *param = plugin_parameters[0];
+ return CADI_STATUS_OK;
+
+}
+
+CADIReturn_t CoverageTrace::GetParameterValues(uint32_t parameter_count,
+ uint32_t* actual_num_of_params_read,
+ CADIParameterValue_t *param_values_out)
+{
+ if (param_values_out == nullptr || actual_num_of_params_read == nullptr)
+ {
+ return CADI_STATUS_IllegalArgument;
+ }
+
+ *actual_num_of_params_read = 0;
+ for (uint32_t i = 0; i < parameter_count; ++i)
+ {
+ CADIParameterValue_t ¶m_value = param_values_out[i];
+
+ switch (param_value.parameterID)
+ {
+ case TRACE_FILE_PREFIX:
+ strncpy(param_value.stringValue,
+ this->trace_file_prefix.c_str(),
+ sizeof(param_value.stringValue));
+ break;
+
+ case TRACE_MODE:
+ param_value.intValue = this->mode_change->mode_mask;
+ break;
+ default: // unknown ID
+
+ *actual_num_of_params_read = i;
+ return CADI_STATUS_IllegalArgument;
+ }
+ }
+
+ *actual_num_of_params_read = parameter_count;
+ return CADI_STATUS_OK;
+}
+
+CADIReturn_t CoverageTrace::SetParameterValues(uint32_t parameter_count,
+ CADIParameterValue_t* parameters,
+ CADIFactoryErrorMessage_t* error)
+{
+ for (uint32_t i = 0; i < parameter_count; ++i)
+ {
+ CADIParameterValue_t ¶meter = parameters[i];
+ switch(parameter.parameterID)
+ {
+ case TRACE_FILE_PREFIX:
+ this->trace_file_prefix = parameter.stringValue;
+ this->Save();
+ break;
+ case TRACE_MODE:
+ this->mode_change->mode_mask = parameter.intValue;
+ break;
+ default:
+ ;
+ break;
+ }
+ }
+ return CADI_STATUS_OK;
+}
// Allows a client to obtain a reference to any of the interfaces that the
// component implements. The client specifies the id and revision of the
@@ -296,7 +465,7 @@
uint32_t ThePluginFactory::GetNumberOfParameters()
{
printf("ThePluginFactory::GetNumberOfParameters\n");
- return 1;
+ return TOTAL_PARAMETERS;
}
eslapi::CADIReturn_t
@@ -304,10 +473,12 @@
eslapi::CADIParameterInfo_t *parameter_info_list)
{
printf("ThePluginFactory::GetParameterInfos\n");
- *parameter_info_list = CADIParameterInfo_t(
- 0, "trace-file-prefix", CADI_PARAM_STRING,
- "Prefix of the trace files.", 0, 0, 0, 0, "covtrace"
- );
+ parameter_info_list[0] = CADIParameterInfo_t(
+ TRACE_FILE_PREFIX, "trace-file-prefix", CADI_PARAM_STRING,
+ "Prefix of the trace files.", true, 0, 0, 0, "covtrace");
+ parameter_info_list[1] = CADIParameterInfo_t(
+ TRACE_MODE, "trace-mode", CADI_PARAM_INT,
+ "Selects which modes to trace.", true, 0, 0xffffffff, 0xffffffff, 0);
return CADI_STATUS_OK;
}
@@ -318,16 +489,21 @@
{
printf("ThePluginFactory::Instantiate\n");
const char *trace_file_prefix = 0;
+ int mode_value = 0xffffffff;
+
printf("CoverageTrace: number of params: %d\n", param_nb);
for (uint32_t i = 0; i < param_nb; ++i) {
- if (values[i].parameterID == 0) {
+ if (values[i].parameterID == TRACE_FILE_PREFIX) {
trace_file_prefix = values[i].stringValue;
+ } else if (values[i].parameterID == TRACE_MODE) {
+ mode_value = values[i].intValue;
} else {
printf("\tCoverageTrace: got unexpected param %d\n",
values[i].parameterID);
}
}
- return new CoverageTrace(instance_name, trace_file_prefix);
+ return (PluginInstance*)new CoverageTrace(instance_name, trace_file_prefix,
+ mode_value);
}
void ThePluginFactory::Release()
@@ -345,5 +521,9 @@
printf("********->GetCAInterface\n");
return &factory_instance;
}
+static ThePluginFactory *GetThePluginFactory()
+{
+ return &factory_instance;
+}
// End of file CoverageTrace.cpp
diff --git a/coverage-tool/coverage-plugin/coverage_trace_parameters_change.py b/coverage-tool/coverage-plugin/coverage_trace_parameters_change.py
new file mode 100644
index 0000000..73841c5
--- /dev/null
+++ b/coverage-tool/coverage-plugin/coverage_trace_parameters_change.py
@@ -0,0 +1,78 @@
+# !/usr/bin/env python
+##############################################################################
+# Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+##############################################################################
+import iris.debug as debug
+import iris.iris as iris
+import argparse
+import textwrap
+
+def arg_parser():
+ parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
+ description = textwrap.dedent('''\
+ Tool to change the plugin parameters of the FVP coverage-plugin.
+
+ To be able to connect to the model, the model needs to have the iris-servier active.
+ The -p of the model can be used to show the port to connect to.
+ When starting a model with the iris-server, the model will wait until a debugger
+ is connect and ran. We can start the model automatically by using the -R option.
+ Example:
+ MODEL --iris-server -R -p
+ '''))
+ parser.add_argument(
+ "-p",
+ "--port",
+ type=int,
+ default=7100,
+ help="set the port of the running model"
+ )
+ parser.add_argument(
+ "-m",
+ "--mode",
+ type=lambda x: int(x,0),
+ default=-1,
+ help="set the mode to trace as a hex number."
+ )
+ parser.add_argument(
+ "-f",
+ "--file",
+ default="",
+ help="set the file-prefix of the trace files"
+ )
+ parser.add_argument(
+ "-s",
+ "--save",
+ action='store_true',
+ help="Save the current trace"
+ )
+ return parser.parse_args()
+
+def main():
+ parsed_args = arg_parser()
+ model = debug.NetworkModel("localhost", parsed_args.port)
+
+ components = model.get_targets()
+ for component in components:
+ if "coverage_trace" in component.instName:
+ trace_component = component
+
+ if trace_component:
+ if parsed_args.mode != -1:
+ trace_component.parameters['trace-mode'] = parsed_args.mode
+ print("Changed trace mode to " + hex(parsed_args.mode))
+ elif parsed_args.file != "":
+ trace_component.parameters['trace-file-prefix'] = parsed_args.file
+ print("Changed trace prefix to" + parsed_args.file)
+ elif parsed_args.save:
+ trace_component.parameters['trace-file-prefix'] = trace_component.parameters['trace-file-prefix']
+ print("Saved trace files to " + trace_component.parameters['trace-file-prefix'])
+ else:
+ print("Nothing to do")
+ else:
+ print("Could not find plugin component")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/coverage-tool/coverage-plugin/trace_sources.h b/coverage-tool/coverage-plugin/trace_sources.h
index 57f6462..e200bc5 100644
--- a/coverage-tool/coverage-plugin/trace_sources.h
+++ b/coverage-tool/coverage-plugin/trace_sources.h
@@ -26,7 +26,7 @@
typedef std::map<uint32_t, InstStat> InstStatMap;
//Defining types for fields
-enum enum_types {u32, boolT};
+enum enum_types {u32, boolT, u8};
typedef enum_types ValueTypes;
/*
@@ -108,6 +108,9 @@
case boolT: it->second.value = new bool(
record->GetBool(event_class, it->second.index));
break;
+ case u8: it->second.value = new uint8_t(
+ record->Get<uint8_t>(event_class, it->second.index));
+ break;
}
}
return tc;
@@ -137,6 +140,10 @@
target->params[it->first].value =
new bool(*((bool*)it->second.value));
break;
+ case u8:
+ target->params[it->first].value =
+ new uint8_t(*((uint8_t*)it->second.value));
+ break;
}
}
}
@@ -226,4 +233,91 @@
};
};
+struct mode_change_type {
+ uint8_t mode_value;
+ char name[5];
+};
+const struct mode_change_type types[] = {
+ {0x0 , "EL0t"}, //0
+ {0x4 , "EL1t"}, //1
+ {0x5 , "EL1h"}, //2
+ {0x8 , "EL2t"}, //3
+ {0x9 , "EL2h"}, //4
+ {0xc , "EL3t"}, //5
+ {0xd , "EL3h"}, //6
+ {0x10 , "usr"}, //7
+ {0x11 , "fiq"}, //8
+ {0x12 , "irq"}, //9
+ {0x13 , "svc"}, //10
+ {0x16 , "mon"}, //11
+ {0x17 , "abt"}, //12
+ {0x1a , "hyp"}, //13
+ {0x1b , "und"}, //14
+ {0x1f , "sys"}, //15
+ /* Secure modes */
+ {0x0 , "EL0t"}, //16
+ {0x4 , "EL1t"}, //17
+ {0x5 , "EL1h"}, //18
+ {0x8 , "EL2t"}, //19
+ {0x9 , "EL2h"}, //20
+ {0xc , "EL3t"}, //21
+ {0xd , "EL3h"}, //22
+ {0x10 , "usr"}, //23
+ {0x11 , "fiq"}, //24
+ {0x12 , "irq"}, //25
+ {0x13 , "svc"}, //26
+ {0x16 , "mon"}, //27
+ {0x17 , "abt"}, //28
+ {0x1a , "hyp"}, //29
+ {0x1b , "und"}, //30
+ {0x1f , "sys"} //31
+};
+
+class ModeChangeTraceContext: public TraceSourceContext {
+ public:
+ using TraceSourceContext::TraceSourceContext;
+ MTI::EventClass *event;
+ uint32_t mode_mask;
+ InstructionTraceContext* itc;
+
+
+ static void Callback(void* user_data,
+ const MTI::EventClass *event_class,
+ const MTI::EventRecord *record)
+ {
+ ModeChangeTraceContext* mtc = static_cast<ModeChangeTraceContext*>
+ (user_data);
+ static bool trace = false;
+ bool new_trace = false;
+ uint8_t mode = record->GetAs<char>(event_class,
+ mtc->fields["MODE"].index);
+ uint8_t nsecure = record->Get<char>(event_class,
+ mtc->fields["NON_SECURE"].index);
+ int start_mask = 0;
+
+ if(nsecure) {
+ start_mask = 0;
+ } else {
+ start_mask = 16;
+ }
+
+ for (int i = start_mask; i < start_mask + 16; i++) {
+ if (types[i].mode_value == mode) {
+ new_trace = new_trace || (mtc->mode_mask & (1 << i));
+ break;
+ }
+ }
+
+ if (new_trace && !trace) {
+ mtc->event->RegisterCallback(InstructionTraceContext::Callback,
+ mtc->itc);
+ } else if (!new_trace && trace){
+ mtc->event->UnregisterCallback(
+ InstructionTraceContext::Callback,
+ mtc->itc);
+ }
+ trace = new_trace;
+ };
+
+};
#endif // _COVERAGE_TOOL_COVERAGE_PLUGIN_TRACE_SOURCES_H_