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