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