xref: /netbsd-src/external/bsd/elftosb/dist/elftosb2/EncoreBootImageGenerator.cpp (revision 993229b6fea628ff8b1fa09146c80b0cfb2768eb)
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