1 /*
2 * Copyright (c) 2011-2014, Intel Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation and/or
13 * other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors
16 * may be used to endorse or promote products derived from this software without
17 * specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 #include "Subsystem.h"
31 #include "ComponentLibrary.h"
32 #include "InstanceDefinition.h"
33 #include "XmlParameterSerializingContext.h"
34 #include "ParameterAccessContext.h"
35 #include "ConfigurationAccessContext.h"
36 #include "SubsystemObjectCreator.h"
37 #include "MappingData.h"
38 #include "Utility.h"
39 #include <assert.h>
40 #include <sstream>
41
42 #define base CConfigurableElementWithMapping
43
44 using std::string;
45 using std::list;
46 using std::ostringstream;
47
CSubsystem(const string & strName)48 CSubsystem::CSubsystem(const string& strName) : base(strName), _pComponentLibrary(new CComponentLibrary), _pInstanceDefinition(new CInstanceDefinition), _bBigEndian(false), _pMappingData(NULL)
49 {
50 // Note: A subsystem contains instance components
51 // InstanceDefintion and ComponentLibrary objects are then not chosen to be children
52 // They'll be delt with locally
53 }
54
~CSubsystem()55 CSubsystem::~CSubsystem()
56 {
57 // Remove subsystem objects
58 SubsystemObjectListIterator subsystemObjectIt;
59
60 for (subsystemObjectIt = _subsystemObjectList.begin(); subsystemObjectIt != _subsystemObjectList.end(); ++subsystemObjectIt) {
61
62 delete *subsystemObjectIt;
63 }
64
65 // Remove susbsystem creators
66 uint32_t uiIndex;
67
68 for (uiIndex = 0; uiIndex < _subsystemObjectCreatorArray.size(); uiIndex++) {
69
70 delete _subsystemObjectCreatorArray[uiIndex];
71 }
72
73 // Order matters!
74 delete _pInstanceDefinition;
75 delete _pComponentLibrary;
76
77 delete _pMappingData;
78 }
79
getKind() const80 string CSubsystem::getKind() const
81 {
82 return "Subsystem";
83 }
84
85 // Susbsystem Endianness
isBigEndian() const86 bool CSubsystem::isBigEndian() const
87 {
88 return _bBigEndian;
89 }
90
91 // Susbsystem sanity
isAlive() const92 bool CSubsystem::isAlive() const
93 {
94 return true;
95 }
96
97 // Resynchronization after subsystem restart needed
needResync(bool bClear)98 bool CSubsystem::needResync(bool bClear)
99 {
100 (void)bClear;
101
102 return false;
103 }
104
105 // From IXmlSink
fromXml(const CXmlElement & xmlElement,CXmlSerializingContext & serializingContext)106 bool CSubsystem::fromXml(const CXmlElement& xmlElement, CXmlSerializingContext& serializingContext)
107 {
108 // Subsystem class does not rely on generic fromXml algorithm of Element class.
109 // So, setting here the description if found as XML attribute.
110 setDescription(getXmlDescriptionAttribute(xmlElement));
111
112 // Context
113 CXmlParameterSerializingContext& parameterBuildContext = static_cast<CXmlParameterSerializingContext&>(serializingContext);
114
115 // Install temporary component library for further component creation
116 parameterBuildContext.setComponentLibrary(_pComponentLibrary);
117
118 CXmlElement childElement;
119
120 // Manage mapping attribute
121 if (xmlElement.hasAttribute("Mapping")) {
122
123 _pMappingData = new CMappingData;
124 if (!_pMappingData->fromXml(xmlElement, serializingContext)) {
125
126 return false;
127 }
128 }
129
130 // XML populate ComponentLibrary
131 xmlElement.getChildElement("ComponentLibrary", childElement);
132
133 if (!_pComponentLibrary->fromXml(childElement, serializingContext)) {
134
135 return false;
136 }
137
138 // XML populate InstanceDefintion
139 xmlElement.getChildElement("InstanceDefintion", childElement);
140 if (!_pInstanceDefinition->fromXml(childElement, serializingContext)) {
141
142 return false;
143 }
144
145 // Create components
146 _pInstanceDefinition->createInstances(this);
147
148 // Execute mapping to create subsystem mapping entities
149 string strError;
150 if (!mapSubsystemElements(strError)) {
151
152 serializingContext.setError(strError);
153
154 return false;
155 }
156
157 // Endianness
158 _bBigEndian = xmlElement.getAttributeBoolean("Endianness", "Big");
159
160 return true;
161 }
162
163 // XML configuration settings parsing
serializeXmlSettings(CXmlElement & xmlConfigurationSettingsElementContent,CConfigurationAccessContext & configurationAccessContext) const164 bool CSubsystem::serializeXmlSettings(CXmlElement& xmlConfigurationSettingsElementContent, CConfigurationAccessContext& configurationAccessContext) const
165 {
166 // Fix Endianness
167 configurationAccessContext.setBigEndianSubsystem(_bBigEndian);
168
169 return base::serializeXmlSettings(xmlConfigurationSettingsElementContent, configurationAccessContext);
170 }
171
172
mapSubsystemElements(string & strError)173 bool CSubsystem::mapSubsystemElements(string& strError)
174 {
175 // Default mapping context
176 CMappingContext context(_contextMappingKeyArray.size());
177 // Add Subsystem-level mapping data, which will be propagated to all children
178 handleMappingContext(this, context, strError);
179
180 _contextStack.push(context);
181
182 // Map all instantiated subelements in subsystem
183 size_t uiNbChildren = getNbChildren();
184 size_t uiChild;
185
186 for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
187
188 CInstanceConfigurableElement* pInstanceConfigurableChildElement = static_cast<CInstanceConfigurableElement*>(getChild(uiChild));
189
190 if (!pInstanceConfigurableChildElement->map(*this, strError)) {
191
192 return false;
193 }
194 }
195 return true;
196 }
197
198 // Parameter access
accessValue(CPathNavigator & pathNavigator,string & strValue,bool bSet,CParameterAccessContext & parameterAccessContext) const199 bool CSubsystem::accessValue(CPathNavigator& pathNavigator, string& strValue, bool bSet, CParameterAccessContext& parameterAccessContext) const
200 {
201 // Deal with Endianness
202 parameterAccessContext.setBigEndianSubsystem(_bBigEndian);
203
204 return base::accessValue(pathNavigator, strValue, bSet, parameterAccessContext);
205 }
206
207 // Formats the mapping of the ConfigurableElements
formatMappingDataList(const list<const CConfigurableElement * > & configurableElementPath) const208 string CSubsystem::formatMappingDataList(
209 const list<const CConfigurableElement*>& configurableElementPath) const
210 {
211 // The list is parsed in reverse order because it has been filled from the leaf to the trunk
212 // of the tree. When formatting the mapping, we want to start from the subsystem level
213 ostringstream ossStream;
214 list<const CConfigurableElement*>::const_reverse_iterator it;
215 for (it = configurableElementPath.rbegin(); it != configurableElementPath.rend(); ++it) {
216
217 const CInstanceConfigurableElement* pInstanceConfigurableElement =
218 static_cast<const CInstanceConfigurableElement*>(*it);
219
220 ossStream << pInstanceConfigurableElement->getFormattedMapping() << ", ";
221 }
222 return ossStream.str();
223 }
224
225 // Find the CSubystemObject containing a specific CInstanceConfigurableElement
findSubsystemObjectFromConfigurableElement(const CInstanceConfigurableElement * pInstanceConfigurableElement) const226 const CSubsystemObject* CSubsystem::findSubsystemObjectFromConfigurableElement(
227 const CInstanceConfigurableElement* pInstanceConfigurableElement) const {
228
229 const CSubsystemObject* pSubsystemObject = NULL;
230
231 list<CSubsystemObject*>::const_iterator it;
232 for (it = _subsystemObjectList.begin(); it != _subsystemObjectList.end(); ++it) {
233
234 // Check if one of the SubsystemObjects is associated with a ConfigurableElement
235 // corresponding to the expected one
236 pSubsystemObject = *it;
237 if (pSubsystemObject->getConfigurableElement() == pInstanceConfigurableElement) {
238
239 break;
240 }
241 }
242
243 return pSubsystemObject;
244 }
245
findSubsystemLevelMappingKeyValue(const CInstanceConfigurableElement * pInstanceConfigurableElement,string & strMappingKey,string & strMappingValue) const246 void CSubsystem::findSubsystemLevelMappingKeyValue(
247 const CInstanceConfigurableElement* pInstanceConfigurableElement,
248 string& strMappingKey,
249 string& strMappingValue) const
250 {
251 // Find creator to get key name
252 std::vector<CSubsystemObjectCreator*>::const_iterator it;
253 for (it = _subsystemObjectCreatorArray.begin();
254 it != _subsystemObjectCreatorArray.end(); ++it) {
255
256 const CSubsystemObjectCreator* pSubsystemObjectCreator = *it;
257
258 strMappingKey = pSubsystemObjectCreator->getMappingKey();
259
260 // Check if the ObjectCreator MappingKey corresponds to the element mapping data
261 const string* pStrValue;
262 if (pInstanceConfigurableElement->getMappingData(strMappingKey, pStrValue)) {
263
264 strMappingValue = *pStrValue;
265 return;
266 }
267 }
268 assert(0);
269 }
270
271 // Formats the mapping data as a comma separated list of key value pairs
getFormattedSubsystemMappingData(const CInstanceConfigurableElement * pInstanceConfigurableElement) const272 string CSubsystem::getFormattedSubsystemMappingData(
273 const CInstanceConfigurableElement* pInstanceConfigurableElement) const
274 {
275 // Find the SubsystemObject related to pInstanceConfigurableElement
276 const CSubsystemObject* pSubsystemObject = findSubsystemObjectFromConfigurableElement(
277 pInstanceConfigurableElement);
278
279 // Exit if node does not correspond to a SubsystemObject
280 if (pSubsystemObject == NULL) {
281
282 return "";
283 }
284
285 // Find SubsystemCreator mapping key
286 string strMappingKey;
287 string strMappingValue; // mapping value where amends are not replaced by their value
288 findSubsystemLevelMappingKeyValue(pInstanceConfigurableElement, strMappingKey, strMappingValue);
289
290 // Find SubSystemObject mapping value (with amends replaced by their value)
291 return strMappingKey + ":" + pSubsystemObject->getFormattedMappingValue();
292 }
293
getMapping(list<const CConfigurableElement * > & configurableElementPath) const294 string CSubsystem::getMapping(list<const CConfigurableElement*>& configurableElementPath) const
295 {
296 if (configurableElementPath.empty()) {
297
298 return "";
299 }
300
301 // Get the first element, which is the element containing the amended mapping
302 const CInstanceConfigurableElement* pInstanceConfigurableElement =
303 static_cast<const CInstanceConfigurableElement*>(configurableElementPath.front());
304 configurableElementPath.pop_front();
305 // Now the list only contains elements whose mapping are related to the context
306
307 // Format context mapping data
308 string strValue = formatMappingDataList(configurableElementPath);
309
310 // Print the mapping of the first node, which corresponds to a SubsystemObject
311 strValue += getFormattedSubsystemMappingData(pInstanceConfigurableElement);
312
313 return strValue;
314 }
315
logValue(string & strValue,CErrorContext & errorContext) const316 void CSubsystem::logValue(string& strValue, CErrorContext& errorContext) const
317 {
318 CParameterAccessContext& parameterAccessContext = static_cast<CParameterAccessContext&>(errorContext);
319
320 // Deal with Endianness
321 parameterAccessContext.setBigEndianSubsystem(_bBigEndian);
322
323 return base::logValue(strValue, errorContext);
324 }
325
326 // Used for simulation and virtual subsystems
setDefaultValues(CParameterAccessContext & parameterAccessContext) const327 void CSubsystem::setDefaultValues(CParameterAccessContext& parameterAccessContext) const
328 {
329 // Deal with Endianness
330 parameterAccessContext.setBigEndianSubsystem(_bBigEndian);
331
332 base::setDefaultValues(parameterAccessContext);
333 }
334
335 // Belonging subsystem
getBelongingSubsystem() const336 const CSubsystem* CSubsystem::getBelongingSubsystem() const
337 {
338 return this;
339 }
340
341 // Subsystem context mapping keys publication
addContextMappingKey(const string & strMappingKey)342 void CSubsystem::addContextMappingKey(const string& strMappingKey)
343 {
344 _contextMappingKeyArray.push_back(strMappingKey);
345 }
346
347 // Subsystem object creator publication (strong reference)
addSubsystemObjectFactory(CSubsystemObjectCreator * pSubsystemObjectCreator)348 void CSubsystem::addSubsystemObjectFactory(CSubsystemObjectCreator* pSubsystemObjectCreator)
349 {
350 _subsystemObjectCreatorArray.push_back(pSubsystemObjectCreator);
351 }
352
353 // Generic error handling from derived subsystem classes
getMappingError(const string & strKey,const string & strMessage,const CConfigurableElementWithMapping * pConfigurableElementWithMapping) const354 string CSubsystem::getMappingError(
355 const string& strKey,
356 const string& strMessage,
357 const CConfigurableElementWithMapping* pConfigurableElementWithMapping) const
358 {
359 return getName() + " " + getKind() + " " +
360 "mapping:\n" + strKey + " " +
361 "error: \"" + strMessage + "\" " +
362 "for element " + pConfigurableElementWithMapping->getPath();
363 }
364
365
getMappingData(const std::string & strKey,const std::string * & pStrValue) const366 bool CSubsystem::getMappingData(const std::string& strKey, const std::string*& pStrValue) const
367 {
368 if (_pMappingData) {
369
370 return _pMappingData->getValue(strKey, pStrValue);
371 }
372 return false;
373 }
374
375 // Mapping generic context handling
handleMappingContext(const CConfigurableElementWithMapping * pConfigurableElementWithMapping,CMappingContext & context,string & strError) const376 bool CSubsystem::handleMappingContext(
377 const CConfigurableElementWithMapping* pConfigurableElementWithMapping,
378 CMappingContext& context,
379 string& strError) const
380 {
381 // Feed context with found mapping data
382 uint32_t uiItem;
383
384 for (uiItem = 0; uiItem < _contextMappingKeyArray.size(); uiItem++) {
385
386 const string& strKey = _contextMappingKeyArray[uiItem];
387 const string* pStrValue;
388
389 if (pConfigurableElementWithMapping->getMappingData(strKey, pStrValue)) {
390 // Assign item to context
391 if (!context.setItem(uiItem, &strKey, pStrValue)) {
392
393 strError = getMappingError(strKey, "Already set", pConfigurableElementWithMapping);
394
395 return false;
396 }
397 }
398 }
399 return true;
400 }
401
402 // Subsystem object creation handling
handleSubsystemObjectCreation(CInstanceConfigurableElement * pInstanceConfigurableElement,CMappingContext & context,bool & bHasCreatedSubsystemObject,string & strError)403 bool CSubsystem::handleSubsystemObjectCreation(
404 CInstanceConfigurableElement* pInstanceConfigurableElement,
405 CMappingContext& context, bool& bHasCreatedSubsystemObject, string& strError)
406 {
407 uint32_t uiItem;
408 bHasCreatedSubsystemObject = false;
409
410 for (uiItem = 0; uiItem < _subsystemObjectCreatorArray.size(); uiItem++) {
411
412 const CSubsystemObjectCreator* pSubsystemObjectCreator =
413 _subsystemObjectCreatorArray[uiItem];
414
415 // Mapping key
416 string strKey = pSubsystemObjectCreator->getMappingKey();
417 // Object id
418 const string* pStrValue;
419
420 if (pInstanceConfigurableElement->getMappingData(strKey, pStrValue)) {
421
422 // First check context consistency
423 // (required ancestors must have been set prior to object creation)
424 uint32_t uiAncestorKey;
425 uint32_t uiAncestorMask = pSubsystemObjectCreator->getAncestorMask();
426
427 for (uiAncestorKey = 0; uiAncestorKey < _contextMappingKeyArray.size(); uiAncestorKey++) {
428
429 if (!((1 << uiAncestorKey) & uiAncestorMask)) {
430 // Ancestor not required
431 continue;
432 }
433 // Check ancestor was provided
434 if (!context.iSet(uiAncestorKey)) {
435
436 strError = getMappingError(strKey, _contextMappingKeyArray[uiAncestorKey] +
437 " not set", pInstanceConfigurableElement);
438
439 return false;
440 }
441 }
442
443 // Then check configurable element size is correct
444 if (pInstanceConfigurableElement->getFootPrint() >
445 pSubsystemObjectCreator->getMaxConfigurableElementSize()) {
446
447 string strSizeError = "Size should not exceed " +
448 CUtility::toString(
449 pSubsystemObjectCreator->getMaxConfigurableElementSize());
450
451 strError = getMappingError(strKey, strSizeError, pInstanceConfigurableElement);
452
453 return false;
454 }
455
456 // Do create object and keep its track
457 _subsystemObjectList.push_back(pSubsystemObjectCreator->objectCreate(
458 *pStrValue, pInstanceConfigurableElement, context));
459
460 // Indicate subsytem creation to caller
461 bHasCreatedSubsystemObject = true;
462
463 // The subsystem Object has been instantiated, no need to continue looking for an
464 // instantiation mapping
465 break;
466 }
467 }
468
469 return true;
470 }
471
472 // From IMapper
473 // Handle a configurable element mapping
mapBegin(CInstanceConfigurableElement * pInstanceConfigurableElement,bool & bKeepDiving,string & strError)474 bool CSubsystem::mapBegin(CInstanceConfigurableElement* pInstanceConfigurableElement,
475 bool& bKeepDiving, string& strError)
476 {
477 // Get current context
478 CMappingContext context = _contextStack.top();
479
480 // Add mapping in context
481 if (!handleMappingContext(pInstanceConfigurableElement, context,
482 strError)) {
483
484 return false;
485 }
486
487 // Push context
488 _contextStack.push(context);
489
490 // Assume diving by default
491 bKeepDiving = true;
492
493 // Deal with ambiguous usage of parameter blocks
494 bool bShouldCreateSubsystemObject = true;
495
496 switch(pInstanceConfigurableElement->getType()) {
497
498 case CInstanceConfigurableElement::EComponent:
499 case CInstanceConfigurableElement::EParameterBlock:
500 // Subsystem object creation is optional in parameter blocks
501 bShouldCreateSubsystemObject = false;
502 // No break
503 case CInstanceConfigurableElement::EBitParameterBlock:
504 case CInstanceConfigurableElement::EParameter:
505 case CInstanceConfigurableElement::EStringParameter:
506
507 bool bHasCreatedSubsystemObject;
508
509 if (!handleSubsystemObjectCreation(pInstanceConfigurableElement, context,
510 bHasCreatedSubsystemObject, strError)) {
511
512 return false;
513 }
514 // Check for creation error
515 if (bShouldCreateSubsystemObject && !bHasCreatedSubsystemObject) {
516
517 strError = getMappingError("Not found",
518 "Subsystem object mapping key is missing",
519 pInstanceConfigurableElement);
520 return false;
521 }
522 // Not created and no error, keep diving
523 bKeepDiving = !bHasCreatedSubsystemObject;
524
525 return true;
526
527 default:
528 assert(0);
529 return false;
530 }
531 }
532
mapEnd()533 void CSubsystem::mapEnd()
534 {
535 // Unstack context
536 _contextStack.pop();
537 }
538