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 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 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 80 string CSubsystem::getKind() const 81 { 82 return "Subsystem"; 83 } 84 85 // Susbsystem Endianness 86 bool CSubsystem::isBigEndian() const 87 { 88 return _bBigEndian; 89 } 90 91 // Susbsystem sanity 92 bool CSubsystem::isAlive() const 93 { 94 return true; 95 } 96 97 // Resynchronization after subsystem restart needed 98 bool CSubsystem::needResync(bool bClear) 99 { 100 (void)bClear; 101 102 return false; 103 } 104 105 // From IXmlSink 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 164 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 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 199 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 208 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 226 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 246 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 272 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 294 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 316 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 327 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 336 const CSubsystem* CSubsystem::getBelongingSubsystem() const 337 { 338 return this; 339 } 340 341 // Subsystem context mapping keys publication 342 void CSubsystem::addContextMappingKey(const string& strMappingKey) 343 { 344 _contextMappingKeyArray.push_back(strMappingKey); 345 } 346 347 // Subsystem object creator publication (strong reference) 348 void CSubsystem::addSubsystemObjectFactory(CSubsystemObjectCreator* pSubsystemObjectCreator) 349 { 350 _subsystemObjectCreatorArray.push_back(pSubsystemObjectCreator); 351 } 352 353 // Generic error handling from derived subsystem classes 354 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 366 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 376 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 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 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 533 void CSubsystem::mapEnd() 534 { 535 // Unstack context 536 _contextStack.pop(); 537 } 538