Home | History | Annotate | Line # | Download | only in common
      1 /*
      2  * File:	EncoreBootImage.cpp
      3  *
      4  * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
      5  * See included license file for license details.
      6  */
      7 
      8 #include "EncoreBootImage.h"
      9 #include <stdexcept>
     10 #include <algorithm>
     11 #include <time.h>
     12 #include "crc.h"
     13 #include "SHA1.h"
     14 #include "Random.h"
     15 #include "rijndael.h"
     16 #include "RijndaelCBCMAC.h"
     17 #include "Logging.h"
     18 #include "EndianUtilities.h"
     19 
     20 using namespace elftosb;
     21 
     22 EncoreBootImage::EncoreBootImage()
     23 :	m_headerFlags(0),
     24 	m_productVersion(),
     25 	m_componentVersion(),
     26 	m_driveTag(0)
     27 {
     28 }
     29 
     30 EncoreBootImage::~EncoreBootImage()
     31 {
     32 	// dispose of all sections
     33 	section_iterator_t it = beginSection();
     34 	for (; it != endSection(); ++it)
     35 	{
     36 		delete *it;
     37 	}
     38 }
     39 
     40 //! \exception std::runtime_error Raised if \a newSection has the same tag as a previously
     41 //!		added section.
     42 void EncoreBootImage::addSection(Section * newSection)
     43 {
     44 	// check for another section with this tag
     45 	section_iterator_t it = beginSection();
     46 	for (; it != endSection(); ++it)
     47 	{
     48 		if ((*it)->getIdentifier() == newSection->getIdentifier())
     49 		{
     50 			throw std::runtime_error("new section with non-unique tag");
     51 		}
     52 	}
     53 
     54 	// no conflicting section tags, so add it
     55 	m_sections.push_back(newSection);
     56 
     57 	// tell the image who owns it now
     58 	newSection->setImage(this);
     59 }
     60 
     61 EncoreBootImage::section_iterator_t EncoreBootImage::findSection(Section * section)
     62 {
     63 	return std::find(beginSection(), endSection(), section);
     64 }
     65 
     66 void EncoreBootImage::setProductVersion(const version_t & version)
     67 {
     68 	m_productVersion = version;
     69 }
     70 
     71 void EncoreBootImage::setComponentVersion(const version_t & version)
     72 {
     73 	m_componentVersion = version;
     74 }
     75 
     76 //! \todo Optimize writing section data. Right now it only writes one block at a
     77 //!		time, which is of course quite slow (in relative terms).
     78 //!	\todo Refactor this into several different methods for writing each region
     79 //!		of the image. Use a context structure to keep track of shared data between
     80 //!		each of the methods.
     81 //! \todo Refactor the section and boot tag writing code to only have a single
     82 //!		copy of the block writing and encryption loop.
     83 void EncoreBootImage::writeToStream(std::ostream & stream)
     84 {
     85 	// always generate the session key or DEK even if image is unencrypted
     86 	m_sessionKey.randomize();
     87 
     88 	// prepare to compute CBC-MACs with each KEK
     89 	unsigned i;
     90 	smart_array_ptr<RijndaelCBCMAC> macs(0);
     91 	if (isEncrypted())
     92 	{
     93 		macs = new RijndaelCBCMAC[m_keys.size()];
     94 		for (i=0; i < m_keys.size(); ++i)
     95 		{
     96 			RijndaelCBCMAC mac(m_keys[i]);
     97 			(macs.get())[i] = mac;
     98 		}
     99 	}
    100 
    101 	// prepare to compute SHA-1 digest over entire image
    102 	CSHA1 hash;
    103 	hash.Reset();
    104 
    105 	// count of total blocks written to the file
    106 	unsigned fileBlocksWritten = 0;
    107 
    108 	// we need some pieces of the header down below
    109 	boot_image_header_t imageHeader;
    110 	prepareImageHeader(imageHeader);
    111 
    112 	// write plaintext header
    113 	{
    114 		// write header
    115 		assert(sizeOfPaddingForCipherBlocks(sizeof(boot_image_header_t)) == 0);
    116 		stream.write(reinterpret_cast<char *>(&imageHeader), sizeof(imageHeader));
    117 		fileBlocksWritten += numberOfCipherBlocks(sizeof(imageHeader));
    118 
    119 		// update CBC-MAC over image header
    120 		if (isEncrypted())
    121 		{
    122 			for (i=0; i < m_keys.size(); ++i)
    123 			{
    124 				(macs.get())[i].update(reinterpret_cast<uint8_t *>(&imageHeader), sizeof(imageHeader));
    125 			}
    126 		}
    127 
    128 		// update SHA-1
    129 		hash.Update(reinterpret_cast<uint8_t *>(&imageHeader), sizeof(imageHeader));
    130 	}
    131 
    132 	// write plaintext section table
    133 	{
    134 		section_iterator_t it = beginSection();
    135 		for (; it != endSection(); ++it)
    136 		{
    137 			Section * section = *it;
    138 
    139 			// write header for this section
    140 			assert(sizeOfPaddingForCipherBlocks(sizeof(section_header_t)) == 0);
    141 			section_header_t sectionHeader;
    142 			section->fillSectionHeader(sectionHeader);
    143 			stream.write(reinterpret_cast<char *>(&sectionHeader), sizeof(sectionHeader));
    144 			fileBlocksWritten += numberOfCipherBlocks(sizeof(sectionHeader));
    145 
    146 			// update CBC-MAC over this entry
    147 			if (isEncrypted())
    148 			{
    149 				for (i=0; i < m_keys.size(); ++i)
    150 				{
    151 					(macs.get())[i].update(reinterpret_cast<uint8_t *>(&sectionHeader), sizeof(sectionHeader));
    152 				}
    153 			}
    154 
    155 			// update SHA-1
    156 			hash.Update(reinterpret_cast<uint8_t *>(&sectionHeader), sizeof(sectionHeader));
    157 		}
    158 	}
    159 
    160 	// finished with the CBC-MAC
    161 	if (isEncrypted())
    162 	{
    163 		for (i=0; i < m_keys.size(); ++i)
    164 		{
    165 			(macs.get())[i].finalize();
    166 		}
    167 	}
    168 
    169 	// write key dictionary
    170 	if (isEncrypted())
    171 	{
    172 		key_iterator_t it = beginKeys();
    173 		for (i=0; it != endKeys(); ++it, ++i)
    174 		{
    175 			// write CBC-MAC result for this key, then update SHA-1
    176 			RijndaelCBCMAC & mac = (macs.get())[i];
    177 			const RijndaelCBCMAC::block_t & macResult = mac.getMAC();
    178 			stream.write(reinterpret_cast<const char *>(&macResult), sizeof(RijndaelCBCMAC::block_t));
    179 			hash.Update(reinterpret_cast<const uint8_t *>(&macResult), sizeof(RijndaelCBCMAC::block_t));
    180 			fileBlocksWritten++;
    181 
    182 			// encrypt DEK with this key, write it out, and update image digest
    183 			Rijndael cipher;
    184 			cipher.init(Rijndael::CBC, Rijndael::Encrypt, *it, Rijndael::Key16Bytes, imageHeader.m_iv);
    185 			AESKey<128>::key_t wrappedSessionKey;
    186 			cipher.blockEncrypt(m_sessionKey, sizeof(AESKey<128>::key_t) * 8, wrappedSessionKey);
    187 			stream.write(reinterpret_cast<char *>(&wrappedSessionKey), sizeof(wrappedSessionKey));
    188 			hash.Update(reinterpret_cast<uint8_t *>(&wrappedSessionKey), sizeof(wrappedSessionKey));
    189 			fileBlocksWritten++;
    190 		}
    191 	}
    192 
    193 	// write sections and boot tags
    194 	{
    195 		section_iterator_t it = beginSection();
    196 		for (; it != endSection(); ++it)
    197 		{
    198 			section_iterator_t itCopy = it;
    199 			bool isLastSection = (++itCopy == endSection());
    200 
    201 			Section * section = *it;
    202 			cipher_block_t block;
    203 			unsigned blockCount = section->getBlockCount();
    204 			unsigned blocksWritten = 0;
    205 
    206 			Rijndael cipher;
    207 			cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_sessionKey, Rijndael::Key16Bytes, imageHeader.m_iv);
    208 
    209 			// Compute the number of padding blocks needed to align the section. This first
    210 			// call to getPadBlockCountForOffset() passes an offset that excludes
    211 			// the boot tag for this section.
    212 			unsigned paddingBlocks = getPadBlockCountForSection(section, fileBlocksWritten);
    213 
    214 			// Insert nop commands as padding to align the start of the section, if
    215 			// the section has special alignment requirements.
    216 			NopCommand nop;
    217 			while (paddingBlocks--)
    218 			{
    219 				blockCount = nop.getBlockCount();
    220 				blocksWritten = 0;
    221 				while (blocksWritten < blockCount)
    222 				{
    223 					nop.getBlocks(blocksWritten, 1, &block);
    224 
    225 					if (isEncrypted())
    226 					{
    227 						// re-init after encrypt to update IV
    228 						cipher.blockEncrypt(block, sizeof(cipher_block_t) * 8, block);
    229 						cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_sessionKey, Rijndael::Key16Bytes, block);
    230 					}
    231 
    232 					stream.write(reinterpret_cast<char *>(&block), sizeof(cipher_block_t));
    233 					hash.Update(reinterpret_cast<uint8_t *>(&block), sizeof(cipher_block_t));
    234 
    235 					blocksWritten++;
    236 					fileBlocksWritten++;
    237 				}
    238 			}
    239 
    240 			// reinit cipher for boot tag
    241 			cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_sessionKey, Rijndael::Key16Bytes, imageHeader.m_iv);
    242 
    243 			// write boot tag
    244 			TagCommand tag(*section);
    245 			tag.setLast(isLastSection);
    246 			if (!isLastSection)
    247 			{
    248 				// If this isn't the last section, the tag needs to include any
    249 				// padding for the next section in its length, otherwise the ROM
    250 				// won't be able to find the next section's boot tag.
    251 				unsigned nextSectionOffset = fileBlocksWritten + section->getBlockCount() + 1;
    252 				tag.setSectionLength(section->getBlockCount() + getPadBlockCountForSection(*itCopy, nextSectionOffset));
    253 			}
    254 			blockCount = tag.getBlockCount();
    255 			blocksWritten = 0;
    256 			while (blocksWritten < blockCount)
    257 			{
    258 				tag.getBlocks(blocksWritten, 1, &block);
    259 
    260 				if (isEncrypted())
    261 				{
    262 					// re-init after encrypt to update IV
    263 					cipher.blockEncrypt(block, sizeof(cipher_block_t) * 8, block);
    264 					cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_sessionKey, Rijndael::Key16Bytes, block);
    265 				}
    266 
    267 				stream.write(reinterpret_cast<char *>(&block), sizeof(cipher_block_t));
    268 				hash.Update(reinterpret_cast<uint8_t *>(&block), sizeof(cipher_block_t));
    269 
    270 				blocksWritten++;
    271 				fileBlocksWritten++;
    272 			}
    273 
    274 			// reinit cipher for section data
    275 			cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_sessionKey, Rijndael::Key16Bytes, imageHeader.m_iv);
    276 
    277 			// write section data
    278 			blockCount = section->getBlockCount();
    279 			blocksWritten = 0;
    280 			while (blocksWritten < blockCount)
    281 			{
    282 				section->getBlocks(blocksWritten, 1, &block);
    283 
    284 				// Only encrypt the section contents if the entire boot image is encrypted
    285 				// and the section doesn't have the "leave unencrypted" flag set. Even if the
    286 				// section is unencrypted the boot tag will remain encrypted.
    287 				if (isEncrypted() && !section->getLeaveUnencrypted())
    288 				{
    289 					// re-init after encrypt to update IV
    290 					cipher.blockEncrypt(block, sizeof(cipher_block_t) * 8, block);
    291 					cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_sessionKey, Rijndael::Key16Bytes, block);
    292 				}
    293 
    294 				stream.write(reinterpret_cast<char *>(&block), sizeof(cipher_block_t));
    295 				hash.Update(reinterpret_cast<uint8_t *>(&block), sizeof(cipher_block_t));
    296 
    297 				blocksWritten++;
    298 				fileBlocksWritten++;
    299 			}
    300 		}
    301 	}
    302 
    303 	// write SHA-1 digest over entire image
    304 	{
    305 		// allocate enough room for digest and bytes to pad out to the next cipher block
    306 		const unsigned padBytes = sizeOfPaddingForCipherBlocks(sizeof(sha1_digest_t));
    307 		unsigned digestBlocksSize = sizeof(sha1_digest_t) + padBytes;
    308 		smart_array_ptr<uint8_t> digestBlocks = new uint8_t[digestBlocksSize];
    309 		hash.Final();
    310 		hash.GetHash(digestBlocks.get());
    311 
    312 		// set the pad bytes to random values
    313 		RandomNumberGenerator rng;
    314 		rng.generateBlock(&(digestBlocks.get())[sizeof(sha1_digest_t)], padBytes);
    315 
    316 		// encrypt with session key
    317 		if (isEncrypted())
    318 		{
    319 			Rijndael cipher;
    320 			cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_sessionKey, Rijndael::Key16Bytes, imageHeader.m_iv);
    321 			cipher.blockEncrypt(digestBlocks.get(), digestBlocksSize * 8, digestBlocks.get());
    322 		}
    323 
    324 		// write to the stream
    325 		stream.write(reinterpret_cast<char *>(digestBlocks.get()), digestBlocksSize);
    326 	}
    327 }
    328 
    329 void EncoreBootImage::prepareImageHeader(boot_image_header_t & header)
    330 {
    331 	// get identifier for the first bootable section
    332 	Section * firstBootSection = findFirstBootableSection();
    333 	section_id_t firstBootSectionID = 0;
    334 	if (firstBootSection)
    335 	{
    336 		firstBootSectionID = firstBootSection->getIdentifier();
    337 	}
    338 
    339 	// fill in header fields
    340 	header.m_signature[0] = 'S';
    341 	header.m_signature[1] = 'T';
    342 	header.m_signature[2] = 'M';
    343 	header.m_signature[3] = 'P';
    344 	header.m_majorVersion = ROM_BOOT_IMAGE_MAJOR_VERSION;
    345 	header.m_minorVersion = ROM_BOOT_IMAGE_MINOR_VERSION;
    346 	header.m_flags = ENDIAN_HOST_TO_LITTLE_U16(m_headerFlags);
    347 	header.m_imageBlocks = ENDIAN_HOST_TO_LITTLE_U32(getImageSize());
    348 	header.m_firstBootableSectionID = ENDIAN_HOST_TO_LITTLE_U32(firstBootSectionID);
    349 	header.m_keyCount = ENDIAN_HOST_TO_LITTLE_U16((uint16_t)m_keys.size());
    350 	header.m_headerBlocks = ENDIAN_HOST_TO_LITTLE_U16((uint16_t)numberOfCipherBlocks(sizeof(header)));
    351 	header.m_sectionCount = ENDIAN_HOST_TO_LITTLE_U16((uint16_t)m_sections.size());
    352 	header.m_sectionHeaderSize = ENDIAN_HOST_TO_LITTLE_U16((uint16_t)numberOfCipherBlocks(sizeof(section_header_t)));
    353 	header.m_signature2[0] = 's';
    354 	header.m_signature2[1] = 'g';
    355 	header.m_signature2[2] = 't';
    356 	header.m_signature2[3] = 'l';
    357 	header.m_timestamp = ENDIAN_HOST_TO_LITTLE_U64(getTimestamp());
    358 	header.m_driveTag = m_driveTag;
    359 
    360 	// Prepare version fields by converting them to the correct byte order.
    361 	header.m_productVersion = m_productVersion;
    362 	header.m_componentVersion = m_componentVersion;
    363 	header.m_productVersion.fixByteOrder();
    364 	header.m_componentVersion.fixByteOrder();
    365 
    366 	// the fields are dependant on others
    367 	header.m_keyDictionaryBlock = ENDIAN_HOST_TO_LITTLE_U16(header.m_headerBlocks + header.m_sectionCount * header.m_sectionHeaderSize);
    368 	header.m_firstBootTagBlock = ENDIAN_HOST_TO_LITTLE_U32(header.m_keyDictionaryBlock + header.m_keyCount * 2);
    369 
    370 	// generate random pad bytes
    371 	RandomNumberGenerator rng;
    372 	rng.generateBlock(header.m_padding0, sizeof(header.m_padding0));
    373 	rng.generateBlock(header.m_padding1, sizeof(header.m_padding1));
    374 
    375 	// compute SHA-1 digest over the image header
    376 	uint8_t * message = reinterpret_cast<uint8_t *>(&header.m_signature);
    377 	uint32_t length = static_cast<uint32_t>(sizeof(header) - sizeof(header.m_digest)); // include padding
    378 
    379 	CSHA1 hash;
    380 	hash.Reset();
    381 	hash.Update(message, length);
    382 	hash.Final();
    383 	hash.GetHash(header.m_digest);
    384 }
    385 
    386 //! Returns the number of microseconds since 00:00 1-1-2000. In actuality, the timestamp
    387 //! is only accurate to seconds, and is simply extended out to microseconds.
    388 //!
    389 //! \todo Use the operating system's low-level functions to get a true microsecond
    390 //!		timestamp, instead of faking it like we do now.
    391 //! \bug The timestamp might be off an hour.
    392 uint64_t EncoreBootImage::getTimestamp()
    393 {
    394 #if defined(WIN32) || defined(__CYGWIN__) || defined(__sun)
    395 	struct tm epoch = { 0, 0, 0, 1, 0, 100, 0, 0 }; // 00:00 1-1-2000
    396 #else
    397 	struct tm epoch = { 0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL }; // 00:00 1-1-2000
    398 #endif
    399 	time_t epochTime = mktime(&epoch);
    400 	time_t now = time(NULL);
    401 	now -= epochTime;
    402 	uint64_t microNow = uint64_t(now) * 1000000;	// convert to microseconds
    403 	return microNow;
    404 }
    405 
    406 //! Scans the section list looking for the first section which has
    407 //! the #ROM_SECTION_BOOTABLE flag set on it.
    408 EncoreBootImage::Section * EncoreBootImage::findFirstBootableSection()
    409 {
    410 	section_iterator_t it = beginSection();
    411 	for (; it != endSection(); ++it)
    412 	{
    413 		if ((*it)->getFlags() & ROM_SECTION_BOOTABLE)
    414 		{
    415 			return *it;
    416 		}
    417 	}
    418 
    419 	// no bootable sections were found
    420 	return NULL;
    421 }
    422 
    423 //! The boot tag for \a section is taken into account, thus making the
    424 //! result offset point to the first block of the actual section data.
    425 //!
    426 //! \note The offset will only be valid if all encryption keys and all
    427 //! sections have already been added to the image.
    428 uint32_t EncoreBootImage::getSectionOffset(Section * section)
    429 {
    430 	// start with boot image headers
    431 	uint32_t offset = numberOfCipherBlocks(sizeof(boot_image_header_t));	// header
    432 	offset += numberOfCipherBlocks(sizeof(section_header_t)) * sectionCount();	// section table
    433 	offset += 2 * keyCount();	// key dictiontary
    434 
    435 	// add up sections before this one
    436 	section_iterator_t it = beginSection();
    437 	for (; it != endSection() && *it != section; ++it)
    438 	{
    439 		Section * thisSection = *it;
    440 
    441 		// insert padding for section alignment
    442 		offset += getPadBlockCountForSection(thisSection, offset);
    443 
    444 		// add one for boot tag associated with this section
    445 		offset++;
    446 
    447 		// now add the section's contents
    448 		offset += thisSection->getBlockCount();
    449 	}
    450 
    451 	// and add padding for this section
    452 	offset += getPadBlockCountForSection(section, offset);
    453 
    454 	// skip over this section's boot tag
    455 	offset++;
    456 
    457 	return offset;
    458 }
    459 
    460 //! Computes the number of blocks of padding required to align \a section while
    461 //! taking into account the boot tag that gets inserted before the section contents.
    462 unsigned EncoreBootImage::getPadBlockCountForSection(Section * section, unsigned offset)
    463 {
    464 	// Compute the number of padding blocks needed to align the section. This first
    465 	// call to getPadBlockCountForOffset() passes an offset that excludes
    466 	// the boot tag for this section.
    467 	unsigned paddingBlocks = section->getPadBlockCountForOffset(offset);
    468 
    469 	// If the pad count comes back as 0 then we need to try again with an offset that
    470 	// includes the boot tag. This is all because we're aligning the section contents
    471 	// start and not the section's boot tag.
    472 	if (paddingBlocks == 0)
    473 	{
    474 		paddingBlocks = section->getPadBlockCountForOffset(offset + 1);
    475 	}
    476 	// Otherwise if we get a nonzero pad amount then we need to subtract the block
    477 	// for the section's boot tag from the pad count.
    478 	else
    479 	{
    480 		paddingBlocks--;
    481 	}
    482 
    483 	return paddingBlocks;
    484 }
    485 
    486 uint32_t EncoreBootImage::getImageSize()
    487 {
    488 	// determine to total size of the image
    489 	const uint32_t headerBlocks = numberOfCipherBlocks(sizeof(boot_image_header_t));
    490 	const uint32_t sectionHeaderSize = numberOfCipherBlocks(sizeof(section_header_t));
    491 	uint32_t imageBlocks = headerBlocks;
    492 	imageBlocks += sectionHeaderSize * m_sections.size();	// section table
    493 	imageBlocks += 2 * m_keys.size();	// key dict
    494 
    495 	// add in each section's size
    496 	section_iterator_t it = beginSection();
    497 	for (; it != endSection(); ++it)
    498 	{
    499 		// add in this section's size, padding to align it, and its boot tag
    500 		imageBlocks += getPadBlockCountForSection(*it, imageBlocks);
    501 		imageBlocks += (*it)->getBlockCount();
    502 		imageBlocks++;
    503 	}
    504 
    505 	// image MAC
    506 	imageBlocks += 2;
    507 
    508 	return imageBlocks;
    509 }
    510 
    511 void EncoreBootImage::debugPrint() const
    512 {
    513 	const_section_iterator_t it = beginSection();
    514 	for (; it != endSection(); ++it)
    515 	{
    516 		const Section * section = *it;
    517 		section->debugPrint();
    518 	}
    519 }
    520 
    521 //! \param blocks Pointer to the raw data blocks.
    522 //! \param count Number of blocks pointed to by \a blocks.
    523 //! \param[out] consumed On exit, this points to the number of cipher blocks that were occupied
    524 //!		by the command. Should be at least 1 for every command. This must not be NULL
    525 //!		on entry!
    526 //!
    527 //! \return A new boot command instance.
    528 //! \retval NULL The boot command pointed to by \a blocks was not recognized as a known
    529 //!     command type.
    530 //!
    531 //! \exception std::runtime_error This exception indicates that a command was recognized
    532 //!     but contained invalid data. Compare this to a NULL result which indicates that
    533 //!     no command was recognized at all.
    534 EncoreBootImage::BootCommand * EncoreBootImage::BootCommand::createFromData(const cipher_block_t * blocks, unsigned count, unsigned * consumed)
    535 {
    536 	const boot_command_t * header = reinterpret_cast<const boot_command_t *>(blocks);
    537     BootCommand * command = NULL;
    538 
    539     switch (header->m_tag)
    540     {
    541         case ROM_NOP_CMD:
    542             command = new NopCommand();
    543             break;
    544         case ROM_TAG_CMD:
    545             command = new TagCommand();
    546             break;
    547         case ROM_LOAD_CMD:
    548             command = new LoadCommand();
    549             break;
    550         case ROM_FILL_CMD:
    551             command = new FillCommand();
    552             break;
    553         case ROM_MODE_CMD:
    554             command = new ModeCommand();
    555             break;
    556         case ROM_JUMP_CMD:
    557             command = new JumpCommand();
    558             break;
    559         case ROM_CALL_CMD:
    560             command = new CallCommand();
    561             break;
    562     }
    563 
    564     if (command)
    565     {
    566         command->initFromData(blocks, count, consumed);
    567     }
    568     return command;
    569 }
    570 
    571 //! The checksum algorithm is totally straightforward, except that the
    572 //! initial checksum byte value is set to 0x5a instead of 0.
    573 uint8_t EncoreBootImage::BootCommand::calculateChecksum(const boot_command_t & header)
    574 {
    575 	const uint8_t * bytes = reinterpret_cast<const uint8_t *>(&header);
    576 	uint8_t checksum = 0x5a;
    577 	int i;
    578 
    579 	// start at one to skip checksum field
    580 	for (i = 1; i < sizeof(header); ++i)
    581 	{
    582 		checksum += bytes[i];
    583 	}
    584 
    585 	return checksum;
    586 }
    587 
    588 //! The default implementation returns 0, indicating that no blocks are
    589 //! available.
    590 unsigned EncoreBootImage::BootCommand::getBlockCount() const
    591 {
    592 	return 1 + getDataBlockCount();
    593 }
    594 
    595 //! Up to \a maxCount cipher blocks are copied into the buffer pointed to by
    596 //! the \a data argument. The index of the first block to copy is
    597 //! held in the \a offset argument.
    598 //!
    599 //! \param offset Starting block number to copy. Zero means the first available block.
    600 //! \param maxCount Up to this number of blocks may be copied into \a data. Must be 1 or greater.
    601 //! \param data Buffer for outgoing cipher blocks. Must have enough room to hold
    602 //!		\a maxCount blocks.
    603 //!
    604 //! \return The number of cipher blocks copied into \a data.
    605 //! \retval 0 No more blocks are available and nothing was written to \a data.
    606 //!
    607 //! \exception std::out_of_range If \a offset is invalid.
    608 unsigned EncoreBootImage::BootCommand::getBlocks(unsigned offset, unsigned maxCount, cipher_block_t * data)
    609 {
    610 	assert(data);
    611 	assert(maxCount >= 1);
    612 
    613 	// check for valid offset
    614 	if (offset >= getBlockCount())
    615 	{
    616 		throw std::out_of_range("invalid offset");
    617 	}
    618 
    619 	// handle the command header block separately
    620 	if (offset == 0)
    621 	{
    622 		assert(sizeof(boot_command_t) == sizeof(cipher_block_t));
    623 
    624 		boot_command_t header;
    625 		fillCommandHeader(header);
    626 		memcpy(data, &header, sizeof(header));
    627 
    628 		return 1;
    629 	}
    630 
    631 	// handle any data blocks
    632 	return getDataBlocks(offset - 1, maxCount, data);
    633 }
    634 
    635 //! The checksum field of \a testHeader is always computed and checked against itself.
    636 //! All other fields are compared to the corresponding value set in \a modelHeader
    637 //! if the appropriate flag is set in \a whichFields. For example, the m_address fields
    638 //! in \a testHeader and \a modelHeader are compared when the CMD_ADDRESS_FIELD bit
    639 //! is set in \a whichFields. An exception is thrown if any comparison fails.
    640 //!
    641 //! \param modelHeader The baseline header to compare against. Only those fields that
    642 //!		have corresponding bits set in \a whichFields need to be set.
    643 //! \param testHeader The actual command header which is being validated.
    644 //! \param whichFields A bitfield used to determine which fields of the boot command
    645 //!		header are compared. Possible values are:
    646 //!			- CMD_TAG_FIELD
    647 //!			- CMD_FLAGS_FIELD
    648 //!			- CMD_ADDRESS_FIELD
    649 //!			- CMD_COUNT_FIELD
    650 //!			- CMD_DATA_FIELD
    651 //!
    652 //! \exception std::runtime_error Thrown if any requested validation fails.
    653 void EncoreBootImage::BootCommand::validateHeader(const boot_command_t * modelHeader, const boot_command_t * testHeader, unsigned whichFields)
    654 {
    655 	// compare all the fields that were requested
    656 	if ((whichFields & CMD_TAG_FIELD) && (testHeader->m_tag != modelHeader->m_tag))
    657 	{
    658 		throw std::runtime_error("invalid tag field");
    659 	}
    660 
    661 	if ((whichFields & CMD_FLAGS_FIELD) && (testHeader->m_flags != modelHeader->m_flags))
    662 	{
    663 		throw std::runtime_error("invalid flags field");
    664 	}
    665 
    666 	if ((whichFields & CMD_ADDRESS_FIELD) && (testHeader->m_address != modelHeader->m_address))
    667 	{
    668 		throw std::runtime_error("invalid address field");
    669 	}
    670 
    671 	if ((whichFields & CMD_COUNT_FIELD) && (testHeader->m_count != modelHeader->m_count))
    672 	{
    673 		throw std::runtime_error("invalid count field");
    674 	}
    675 
    676 	if ((whichFields & CMD_DATA_FIELD) && (testHeader->m_data != modelHeader->m_data))
    677 	{
    678 		throw std::runtime_error("invalid data field");
    679 	}
    680 
    681 	// calculate checksum
    682 	uint8_t testChecksum = calculateChecksum(*testHeader);
    683 	if (testChecksum != testHeader->m_checksum)
    684 	{
    685 		throw std::runtime_error("invalid checksum");
    686 	}
    687 }
    688 
    689 //! Since the NOP command has no data, this method just validates the command header.
    690 //! All fields except the checksum are expected to be set to 0.
    691 //!
    692 //! \param blocks Pointer to the raw data blocks.
    693 //! \param count Number of blocks pointed to by \a blocks.
    694 //! \param[out] consumed On exit, this points to the number of cipher blocks that were occupied
    695 //!		by the command. Should be at least 1 for every command. This must not be NULL
    696 //!		on entry!
    697 //!
    698 //! \exception std::runtime_error Thrown if header fields are invalid.
    699 void EncoreBootImage::NopCommand::initFromData(const cipher_block_t * blocks, unsigned count, unsigned * consumed)
    700 {
    701 	const boot_command_t model = { 0, ROM_NOP_CMD, 0, 0, 0, 0 };
    702 	const boot_command_t * header = reinterpret_cast<const boot_command_t *>(blocks);
    703 	validateHeader(&model, header, CMD_TAG_FIELD | CMD_FLAGS_FIELD | CMD_ADDRESS_FIELD | CMD_COUNT_FIELD | CMD_DATA_FIELD);
    704 
    705 	*consumed = 1;
    706 }
    707 
    708 //! All fields of the boot command header structure are set to 0, except
    709 //! for the checksum. This includes the tag field since the tag value for
    710 //! the #ROM_NOP_CMD is zero. And since all fields are zeroes the checksum
    711 //! remains the initial checksum value of 0x5a.
    712 void EncoreBootImage::NopCommand::fillCommandHeader(boot_command_t & header)
    713 {
    714 	header.m_tag = getTag();
    715 	header.m_flags = 0;
    716 	header.m_address = 0;
    717 	header.m_count = 0;
    718 	header.m_data = 0;
    719 	header.m_checksum = calculateChecksum(header);	// do this last
    720 }
    721 
    722 void EncoreBootImage::NopCommand::debugPrint() const
    723 {
    724 	Log::log(Logger::INFO2, "\tNOOP\n");
    725 }
    726 
    727 //! The identifier, length, and flags fields are taken from \a section.
    728 //!
    729 //! \todo How does length get set correctly if the length is supposed to include
    730 //!		this command?
    731 EncoreBootImage::TagCommand::TagCommand(const Section & section)
    732 {
    733 	m_sectionIdentifier = section.getIdentifier();
    734 	m_sectionLength = section.getBlockCount();
    735 	m_sectionFlags = section.getFlags();
    736 }
    737 
    738 //! \param blocks Pointer to the raw data blocks.
    739 //! \param count Number of blocks pointed to by \a blocks.
    740 //! \param[out] consumed On exit, this points to the number of cipher blocks that were occupied
    741 //!		by the command. Should be at least 1 for every command. This must not be NULL
    742 //!		on entry!
    743 //!
    744 //! \exception std::runtime_error Thrown if header fields are invalid.
    745 void EncoreBootImage::TagCommand::initFromData(const cipher_block_t * blocks, unsigned count, unsigned * consumed)
    746 {
    747 	const boot_command_t model = { 0, ROM_TAG_CMD, 0, 0, 0, 0 };
    748 	const boot_command_t * header = reinterpret_cast<const boot_command_t *>(blocks);
    749 	validateHeader(&model, header, CMD_TAG_FIELD);
    750 
    751     // read fields from header
    752 	m_isLast = (ENDIAN_LITTLE_TO_HOST_U16(header->m_flags) & ROM_LAST_TAG) != 0;
    753 	m_sectionIdentifier = ENDIAN_LITTLE_TO_HOST_U32(header->m_address);
    754 	m_sectionLength = ENDIAN_LITTLE_TO_HOST_U32(header->m_count);
    755 	m_sectionFlags = ENDIAN_LITTLE_TO_HOST_U32(header->m_data);
    756 
    757 	*consumed = 1;
    758 }
    759 
    760 //! This method currently assumes that the next tag command will come immediately
    761 //! after the data for this section.
    762 void EncoreBootImage::TagCommand::fillCommandHeader(boot_command_t & header)
    763 {
    764 	header.m_tag = getTag();
    765 	header.m_flags = ENDIAN_HOST_TO_LITTLE_U16(m_isLast ? ROM_LAST_TAG : 0);
    766 	header.m_address = ENDIAN_HOST_TO_LITTLE_U32(m_sectionIdentifier);
    767 	header.m_count = ENDIAN_HOST_TO_LITTLE_U32(m_sectionLength);
    768 	header.m_data = ENDIAN_HOST_TO_LITTLE_U32(m_sectionFlags);
    769 	header.m_checksum = calculateChecksum(header);	// do this last
    770 }
    771 
    772 void EncoreBootImage::TagCommand::debugPrint() const
    773 {
    774 	Log::log(Logger::INFO2, "  BTAG | sec=0x%08x | cnt=0x%08x | flg=0x%08x\n", m_sectionIdentifier, m_sectionLength, m_sectionFlags);
    775 }
    776 
    777 //! All fields are set to zero.
    778 //!
    779 EncoreBootImage::LoadCommand::LoadCommand()
    780 :	BootCommand(), m_data(), m_padCount(0), m_length(0), m_address(0), m_loadDCD(false)
    781 {
    782 	fillPadding();
    783 }
    784 
    785 EncoreBootImage::LoadCommand::LoadCommand(uint32_t address, const uint8_t * data, uint32_t length)
    786 :	BootCommand(), m_data(), m_padCount(0), m_length(0), m_address(address), m_loadDCD(false)
    787 {
    788 	fillPadding();
    789 	setData(data, length);
    790 }
    791 
    792 //! \param blocks Pointer to the raw data blocks.
    793 //! \param count Number of blocks pointed to by \a blocks.
    794 //! \param[out] consumed On exit, this points to the number of cipher blocks that were occupied
    795 //!		by the command. Should be at least 1 for every command. This must not be NULL
    796 //!		on entry!
    797 //!
    798 //! \exception std::runtime_error This exception is thrown if the actual CRC of the load
    799 //!     data does not match the CRC stored in the command header. Also thrown if the
    800 //!     \a count parameter is less than the number of data blocks needed for the length
    801 //!     specified in the command header or if header fields are invalid.
    802 void EncoreBootImage::LoadCommand::initFromData(const cipher_block_t * blocks, unsigned count, unsigned * consumed)
    803 {
    804     // check static fields
    805 	const boot_command_t model = { 0, ROM_LOAD_CMD, 0, 0, 0, 0 };
    806 	const boot_command_t * header = reinterpret_cast<const boot_command_t *>(blocks);
    807 	validateHeader(&model, header, CMD_TAG_FIELD);
    808 
    809     // read fields from header
    810 	m_address = ENDIAN_LITTLE_TO_HOST_U32(header->m_address);
    811 	m_length = ENDIAN_LITTLE_TO_HOST_U32(header->m_count);
    812     unsigned crc = ENDIAN_LITTLE_TO_HOST_U32(header->m_data);
    813     unsigned dataBlockCount = numberOfCipherBlocks(m_length);
    814     m_padCount = sizeOfPaddingForCipherBlocks(dataBlockCount);
    815 	m_loadDCD = (ENDIAN_LITTLE_TO_HOST_U16(header->m_flags) & ROM_LOAD_DCD) != 0;
    816 
    817     // make sure there are enough blocks
    818     if (count - 1 < dataBlockCount)
    819     {
    820         throw std::runtime_error("not enough cipher blocks for load data");
    821     }
    822 
    823     // copy data
    824     setData(reinterpret_cast<const uint8_t *>(blocks + 1), m_length);
    825 
    826     // copy padding
    827     if (m_padCount)
    828     {
    829         const uint8_t * firstPadByte = reinterpret_cast<const uint8_t *> (blocks + (1 + dataBlockCount)) - m_padCount;
    830         memcpy(m_padding, firstPadByte, m_padCount);
    831     }
    832 
    833     // check CRC
    834     uint32_t actualCRC = calculateCRC();
    835     if (actualCRC != crc)
    836     {
    837         throw std::runtime_error("load data failed CRC check");
    838     }
    839 
    840 	*consumed = 1 + dataBlockCount;
    841 }
    842 
    843 //! The only thing unique in the load command header is the
    844 //! #elftosb::EncoreBootImage::boot_command_t::m_data. It contains a CRC-32 over the
    845 //! load data, plus any bytes of padding in the last data cipher block.
    846 void EncoreBootImage::LoadCommand::fillCommandHeader(boot_command_t & header)
    847 {
    848 	header.m_tag = getTag();
    849 	header.m_flags = ENDIAN_HOST_TO_LITTLE_U16(m_loadDCD ? ROM_LOAD_DCD : 0);
    850 	header.m_address = ENDIAN_HOST_TO_LITTLE_U32(m_address);
    851 	header.m_count = ENDIAN_HOST_TO_LITTLE_U32(m_length);
    852 	header.m_data = ENDIAN_HOST_TO_LITTLE_U32(calculateCRC());
    853 
    854 	// do this last
    855 	header.m_checksum = calculateChecksum(header);
    856 }
    857 
    858 //! A CRC-32 is calculated over the load data, including any pad bytes
    859 //! that are required in the last data cipher block. Including the
    860 //! pad bytes in the CRC makes it vastly easier for the ROM to calculate
    861 //! the CRC for validation.
    862 uint32_t EncoreBootImage::LoadCommand::calculateCRC() const
    863 {
    864 	uint32_t result;
    865 	CRC32 crc;
    866 	crc.update(m_data, m_length);
    867 	if (m_padCount)
    868 	{
    869 		// include random padding in the CRC
    870 		crc.update(m_padding, m_padCount);
    871 	}
    872 	crc.truncatedFinal(reinterpret_cast<uint8_t*>(&result), sizeof(result));
    873 
    874 	return result;
    875 }
    876 
    877 //! A local copy of the load data is made. This copy will be disposed of when this object
    878 //! is destroyed. This means the caller is free to deallocate \a data after this call
    879 //! returns. It also means the caller can pass a pointer into the middle of a buffer for
    880 //! \a data and not worry about ownership issues.
    881 void EncoreBootImage::LoadCommand::setData(const uint8_t * data, uint32_t length)
    882 {
    883 	assert(data);
    884 	assert(length);
    885 
    886 	uint8_t * dataCopy = new uint8_t[length];
    887 	memcpy(dataCopy, data, length);
    888 
    889 	m_data = dataCopy;
    890 	m_length = length;
    891 
    892 	m_padCount = sizeOfPaddingForCipherBlocks(m_length);
    893 }
    894 
    895 //! \return The number of cipher blocks required to hold the load data,
    896 //!		rounded up as necessary.
    897 unsigned EncoreBootImage::LoadCommand::getDataBlockCount() const
    898 {
    899 	// round up to the next cipher block
    900 	return numberOfCipherBlocks(m_length);
    901 }
    902 
    903 //! Up to \a maxCount data blocks are copied into the buffer pointed to by
    904 //! the \a data argument. This is only a request for \a maxCount blocks.
    905 //! A return value of 0 indicates that no more blocks are available. The
    906 //! index of the first block to copy is held in the \a offset argument.
    907 //! If there are pad bytes needed to fill out the last data block, they
    908 //! will be filled with random data in order to add to the "whiteness" of
    909 //! the data on both sides of encryption.
    910 //!
    911 //! \param offset Starting block number to copy. Zero means the first available block.
    912 //! \param maxCount Up to this number of blocks may be copied into \a data. Must be 1 or greater.
    913 //! \param data Buffer for outgoing data blocks. Must have enough room to hold
    914 //!		\a maxCount blocks.
    915 //!
    916 //! \return The number of data blocks copied into \a data.
    917 //! \retval 0 No more blocks are available and nothing was written to \a data.
    918 //!
    919 //! \exception std::out_of_range Thrown when offset is invalid.
    920 //!
    921 //! \todo fill pad bytes with random bytes
    922 unsigned EncoreBootImage::LoadCommand::getDataBlocks(unsigned offset, unsigned maxCount, cipher_block_t * data)
    923 {
    924 	assert(data);
    925 	assert(maxCount != 0);
    926 
    927 	uint32_t blockCount = getDataBlockCount();
    928 
    929 	// check offset
    930 	if (offset >= blockCount)
    931 	{
    932 		throw std::out_of_range("invalid offset");
    933 	}
    934 
    935 	// figure out how many blocks to return
    936 	unsigned resultBlocks = blockCount - offset;
    937 	if (resultBlocks > maxCount)
    938 	{
    939 		resultBlocks = maxCount;
    940 
    941 		// exclude last block if there is padding
    942 		if (m_padCount && (offset != blockCount - 1) && (offset + resultBlocks == blockCount))
    943 		{
    944 			resultBlocks--;
    945 		}
    946 	}
    947 
    948 	// if there are pad bytes, handle the last block specially
    949 	if (m_padCount && offset == blockCount - 1)
    950 	{
    951 		// copy the remainder of the load data into the first part of the result block
    952 		unsigned remainderLength = sizeof(cipher_block_t) - m_padCount;
    953 		memcpy(data, &m_data[sizeof(cipher_block_t) * offset], remainderLength);
    954 
    955 		// copy pad bytes we previously generated into the last part of the result block
    956 		// data is a cipher block pointer, so indexing is done on cipher block
    957 		// boundaries, thus we need a byte pointer to index properly
    958 		uint8_t * bytePtr = reinterpret_cast<uint8_t*>(data);
    959 		memcpy(bytePtr + remainderLength, &m_padding, m_padCount);
    960 	}
    961 	else
    962 	{
    963 		memcpy(data, &m_data[sizeof(cipher_block_t) * offset], sizeof(cipher_block_t) * resultBlocks);
    964 	}
    965 
    966 	return resultBlocks;
    967 }
    968 
    969 //! Fills #m_padding with random bytes that may be used to fill up the last data
    970 //! cipher block.
    971 void EncoreBootImage::LoadCommand::fillPadding()
    972 {
    973 	RandomNumberGenerator rng;
    974 	rng.generateBlock(m_padding, sizeof(m_padding));
    975 }
    976 
    977 void EncoreBootImage::LoadCommand::debugPrint() const
    978 {
    979 	Log::log(Logger::INFO2, "  LOAD | adr=0x%08x | len=0x%08x | crc=0x%08x | flg=0x%08x\n", m_address, m_length, calculateCRC(), m_loadDCD ? ROM_LOAD_DCD : 0);
    980 }
    981 
    982 //! The pattern, address, and count are all initialized to zero, and the pattern
    983 //! size is set to a word.
    984 EncoreBootImage::FillCommand::FillCommand()
    985 :	BootCommand(), m_address(0), m_count(0), m_pattern(0)
    986 {
    987 }
    988 
    989 //! \param blocks Pointer to the raw data blocks.
    990 //! \param count Number of blocks pointed to by \a blocks.
    991 //! \param[out] consumed On exit, this points to the number of cipher blocks that were occupied
    992 //!		by the command. Should be at least 1 for every command. This must not be NULL
    993 //!		on entry!
    994 //!
    995 //! \exception std::runtime_error Thrown if header fields are invalid.
    996 void EncoreBootImage::FillCommand::initFromData(const cipher_block_t * blocks, unsigned count, unsigned * consumed)
    997 {
    998     // check static fields
    999 	const boot_command_t model = { 0, ROM_FILL_CMD, 0, 0, 0, 0 };
   1000 	const boot_command_t * header = reinterpret_cast<const boot_command_t *>(blocks);
   1001 	validateHeader(&model, header, CMD_TAG_FIELD | CMD_FLAGS_FIELD);
   1002 
   1003     // read fields from header
   1004 	m_address = ENDIAN_LITTLE_TO_HOST_U32(header->m_address);
   1005 	m_count = ENDIAN_LITTLE_TO_HOST_U32(header->m_count);
   1006     m_pattern = ENDIAN_LITTLE_TO_HOST_U32(header->m_data);
   1007 
   1008 	*consumed = 1;
   1009 }
   1010 
   1011 void EncoreBootImage::FillCommand::fillCommandHeader(boot_command_t & header)
   1012 {
   1013 	header.m_tag = getTag();
   1014 	header.m_flags = 0;
   1015 	header.m_address = ENDIAN_HOST_TO_LITTLE_U32(m_address);
   1016 	header.m_count = ENDIAN_HOST_TO_LITTLE_U32(m_count);
   1017 	header.m_data = ENDIAN_HOST_TO_LITTLE_U32(m_pattern);
   1018 	header.m_checksum = calculateChecksum(header);	// do this last
   1019 }
   1020 
   1021 //! Extends the pattern across 32 bits.
   1022 //!
   1023 void EncoreBootImage::FillCommand::setPattern(uint8_t pattern)
   1024 {
   1025 	m_pattern = (pattern << 24) | (pattern << 16) | (pattern << 8) | pattern;
   1026 }
   1027 
   1028 //! Extends the pattern across 32 bits.
   1029 //!
   1030 void EncoreBootImage::FillCommand::setPattern(uint16_t pattern)
   1031 {
   1032 	m_pattern = (pattern << 16) | pattern;
   1033 }
   1034 
   1035 void EncoreBootImage::FillCommand::setPattern(uint32_t pattern)
   1036 {
   1037 	m_pattern = pattern;
   1038 }
   1039 
   1040 void EncoreBootImage::FillCommand::debugPrint() const
   1041 {
   1042 	Log::log(Logger::INFO2, "  FILL | adr=0x%08x | len=0x%08x | ptn=0x%08x\n", m_address, m_count, m_pattern);
   1043 }
   1044 
   1045 //! \param blocks Pointer to the raw data blocks.
   1046 //! \param count Number of blocks pointed to by \a blocks.
   1047 //! \param[out] consumed On exit, this points to the number of cipher blocks that were occupied
   1048 //!		by the command. Should be at least 1 for every command. This must not be NULL
   1049 //!		on entry!
   1050 //!
   1051 //! \exception std::runtime_error Thrown if header fields are invalid.
   1052 void EncoreBootImage::ModeCommand::initFromData(const cipher_block_t * blocks, unsigned count, unsigned * consumed)
   1053 {
   1054     // check static fields
   1055 	const boot_command_t model = { 0, ROM_MODE_CMD, 0, 0, 0, 0 };
   1056 	const boot_command_t * header = reinterpret_cast<const boot_command_t *>(blocks);
   1057 	validateHeader(&model, header, CMD_TAG_FIELD | CMD_FLAGS_FIELD | CMD_ADDRESS_FIELD | CMD_COUNT_FIELD);
   1058 
   1059     // read fields from header
   1060     m_mode = ENDIAN_LITTLE_TO_HOST_U32(header->m_data);
   1061 
   1062 	*consumed = 1;
   1063 }
   1064 
   1065 void EncoreBootImage::ModeCommand::fillCommandHeader(boot_command_t & header)
   1066 {
   1067 	header.m_tag = getTag();
   1068 	header.m_flags = 0;
   1069 	header.m_address = 0;
   1070 	header.m_count = 0;
   1071 	header.m_data = ENDIAN_HOST_TO_LITTLE_U32(m_mode);
   1072 	header.m_checksum = calculateChecksum(header);	// do this last
   1073 }
   1074 
   1075 void EncoreBootImage::ModeCommand::debugPrint() const
   1076 {
   1077 	Log::log(Logger::INFO2, "  MODE | mod=0x%08x\n", m_mode);
   1078 }
   1079 
   1080 //! \param blocks Pointer to the raw data blocks.
   1081 //! \param count Number of blocks pointed to by \a blocks.
   1082 //! \param[out] consumed On exit, this points to the number of cipher blocks that were occupied
   1083 //!		by the command. Should be at least 1 for every command. This must not be NULL
   1084 //!		on entry!
   1085 //!
   1086 //! \exception std::runtime_error Thrown if header fields are invalid.
   1087 void EncoreBootImage::JumpCommand::initFromData(const cipher_block_t * blocks, unsigned count, unsigned * consumed)
   1088 {
   1089     // check static fields
   1090 	const boot_command_t model = { 0, getTag(), 0, 0, 0, 0 };
   1091 	const boot_command_t * header = reinterpret_cast<const boot_command_t *>(blocks);
   1092 	validateHeader(&model, header, CMD_TAG_FIELD | CMD_COUNT_FIELD);
   1093 
   1094     // read fields from header
   1095     m_address = ENDIAN_LITTLE_TO_HOST_U32(header->m_address);
   1096     m_argument = ENDIAN_LITTLE_TO_HOST_U32(header->m_data);
   1097 	m_isHAB = (ENDIAN_LITTLE_TO_HOST_U16(header->m_flags) & ROM_HAB_EXEC) != 0;
   1098 
   1099 	*consumed = 1;
   1100 }
   1101 
   1102 void EncoreBootImage::JumpCommand::fillCommandHeader(boot_command_t & header)
   1103 {
   1104 	header.m_tag = getTag();
   1105 	header.m_flags = ENDIAN_HOST_TO_LITTLE_U16(m_isHAB ? ROM_HAB_EXEC : 0);
   1106 	header.m_address = ENDIAN_HOST_TO_LITTLE_U32(m_address);
   1107 	header.m_count = 0;
   1108 	header.m_data = ENDIAN_HOST_TO_LITTLE_U32(m_argument);
   1109 	header.m_checksum = calculateChecksum(header);	// do this last
   1110 }
   1111 
   1112 void EncoreBootImage::JumpCommand::debugPrint() const
   1113 {
   1114 	Log::log(Logger::INFO2, "  JUMP | adr=0x%08x | arg=0x%08x | flg=0x%08x\n", m_address, m_argument, m_isHAB ? ROM_HAB_EXEC : 0);
   1115 }
   1116 
   1117 void EncoreBootImage::CallCommand::debugPrint() const
   1118 {
   1119 	Log::log(Logger::INFO2, "  CALL | adr=0x%08x | arg=0x%08x | flg=0x%08x\n", m_address, m_argument, m_isHAB ? ROM_HAB_EXEC : 0);
   1120 }
   1121 
   1122 //! Only if the section has been assigned a boot image owner object will this
   1123 //! method be able to fill in the #section_header_t::m_offset field. If no
   1124 //! boot image has been set the offset will be set to 0.
   1125 void EncoreBootImage::Section::fillSectionHeader(section_header_t & header)
   1126 {
   1127 	header.m_tag = getIdentifier();
   1128 	header.m_offset = 0;
   1129 	header.m_length = ENDIAN_HOST_TO_LITTLE_U32(getBlockCount());
   1130 	header.m_flags = ENDIAN_HOST_TO_LITTLE_U32(getFlags());
   1131 
   1132 	// if we're attached to an image, we can compute our real offset
   1133 	if (m_image)
   1134 	{
   1135 		header.m_offset = ENDIAN_HOST_TO_LITTLE_U32(m_image->getSectionOffset(this));
   1136 	}
   1137 }
   1138 
   1139 //! The alignment will never be less than 16, since that is the size of the
   1140 //! cipher block which is the basic unit of the boot image format. If an
   1141 //! alignment less than 16 is set it will be ignored.
   1142 //!
   1143 //! \param alignment Alignment in bytes for this section. Must be a power of two.
   1144 //!		Ignored if less than 16.
   1145 void EncoreBootImage::Section::setAlignment(unsigned alignment)
   1146 {
   1147 	if (alignment > BOOT_IMAGE_MINIMUM_SECTION_ALIGNMENT)
   1148 	{
   1149 		m_alignment = alignment;
   1150 	}
   1151 }
   1152 
   1153 //! This method calculates the number of padding blocks that need to be inserted
   1154 //! from a given offset for the section to be properly aligned. The value returned
   1155 //! is the number of padding blocks that should be inserted starting just after
   1156 //! \a offset to align the first cipher block of the section contents. The section's
   1157 //! boot tag is \i not taken into account by this method, so the caller must
   1158 //! deal with that herself.
   1159 //!
   1160 //! \param offset Start offset in cipher blocks (not bytes).
   1161 //!
   1162 //! \return A number of cipher blocks of padding to insert.
   1163 unsigned EncoreBootImage::Section::getPadBlockCountForOffset(unsigned offset)
   1164 {
   1165 	// convert alignment from byte to block alignment
   1166 	unsigned blockAlignment = m_alignment >> 4;
   1167 
   1168 	unsigned nextAlignmentOffset = (offset + blockAlignment - 1) / blockAlignment * blockAlignment;
   1169 
   1170 	return nextAlignmentOffset - offset;
   1171 }
   1172 
   1173 EncoreBootImage::BootSection::~BootSection()
   1174 {
   1175 	deleteCommands();
   1176 }
   1177 
   1178 void EncoreBootImage::BootSection::deleteCommands()
   1179 {
   1180 	// dispose of all sections
   1181 	iterator_t it = begin();
   1182 	for (; it != end(); ++it)
   1183 	{
   1184 		delete *it;
   1185 	}
   1186 }
   1187 
   1188 //! Always returns at least 1 for the required tag command.
   1189 //!
   1190 unsigned EncoreBootImage::BootSection::getBlockCount() const
   1191 {
   1192 	unsigned count = 0;
   1193 
   1194 	const_iterator_t it = begin();
   1195 	for (; it != end(); ++it)
   1196 	{
   1197 		count += (*it)->getBlockCount();
   1198 	}
   1199 
   1200 	return count;
   1201 }
   1202 
   1203 //! Up to \a maxCount cipher blocks are copied into the buffer pointed to by
   1204 //! the \a data argument. A return value of 0 indicates that
   1205 //! no more blocks are available. The index of the first block to copy is
   1206 //! held in the \a offset argument.
   1207 //!
   1208 //! \param offset Starting block number to copy. Zero means the first available block.
   1209 //! \param maxCount Up to this number of blocks may be copied into \a data.
   1210 //! \param data Buffer for outgoing cipher blocks. Must have enough room to hold
   1211 //!		\a maxCount blocks.
   1212 //!
   1213 //! \return The number of cipher blocks copied into \a data.
   1214 //! \retval 0 No more blocks are available and nothing was written to \a data.
   1215 unsigned EncoreBootImage::BootSection::getBlocks(unsigned offset, unsigned maxCount, cipher_block_t * data)
   1216 {
   1217 	assert(data);
   1218 	assert(maxCount >= 1);
   1219 
   1220 	unsigned currentOffset = 0;
   1221 	unsigned readCount = maxCount;
   1222 
   1223 	iterator_t it = begin();
   1224 	for (; it != end(); ++it)
   1225 	{
   1226 		BootCommand * command = *it;
   1227 		unsigned commandBlocks = command->getBlockCount();
   1228 
   1229 		// this should never be false!
   1230 		assert(offset >= currentOffset);
   1231 
   1232 		// skip forward until we hit the requested offset
   1233 		if (offset >= currentOffset + commandBlocks)
   1234 		{
   1235 			currentOffset += commandBlocks;
   1236 			continue;
   1237 		}
   1238 
   1239 		// read from this command
   1240 		unsigned commandOffset = offset - currentOffset;
   1241 		unsigned commandRemaining = commandBlocks - commandOffset;
   1242 		if (readCount > commandRemaining)
   1243 		{
   1244 			readCount = commandRemaining;
   1245 		}
   1246 		return command->getBlocks(commandOffset, readCount, data);
   1247 	}
   1248 
   1249 	return 0;
   1250 }
   1251 
   1252 //! The entire contents of the section must be in memory, pointed to by \a blocks.
   1253 //! Any commands that had previously been added to the section are disposed of.
   1254 //!
   1255 //! \param blocks Pointer to the section contents.
   1256 //! \param count Number of blocks pointed to by \a blocks.
   1257 //!
   1258 //! \exception std::runtime_error Thrown if a boot command cannot be created from
   1259 //!		the cipher block stream.
   1260 void EncoreBootImage::BootSection::fillFromData(const cipher_block_t * blocks, unsigned count)
   1261 {
   1262 	// start with an empty slate
   1263 	deleteCommands();
   1264 
   1265 	const cipher_block_t * currentBlock = blocks;
   1266 	unsigned remaining = count;
   1267 	while (remaining)
   1268 	{
   1269 		// try to create a command from the next cipher block. the number of
   1270 		// blocks the command used up is returned in consumed.
   1271 		unsigned consumed;
   1272 		BootCommand * command = BootCommand::createFromData(currentBlock, remaining, &consumed);
   1273 		if (!command)
   1274 		{
   1275 			throw std::runtime_error("invalid boot section data");
   1276 		}
   1277 
   1278 		addCommand(command);
   1279 
   1280 		// update loop counters
   1281 		remaining -= consumed;
   1282 		currentBlock += consumed;
   1283 	}
   1284 }
   1285 
   1286 void EncoreBootImage::BootSection::debugPrint() const
   1287 {
   1288 	Log::log(Logger::INFO2, "Boot Section 0x%08x:\n", m_identifier);
   1289 
   1290 	const_iterator_t it = begin();
   1291 	for (; it != end(); ++it)
   1292 	{
   1293 		const BootCommand * command = *it;
   1294 		command->debugPrint();
   1295 	}
   1296 }
   1297 
   1298 //! A copy is made of \a data. Any previously assigned data is disposed of.
   1299 //!
   1300 void EncoreBootImage::DataSection::setData(const uint8_t * data, unsigned length)
   1301 {
   1302 	m_data = new uint8_t[length];
   1303 	memcpy(m_data.get(), data, length);
   1304 	m_length = length;
   1305 }
   1306 
   1307 //! The section takes ownership of \a data and will dispose of it using the
   1308 //! array delete operator upon its destruction.
   1309 void EncoreBootImage::DataSection::setDataNoCopy(const uint8_t * data, unsigned length)
   1310 {
   1311 	m_data = data;
   1312 	m_length = length;
   1313 }
   1314 
   1315 unsigned EncoreBootImage::DataSection::getBlockCount() const
   1316 {
   1317 	return numberOfCipherBlocks(m_length);
   1318 }
   1319 
   1320 unsigned EncoreBootImage::DataSection::getBlocks(unsigned offset, unsigned maxCount, cipher_block_t * data)
   1321 {
   1322 	assert(data);
   1323 	assert(maxCount != 0);
   1324 
   1325 	unsigned blockCount = getBlockCount();
   1326 	unsigned padCount = sizeOfPaddingForCipherBlocks(m_length);
   1327 
   1328 	// check offset
   1329 	if (offset >= blockCount)
   1330 	{
   1331 		throw std::out_of_range("invalid offset");
   1332 	}
   1333 
   1334 	// figure out how many blocks to return
   1335 	unsigned resultBlocks = blockCount - offset;
   1336 	if (resultBlocks > maxCount)
   1337 	{
   1338 		resultBlocks = maxCount;
   1339 
   1340 		// exclude last block if there is padding
   1341 		if (padCount && (offset != blockCount - 1) && (offset + resultBlocks == blockCount))
   1342 		{
   1343 			resultBlocks--;
   1344 		}
   1345 	}
   1346 
   1347 	// if there are pad bytes, handle the last block specially
   1348 	if (padCount && offset == blockCount - 1)
   1349 	{
   1350 		// copy the remainder of the load data into the first part of the result block
   1351 		unsigned remainderLength = sizeof(cipher_block_t) - padCount;
   1352 		memcpy(data, &m_data[sizeOfCipherBlocks(offset)], remainderLength);
   1353 
   1354 		// set pad bytes to zeroes.
   1355 		// data is a cipher block pointer, so indexing is done on cipher block
   1356 		// boundaries, thus we need a byte pointer to index properly
   1357 		uint8_t * bytePtr = reinterpret_cast<uint8_t*>(data);
   1358 		memset(bytePtr + remainderLength, 0, padCount);
   1359 	}
   1360 	else
   1361 	{
   1362 		memcpy(data, &m_data[sizeOfCipherBlocks(offset)], sizeOfCipherBlocks(resultBlocks));
   1363 	}
   1364 
   1365 	return resultBlocks;
   1366 }
   1367 
   1368 void EncoreBootImage::DataSection::debugPrint() const
   1369 {
   1370 	Log::log(Logger::INFO2, "Data Section 0x%08x: (%d bytes, %d blocks)\n", m_identifier, m_length, getBlockCount());
   1371 }
   1372 
   1373