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 
18 using namespace elftosb;
19 
generate()20 BootImage * 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 
processOptions(EncoreBootImage * image)53 void 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 
processSectionOptions(EncoreBootImage::Section * imageSection,OutputSection * modelSection)79 void 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 
processOperationSection(OperationSequenceSection * section,EncoreBootImage * image)142 void 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 
processLoadOperation(LoadOperation * op,EncoreBootImage::BootSection * section)183 void 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 
setFillPatternFromValue(EncoreBootImage::FillCommand & command,SizedIntegerValue & pattern)229 void 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 
processExecuteOperation(ExecuteOperation * op,EncoreBootImage::BootSection * section)255 void 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 
processBootModeOperation(BootModeOperation * op,EncoreBootImage::BootSection * section)279 void 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 
processDataSection(BinaryDataSection * section,EncoreBootImage * image)287 void 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