diff -r 820b22e13ff1 -r 39c28ec933dd imgtools/romtools/rofsbuild/r_rofs.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imgtools/romtools/rofsbuild/r_rofs.cpp Mon May 10 19:54:49 2010 +0100 @@ -0,0 +1,618 @@ +/* +* Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + +#include +#include +#include +#include +#include "h_utl.h" +#include +#include +#include "r_obey.h" +#include "r_rofs.h" +#include "r_coreimage.h" +#include "memmap.h" +extern TInt gLogLevel; +extern TBool gLowMem; +extern TBool gFastCompress; +extern TInt gThreadNum; +//////////////////////////////////////////////////////////////////////// + + + +inline TUint32 AlignData(TUint32 anAddr) + { + return ((anAddr+0x0f)&~0x0f); + } + + +//////////////////////////////////////////////////////////////////////// + +E32Rofs::E32Rofs(CObeyFile *aObey) +// +// Constructor +// + : iObey( aObey ), iOverhead(0) + { + + iSize=aObey->iRomSize; + if(gLowMem) + { + iImageMap = new Memmap(); + + if(iImageMap == NULL) + { + iSize = 0; + Print(EError, "Out of memory.\n"); + } + else + { + iImageMap->SetMaxMapSize(iSize); + if(iImageMap->CreateMemoryMap(0, 0xff) == EFalse) + { + iSize = 0; + Print(EError, "Failed to create image map object"); + + iImageMap->CloseMemoryMap(ETrue); + delete iImageMap; + iImageMap = NULL; + } + else + { + iData = iImageMap->GetMemoryMapPointer(); + } + } + } + else + { + iData=new char [iSize]; + if (iData==NULL) + iSize=0; + HMem::Set(iData, 0xff, iSize); + } + + } + +E32Rofs::~E32Rofs() +// +// Destructor +// + { + + if(gLowMem) + { + iImageMap->CloseMemoryMap(ETrue); + delete iImageMap; + } + else + delete iData; + } + + +TInt E32Rofs::CreateExtension(MRofsImage* aImage) + { + + TUint8* addr=(TUint8*)iData; + + TRomNode* pRootDir = aImage->RootDirectory(); + + + const TInt extensionRofsheaderSize = KExtensionRofsHeaderSize; + + // aImage->iSize contains the max size of the core image + + // Layout the directory structure. Does not actually write it + // to the image. Returns the number of bytes used for the directory + // structure within the image. + TInt directoryOffset = extensionRofsheaderSize; + const TInt directorySize = LayoutDirectory( pRootDir, aImage->Size()+directoryOffset ); + if( directorySize <= 0 ) + { + Print(EError, "Failed laying out directories - return code %d\n", directorySize); + return KErrGeneral; + } + + // get offset to start of file data, rounded up to next word boundary + TInt offs = extensionRofsheaderSize + directorySize; + const TInt fileDataStartOffset = offs + ( (4 - offs) & 3); + + // Now we traverse the list of entries placing each file + // This updates the directory entries to point to the correct offset + // to the start of the file + const TInt fileDataSize = PlaceFiles( pRootDir, addr + fileDataStartOffset, fileDataStartOffset + aImage->Size(), aImage->Size()); + if( fileDataSize <= 0 ) + { + Print(EError, "Failed placing files - return code %d\n", fileDataSize); + return KErrGeneral; + } + + // and then put the directory into the image + TInt err = PlaceDirectory( pRootDir, addr - aImage->Size() ); // offset pointer by size of core image + if( err != KErrNone ) + { + Print(EError, "Failed placing directory - return code %d\n", err); + return err; + } + + directoryOffset+=aImage->Size(); // offset offset by size of core image + // Now write the header + TExtensionRofsHeader * pHeader = (TExtensionRofsHeader*)iData; + pHeader->iIdentifier[0] = 'R'; + pHeader->iIdentifier[1] = 'O'; + pHeader->iIdentifier[2] = 'F'; + pHeader->iIdentifier[3] = 'x'; + pHeader->iHeaderSize = KExtensionRofsHeaderSize; + pHeader->iDirTreeOffset = directoryOffset; + pHeader->iDirTreeSize = iTotalDirectoryBlockSize; + pHeader->iDirFileEntriesOffset = directoryOffset + iTotalDirectoryBlockSize; + pHeader->iDirFileEntriesSize = iTotalFileBlockSize; + pHeader->iRofsFormatVersion = KRofsFormatVersion; + pHeader->iTime = iObey->iTime; + iSizeUsed = fileDataSize + fileDataStartOffset; + pHeader->iImageSize = iSizeUsed; + if (iObey->AutoSize()) + MakeAutomaticSize(iObey->AutoPageSize()); // change iSize to nearest page size + pHeader->iMaxImageSize = iSize; + pHeader->iCheckSum = 0; // not used yet + + return KErrNone; + } + +void E32Rofs::MakeAutomaticSize(TUint32 aPageSize) + { + TUint32 size = iSizeUsed; + if (iSizeUsed % aPageSize > 0) + { + //used size needs to be rounded up to nearest page size + size = (iSizeUsed/aPageSize + 1)*aPageSize; + } + iSize = size; + } + +TInt E32Rofs::Create() +// +// This is the main entry point to the ROFS image creation +// + { + TUint8* addr=(TUint8*)iData; + + TRomNode* pRootDir = iObey->iRootDirectory; + const TInt headerSize = KRofsHeaderSize; + // Layout the directory structure. Does not actually write it + // to the image. Returns the number of bytes used for the directory + // structure within the image. + const TInt directoryOffset = headerSize; + const TInt directorySize = LayoutDirectory( pRootDir, directoryOffset ); + if( directorySize <= 0 ) + { + Print(EError, "Failed laying out directories - return code %d\n", directorySize); + return KErrGeneral; + } + + // get offset to start of file data, rounded up to next word boundary + TInt offs = headerSize + directorySize; + const TInt fileDataStartOffset = offs + ( (4 - offs) & 3); + + // Now we traverse the list of entries placing each file + // This updates the directory entries to point to the correct offset + // to the start of the file + const TInt fileDataSize = PlaceFiles( pRootDir, addr + fileDataStartOffset, fileDataStartOffset ); + if( fileDataSize < 0 ) + { + Print(EError, "Failed placing files - return code %d\n", fileDataSize); + return KErrGeneral; + } + + // and then put the directory into the image + TInt err = PlaceDirectory( pRootDir, addr ); + if( err != KErrNone ) + { + Print(EError, "Failed placing directory - return code %d\n", err); + return err; + } + + // Now write the header + TRofsHeader* pHeader = (TRofsHeader*)iData; + pHeader->iIdentifier[0] = 'R'; + pHeader->iIdentifier[1] = 'O'; + pHeader->iIdentifier[2] = 'F'; + pHeader->iIdentifier[3] = 'S'; + pHeader->iHeaderSize = KExtensionRofsHeaderSize; + pHeader->iDirTreeOffset = directoryOffset; + pHeader->iDirTreeSize = iTotalDirectoryBlockSize; + pHeader->iDirFileEntriesOffset = directoryOffset + iTotalDirectoryBlockSize; + pHeader->iDirFileEntriesSize = iTotalFileBlockSize; + pHeader->iRofsFormatVersion = KRofsFormatVersion; + pHeader->iTime = iObey->iTime; + iSizeUsed = fileDataSize + fileDataStartOffset; + pHeader->iImageSize = iSizeUsed; + pHeader->iImageVersion = iObey->iVersion; + if (iObey->AutoSize()) + MakeAutomaticSize(iObey->AutoPageSize()); // change iSize to nearest page size + + pHeader->iMaxImageSize = iSize; + pHeader->iCheckSum = 0; // not used yet + + return KErrNone; + } +void E32Rofs::DisplaySizes(TPrintType aWhere) +{ + Print(aWhere, "Summary of file sizes in rofs:\n"); + TRomBuilderEntry *file=iObey->FirstFile(); + while(file) + { + file->DisplaySize(aWhere); + file=iObey->NextFile(); + } + Print( aWhere, "Directory block size: %d\n" + "File block size: %d\n" + "Total directory size: %d\n" + "Total image size: %d\n", + iTotalDirectoryBlockSize, + iTotalFileBlockSize, + iTotalDirectoryBlockSize + iTotalFileBlockSize, + iSizeUsed ); + +} + +void E32Rofs::LogExecutableAttributes(E32ImageHeaderV *aHdr) +{ + Print(ELog, "Uids: %08x %08x %08x %08x\n", aHdr->iUid1, aHdr->iUid2, aHdr->iUid3, aHdr->iUidChecksum); + Print(ELog, "Data size: %08x\n", aHdr->iDataSize); + Print(ELog, "Heap min: %08x\n", aHdr->iHeapSizeMin); + Print(ELog, "Heap max: %08x\n", aHdr->iHeapSizeMax); + Print(ELog, "Stack size: %08x\n", aHdr->iStackSize); + Print(ELog, "Secure ID: %08x\n", aHdr->iS.iSecureId); + Print(ELog, "Vendor ID: %08x\n", aHdr->iS.iVendorId); + Print(ELog, "Priority: %d\n\n", aHdr->iProcessPriority); +} +class Worker : public boost::thread { + public: + static void thrd_func(E32Rofs* rofs){ + CBytePair bpe(gFastCompress); + + bool deferred = false; + TPlacingSection* p = rofs->GetFileNode(deferred); + while(p) { + if(!deferred) + p->len = p->node->PlaceFile(p->buf, (TUint32)-1, 0, &bpe); + p = rofs->GetFileNode(deferred); + } + rofs->ArriveDeferPoint(); + p = rofs->GetDeferredJob(); + while(p) { + p->len = p->node->PlaceFile(p->buf, (TUint32)-1, 0, &bpe); + p = rofs->GetDeferredJob(); + } + } + Worker(E32Rofs* rofs) : boost::thread(thrd_func,rofs) { + } +}; + +TPlacingSection* E32Rofs::GetFileNode(bool &aDeferred) { + //get a node from the node list, the node list is protected by mutex iMuxTree. + //The iMuxTree also helps to make sure the order in iVPS is consistent with the node list. + //And this is the guarantee of same outputs regardless of how many threads being used. + boost::mutex::scoped_lock lock(iMuxTree); + aDeferred = false; + TRomNode* node = iLastNode; + while(node) { + if( node->IsFile()) { + if(!node->iHidden) { + iLastNode = node->NextNode(); + break; + } + } + node = node->NextNode(); + } + + if(node && node->IsFile() && !node->iHidden) { + TPlacingSection* pps = new TPlacingSection(node); + iVPS.push_back(pps); + if(node->iAlias) { + iQueueAliasNode.push(pps); + aDeferred = true; + } + return pps; + } + return NULL; +} +TPlacingSection* E32Rofs::GetDeferredJob() { + // waiting all the normal node have been placed. + while(iWorkerArrived < gThreadNum) + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + + // now we can safely handle the alias nodes. + boost::mutex::scoped_lock lock(iMuxTree); + TPlacingSection* p = NULL; + if(!iQueueAliasNode.empty()) { + p = iQueueAliasNode.front(); + iQueueAliasNode.pop(); + } + return p; +} +void E32Rofs::ArriveDeferPoint() { + boost::mutex::scoped_lock lock(iMuxTree); + ++iWorkerArrived; +} +TInt E32Rofs::PlaceFiles( TRomNode* /*aRootDir*/, TUint8* aDestBase, TUint aBaseOffset, TInt aCoreSize ) + // + // Traverses all entries placing all files and updating directory entry pointers. + // Returns number of bytes placed or -ve error code. + // + { + iLastNode = TRomNode::FirstNode(); + iWorkerArrived = 0; + + boost::thread_group thrds; + Worker** workers = new Worker*[gThreadNum]; + int i; + for (i = 0; i < gThreadNum; ++i) { + workers[i] = new Worker(this); + thrds.add_thread(workers[i]); + } + + thrds.join_all(); + delete [] workers; + + TUint offset = aBaseOffset; + TUint8* dest = aDestBase; + TBool aIgnoreHiddenAttrib = ETrue; + TInt len = iVPS.size(); + TInt maxSize; + for(i=0;inode->iFileStartOffset != (TUint)KFileHidden) { + memcpy(dest,iVPS[i]->buf,iVPS[i]->len); + if(iVPS[i]->node->iEntry->iFileOffset == -1) { + iVPS[i]->node->iEntry->iFileOffset = offset; + iVPS[i]->node->iFileStartOffset = iVPS[i]->node->iEntry->iFileOffset; + } + else { + TRomBuilderEntry* aEntry = (TRomBuilderEntry*)(iVPS[i]->node->iFileStartOffset); + iVPS[i]->node->iFileStartOffset = aEntry->iFileOffset; + } + } + iVPS[i]->len += (4-iVPS[i]->len) & 3;// round up to next word boundary + dest += iVPS[i]->len; + offset += iVPS[i]->len; + + if(gLogLevel > DEFAULT_LOG_LEVEL ) + { + TRomNode* node = iVPS[i]->node; + TInt aLen = node->FullNameLength(aIgnoreHiddenAttrib); + char *aBuf = new char[aLen+1]; + if(gLogLevel & LOG_LEVEL_FILE_DETAILS) + { + node->GetFullName(aBuf, aIgnoreHiddenAttrib); + if(node->iEntry->iFileName) + Print(ELog,"%s\t%d\t%s\t%s\n", node->iEntry->iFileName, node->iEntry->RealFileSize(), (node->iHidden || node->iEntry->iHidden)? "hidden":"", aBuf); + else + Print(ELog,"%s\t%s\n", (node->iHidden || node->iEntry->iHidden) ? "hidden":"", aBuf); + } + + if(gLogLevel & LOG_LEVEL_FILE_ATTRIBUTES) + { + if(!node->iHidden && !node->iEntry->iHidden) + Print(ELog, "Device file name: %s\n", aBuf); + if(node->iEntry->iExecutable) + LogExecutableAttributes((E32ImageHeaderV*)(dest-len)); + } + delete[] aBuf; + } + } + return offset - aBaseOffset; // number of bytes used + } + + + + + + +TInt E32Rofs::LayoutDirectory( TRomNode* /*aRootDir*/, TUint aBaseOffset ) + // + // Creates the directory layout but does not write it to the image. + // All directories are given a location in the image. + // Returns the total number of bytes used for the directory (rounded + // up to the nearest word) or a -ve error code. + // + { + TRomNode* node = TRomNode::FirstNode(); + + TUint offset = aBaseOffset; + while( node ) + { + if( node->IsDirectory()) + { + // it is a directory block so we have to give it a location + node->SetImagePosition( offset ); + + // work out how much space it requires for the directory block + TInt dirLen; + TInt fileLen; + TInt err = node->CalculateDirectoryEntrySize( dirLen, fileLen ); + if( err != KErrNone ) + { + return err; + } + Print( ELog, "Directory '%s' @offs=0x%x, size=%d\n", node->iName, offset, dirLen ); + dirLen += (4-dirLen) & 3; // round up to next word boundary + offset += dirLen; + } + + node = node->NextNode(); + } + + TInt totalDirectoryBlockSize = offset - aBaseOffset; // number of bytes used + totalDirectoryBlockSize += (4 - totalDirectoryBlockSize) & 3; // round up + + // Now go round again placing the file blocks + offset = aBaseOffset + totalDirectoryBlockSize; + const TUint fileBlockStartOffset = offset; + node = TRomNode::FirstNode(); + while( node ) + { + if( node->IsDirectory() ) + { + // work out how much space it requires for the file block + TInt dummy; + TInt fileLen; + TInt err = node->CalculateDirectoryEntrySize( dummy, fileLen ); + + if( err != KErrNone ) + { + return fileLen; + } + if( fileLen ) + { + node->SetFileBlockPosition( offset ); + Print( ELog, "File block for dir '%s' @offs=0x%x, size=%d\n", node->iName, offset, fileLen ); + } + + fileLen += (4-fileLen) & 3; // round up to next word boundary + offset += fileLen; + } + + node = node->NextNode(); + } + + TInt totalFileBlockSize = offset - fileBlockStartOffset; // number of bytes used + totalFileBlockSize += (4 - totalFileBlockSize) & 3; // round up + + iTotalDirectoryBlockSize = totalDirectoryBlockSize; + iTotalFileBlockSize = totalFileBlockSize; + + return totalDirectoryBlockSize + totalFileBlockSize; + } + + +TInt E32Rofs::PlaceDirectory( TRomNode* /*aRootDir*/, TUint8* aDestBase ) + // + // Writes the directory into the image. + // Returns KErrNone on success, or error code + // + { + TRomNode* node = TRomNode::FirstNode(); + + while( node ) + { + if( node->IsDirectory() ) + { + TInt err = node->Place( aDestBase ); + if( err != KErrNone ) + { + return err; + } + } + node = node->NextNode(); + } + return KErrNone; + } + +TInt E32Rofs::WriteImage( TInt aHeaderType ) + { + ofstream romFile((const char *)iObey->iRomFileName,ios::binary); + if (!romFile) + return Print(EError,"Cannot open ROM file %s for output\n",iObey->iRomFileName); + Write(romFile, aHeaderType); + romFile.close(); + + return KErrNone; + } + +TRomNode* E32Rofs::CopyDirectory(TRomNode*& aLastExecutable) + { + return iObey->iRootDirectory->CopyDirectory(aLastExecutable); + } + + +void E32Rofs::Write(ofstream &os, TInt aHeaderType) + +// Output a rom image + + { + + switch (aHeaderType) + { + default: + case 0: + Print(EAlways, "\nWriting Rom image without"); + break; + case 2: + Print(EAlways, "\nWriting Rom image with PE-COFF"); + { + unsigned char coffhead[0x58] = {0}; // zero all the elements + + // fill in the constant bits + // this is supposed to be simple, remember + coffhead[1] = 0x0a; + coffhead[2] = 0x01; + coffhead[0x10] = 0x1c; + coffhead[0x12] = 0x0f; + coffhead[0x13] = 0xa1; + coffhead[0x14] = 0x0b; + coffhead[0x15] = 0x01; + coffhead[0x26] = 0x40; + coffhead[0x2a] = 0x40; + coffhead[0x30] = 0x2e; + coffhead[0x31] = 0x74; + coffhead[0x32] = 0x65; + coffhead[0x33] = 0x78; + coffhead[0x34] = 0x74; + coffhead[0x3a] = 0x40; + coffhead[0x3e] = 0x40; + coffhead[0x44] = 0x58; + coffhead[0x54] = 0x20; + + // now fill in the text segment size + TUint32 * p0x18 = reinterpret_cast(&coffhead[0x18]); + *p0x18 = ALIGN4K(iSizeUsed); + TUint32 * p0x40 = reinterpret_cast(&coffhead[0x40]); + *p0x40 = ALIGN4K(iSizeUsed); + os.write(reinterpret_cast(coffhead), sizeof(coffhead)); + } + break; + } + Print(EAlways, " header to file %s\n", iObey->iRomFileName); + os.write( iData, iSizeUsed ); + } + + +TRomNode* E32Rofs::RootDirectory() + { + return iObey->iRootDirectory; + } +void E32Rofs::SetRootDirectory(TRomNode* aDir) + { + iObey->iRootDirectory = aDir; + } +TText* E32Rofs::RomFileName() + { + return iObey->iRomFileName; + } +TInt E32Rofs::Size() + { + return iSize; + } + +/////////////////// +