/* * File: EncoreBootImageGenerator.cpp * * Copyright (c) Freescale Semiconductor, Inc. All rights reserved. * See included license file for license details. */ #include "EncoreBootImageGenerator.h" #include "Logging.h" #define kFlagsOption "flags" #define kSectionFlagsOption "sectionFlags" #define kProductVersionOption "productVersion" #define kComponentVersionOption "componentVersion" #define kAlignmentOption "alignment" #define kCleartextOption "cleartext" using namespace elftosb; BootImage * EncoreBootImageGenerator::generate() { EncoreBootImage * image = new EncoreBootImage(); // process each output section section_vector_t::iterator it = m_sections.begin(); for (; it != m_sections.end(); ++it) { OutputSection * section = *it; OperationSequenceSection * opSection = dynamic_cast(section); if (opSection) { processOperationSection(opSection, image); continue; } BinaryDataSection * dataSection = dynamic_cast(section); if (dataSection) { processDataSection(dataSection, image); continue; } Log::log(Logger::WARNING, "warning: unexpected output section type\n"); } // handle global options that affect the image processOptions(image); return image; } void EncoreBootImageGenerator::processOptions(EncoreBootImage * image) { // bail if no option context was set if (!m_options) { return; } if (m_options->hasOption(kFlagsOption)) { const IntegerValue * intValue = dynamic_cast(m_options->getOption(kFlagsOption)); if (intValue) { image->setFlags(intValue->getValue()); } else { Log::log(Logger::WARNING, "warning: flags option is an unexpected type\n"); } } // handle common options processVersionOptions(image); processDriveTagOption(image); } void EncoreBootImageGenerator::processSectionOptions(EncoreBootImage::Section * imageSection, OutputSection * modelSection) { // Get options context for this output section. const OptionContext * context = modelSection->getOptions(); if (!context) { return; } // Check for and handle "sectionFlags" option. if (context->hasOption(kSectionFlagsOption)) { const Value * value = context->getOption(kSectionFlagsOption); const IntegerValue * intValue = dynamic_cast(value); if (intValue) { // set explicit flags for this section imageSection->setFlags(intValue->getValue()); } else { Log::log(Logger::WARNING, "warning: sectionFlags option is an unexpected type\n"); } } // Check for and handle "alignment" option. if (context->hasOption(kAlignmentOption)) { const Value * value = context->getOption(kAlignmentOption); const IntegerValue * intValue = dynamic_cast(value); if (intValue) { // verify alignment value if (intValue->getValue() < EncoreBootImage::BOOT_IMAGE_MINIMUM_SECTION_ALIGNMENT) { Log::log(Logger::WARNING, "warning: alignment option value must be 16 or greater\n"); } imageSection->setAlignment(intValue->getValue()); } else { Log::log(Logger::WARNING, "warning: alignment option is an unexpected type\n"); } } // Check for and handle "cleartext" option. if (context->hasOption(kCleartextOption)) { const Value * value = context->getOption(kCleartextOption); const IntegerValue * intValue = dynamic_cast(value); if (intValue) { bool leaveUnencrypted = intValue->getValue() != 0; imageSection->setLeaveUnencrypted(leaveUnencrypted); } else { Log::log(Logger::WARNING, "warning: cleartext option is an unexpected type\n"); } } } void EncoreBootImageGenerator::processOperationSection(OperationSequenceSection * section, EncoreBootImage * image) { EncoreBootImage::BootSection * newSection = new EncoreBootImage::BootSection(section->getIdentifier()); OperationSequence & sequence = section->getSequence(); OperationSequence::iterator_t it = sequence.begin(); for (; it != sequence.end(); ++it) { Operation * op = *it; LoadOperation * loadOp = dynamic_cast(op); if (loadOp) { processLoadOperation(loadOp, newSection); continue; } ExecuteOperation * execOp = dynamic_cast(op); if (execOp) { processExecuteOperation(execOp, newSection); continue; } BootModeOperation * modeOp = dynamic_cast(op); if (modeOp) { processBootModeOperation(modeOp, newSection); continue; } Log::log(Logger::WARNING, "warning: unexpected operation type\n"); } // Deal with options that apply to sections. processSectionOptions(newSection, section); // add the boot section to the image image->addSection(newSection); } void EncoreBootImageGenerator::processLoadOperation(LoadOperation * op, EncoreBootImage::BootSection * section) { DataSource * source = op->getSource(); DataTarget * target = op->getTarget(); // other sources get handled the same way unsigned segmentCount = source->getSegmentCount(); unsigned index = 0; for (; index < segmentCount; ++index) { DataSource::Segment * segment = source->getSegmentAt(index); DataTarget::AddressRange range = target->getRangeForSegment(*source, *segment); unsigned rangeLength = range.m_end - range.m_begin; // handle a pattern segment as a special case to create a fill command DataSource::PatternSegment * patternSegment = dynamic_cast(segment); if (patternSegment) { SizedIntegerValue & pattern = patternSegment->getPattern(); EncoreBootImage::FillCommand * command = new EncoreBootImage::FillCommand(); command->setAddress(range.m_begin); command->setFillCount(rangeLength); setFillPatternFromValue(*command, pattern); section->addCommand(command); continue; } // get the data from the segment uint8_t * data = new uint8_t[rangeLength]; segment->getData(0, rangeLength, data); // create the boot command EncoreBootImage::LoadCommand * command = new EncoreBootImage::LoadCommand(); command->setData(data, rangeLength); // Makes a copy of the data buffer. command->setLoadAddress(range.m_begin); command->setDCD(op->isDCDLoad()); section->addCommand(command); // Free the segment buffer. delete [] data; } } void EncoreBootImageGenerator::setFillPatternFromValue(EncoreBootImage::FillCommand & command, SizedIntegerValue & pattern) { uint32_t u32PatternValue = pattern.getValue() & pattern.getWordSizeMask(); switch (pattern.getWordSize()) { case kWordSize: { command.setPattern(u32PatternValue); break; } case kHalfWordSize: { uint16_t u16PatternValue = static_cast(u32PatternValue); command.setPattern(u16PatternValue); break; } case kByteSize: { uint8_t u8PatternValue = static_cast(u32PatternValue); command.setPattern(u8PatternValue); } } } void EncoreBootImageGenerator::processExecuteOperation(ExecuteOperation * op, EncoreBootImage::BootSection * section) { DataTarget * target = op->getTarget(); uint32_t arg = static_cast(op->getArgument()); EncoreBootImage::JumpCommand * command; switch (op->getExecuteType()) { case ExecuteOperation::kJump: command = new EncoreBootImage::JumpCommand(); break; case ExecuteOperation::kCall: command = new EncoreBootImage::CallCommand(); break; } command->setAddress(target->getBeginAddress()); command->setArgument(arg); command->setIsHAB(op->isHAB()); section->addCommand(command); } void EncoreBootImageGenerator::processBootModeOperation(BootModeOperation * op, EncoreBootImage::BootSection * section) { EncoreBootImage::ModeCommand * command = new EncoreBootImage::ModeCommand(); command->setBootMode(op->getBootMode()); section->addCommand(command); } void EncoreBootImageGenerator::processDataSection(BinaryDataSection * section, EncoreBootImage * image) { EncoreBootImage::DataSection * dataSection = new EncoreBootImage::DataSection(section->getIdentifier()); dataSection->setData(section->getData(), section->getLength()); // Handle alignment option. processSectionOptions(dataSection, section); image->addSection(dataSection); }