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