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