1/* 2 * File: EncoreBootImageGenerator.cpp 3 * 4 * Copyright (c) Freescale Semiconductor, Inc. All rights reserved. 5 * See included license file for license details. 6 */ 7 8#include "EncoreBootImageGenerator.h" 9#include "Logging.h" 10 11#define kFlagsOption "flags" 12#define kSectionFlagsOption "sectionFlags" 13#define kProductVersionOption "productVersion" 14#define kComponentVersionOption "componentVersion" 15#define kAlignmentOption "alignment" 16#define kCleartextOption "cleartext" 17 18using namespace elftosb; 19 20BootImage * EncoreBootImageGenerator::generate() 21{ 22 EncoreBootImage * image = new EncoreBootImage(); 23 24 // process each output section 25 section_vector_t::iterator it = m_sections.begin(); 26 for (; it != m_sections.end(); ++it) 27 { 28 OutputSection * section = *it; 29 30 OperationSequenceSection * opSection = dynamic_cast<OperationSequenceSection*>(section); 31 if (opSection) 32 { 33 processOperationSection(opSection, image); 34 continue; 35 } 36 37 BinaryDataSection * dataSection = dynamic_cast<BinaryDataSection*>(section); 38 if (dataSection) 39 { 40 processDataSection(dataSection, image); 41 continue; 42 } 43 44 Log::log(Logger::WARNING, "warning: unexpected output section type\n"); 45 } 46 47 // handle global options that affect the image 48 processOptions(image); 49 50 return image; 51} 52 53void EncoreBootImageGenerator::processOptions(EncoreBootImage * image) 54{ 55 // bail if no option context was set 56 if (!m_options) 57 { 58 return; 59 } 60 61 if (m_options->hasOption(kFlagsOption)) 62 { 63 const IntegerValue * intValue = dynamic_cast<const IntegerValue *>(m_options->getOption(kFlagsOption)); 64 if (intValue) 65 { 66 image->setFlags(intValue->getValue()); 67 } 68 else 69 { 70 Log::log(Logger::WARNING, "warning: flags option is an unexpected type\n"); 71 } 72 } 73 74 // handle common options 75 processVersionOptions(image); 76 processDriveTagOption(image); 77} 78 79void EncoreBootImageGenerator::processSectionOptions(EncoreBootImage::Section * imageSection, OutputSection * modelSection) 80{ 81 // Get options context for this output section. 82 const OptionContext * context = modelSection->getOptions(); 83 if (!context) 84 { 85 return; 86 } 87 88 // Check for and handle "sectionFlags" option. 89 if (context->hasOption(kSectionFlagsOption)) 90 { 91 const Value * value = context->getOption(kSectionFlagsOption); 92 const IntegerValue * intValue = dynamic_cast<const IntegerValue *>(value); 93 if (intValue) 94 { 95 // set explicit flags for this section 96 imageSection->setFlags(intValue->getValue()); 97 } 98 else 99 { 100 Log::log(Logger::WARNING, "warning: sectionFlags option is an unexpected type\n"); 101 } 102 } 103 104 // Check for and handle "alignment" option. 105 if (context->hasOption(kAlignmentOption)) 106 { 107 const Value * value = context->getOption(kAlignmentOption); 108 const IntegerValue * intValue = dynamic_cast<const IntegerValue *>(value); 109 if (intValue) 110 { 111 // verify alignment value 112 if (intValue->getValue() < EncoreBootImage::BOOT_IMAGE_MINIMUM_SECTION_ALIGNMENT) 113 { 114 Log::log(Logger::WARNING, "warning: alignment option value must be 16 or greater\n"); 115 } 116 117 imageSection->setAlignment(intValue->getValue()); 118 } 119 else 120 { 121 Log::log(Logger::WARNING, "warning: alignment option is an unexpected type\n"); 122 } 123 } 124 125 // Check for and handle "cleartext" option. 126 if (context->hasOption(kCleartextOption)) 127 { 128 const Value * value = context->getOption(kCleartextOption); 129 const IntegerValue * intValue = dynamic_cast<const IntegerValue *>(value); 130 if (intValue) 131 { 132 bool leaveUnencrypted = intValue->getValue() != 0; 133 imageSection->setLeaveUnencrypted(leaveUnencrypted); 134 } 135 else 136 { 137 Log::log(Logger::WARNING, "warning: cleartext option is an unexpected type\n"); 138 } 139 } 140} 141 142void EncoreBootImageGenerator::processOperationSection(OperationSequenceSection * section, EncoreBootImage * image) 143{ 144 EncoreBootImage::BootSection * newSection = new EncoreBootImage::BootSection(section->getIdentifier()); 145 146 OperationSequence & sequence = section->getSequence(); 147 OperationSequence::iterator_t it = sequence.begin(); 148 for (; it != sequence.end(); ++it) 149 { 150 Operation * op = *it; 151 152 LoadOperation * loadOp = dynamic_cast<LoadOperation*>(op); 153 if (loadOp) 154 { 155 processLoadOperation(loadOp, newSection); 156 continue; 157 } 158 159 ExecuteOperation * execOp = dynamic_cast<ExecuteOperation*>(op); 160 if (execOp) 161 { 162 processExecuteOperation(execOp, newSection); 163 continue; 164 } 165 166 BootModeOperation * modeOp = dynamic_cast<BootModeOperation*>(op); 167 if (modeOp) 168 { 169 processBootModeOperation(modeOp, newSection); 170 continue; 171 } 172 173 Log::log(Logger::WARNING, "warning: unexpected operation type\n"); 174 } 175 176 // Deal with options that apply to sections. 177 processSectionOptions(newSection, section); 178 179 // add the boot section to the image 180 image->addSection(newSection); 181} 182 183void EncoreBootImageGenerator::processLoadOperation(LoadOperation * op, EncoreBootImage::BootSection * section) 184{ 185 DataSource * source = op->getSource(); 186 DataTarget * target = op->getTarget(); 187 188 // other sources get handled the same way 189 unsigned segmentCount = source->getSegmentCount(); 190 unsigned index = 0; 191 for (; index < segmentCount; ++index) 192 { 193 DataSource::Segment * segment = source->getSegmentAt(index); 194 DataTarget::AddressRange range = target->getRangeForSegment(*source, *segment); 195 unsigned rangeLength = range.m_end - range.m_begin; 196 197 // handle a pattern segment as a special case to create a fill command 198 DataSource::PatternSegment * patternSegment = dynamic_cast<DataSource::PatternSegment*>(segment); 199 if (patternSegment) 200 { 201 SizedIntegerValue & pattern = patternSegment->getPattern(); 202 203 EncoreBootImage::FillCommand * command = new EncoreBootImage::FillCommand(); 204 command->setAddress(range.m_begin); 205 command->setFillCount(rangeLength); 206 setFillPatternFromValue(*command, pattern); 207 208 section->addCommand(command); 209 continue; 210 } 211 212 // get the data from the segment 213 uint8_t * data = new uint8_t[rangeLength]; 214 segment->getData(0, rangeLength, data); 215 216 // create the boot command 217 EncoreBootImage::LoadCommand * command = new EncoreBootImage::LoadCommand(); 218 command->setData(data, rangeLength); // Makes a copy of the data buffer. 219 command->setLoadAddress(range.m_begin); 220 command->setDCD(op->isDCDLoad()); 221 222 section->addCommand(command); 223 224 // Free the segment buffer. 225 delete [] data; 226 } 227} 228 229void EncoreBootImageGenerator::setFillPatternFromValue(EncoreBootImage::FillCommand & command, SizedIntegerValue & pattern) 230{ 231 uint32_t u32PatternValue = pattern.getValue() & pattern.getWordSizeMask(); 232 switch (pattern.getWordSize()) 233 { 234 case kWordSize: 235 { 236 command.setPattern(u32PatternValue); 237 break; 238 } 239 240 case kHalfWordSize: 241 { 242 uint16_t u16PatternValue = static_cast<uint16_t>(u32PatternValue); 243 command.setPattern(u16PatternValue); 244 break; 245 } 246 247 case kByteSize: 248 { 249 uint8_t u8PatternValue = static_cast<uint8_t>(u32PatternValue); 250 command.setPattern(u8PatternValue); 251 } 252 } 253} 254 255void EncoreBootImageGenerator::processExecuteOperation(ExecuteOperation * op, EncoreBootImage::BootSection * section) 256{ 257 DataTarget * target = op->getTarget(); 258 uint32_t arg = static_cast<uint32_t>(op->getArgument()); 259 260 EncoreBootImage::JumpCommand * command; 261 switch (op->getExecuteType()) 262 { 263 case ExecuteOperation::kJump: 264 command = new EncoreBootImage::JumpCommand(); 265 break; 266 267 case ExecuteOperation::kCall: 268 command = new EncoreBootImage::CallCommand(); 269 break; 270 } 271 272 command->setAddress(target->getBeginAddress()); 273 command->setArgument(arg); 274 command->setIsHAB(op->isHAB()); 275 276 section->addCommand(command); 277} 278 279void EncoreBootImageGenerator::processBootModeOperation(BootModeOperation * op, EncoreBootImage::BootSection * section) 280{ 281 EncoreBootImage::ModeCommand * command = new EncoreBootImage::ModeCommand(); 282 command->setBootMode(op->getBootMode()); 283 284 section->addCommand(command); 285} 286 287void EncoreBootImageGenerator::processDataSection(BinaryDataSection * section, EncoreBootImage * image) 288{ 289 EncoreBootImage::DataSection * dataSection = new EncoreBootImage::DataSection(section->getIdentifier()); 290 dataSection->setData(section->getData(), section->getLength()); 291 292 // Handle alignment option. 293 processSectionOptions(dataSection, section); 294 295 image->addSection(dataSection); 296} 297 298