diff -r 820b22e13ff1 -r 39c28ec933dd imgtools/romtools/rombuild/r_rom.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imgtools/romtools/rombuild/r_rom.cpp Mon May 10 19:54:49 2010 +0100 @@ -0,0 +1,2711 @@ +/* +* 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 "h_utl.h" +#include +#include + +#if defined(__MSVCDOTNET__) || defined(__TOOLS2__) +#include +#else //!__MSVCDOTNET__ +#include +#endif //__MSVCDOTNET__ + +#include "r_global.h" +#include "r_obey.h" +#include "r_rom.h" +#include "r_dir.h" +#include "patchdataprocessor.h" +#include "memmap.h" +#include "byte_pair.h" + +const TInt KSpareExports=16; +extern TInt gThreadNum; +extern char* gDepInfoFile; +extern TBool gGenDepGraph; + +TUint32 DeflateCompressCheck(char *bytes,TInt size,ostream &os); +void DeflateCompress(char *bytes,TInt size,ostream &os); +void InflateUnCompress(unsigned char* source, int sourcesize,unsigned char* dest, int destsize); + +EntryQueue* LoadImageWorker::m_queue = NULL; +TInt LoadImageWorker::m_errors = 0; +TMemModel LoadImageWorker::m_memmodel; +boost::mutex LoadImageWorker::m_mutex; +LoadImageWorker::LoadImageWorker(EntryQueue* aQueue, TMemModel aMemModel) + { + m_queue = aQueue; + m_memmodel = aMemModel; + } +void LoadImageWorker::operator()() + { + while(1) + { + m_mutex.lock(); + if(m_queue->size() > 0) + { + TRomBuilderEntry * current = m_queue->front(); + m_queue->pop(); + m_mutex.unlock(); + TInt err = current->OpenImageFile(); + if(err) + { + m_mutex.lock(); + ++m_errors; + m_mutex.unlock(); + continue; + } + if(current->iOverrideFlags&KOverrideAddress || current->iHdr->iFlags & KImageFixedAddressExe) + { + if(m_memmodel != E_MM_Multiple && m_memmodel != E_MM_Flexible && !current->IsDll()) + current->iRomImageFlags |=KRomImageFlagFixedAddressExe; + } + if(gPagedRom) + { + if(current->iHdr->iFlags&KImageCodePaged) + { + current->iRomImageFlags&=~KRomImageFlagCodeUnpaged; + current->iRomImageFlags|=KRomImageFlagCodePaged; + } + if(current->iHdr->iFlags&KImageCodeUnpaged) + { + current->iRomImageFlags|=KRomImageFlagCodeUnpaged; + current->iRomImageFlags&=~KRomImageFlagCodePaged; + } + } + if(current->iHdr->iFlags&KImageDataPaged) + { + current->iRomImageFlags&=~KRomImageFlagDataUnpaged; + current->iRomImageFlags|=KRomImageFlagDataPaged; + } + if(current->iHdr->iFlags&KImageDataUnpaged) + { + current->iRomImageFlags|=KRomImageFlagDataUnpaged; + current->iRomImageFlags&=~KRomImageFlagDataPaged; + } + if(current->iHdr->iFlags&KImageDebuggable) + { + current->iRomImageFlags|=KRomImageDebuggable; + } + else + { + current->iRomImageFlags&=~KRomImageDebuggable; + } + } + else + { + m_mutex.unlock(); + break; + } + } + } +E32Rom* CompressPageWorker::m_rom = NULL; +TInt CompressPageWorker::m_nextpage = 0; +TInt CompressPageWorker::m_totalpages = 0; +TInt CompressPageWorker::m_pagesize = 0; +boost::mutex CompressPageWorker::m_mutex; +TInt CompressPageWorker::m_error = 0; +CompressPageWorker::CompressPageWorker(E32Rom* aRom, TInt aPageSize, TInt aTotalPages, TInt aNextPage) + { + m_rom = aRom; + m_pagesize = aPageSize; + m_totalpages = aTotalPages; + m_nextpage = aNextPage; + } +void CompressPageWorker::operator()() + { + SRomPageInfo* pPageBase = (SRomPageInfo*)((TInt)m_rom->iHeader + m_rom->iHeader->iRomPageIndex); + CBytePair bpe(gFastCompress); + while(1) + { + m_mutex.lock(); + TInt currentPageIndex = m_nextpage++; + m_mutex.unlock(); + if(currentPageIndex < m_totalpages) + { + TInt inOffset = m_pagesize * currentPageIndex; + TUint8 attrib = (TUint8)SRomPageInfo::EPageable; + SRomPageInfo info ={ (TUint32)inOffset, (TUint16)m_pagesize, (TUint8)SRomPageInfo::EBytePair, attrib }; + TUint8* in = (TUint8*) m_rom->iHeader + inOffset; + TUint8* out = in; + TInt outSize = BytePairCompress(out, in, m_pagesize, &bpe); + if(outSize == KErrTooBig) + { + info.iCompressionType = SRomPageInfo::ENoCompression; + memcpy(out, in, m_pagesize); + outSize = m_pagesize; + } + if(outSize < 0 ) + { + m_mutex.lock(); + m_error = outSize; + m_mutex.unlock(); + break; + } + info.iDataSize = (TUint16) outSize; + *(pPageBase + currentPageIndex) = info; + if((currentPageIndex & 255) == 255) + { + m_mutex.lock(); + Print(EAlways, ".\n"); + m_mutex.unlock(); + } + } + else + { + break; + } + } + } + +//////////////////////////////////////////////////////////////////////// + +TAddressRange::TAddressRange() + : iImagePtr(0), iImageAddr(0), iRunAddr(0), iSize(0) + { + } + +void TAddressRange::Append(TAddressRange& aRange) + { + if(aRange.iSize) + { + aRange.iImagePtr = iImagePtr; + aRange.iImageAddr = iImageAddr; + aRange.iRunAddr = iRunAddr; + Extend(aRange.iSize); + } + } + +void TAddressRange::Move(TInt aOffset) + { + iImagePtr = static_cast(iImagePtr) + aOffset; + iImageAddr += aOffset; + iRunAddr += aOffset; + } + +void TAddressRange::Extend(TInt aOffset) + { + Move(aOffset); + iSize += aOffset; + } + +//////////////////////////////////////////////////////////////////////// + +inline TUint32 AlignData(TUint32 anAddr) + { + return ((anAddr+0x0f)&~0x0f); + } + +TUint32 E32Rom::AlignToPage(TUint32 anAddr) + { + TUint a=(TUint)iObey->iPageSize-1; + return ((anAddr+a)&~a); + } + +/* +Allocate virtual memory for static data in rom. +@param aAddr Base address of last allocated memory. +@param aSize Size of memory to allocate. +@return Address allocated. This is below aAddr. +*/ +TUint32 E32Rom::AllocVirtual(TUint32 aAddr,TUint aSize) + { + TInt align = iObey->iVirtualAllocSize; + if(align<0) + { + align = -align; // get correct sign + // -ve align means also align to next power-of-two >= aSize... + while(aSize>(TUint)align) + align <<=1; + } + + TUint mask = (TUint)align-1; + aSize = (aSize+mask)&~mask; // round up + aAddr &= ~mask; // round down + return aAddr-aSize; + } + +TUint32 E32Rom::AlignToChunk(TUint32 anAddr) + { + TUint a=(TUint)iObey->iChunkSize-1; + return ((anAddr+a)&~a); + } + +COrderedFileList::COrderedFileList(TInt aMaxFiles) + : iCount(0), iMaxFiles(aMaxFiles), iOrderedFiles(NULL) + {} + +COrderedFileList::~COrderedFileList() + { + iCount=0; + delete[] iOrderedFiles; + } + +COrderedFileList* COrderedFileList::New(TInt aMaxFiles) + { + COrderedFileList *pL=new COrderedFileList(aMaxFiles); + pL->iOrderedFiles=new TRomBuilderEntry*[aMaxFiles]; + return pL; + } + +void COrderedFileList::Add(TRomBuilderEntry* anEntry) + { + // note: this routine assumes that the set of kernel-mode files + // (primary/extension/device) required by a given variant is linearly ordered by <= + // e.g. can't have three variants {A,B,V1} {A,B,C,V2} {A,C,V3} because B and C + // are unordered with respect to <=, since neither of + // {n | Vn requires B} and {n | Vn requires C} is a subset of the other. + // In a case like this, ROMBUILD may fail to resolve the addresses of some global data + THardwareVariant& v=anEntry->iHardwareVariant; + TInt i=0; + while(iiHardwareVariant) i++; + TInt j=iCount; + while(j>i) + { + iOrderedFiles[j]=iOrderedFiles[j-1]; + j--; + } + iOrderedFiles[i]=anEntry; + iCount++; + } + +void GetFileNameAndUid(char *aDllName, TUid &aDllUid, char *aExportName) + { + strcpy(aDllName, aExportName); + aDllUid=KNullUid; + TInt start; + for (start=0; start<(TInt)strlen(aExportName) && aExportName[start]!='['; start++) + ; + if (start==(TInt)strlen(aExportName)) + start=KErrNotFound; + TInt end=strlen(aExportName)-1; + while (end>=0) + { + if (aExportName[end]==']') + break; + --end; + } + if (end<0) + end=KErrNotFound; + + if ((start!=KErrNotFound) && (end!=KErrNotFound) && (end>start)) + { + // Importing from DLL with Uid + char uidStr[0x100]; + strcpy(uidStr, "0x"); + strncat(uidStr, aExportName+start+1, end-start-1); + #ifdef __TOOLS2__ + istringstream val(uidStr); + #else + istrstream val(uidStr,strlen(uidStr)); + #endif + +#if defined(__MSVCDOTNET__) || defined(__TOOLS2__) + val >> setbase(0); +#endif //__MSVCDOTNET__ + + TUint32 u; + val >> u; + val.peek(); + if (val.eof()) + { + aDllUid=TUid::Uid(u); + char *dot=aExportName+strlen(aExportName)-1; + while (dot>=aExportName) + { + if (*dot=='.') + break; + dot--; + } + if (dotiRomSize; + iObey=aObey; + iPeFiles=NULL; + + 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; + Print(EError, "Out of memory.\n"); + } + HMem::Set(iData, 0xff, iSize); + } + iHeader=(TRomHeader *)(iData+sizeof(TRomLoaderHeader)); + iExtensionRomHeader=NULL; + iLoaderHeader=(TRomLoaderHeader *)iData; + iSectionPtr=(char *)iHeader+aObey->iSectionStart-aObey->iRomLinearBase+sizeof(TRomSectionHeader); + TheRomHeader=(ImpTRomHeader *)iHeader; + TheRomMem=(TUint32)iHeader; + iNextDataChunkBase=aObey->iKernDataRunAddress; + iTotalSvDataSize=0; + iNextDllDataAddr=aObey->iDllDataTop; + iPrevPrimaryAddress=NULL; + iPrevVariantAddress=NULL; + iVariantFileLists=NULL; + iImportsFixedUp=0; + iBranchesFixedUp=0; + iVtableEntriesFixedUp=0; + iOverhead=0; + } + +E32Rom::~E32Rom() +// +// Destructor +// + { + + if(gLowMem) + { + iImageMap->CloseMemoryMap(ETrue); + delete iImageMap; + } + else + delete iData; + delete [] iPeFiles; + if (iVariantFileLists) + { + TInt i; + for (i=0; iiNumberOfVariants; i++) + delete iVariantFileLists[i]; + delete [] iVariantFileLists; + } + } + +TInt E32Rom::Align(TInt aVal) +// +// Align to romalign +// + { + + return ((aVal+iObey->iRomAlign-1)/iObey->iRomAlign)*iObey->iRomAlign; + } + +TInt E32Rom::LoadContents(char*& anAddr, TRomHeader* aHeader) + { + // Load all the PE/E32Image files + TInt nfiles=iObey->iNumberOfPeFiles; + iPeFiles=new TRomBuilderEntry* [nfiles]; + if (!iPeFiles) + return Print(EError, "Out of memory.\n"); + + TInt r=TranslateFiles(); + if (r!=KErrNone) + return r; + + ProcessDllData(); + + EnumerateVariants(); + + r=BuildDependenceGraph(); + if (r!=KErrNone) + return r; + + // Update the ROM image headers with SMP information. + SetSmpFlags(); + + r=ProcessDependencies(); + if (r!=KErrNone) + return r; + + char* addr = anAddr; + TRomExceptionSearchTable* exceptionSearchTable = 0; + + if(gPagedRom) + { + gDepInfoFile = (char* )malloc(strlen((char *)iObey->iRomFileName) + 1); + strcpy(gDepInfoFile, (char *)iObey->iRomFileName); + iObey->SetArea().DefaultArea()->SortFilesForPagedRom(); + // exception search table needs to go at start of ROM to make it not demand paged... + addr = ReserveRomExceptionSearchTable(addr,exceptionSearchTable); + } + else if(gGenDepGraph) + { + Print(EWarning, "Not dependence information in an unpaged ROM."); + } + + addr=WriteDirectory(addr, aHeader); + // Aligned + + TRACE(TSCRATCH,Print(EAlways,"Directory written\n")); + + // Stick all the files in ROM + + TReloc* relocationTable; + addr = AllocateRelocationTable(addr, relocationTable); + aHeader->iRelocInfo = relocationTable ? ActualToRomAddress(relocationTable) : 0; + // Aligned + + TRACE(TSCRATCH,Print(EAlways,"Done AllocateRelocationTable\n")); + + CalculateDataAddresses(); + addr = LayoutRom(addr); + + TRACE(TSCRATCH,Print(EAlways,"Done LayoutRom\n")); + + FillInRelocationTable(relocationTable); + + TRACE(TSCRATCH,Print(EAlways,"Done FillInRelocationTable\n")); + + if(!exceptionSearchTable) + addr = ReserveRomExceptionSearchTable(addr,exceptionSearchTable); + ConstructRomExceptionSearchTable(exceptionSearchTable); + + TRACE(TSCRATCH,Print(EAlways,"Done ConstructRomExceptionSearchTable\n")); + + LinkKernelExtensions(iObey->iExtensions, iObey->iNumberOfExtensions); + + TRACE(TSCRATCH,Print(EAlways,"Done LinkKernelExtensions\n")); + + r=ResolveDllRefTables(); + if (r!=KErrNone) + return r; + r=ResolveImports(); + if (r!=KErrNone) + return r; + if (iObey->iCollapseMode>ECollapseNone) + { + r=CollapseImportThunks(); + if (r!=KErrNone) + return r; + if (iObey->iCollapseMode>ECollapseImportThunksOnly) + { + r=CollapseBranches(); + if (r!=KErrNone) + return r; + } + Print(ELog,"%d imports, %d branches, %d vtable entries fixed up\n", + iImportsFixedUp,iBranchesFixedUp,iVtableEntriesFixedUp); + } + + iSizeUsed=(TInt)addr-(TInt)iHeader; + Print(ELog, "\n%08x of %08x bytes used.\n", iSizeUsed, iSize-sizeof(TRomLoaderHeader)); + + // round the rom size in the header to a multiple of 1 Megabyte + TInt rounded = ((iSizeUsed+0xfffff)&0xfff00000); + if (rounded < iObey->iRomSize) + iObey->iRomSize = rounded; + iUncompressedSize = iSizeUsed; + + anAddr = addr; + + return KErrNone; + } + + +void E32Rom::CreatePageIndex(char*& aAddr) + { + iHeader->iRomPageIndex = 0; + if(gPagedRom==0 || gEnableCompress==0) + return; + + // Insert space for Rom Page Info table... + iHeader->iRomPageIndex = (TInt)aAddr-(TInt)iHeader; + TInt pageSize = iObey->iPageSize; + TInt numPages = iSize/pageSize+1; + TInt pageInfoSize = numPages*sizeof(SRomPageInfo); + + gPageIndexTableSize = pageInfoSize; // For accumulate uncompressed un-paged size added Page Index Table + + Print(ELog, "Inserting %d bytes for RomPageInfo at ROM offset 0x%08x\n", pageInfoSize, iHeader->iRomPageIndex); + memset(aAddr,0,pageInfoSize); + iOverhead += pageInfoSize; + aAddr += pageInfoSize; + } + +TInt E32Rom::SetupPages() + { + iHeader->iPageableRomStart = 0; + iHeader->iPageableRomSize = 0; + iHeader->iDemandPagingConfig = gDemandPagingConfig; + + if(!gPagedRom) + return KErrNone; + + // Initialise the Rom Page Info for each page which indicates it is uncompressed... + TInt pageSize = iObey->iPageSize; + + TInt pagedStartOffset = 0x7fffffff; + TRomBuilderEntry* e = iObey->SetArea().DefaultArea()->iFirstPagedCode; + if(e) + { + // we have paged code... + pagedStartOffset = e->RomEntry()->iAddressLin-iObey->iRomLinearBase; + pagedStartOffset = (pagedStartOffset+pageSize-1)&~(pageSize-1); // round up to next page; + iHeader->iPageableRomStart = pagedStartOffset; + TInt pageableSize = iSizeUsed-pagedStartOffset; + if(pageableSize>0) + iHeader->iPageableRomSize = pageableSize; + } + + return KErrNone; + } + +TInt E32Rom::CompressPages() + { + + if(!gPagedRom || !gEnableCompress) + return KErrNone; + + // Initialise the Rom Page Info for each page which indicates it is uncompressed... + TInt pageSize = iObey->iPageSize; + TInt numPages = (iSizeUsed+pageSize-1)/pageSize; + + TInt pagedStartOffset = iHeader->iPageableRomStart; + + Print(EAlways, "\nCompressing pages...\n"); + TInt inOffset = 0; + SRomPageInfo* pi = (SRomPageInfo*)((TInt)iHeader+iHeader->iRomPageIndex); + TInt currentIndex = 0; + while(inOffset < pagedStartOffset) + { + + TUint8 attrib = (TUint8)0; + SRomPageInfo info = {(TUint32)inOffset,(TUint16)pageSize,(TUint8)SRomPageInfo::EBytePair,(TUint8)attrib}; + info.iDataSize = (TUint16) pageSize; + *pi++ = info; + inOffset += pageSize; + if((currentIndex & 255) == 255) + Print(EAlways, ".\n"); + currentIndex++; + } + CompressPageWorker compressworker(this, pageSize, numPages, currentIndex); + + boost::thread_group threads; + for(int i = 0; i < gThreadNum; i++) + { + threads.create_thread(compressworker); + } + threads.join_all(); + if(compressworker.m_error < 0) + return compressworker.m_error; + for(;currentIndex < numPages - 1; currentIndex++) + { + pi++; + SRomPageInfo* prev = pi - 1; + TUint8* dest = (TUint8*) iHeader + prev->iDataStart + prev->iDataSize; + TUint8* src = (TUint8*) iHeader + pi->iDataStart; + memcpy(dest, src, pi->iDataSize); + pi->iDataStart = prev->iDataStart + prev->iDataSize; + } + TInt relSize = pi->iDataStart + pi->iDataSize; + + memset((TUint8*)iHeader + relSize, 0xff, iSizeUsed - relSize); + TInt compression = (iSizeUsed >= 1000) ? (relSize*10)/(iSizeUsed/1000) : (relSize*10000)/iSizeUsed; + Print(EAlways, "%d.%02d%%\n", compression/100, compression%100); + iSizeUsed = relSize; + return KErrNone; + } + +TInt E32Rom::CompressPage(SRomPageInfo& aPageInfo, TInt aOutOffset, CBytePair * aBPE) + { + TUint8* in = (TUint8*)iHeader+aPageInfo.iDataStart; + TInt inSize = aPageInfo.iDataSize; + TUint8* out = (TUint8*)iHeader+aOutOffset; + switch(aPageInfo.iCompressionType) + { + case SRomPageInfo::ENoCompression: + memcpy(out,in,inSize); + return inSize; + + case SRomPageInfo::EBytePair: + { + TInt r = BytePairCompress(out, in, inSize, aBPE); + if(r!=KErrTooBig) + return r; + // data can't be compressed... + aPageInfo.iCompressionType = SRomPageInfo::ENoCompression; + memcpy(out,in,inSize); + return inSize; + } + + default: + Print(EError, "Unsupported page compression type (%d)\n", aPageInfo.iCompressionType); + return KErrNotSupported; + } + } + + +// Avoid "warning" about constant expression +static void checksize(const char* aTypeName, int aSize, int aCorrectSize) + { + if (aSize != aCorrectSize) + Print(EError, "sizeof(%s) = %d, should be %d\n", aTypeName, aSize, aCorrectSize); + } + +TInt E32Rom::CreateExtension(MRomImage* aKernelRom) + { + + // sanity check + checksize("TExtensionRomHeader", sizeof(TExtensionRomHeader), 128); + + char *addr=(char *)iHeader; + iExtensionRomHeader=(TExtensionRomHeader*)addr; + addr += sizeof(TExtensionRomHeader); + // Aligned + + TRomHeader dummy; + TInt r=LoadContents(addr, &dummy); + if (r!=KErrNone) + { + Print(EError, "LoadContents failed - return code %d\n", r); + return r; + } + iExtensionRomHeader->iRomRootDirectoryList = dummy.iRomRootDirectoryList; + + iLoaderHeader->SetUp(iObey); + FinaliseExtensionHeader(aKernelRom); + DisplayExtensionHeader(); + + return KErrNone; + } + +TInt E32Rom::Create() + { + + TVariantList::Setup(iObey); + char *addr=(char *)iHeader; + // Aligned + + // Put the bootstrap in rom - it contains a hole at offset 0x80 where the + // TRomHeader information will be placed later + + gBootstrapSize = HFile::Read(iObey->iBootFileName, iHeader); + if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO) + Print(ELog, "bootstrapSize: 0x%08x, (%d)\n", gBootstrapSize, gBootstrapSize); + + if (gBootstrapSize==0) + return Print(EError, "Cannot open the bootstrap file '%s'.\n", iObey->iBootFileName); + gBootstrapSize=Align(gBootstrapSize); + addr+=gBootstrapSize; + iOverhead=gBootstrapSize; + // Aligned + + CreatePageIndex(addr); + + TInt r=LoadContents(addr, iHeader); + if (r!=KErrNone) + { + Print(EError, "LoadContents failed - return code %d\n", r); + return r; + } + + r = SetupPages(); // initialize ROM paging info... + if(r!=KErrNone) + { + Print(EError, "Setup pages information failed - return code %d\n", r); + return r; + } + + r = CheckUnpagedMemSize(); // check for unpaged memory overflow + if(r!=KErrNone) + { + return r; + } + + r = CompressPages(); // setup ROM paging info... + if(r!=KErrNone) + { + Print(EError, "CompressPages failed - return code %d\n", r); + return r; + } + + iLoaderHeader->SetUp(iObey); + ImpTRomHeader* header = (ImpTRomHeader *)iHeader; + header->SetUp(iObey); + header->iTotalSvDataSize=iTotalSvDataSize; + if (iObey->iMemModel==E_MM_Direct) + { + header->iUserDataAddress=iObey->iDataRunAddress; + header->iTotalUserDataSize=iNextDataChunkBase-iObey->iDataRunAddress; + } + else + { + header->iUserDataAddress=iObey->iDllDataTop; + header->iTotalUserDataSize=iObey->iDllDataTop-iNextDllDataAddr; + } + if (header->iRomSectionHeader) + FinaliseSectionHeader(); // sorts out the second section checksum + + header->CheckSum(iObey->iCheckSum); // finally, sort out the overall checksum + + header->Display(); + + TUint testCheckSum = HMem::CheckSum((TUint *)iHeader, iHeader->iRomSize); + Print(ELog, "Rom 32bit words sum to %08x\n", testCheckSum); + if (testCheckSum != iObey->iCheckSum) + return Print(EError, "Rom checksum is incorrect: %08x should be %08x\n", + testCheckSum, iObey->iCheckSum); + + // 8bit checksum = sum of bytes + // odd/even checksum = checksum of the odd and even halfwords of the image + + Print(ELog, "Rom 8bit checksum %08x\n", HMem::CheckSum8((TUint8 *)iHeader, iHeader->iRomSize)); + Print(ELog, "Rom 8bit odd checksum %08x\n", HMem::CheckSumOdd8((TUint8 *)iHeader, iHeader->iRomSize)); + Print(ELog, "Rom 8bit even checksum %08x\n", HMem::CheckSumEven8((TUint8 *)iHeader, iHeader->iRomSize)); + + if (iHeader->iPrimaryFile) + { + if (iObey->iKernelModel==ESingleKernel) + { + Print(ELog,"\nPrimary details (Single Kernel):\n"); + TRomEntry *r = (TRomEntry *)(iHeader->iPrimaryFile-iObey->iRomLinearBase+(char *)iHeader); + TRomImageHeader *hdr = (TRomImageHeader *)(r->iAddressLin-iObey->iRomLinearBase+(char *)iHeader); + Display(hdr); + Print(ELog,"\n"); + } + else if (iObey->iKernelModel==EMultipleKernels) + { + Print(ELog,"\nPrimary details (Multiple Kernels):\n"); + TRomEntry *r = (TRomEntry *)(iHeader->iPrimaryFile-iObey->iRomLinearBase+(char *)iHeader); + TInt n=1; + FOREVER + { + Print(ELog,"\nKernel %d:\n",n); + TRomImageHeader *hdr = (TRomImageHeader *)(r->iAddressLin-iObey->iRomLinearBase+(char *)iHeader); + Display(hdr); + Print(ELog,"\n"); + if (!hdr->iNextExtension) + break; + r=(TRomEntry*)(hdr->iNextExtension-iObey->iRomLinearBase+(char*)iHeader); + n++; + } + } + } + + return KErrNone; + } + +char *E32Rom::WriteDirectory(char *aAddr, TRomHeader* aHeader) +// +// Write the directory structure where appropriate +// + { + + TLinAddr dirptr=ActualToRomAddress(aAddr); + if (iObey->iSectionPosition==-1) + { + // Just the one rom. Put the directory structure at aAddr + iDirectorySize=WriteHeadersToRom(aAddr); + aAddr+=Align(iDirectorySize); + } + else + { + // Put the directory structure in the second ROM, after the SectionHeader + // and the second section information for first section files + TInt size=0; + TInt i; + for (i=0; iiNumberOfPeFiles; i++) + { + TRomBuilderEntry *file=iPeFiles[i]; + if (file->iRomSectionNumber!=0) + break; + TInt size1, size2; + file->SizeInSections(size1,size2); + size+=size2; + } + dirptr=ActualToRomAddress(iSectionPtr)+size; + iDirectorySize=WriteHeadersToRom(RomToActualAddress(dirptr)); + } + aHeader->iRomRootDirectoryList=dirptr; + return aAddr; + } + +void E32Rom::Display(TRomImageHeader *aHdr) +// +// Print info on a file +// + { + TRACE(TAREA, Print(ELog, "+Display header %08x\n", aHdr)); + Print(ELog, "Uids: %08x %08x %08x %08x\n", aHdr->iUid1, aHdr->iUid2, aHdr->iUid3, aHdr->iUidChecksum); + Print(ELog, "Entry point: %08x\n", aHdr->iEntryPoint); + Print(ELog, "Code start addr: %08x\n", aHdr->iCodeAddress); + Print(ELog, "Data start addr: %08x\n", aHdr->iDataAddress); + Print(ELog, "DataBssLinearBase: %08x\n", aHdr->iDataBssLinearBase); + Print(ELog, "Text size: %08x\n", aHdr->iTextSize); + Print(ELog, "Code size: %08x\n", aHdr->iCodeSize); + Print(ELog, "Data size: %08x\n", aHdr->iDataSize); + Print(ELog, "BssSize: %08x\n", aHdr->iBssSize); + Print(ELog, "Total data size: %08x\n", aHdr->iTotalDataSize); + 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, "Dll ref table: %08x\n", aHdr->iDllRefTable); + Print(ELog, "Export directory: %08x\n", aHdr->iExportDir); + Print(ELog, "Export dir count: %08x\n", aHdr->iExportDirCount); + Print(ELog, "Hardware variant: %08x\n", aHdr->iHardwareVariant); + Print(ELog, "Flags: %08x\n", aHdr->iFlags); + Print(ELog, "Secure ID: %08x\n", aHdr->iS.iSecureId); + Print(ELog, "Vendor ID: %08x\n", aHdr->iS.iVendorId); + Print(ELog, "Capability: %08x %08x\n", aHdr->iS.iCaps[1], aHdr->iS.iCaps[0]); + Print(ELog, "Tools Version: %d.%02d(%d)\n", aHdr->iToolsVersion.iMajor, aHdr->iToolsVersion.iMinor, aHdr->iToolsVersion.iBuild); + Print(ELog, "Module Version: %d.%d\n", aHdr->iModuleVersion>>16, aHdr->iModuleVersion&0x0000ffffu); + Print(ELog, "Exception Descriptor: %08x\n", aHdr->iExceptionDescriptor); + Print(ELog, "Priority: %d\n", aHdr->iPriority); + } + +void E32Rom::DisplaySizes(TPrintType aWhere) + { + + Print(aWhere, "Summary of file sizes in rom:\n"); + Print(aWhere, "Overhead (bootstrap+gaps+sectioning)\t%d\n", iOverhead); + Print(aWhere, "Overhead (directory size)\t%d\n", iDirectorySize); + TRomBuilderEntry *file=iObey->FirstFile(); + while (file) + { + file->DisplaySize(aWhere); + file=iObey->NextFile(); + } + Print(aWhere, "\nTotal used\t%d\n", iSizeUsed); + Print(aWhere, "Free\t%d\n", iObey->iRomSize-iSizeUsed); + + if (iObey->SetArea().Count() > 1) + { + Print(aWhere, "\nArea summary:\n"); + for (NonDefaultAreasIterator it(iObey->SetArea()); + ! it.IsDone(); + it.GoToNext()) + { + const Area& a = it.Current(); + Print(aWhere, "%s\t used: %d bytes / free: %d bytes\n", + a.Name(), a.UsedSize(), a.MaxSize()-a.UsedSize()); + } + } + } + +TInt E32Rom::RequiredSize() +// +// Get the (approximate) required size of the Rom +// + { + + TInt sum=0; + TRomBuilderEntry *current=iObey->FirstFile(); + while (current) + { + if (current->iResource || current->HCRDataFile()) + sum+=Align(HFile::GetLength((TText*)current->iFileName)); + else + sum+=Align(current->SizeInRom()); + current=iObey->NextFile(); + } + return sum+iOverhead+Align(iDirectorySize); + } + +TInt E32Rom::TranslateFiles() +// +// Load and translate all PE/E32 image files +// + { + + TInt i=0; + TInt total_errors = 0; + TRomBuilderEntry* current = 0; + EntryQueue imagesQueue; + for (current = iObey->FirstFile(); current; current = iObey->NextFile() ) + { + if ((!current->iResource) && (!current->HCRDataFile())) + { + iPeFiles[i++]=current; + imagesQueue.push(current); + } + } + LoadImageWorker loadworker(&imagesQueue, iObey->iMemModel); + boost::thread_group threads; + for(int i = 0; i < gThreadNum; i++) + { + threads.create_thread(loadworker); + } + threads.join_all(); + + total_errors = loadworker.m_errors; + if (total_errors) + return KErrGeneral; + for (current = iObey->FirstFile(); current; current = iObey->NextFile() ) + { + if ((!current->iResource) && (!current->HCRDataFile())) + { + TInt err = CheckForVersionConflicts(current); + total_errors += err; + } + } + return total_errors ? KErrGeneral : KErrNone; + } + +const TText FileTypeFile[]= "File "; +const TText FileTypePrimary[]= "Primary "; +const TText FileTypeVariant[]= "Variant "; +const TText FileTypeExtension[]="Extension"; +const TText FileTypeDevice[]= "Device "; + +void E32Rom::EnumerateVariants() + { + TInt vIndex; + TInt nFiles=iObey->iNumberOfExtensions+iObey->iNumberOfDevices+3; + iVariantFileLists=new COrderedFileList*[iObey->iNumberOfVariants]; + for (vIndex=0; vIndexiNumberOfVariants; vIndex++) + iVariantFileLists[vIndex]=COrderedFileList::New(nFiles); + for (vIndex=0; vIndexiNumberOfVariants; vIndex++) + { + TRomBuilderEntry *variant=iObey->iVariants[vIndex]; + THardwareVariant& v=variant->iHardwareVariant; + TInt i; + for (i=0; iiNumberOfPrimaries; i++) + { + TRomBuilderEntry *primary=iObey->iPrimaries[i]; + if (v<=primary->iHardwareVariant) + { + iVariantFileLists[vIndex]->Add(primary); + break; + } + } + iVariantFileLists[vIndex]->Add(variant); + for (i=0; iiNumberOfExtensions; i++) + { + TRomBuilderEntry *ext=iObey->iExtensions[i]; + if (v<=ext->iHardwareVariant) + { + iVariantFileLists[vIndex]->Add(ext); + } + } + for (i=0; iiNumberOfDevices; i++) + { + TRomBuilderEntry *dev=iObey->iDevices[i]; + if (v<=dev->iHardwareVariant) + { + iVariantFileLists[vIndex]->Add(dev); + } + } + } + TUint totalDataBss=0; + for (vIndex=0; vIndexiNumberOfVariants; vIndex++) + { + TRomBuilderEntry *variant=iObey->iVariants[vIndex]; + THardwareVariant& v=variant->iHardwareVariant; + COrderedFileList& files=*iVariantFileLists[vIndex]; + TInt count=files.Count(); + Print(ELog,"\nVariant %08x, %d Files:\n",v.ReturnVariant(),count); + TInt i; + TUint dataOffset=0; + for (i=0; iiDataAlignment>0) + { + gap=(pF->iDataAlignment-dataOffset)%(pF->iDataAlignment); + dataOffset+=gap; + } + E32ImageHeader *pH=pF->iHdr; + if (pF->iDataBssOffset!=0xffffffff && pF->iDataBssOffset!=dataOffset) + Print(EError,"Conflicting DataBss addresses\n"); + pF->iDataBssOffset=dataOffset; + TInt dataSize=AlignData(pH->iDataSize+pH->iBssSize); + const TText* pT=FileTypeFile; + if (pF->Primary()) + pT=FileTypePrimary; + if (pF->Variant()) + pT=FileTypeVariant; + if (pF->Extension()) + pT=FileTypeExtension; + if (pF->Device()) + pT=FileTypeDevice; + Print(ELog,"%s %12s[%08x] DataSize=%6x DataOffset=%6x",pT,pF->iName,pF->iHardwareVariant.ReturnVariant(),dataSize,dataOffset); + if (gap) + Print(ELog, " (gap %x for %x alignment)\n", gap, pF->iDataAlignment); + Print(ELog, "\n"); + dataOffset+=dataSize; + } + if (dataOffset>totalDataBss) + totalDataBss=dataOffset; + } + Print(ELog,"\nTotal SvData size=%6x\n",totalDataBss); + iTotalSvDataSize=totalDataBss; + } + +TInt E32Rom::LoadDataToRom(TRomBuilderEntry *aFile, TAddressRange& aAddress, CBytePair* aBPE) +// +// Load a data file to rom +// + { + const char* tn = "resource"; + if (aFile->iNonXIP) + tn = (aFile->iCompression) ? "compressed executable" : "uncompressed executable"; + Print(ELog,"Reading %s %s to rom linear address %08x\n", tn, aFile->iFileName, aAddress.iImageAddr); + + TUint32 size=HFile::GetLength((TText*)aFile->iFileName); + if (size==0) + { + Print(EWarning, "File %s does not exist or is 0 bytes in length.\n",aFile->iFileName); + return size; + } + + aFile->iHeaderRange=aAddress; + char* addr = (char*)aFile->iHeaderRange.iImagePtr; + const char* src = NULL; + #ifdef __TOOLS2__ + ostringstream os; + #else + ostrstream os; + #endif + if (aFile->iNonXIP) + { + E32ImageFile f(aBPE); + TInt r = f.Open(aFile->iFileName); + // is it really a valid E32ImageFile? + if (r != KErrNone) + { + Print(EWarning, "File '%s' is not a valid executable. Loading file as data.\n", aFile->iFileName); + aFile->iNonXIP = EFalse; + } + else + { + TUint compression = f.iHdr->CompressionType(); + if (compression != aFile->iCompression || aFile->iPreferred) + { + if (compression == 0) + Print(ELog, "Compressing file %s\n", aFile->iFileName); + else if (aFile->iCompression == 0) + Print(ELog, "Decompressing file %s\n", aFile->iFileName); + f.iHdr->iCompressionType = aFile->iCompression; + if (aFile->iPreferred) + { + f.iHdr->iModuleVersion &= ~0xffffu; + f.iHdr->iModuleVersion |= 0x8000u; + } + f.UpdateHeaderCrc(); + } + Print(ELog, "Compression Method:0x%08x/0x%08x \n", f.iHdr->CompressionType(), aFile->iCompression); + os << f; + #ifdef __TOOLS2__ + size = (os.str()).length(); + src = (os.str()).c_str(); + #else + size = os.pcount(); + src = os.str(); + #endif + } + } + if (addr+size>iData+iSize) + { + Print(EError, "Can't fit '%s' in Rom.\n", aFile->iFileName); + Print(EError, "Rom overflowed by approximately 0x%x bytes.\n", RequiredSize()-iObey->iRomSize); + exit(667); + } + if (src) + memcpy(addr, src, size); + else + size = HFile::Read((TText*)aFile->iFileName, (TAny *)addr); + Print(ELog,"Size: %08x\n", size); + + aFile->iHeaderRange.iSize=size; + aAddress.Extend(aFile->iHeaderRange.iSize); + return size; + } + + +void E32Rom::CalculateDataAddresses() +// +// +// + { + + TInt i; + TUint32 maxkern = 0; + Print(ELog, "\nCalculating kernel limit.\n"); + for (i=0; iiNumberOfPeFiles; i++) + { + TRomBuilderEntry* e = iPeFiles[i]; + if (e->Primary()) + { + // this is a kernel + TUint32 stack = AlignToPage(e->iHdr->iStackSize); + TUint32 heap = AlignToPage(e->iHdr->iHeapSizeMax); + if (stack + heap > maxkern) + maxkern = stack + heap; + } + } + iObey->iKernelLimit = AlignToChunk(maxkern + iTotalSvDataSize) + iObey->iKernDataRunAddress; + if (iObey->iMemModel==E_MM_Direct) + iNextDataChunkBase=iObey->iDataRunAddress; + else + iNextDataChunkBase = iObey->iKernelLimit; + Print(ELog, "\nCalculating data addresses.\n"); + for (i=0; iiNumberOfPeFiles; i++) + { + TRACE(TAREA,Print(ELog,"CalculateDataAddresses %d %s\n",i,iPeFiles[i]->iFileName)); + CalculateDataAddress(iPeFiles[i]); + } + TRACE(TIMPORT,Print(ELog,"CalculateDataAddresses complete\n")); + + // On moving model, advance kernel limit past fixed process data areas + if (iObey->iMemModel==E_MM_Moving) + iObey->iKernelLimit = iNextDataChunkBase; + } + +void E32Rom::CalculateDataAddress(TRomBuilderEntry *aFile) +// +// Work out where the .data/.bss will be +// + { + TUint32 dataBssSize=aFile->iRomNode->iRomFile->iTotalDataBss; + TUint32 dataRunAddr; + if (aFile->Primary()) + { + dataRunAddr = iObey->iKernDataRunAddress; + CPU = aFile->iHdr->CpuIdentifier(); + } + else + { + dataRunAddr = iObey->iDataRunAddress; + if (iObey->iMemModel!=E_MM_Multiple && iObey->iMemModel!=E_MM_Flexible && (aFile->iHdr->iFlags & KImageFixedAddressExe)) // propagate 'fixed' from PETRAN + { + dataRunAddr=0xffffffff; + } + } + if (aFile->iOverrideFlags&KOverrideAddress) + { + if ((iObey->iMemModel!=E_MM_Multiple && iObey->iMemModel!=E_MM_Flexible) || aFile->iRelocationAddress!=0xffffffff) + dataRunAddr=aFile->iRelocationAddress; + if (aFile->Extension() || aFile->Variant() || aFile->Device()) + Print(EError, "reloc not permitted with extension/variant/device\n"); + } + if (!aFile->IsDll() && !aFile->Primary() && (dataRunAddr==0xffffffff || iObey->iMemModel==E_MM_Direct)) + { + dataRunAddr=iNextDataChunkBase; + TInt stackreserve=iObey->iDefaultStackReserve; + if (aFile->iOverrideFlags & KOverrideStackReserve) + stackreserve=aFile->iStackReserve; + TInt datsize=AlignToChunk(dataBssSize+stackreserve); + // Move target data address to next free chunk + iNextDataChunkBase+=datsize; + } + if (aFile->Extension() || aFile->Device() || aFile->Variant()) + { + dataRunAddr=iObey->iKernDataRunAddress+aFile->iDataBssOffset; + } + else if (aFile->IsDll() && dataBssSize!=0 && aFile->iRomNode->iRomFile->iDataBssOffsetInExe<0) + { + iNextDllDataAddr = AllocVirtual(iNextDllDataAddr,dataBssSize); + dataRunAddr=iNextDllDataAddr; + } + if (iObey->iMemModel==E_MM_Moving && dataRunAddr==iObey->iDataRunAddress && aFile->Secondary()) + { + Print(EWarning,"Secondary not fixed\n"); + } + + TRACE(TAREA, Print(ELog, "Data run address %08x\n", dataRunAddr)); + aFile->iDataBssLinearBase=dataRunAddr; + } + +void E32Rom::LoadFileToRom(TRomBuilderEntry *aFile) +// +// Load an E32Image/PE file to rom +// + { + + char* addr = (char*)aFile->iHeaderRange.iImagePtr; + TRACE(TAREA, Print(ELog,"+LoadFileToRom addr %08x %08x %08x\n", addr, + aFile->iHeaderRange.iImageAddr, aFile->iHeaderRange.iRunAddr)); + + if (addr+aFile->SizeInRom()>iData+iSize) // check this + { + Print(EError, "Can't fit '%s' in Rom.\n", aFile->iFileName); + Print(EError, "Rom overflowed by approximately 0x%x bytes.\n", RequiredSize()-iObey->iRomSize); + exit(666); + } + + // check file will not overflow into next ROM + if (aFile->Primary()) + { + if (!iPrevPrimaryAddress) + iHeader->iPrimaryFile=ActualToRomAddress(aFile->RomEntry()); + else if (iObey->iKernelModel==EMultipleKernels) + { + ((TRomImageHeader*)iPrevPrimaryAddress)->iNextExtension=ActualToRomAddress(aFile->RomEntry()); + } + iPrevPrimaryAddress=addr; + TRACE(TAREA, Print(ELog, "iHeader->iPrimaryFile = %08x\n", iHeader->iPrimaryFile)); + } + + // Place the file in rom + if (aFile->Variant()) + { + if (iPrevVariantAddress) + ((TRomImageHeader*)iPrevVariantAddress)->iNextExtension=ActualToRomAddress(aFile->RomEntry()); + else + iHeader->iVariantFile=ActualToRomAddress(aFile->RomEntry()); + iPrevVariantAddress=addr; + } + if (aFile->IsDll() && aFile->iRomNode->iRomFile->iTotalDataBss!=0 && aFile->iRomNode->iRomFile->iDataBssOffsetInExe>=0) + { + TRomFile* f=aFile->iRomNode->iRomFile->iPDeps[0]; // attach process + aFile->iDataBssLinearBase = f->DataBssLinearBase() + aFile->iRomNode->iRomFile->iDataBssOffsetInExe; + } + + aFile->LoadToRom(); + } + +char *E32Rom::LayoutRom(char *romaddr) +// +// Layout the files from the obey file starting at romaddr in the image +// dealing correctly with areas +// Also deals with two section ROMs +// + { + + TAddressRange main; + TAddressRange* mainptr=&main; + SetImageAddr(main, romaddr); + + TAddressRange second; + TAddressRange* secondptr=0; + if (iObey->iSectionStart != 0) + { + SetImageAddr(second,iSectionPtr); + secondptr = &second; + } + + TInt fileCount=0; + + // + // Process files in non default areas + // + + CBytePair bpe(gFastCompress); + for (NonDefaultAreasIterator areaIt(iObey->SetArea()); + ! areaIt.IsDone(); + areaIt.GoToNext()) + { + Area& currentArea = areaIt.Current(); + currentArea.SetSrcBaseAddr(mainptr->iImageAddr); + + mainptr->iRunAddr = currentArea.DestBaseAddr(); + + for (FilesInAreaIterator fileIt(currentArea); + ! fileIt.IsDone(); + fileIt.GoToNext()) + { + TRomBuilderEntry* currentFile = fileIt.Current(); + + LayoutFile(currentFile, *mainptr, secondptr, &bpe); + + TUint overflow; + if (! currentArea.ExtendSrcLimitAddr(mainptr->iImageAddr, overflow)) + { + Print(EError, "Can't fit '%s' in area '%s'\n", currentFile->iFileName, currentArea.Name()); + Print(EError, "Area overflowed by 0x%x bytes.\n", overflow); + exit(666); + } + + ++fileCount; + assert(iObey->iSectionPosition == -1 || fileCount < iObey->iSectionPosition); + } + + TInt offset=(char*)mainptr->iImagePtr-romaddr; + mainptr->Extend(Align(offset)-offset); + } // for every non default area + + + // + // Process files in default area + // + + mainptr->iRunAddr = mainptr->iImageAddr; + + for (FilesInAreaIterator fileIt(*(iObey->SetArea().DefaultArea())); + ! fileIt.IsDone(); + fileIt.GoToNext()) + { + if (fileCount==iObey->iSectionPosition) + { + // skip rest of first section and pick up after the + // information already accumulated in the second section + NextRom(mainptr, secondptr); + mainptr = secondptr; + secondptr = 0; + } + + LayoutFile(fileIt.Current(), *mainptr, secondptr, &bpe); + + ++fileCount; + } + + // align to likely position of next file + TInt offset=(char*)mainptr->iImagePtr-romaddr; + offset = Align(offset)-offset; + mainptr->Extend(offset); + iOverhead +=offset; + + return (char*)mainptr->iImagePtr; + } + +void E32Rom::LayoutFile(TRomBuilderEntry* current, TAddressRange& aMain, TAddressRange* aSecond, CBytePair * aBPE) +// +// Work out where to place a file in ROM and set up the +// appropriate TAddressRange information +// + { + TInt alignment = iObey->iRomAlign; + if (current->iAlignment > alignment) + alignment = current->iAlignment; + + if (alignment) + { + // Align this file on a boundary + TUint32 romaddr=aMain.iRunAddr; + TInt i=romaddr & (alignment-1); + TInt gap=0; + if (i!=0) + gap=alignment-i; + if (current->iAlignment) + Print(ELog, "\nAlign to %08x. Skipped %d bytes\n", romaddr+gap, gap); + aMain.Extend(gap); + iOverhead += gap; + } + + if (current->iCodeAlignment != 0) + { + TUint32 runaddr=aMain.iRunAddr + sizeof(TRomImageHeader); + TInt i=runaddr & (current->iCodeAlignment-1); + TInt gap=0; + if (i!=0) + gap=current->iCodeAlignment-i; + Print(ELog, "\nCode Align to %08x. Skipped %d bytes\n", runaddr+gap, gap); + aMain.Extend(gap); + iOverhead += gap; + } + + Print(ELog,"\n********************************************************************\n"); + + if (current->iPatched) + Print(ELog, "[Patched file]\n"); + + if (current->iResource) + { + TInt size=LoadDataToRom(current, aMain, aBPE); + if (aSecond != 0 && aMain.iImageAddr > iObey->iSectionStart) + return; // first section has overflowed + current->FixupRomEntries(size); + return; + } + if(current->HCRDataFile()){ + TInt size=LoadDataToRom(current, aMain, aBPE); + if (aSecond != 0 && aMain.iImageAddr > iObey->iSectionStart) + return; // first section has overflowed + current->FixupRomEntries(size); + iHeader->iHcrFileAddress = current->iHeaderRange.iImageAddr ; + TRACE(TAREA, Print(ELog, "iHeader->iHcrFileAddress = %08x\n", iHeader->iHcrFileAddress)); + return ; + } + Print(ELog,"Processing file %s\n",current->iFileName); + + if (current->Primary()) + { + Print(ELog, "[Primary]\n"); + } + + if (current->Secondary()) + { + iHeader->iSecondaryFile=ActualToRomAddress(current->RomEntry()); + Print(ELog, "[Secondary]\n"); + } + + // Section 1 things + // + // TRomImageHeader, text, export directory, data + + aMain.Append(current->iHeaderRange); + aMain.Append(current->iCodeSection); + aMain.Append(current->iDataSection); + + // section 2 things + // + // dll ref table + + if (aSecond != 0) + { + // two section ROM - split image between both sections + aSecond->Append(current->iExportDirSection); + aSecond->Append(current->iDllRefTableRange); + } + else + { + // default placement in first section + aMain.Append(current->iExportDirSection); + aMain.Append(current->iDllRefTableRange); + } + + TInt section1size = aMain.iRunAddr-current->iCodeSection.iRunAddr; + + if (aMain.iRunAddr == aMain.iImageAddr) + { + Print(ELog, "Load Address: %08x\n", current->iHeaderRange.iImageAddr); + } + else + { + Print(ELog, "Rom Address: %08x\n", current->iHeaderRange.iImageAddr); + Print(ELog, "Area Address: %08x\n", current->iHeaderRange.iRunAddr); + } + Print(ELog, "Size: %08x\n", section1size); + + if (aSecond != 0 && aMain.iImageAddr > iObey->iSectionStart) + return; // first section has overflowed + + LoadFileToRom(current); + Display(current->iRomImageHeader); + Print(ELog, "Dll ref table size: %08x\n", current->iDllRefTableRange.iSize); + Print(ELog, "Compression: %08x\n", current->iCompression); + Print(ELog, "\n"); + + current->FixupRomEntries(section1size); + } + +static int CompareAddresses(const void * arg1, const void * arg2) + { + return (* (TUint32 *)arg1) < (* (TUint32 *)arg2) ? -1: 1; + } + +char *E32Rom::ReserveRomExceptionSearchTable(char *anAddr, TRomExceptionSearchTable*& exceptionSearchTable) + { + TRomExceptionSearchTable *pT = (TRomExceptionSearchTable *)anAddr; + exceptionSearchTable = pT; + if (iExtensionRomHeader) + { + iExtensionRomHeader->iRomExceptionSearchTable = ActualToRomAddress(anAddr); + } + else + { + iHeader->iRomExceptionSearchTable = ActualToRomAddress(anAddr); + } + TLinAddr * addr = &pT->iEntries[0]; + int numEntries = 0; + int errors = 0; + // Count number of entries needed + for (int i = 0; i < iObey->iNumberOfPeFiles; i++) + { + TUint32 xd = iPeFiles[i]->iHdr->iExceptionDescriptor; + if ((xd & 1) && (xd != 0xffffffffu)) + { + numEntries++; + } + else if (!iPeFiles[i]->iHdr->iExceptionDescriptor) + { +#ifdef __REJECT_NON_EXCEPTION_AWARE_BINARIES__ + Print(EError, "Executable not exception aware: %s\n", iPeFiles[i]->iName); + errors++; +#else + Print(ELog, "Executable not exception aware: %s\n", iPeFiles[i]->iName); +#endif + } + } + if (errors > 0) exit(666); + // NB we add one to numEntries to allow space for a fencepost value (see below for more) + int spaceNeeded = sizeof(pT->iNumEntries) + sizeof(pT->iEntries[0])*(numEntries+1); + int delta = (int)(addr+spaceNeeded) - (int)(iData+iSize); + // Check we've got enough room + if (delta > 0) + { + Print(EError, "Can't fit Rom Exception Search Table in Rom.\n"); + Print(EError, "Rom overflowed by approximately 0x%x bytes.\n", delta); + exit(666); + } + pT->iNumEntries = numEntries; + return anAddr+spaceNeeded; + } + +void E32Rom::ConstructRomExceptionSearchTable(TRomExceptionSearchTable* exceptionSearchTable) + { + TRomExceptionSearchTable *pT = exceptionSearchTable; + TLinAddr * addr = &pT->iEntries[0]; + // Initialize the table + int numEntries = pT->iNumEntries; + TLinAddr fencepost = 0xffffffff; + if (numEntries) + { + TLinAddr fp = 0; + for (int j = 0; j < iObey->iNumberOfPeFiles; j++) + { + TUint32 xd = iPeFiles[j]->iHdr->iExceptionDescriptor; + if ((xd & 1) && (xd != 0xffffffff)) + { + // mask out bottom bit set by ELFTRAN. + xd &= ~1; + *addr++ = iPeFiles[j]->iHdr->iCodeBase; + TLinAddr aEDAddr = iPeFiles[j]->iHdr->iCodeBase + xd; + // Keep track of greatest code limit so we can use it as the fencepost value + TExceptionDescriptor * aEDp = (TExceptionDescriptor *)RomToActualAddress(aEDAddr); + TLinAddr codeLimit = aEDp->iROSegmentLimit; + if (codeLimit>fp) fp=codeLimit; + } + } + if (fp) fencepost=fp; + // now check they're in order (they should be). + int inOrder = 1; + for (int k=numEntries-1;inOrder && k; k--) + { + inOrder = pT->iEntries[k]>pT->iEntries[k-1]?1:0; + } + + if (!inOrder) + { + Print(ELog, "Sorting Rom Exception Table.\n"); + qsort(&pT->iEntries[0],numEntries,sizeof(pT->iEntries[0]), CompareAddresses); + } + } + /* + Add the fencepost value at the end of the table. This is used to optimize the comparison + function passed to bsearch when retrieving values from the search table. It also allows a certain + amount of error checking on lookup keys. + */ + *addr++ = fencepost; + } + +void TRomBuilderEntry::SizeInSections(TInt& aSize1, TInt& aSize2) +// +// Exact size of the upper & lower section information +// lower = text + data +// upper = export directory + dllref table +// + { + aSize1 = iHeaderRange.iSize; + aSize1 += iCodeSection.iSize; // text (including rdata) + aSize1 += iDataSection.iSize; // static data + + aSize2 = iExportDirSection.iSize; // export directory + aSize2 += iDllRefTableRange.iSize; // DLL ref table + } + + +void E32Rom::NextRom(TAddressRange* aFirst, TAddressRange* aSecond) +// +// Move on to the next Rom bank, taking the IATs with us +// + { + + Print(ELog,"\n####################################################################\n"); + TInt gap=iObey->iSectionStart-aFirst->iImageAddr; + if (gap<0) + { + Print(EError, "First section overflowed by %08x bytes\n", -gap); + exit(669); + } + iOverhead+=gap+sizeof(TRomSectionHeader); + Print(ELog, "[Next rom section]\n"); + Print(ELog, "Skipping %08x bytes\n", gap); + Print(ELog, "LinAddr: %08x\n", iObey->iSectionStart); + Print(ELog, "First section tables: %08x\n", iObey->iSectionStart+sizeof(TRomSectionHeader)); + TInt size=aSecond->iImageAddr-iObey->iSectionStart; + Print(ELog, "Tables size: %08x\n", size-sizeof(TRomSectionHeader)); + Print(ELog, "Rom Directory %08x\n", iHeader->iRomRootDirectoryList); + Print(ELog, "Rom Directory size %08x\n", iDirectorySize); + + if (aSecond->iImageAddr != iHeader->iRomRootDirectoryList) + { + Print(EError, "Second section has overwritten the Rom directory\n"); + exit(669); + } + aSecond->Extend(iDirectorySize); + + Print(ELog, "\n"); + } + +TInt E32Rom::ResolveDllRefTables() +// +// +// + { + + Print(ELog, "\nResolving Dll reference tables.\n"); + TInt i; + TInt err = KErrNone; + for (i=0; iiNumberOfPeFiles; i++) + { + TRACE(TIMPORT,Print(ELog,"ResolveDllRefTables %d\n",i)); + TInt r=iPeFiles[i]->ResolveDllRefTable(*this); + if (r!=KErrNone) + err=r; + } + TRACE(TIMPORT,Print(ELog,"ResolveDllRefTables complete\n")); + return err; + } + + +TInt E32Rom::BuildDependenceGraph() + { + Print(ELog, "\nBuilding dependence graph.\n"); + TInt i; + TInt err = KErrNone; + for (i=0; iiNumberOfPeFiles; i++) + { + TRACE(TIMPORT,Print(ELog,"BuildDep %d\n",i)); + TRomBuilderEntry* e=iPeFiles[i]; + TInt r=e->BuildDependenceGraph(*this); + if (r!=KErrNone) + err=r; + if (!e->IsDll()) + { + if (e->iHdr->iDataSize!=0 || e->iHdr->iBssSize!=0) + e->iRomImageFlags|=(KRomImageFlagData|KRomImageFlagDataPresent); // EXE with static data + } + else if ((e->iHdr->iDataSize!=0 || e->iHdr->iBssSize!=0) && !e->Variant() && !e->Extension()) + { + // requires normal case DLL data initialisation + e->iRomImageFlags|=(KRomImageFlagData|KRomImageFlagDataInit|KRomImageFlagDataPresent); + } + } + TRACE(TIMPORT,Print(ELog,"BuildDep complete\n")); + + if(!gPagedRom) + return err; + + Print(ELog,"\n"); + + return err; + } + +#define MARK_BEEN_HERE 1 +#define MARK_KEEP 2 +#define MARK_EXE 4 +#define MARK_CHECKED 8 +void E32Rom::UnmarkGraph(TInt aMark) + { + TRomNode* x = 0; + for (x=iObey->iRootDirectory->iNextExecutable; x; x=x->iNextExecutable) + x->iRomFile->iMark &= ~aMark; + } + +void E32Rom::FindMarked(TInt aMarkMask, TInt aMark, TRomFile**& aList) + { + UnmarkGraph(MARK_CHECKED); + TRomNode* x = 0; + aMarkMask |= MARK_CHECKED; + aMark &= ~MARK_CHECKED; + for (x=iObey->iRootDirectory->iNextExecutable; x; x=x->iNextExecutable) + { + TRomFile* e = x->iRomFile; + if ((e->iMark&aMarkMask)==aMark) + { + *aList++=e; + e->iMark |= MARK_CHECKED; + } + } + } + +TInt TRomFile::MarkDeps() + { + TInt n=0; + TInt i; + for (i=0; iiMark & MARK_BEEN_HERE)) + { + e->iMark|=MARK_BEEN_HERE; + ++n; + n+=e->MarkDeps(); + TUint32 flg = RomImageFlags(); + TUint32 eflg = e->RomImageFlags(); + if (eflg & KRomImageFlagDataPresent) + iRbEntry->iRomImageFlags |= KRomImageFlagDataPresent; + TBool e_is_dll = eflg & KImageDll; + if ((flg & KImageDll) && e_is_dll && (eflg & KRomImageFlagDataInit)) + iRbEntry->iRomImageFlags |= KRomImageFlagDataInit; + if (!e_is_dll) + e->iMark|=MARK_EXE; + if (eflg&KRomImageFlagData) + e->iMark|=MARK_KEEP; + } + } + return n; + } + +TInt TRomFile::FindRouteTo(TRomFile* aDest, TRomFile** aStack, TInt aIndex) + { + TInt i; + for (i=0; iiMark & MARK_BEEN_HERE)) + { + e->iMark|=MARK_BEEN_HERE; + aStack[aIndex] = e; + TInt r = e->FindRouteTo(aDest, aStack, aIndex+1); + if (r >= 0) + return r; + } + } + return KErrNotFound; + } + +void E32Rom::ListRouteTo(TRomFile* aStart, TRomFile* aDest, TInt aNDeps) + { + TRomNode* rootdir = iObey->iRootDirectory; + TRomFile** stack = new TRomFile*[aNDeps]; + UnmarkGraph(); + TInt depth = aStart->FindRouteTo(aDest, stack, 0); + assert(depth >= 0); + Print(EAlways, "\t--->%s\n", (const char*)TModuleName(*aDest, rootdir)); + while(--depth >= 0) + Print(EAlways, "\tvia %s\n", (const char*)TModuleName(*stack[depth], rootdir)); + delete[] stack; + } + +TInt E32Rom::ProcessDependencies() + { + TInt i; + TInt errors = 0; + for (i=0; iiNumberOfPeFiles; i++) + { + TRomBuilderEntry* e=iPeFiles[i]; + TRomNode* rn = e->iRomNode; + TRomFile* rf = rn->iRomFile; + UnmarkGraph(); + TInt n=rf->MarkDeps(); + rf->iNumPDeps=n; + if (n) + { + rf->iPDeps=new TRomFile* [n]; + if (!rf->iPDeps) + return KErrNoMemory; + TRomFile** l=rf->iPDeps; + FindMarked(MARK_EXE, MARK_EXE, l); + TInt nx=l-rf->iPDeps; + if (!e->IsDll() && (nx>1 || (nx==1 && l[-1]!=rf))) + { + Print(EError,"EXE %s links to the following other EXEs:\n", e->iFileName); + TInt j; + for (j=0; jiPDeps[j] != rf) + ListRouteTo(rf, rf->iPDeps[j], n); + } + ++errors; + continue; + } + else if (nx>1) + { + Print(EError,"DLL %s links to more than one EXE:\n",e->iFileName); + TInt j; + for (j=0; jiPDeps[j], n); + ++errors; + continue; + } + if (nx) + e->iRomImageFlags|=KRomImageFlagExeInTree; + FindMarked(MARK_KEEP|MARK_EXE, MARK_KEEP, l); + rf->iNumPDeps=l-rf->iPDeps; + if (rf->iNumPDeps) + { + e->iDllRefTableRange.iSize=(rf->iNumPDeps-1)*sizeof(TRomImageHeader*)+sizeof(TDllRefTable); + if (e->IsDll() && rf->iTotalDataBss) + { + TRomFile* f=rf->iPDeps[0]; // first dependency, EXE if there is one + TUint fflg = f->RomImageFlags(); + TBool f_is_dll = fflg & KImageDll; + if (!f_is_dll) + { + // DLL with data/bss depends on EXE + if ((fflg & KRomImageFlagFixedAddressExe) || iObey->iMemModel==E_MM_Direct) + { + // assign the DLL data address in the EXE bss section + rf->iDataBssOffsetInExe=f->iTotalDataBss; + f->iTotalDataBss+=rf->iTotalDataBss; + } + } + else if (iObey->iMemModel==E_MM_Direct) + { + Print(EError, "DLL with data/bss must have attach process specified\n"); + return KErrGeneral; + } + } + } + else + { + delete[] rf->iPDeps; + rf->iPDeps=NULL; + } + } + if (!rf->iNumPDeps) + e->iDllRefTableRange.iSize=0; + } + if (iObey->iMemModel == E_MM_Moving) + { + // On moving model only, we must verify that no fixed process links to a + // DLL with data/bss which is attached to a fixed process. + // On multiple model there is no restriction. + // On direct model all DLLs with data/bss must specify an attach process + // and the error will show up as one EXE depending on another. + for (i=0; iiNumberOfPeFiles; i++) + { + TRomBuilderEntry* e=iPeFiles[i]; + TRomNode* rn = e->iRomNode; + TRomFile* rf = rn->iRomFile; + TUint rif = rf->RomImageFlags(); + if (e->IsDll() || e->Primary() || !(rif & KRomImageFlagFixedAddressExe)) + continue; // only need to check fixed address user mode EXEs + TInt n = rf->iNumPDeps; + TInt j; + for (j=0; jiPDeps[j]; + TUint fflg = f->RomImageFlags(); + if ((fflg & KImageDll) && (f->iDataBssOffsetInExe < 0)) + { + // fixed user EXE links to DLL with data/bss and no attach process + Print(EError,"Fixed EXE %s links to DLL with data/bss and no attach process:\n", e->iFileName); + ListRouteTo(rf, rf->iPDeps[j], n); + ++errors; + } + } + } + } + if (errors) + return KErrGeneral; + + STRACE(TIMPORT, + { + for (i=0; iiNumberOfPeFiles; i++) + { + TRomBuilderEntry* e=iPeFiles[i]; + TRomNode* rn = e->iRomNode; + TRomFile* rf = rn->iRomFile; + Print(ELog,"File %s: PN=%d\n",e->iFileName,rf->iNumPDeps); + TInt j; + for (j=0; jiNumPDeps; ++j) + { + TRomFile* f=rf->iPDeps[j]; + Print(ELog,"\t%s\n", (const char*)TModuleName(*f, iObey->iRootDirectory)); + } + } + }) + return KErrNone; + } + +void E32Rom::SetSmpFlags() + { + if (gLogLevel & LOG_LEVEL_SMP_INFO) + { + Print(ELog,"\nComputing SMP properties. The following components are SMP-unsafe:\n"); + } + + bool is_all_safe = 1; + + for (int i = 0; i < iObey->iNumberOfPeFiles; i++) + { + TRomBuilderEntry* e = iPeFiles[i]; + + if ( e->iRomNode->iRomFile->ComputeSmpSafe(e) ) + { + e->iRomImageFlags |= KRomImageSMPSafe; + } + else + { + is_all_safe = 0; + e->iRomImageFlags &= ~KRomImageSMPSafe; + } + } + + if ( (gLogLevel & LOG_LEVEL_SMP_INFO) && is_all_safe) + { + Print(ELog,"There are no unsafe components."); + } + } + +TInt E32Rom::ResolveImports() +// +// Fix the import address table for each of the files in rom +// + { + + Print(ELog, "Resolving Imports.\n"); + TInt i; + for (i=0; iiNumberOfPeFiles; i++) + { + TInt r=iPeFiles[i]->FixupImports(*this); + if (r!=KErrNone) + return r; + } + return KErrNone; + } + +char *E32Rom::RomToActualAddress(TUint aPtr) + { + return (char *)(aPtr-iObey->iRomLinearBase+(TUint)iHeader); + } + +TUint E32Rom::ActualToRomAddress(TAny *aPtr) + { + return ((TUint)aPtr)-(TUint32)iHeader+iObey->iRomLinearBase; + } + +void E32Rom::SetImageAddr(TAddressRange& aRange, TAny* aPtr, TUint32 aRunOffset) + { + aRange.iImagePtr=aPtr; + aRange.iImageAddr=ActualToRomAddress(aPtr); + aRange.iRunAddr=aRange.iImageAddr+aRunOffset; + } + +void E32Rom::SetImageAddr(TAddressRange& aRange, TUint aAddr, TUint32 aRunOffset) + { + aRange.iImagePtr=RomToActualAddress(aAddr); + aRange.iImageAddr=aAddr; + aRange.iRunAddr=aAddr+aRunOffset; + } + +TRomNode* E32Rom::FindImageFileByName(const TDllFindInfo& aInfo, TBool aPrintDiag, TBool& aFallBack) +// +// return the file with the name aName +// + { + return iObey->iRootDirectory->FindImageFileByName(aInfo, aPrintDiag, aFallBack); + } + +TInt E32Rom::CheckForVersionConflicts(const TRomBuilderEntry* a) + { + return iObey->iRootDirectory->CheckForVersionConflicts(a); + } + +TRomNode* E32Rom::CopyDirectory(TRomNode*& aLastExecutable) + { + return iObey->iRootDirectory->CopyDirectory(aLastExecutable, 0); + } + +TInt E32Rom::CollapseImportThunks() +// +// Collapse 3-word import thunks into a single branch +// + { + + Print(ELog, "\nCollapsing Import Thunks.\n"); + TInt i; + for (i=0; iiNumberOfPeFiles; i++) + { + if (iPeFiles[i]->iHdr->iImportOffset) + { + TInt r=CollapseImportThunks(iPeFiles[i]); + if (r!=KErrNone) + return r; + } + } + return KErrNone; + } + +TInt E32Rom::WriteImages(TInt aHeaderType) + { + if (aHeaderType < 0) + aHeaderType = 1; + 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(); + + // Write out the odd/even 16-bits of the images + + char sname[256]; + if (iObey->iRomOddFileName) + { + strcpy(sname, (const char*)iObey->iRomOddFileName); + if (strcmp(sname, "*")==0) + { + // use romname with ".odd" appended. + sprintf(sname,"%s.odd",(const char *)iObey->iRomFileName); + } + ofstream oFile(sname,ios::binary); + if (!oFile) + return Print(EError,"Cannot open file %s for output\n",sname); + Print(EAlways, "Writing odd half words to file %s\n",sname); + WriteOdd(oFile); + oFile.close(); + } + if (iObey->iRomEvenFileName) + { + strcpy(sname, (const char*)iObey->iRomEvenFileName); + if (strcmp(sname, "*")==0) + { + // use romname with ".even" appended. + sprintf(sname,"%s.even",(const char *)iObey->iRomFileName); + } + ofstream oFile(sname,ios::binary); + if (!oFile) + return Print(EError,"Cannot open file %s for output\n",sname); + Print(EAlways, "Writing even half words to file %s\n",sname); + WriteEven(oFile); + oFile.close(); + } + + // Write out the ROM in the SREC or S19 format + + if (iObey->iSRecordFileName) + { + strcpy(sname, (const char*)iObey->iSRecordFileName); + if (strcmp(sname, "*")==0) + { + // use romname with ".srec" appended. + sprintf(sname,"%s.srec",(const char *)iObey->iRomFileName); + } + ofstream sFile(sname,ios::binary); + if (!romFile) + return Print(EError,"Cannot open file %s for output\n",sname); + Print(EAlways, "Writing S record format to file %s\n",sname); + WriteSRecord(sFile); + sFile.close(); + } + return KErrNone; + } + +void E32Rom::WriteOdd(ofstream &os) + { + char *ptr=(char *)iHeader+2; + TInt i; + for (i=2; iiRomSize; i+=4, ptr+=4) + os.write(ptr, 2); + } + +void E32Rom::WriteEven(ofstream &os) + { + char *ptr=(char *)iHeader; + TInt i; + for (i=0; iiRomSize; i+=4, ptr+=4) + os.write(ptr, 2); + } + +void E32Rom::SetCompressionInfo(TUint aCompressionType, TUint aCompressedSize, TUint aUncompressedSize) + { + + if (iExtensionRomHeader) + { + iExtensionRomHeader->iCompressionType=aCompressionType; + iExtensionRomHeader->iCompressedSize=aCompressedSize; + iExtensionRomHeader->iUncompressedSize=aUncompressedSize; + } + else + { + iHeader->iCompressionType=aCompressionType; + iHeader->iCompressedSize=aCompressedSize; + iHeader->iUncompressedSize=aUncompressedSize; + } + } + +void E32Rom::Write(ofstream &os, TInt aHeaderType) +// +// Output a rom image +// + { + + const char *compressed=gEnableCompress ? " compressed" : " uncompressed"; + + switch (aHeaderType) + { + case 0: + Print(EAlways, "\nWriting%s Rom image without",compressed); + break; + case 1: + default: + Print(EAlways, "\nWriting%sRom image with repro",compressed); + os.write(iData, sizeof(TRomLoaderHeader)); + break; + case 2: + Print(EAlways, "\nWriting%s Rom image with PE-COFF",compressed); + { + 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); + + iHeader->iUnpagedCompressedSize = 0; + iHeader->iUnpagedUncompressedSize = iHeader->iPageableRomStart; + iHeader->iCompressedUnpagedStart = gBootstrapSize + gPageIndexTableSize; // AttilaV calculate uncompressed un-paged size + + if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO) + { + Print(ELog, "iUnpagedCompressedSize :0x%08x (%d)\n", iHeader->iUnpagedCompressedSize); + Print(ELog, "iUnpagedUncompressedSize:0x%08x (%d)\n\n", iHeader->iUnpagedUncompressedSize); + + Print(ELog, "iExtensionRomHeader :%d\n", iExtensionRomHeader); + Print(ELog, "iCompressionType :0x%08x\n", (iExtensionRomHeader ? iExtensionRomHeader->iCompressionType : iHeader->iCompressionType )); + Print(ELog, "iCompressedSize :0x%08x (%d)\n", (iExtensionRomHeader ? iExtensionRomHeader->iCompressedSize : iHeader->iCompressedSize ), (iExtensionRomHeader ? iExtensionRomHeader->iCompressedSize : iHeader->iCompressedSize )); + Print(ELog, "iUncompressedSize :0x%08x (%d)\n\n", (iExtensionRomHeader ? iExtensionRomHeader->iUncompressedSize: iHeader->iUncompressedSize ), (iExtensionRomHeader ? iExtensionRomHeader->iUncompressedSize: iHeader->iUncompressedSize )); + + Print(ELog, "iPageableRomStart :0x%08x (%d)\n", iHeader->iPageableRomStart, iHeader->iPageableRomStart ); + Print(ELog, "iPageableRomSize :0x%08x (%d)\n", iHeader->iPageableRomSize, iHeader->iPageableRomSize ); + Print(ELog, "iRomPageIndex :0x%08x (%d)\n", iHeader->iRomPageIndex, iHeader->iRomPageIndex ); + + Print(ELog, "iSizeUsed :0x%08x (%d)\n", iSizeUsed, iSizeUsed ); + Print(ELog, "Linear base address :0x%08x\n",iHeader->iRomBase); + Print(ELog, "Size: 0x%08x\n",iHeader->iRomSize); + } + + if ( gPagedRom && gCompressUnpaged) + { + if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO) + Print(ELog, "Write out compressed un-paged and paged sections\n\n"); + ImpTRomHeader* header = (ImpTRomHeader *)iHeader; + + if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO) + { + Print(ELog, "Header:\n"); + header->Display(); + } + + streampos headerpos=os.tellp(); + + // Write out uncompressed un-paged part (bootstrap + Page Index Table) + os.write((char *)(iHeader), iHeader->iCompressedUnpagedStart); + + // write out the compressed unpaged part + int srcsize=iHeader->iPageableRomStart - iHeader->iCompressedUnpagedStart; + + int rawimagelen=DeflateCompressCheck(((char *)iHeader)+iHeader->iCompressedUnpagedStart,srcsize,os); + iHeader->iUnpagedCompressedSize = rawimagelen; + iHeader->iUnpagedUncompressedSize = srcsize ; + + // align to 4kbyte boundary if neccessary + TUint32 distanceFrom4kBoundary = ((~(iHeader->iCompressedUnpagedStart + rawimagelen /*+ sizeof(TRomLoaderHeader)*/ )) & 0xfff) + 1; + if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO) + Print(ELog, "distanceFrom4kBoundary :0x%08x (%d)\n", distanceFrom4kBoundary, distanceFrom4kBoundary); + char filer[0x1000]; + memset( filer, 0, 0x1000); + os.write((char *)filer, distanceFrom4kBoundary); + + + // write out the paged part + os.write((char *)iHeader + iHeader->iPageableRomStart, ALIGN4K(iSizeUsed - iHeader->iPageableRomStart)); + + // update size and compression information of paged-part + SetCompressionInfo(KUidCompressionDeflate, ALIGN4K(iSizeUsed), ALIGN4K(iUncompressedSize)); + + // Calculate starting index of the Pageable Rom Start + if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO) + { + Print(ELog, "iPageableRomStart : %d (0x%08x)\n", iHeader->iPageableRomStart, iHeader->iPageableRomStart); + Print(ELog, "iCompressedUnpagedStart : %d (0x%08x)\n", iHeader->iCompressedUnpagedStart, iHeader->iCompressedUnpagedStart); + Print(ELog, "rawimagelen : %d (0x%08x)\n", rawimagelen, rawimagelen); + } + + TInt displacement = iHeader->iCompressedUnpagedStart + rawimagelen + distanceFrom4kBoundary; + if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO) + Print(ELog, "new iPageableRomStart : %d (0x%08x)\n", (iHeader->iCompressedUnpagedStart + rawimagelen + distanceFrom4kBoundary), (iHeader->iCompressedUnpagedStart + rawimagelen + distanceFrom4kBoundary)); + displacement = iHeader->iPageableRomStart-displacement; + if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO) + Print(ELog, "displacement : %d (0x%08x)\n", displacement, displacement); + + SRomPageInfo* pi = (SRomPageInfo*)((TInt)iHeader+iHeader->iRomPageIndex); + if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO) + Print(ELog, "First Pageable page info[0x%08x]:(iDataStart:0x%08x, iDataSize:0x%08x (%d))\n\n", pi, pi->iDataStart, pi->iDataSize, pi->iDataSize); + + TInt startPageableIndex = (iHeader->iPageableRomStart) / (iObey->iPageSize); + if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO) + { + Print(ELog, "iObey->iPageSize : %d (0x%08x)\n", iObey->iPageSize, iObey->iPageSize); + Print(ELog, "startPageableIndex : %d (0x%08x)\n", startPageableIndex, startPageableIndex); + } + pi += startPageableIndex; + + + while ( 0 != pi->iDataStart) + { + if (H.iVerbose) Print(ELog, "\t\tinfo[0x%08x]:(iDataStart:0x%08x, iDataSize:0x%08x (%d))\n\n", pi, pi->iDataStart, pi->iDataSize, pi->iDataSize); + + pi->iDataStart -= displacement; + + if (H.iVerbose) Print(ELog, "\t\tinfo[0x%08x]:(iDataStart:0x%08x, iDataSize:0x%08x (%d))\n\n", pi, pi->iDataStart, pi->iDataSize, pi->iDataSize); + + ++pi; + } + + + + // Rewrite the header with updated info + #ifdef __TOOLS2__ + os.seekp(headerpos); + #else + os.seekp(headerpos,ios::beg); + #endif + + // Rewrite uncompressed un-paged part (bootstrap + Page Index Table) + os.write((char *)(iHeader), iHeader->iCompressedUnpagedStart); + + + if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO) + { + Print(ELog, "iUnpagedCompressedSize :0x%08x (%d)\n", iHeader->iUnpagedCompressedSize, iHeader->iUnpagedCompressedSize); + Print(ELog, "iUnpagedUncompressedSize:0x%08x (%d)\n\n", iHeader->iUnpagedUncompressedSize, iHeader->iUnpagedUncompressedSize); + + Print(ELog, "iCompressionType :0x%08x\n", (iExtensionRomHeader ? iExtensionRomHeader->iCompressionType : iHeader->iCompressionType )); + Print(ELog, "iCompressedSize :0x%08x (%d)\n", (iExtensionRomHeader ? iExtensionRomHeader->iCompressedSize : iHeader->iCompressedSize ), (iExtensionRomHeader ? iExtensionRomHeader->iCompressedSize : iHeader->iCompressedSize )); + Print(ELog, "iUncompressedSize :0x%08x (%d)\n\n", (iExtensionRomHeader ? iExtensionRomHeader->iUncompressedSize: iHeader->iUncompressedSize ), (iExtensionRomHeader ? iExtensionRomHeader->iUncompressedSize: iHeader->iUncompressedSize )); + + Print(ELog, "iPageableRomStart :0x%08x (%d)\n", iHeader->iPageableRomStart, iHeader->iPageableRomStart ); + Print(ELog, "iPageableRomSize :0x%08x (%d)\n", iHeader->iPageableRomSize, iHeader->iPageableRomSize ); + Print(ELog, "iRomPageIndex :0x%08x (%d)\n", iHeader->iRomPageIndex, iHeader->iRomPageIndex ); + Print(ELog, "\t\tinfo(iDataStart:0x%08x, iDataSize:0x%08x (%d))\n\n", pi->iDataStart, pi->iDataSize, pi->iDataSize); + + Print(ELog, "Linear base address: %08x\n",iHeader->iRomBase); + Print(ELog, "Size: %08x\n",iHeader->iRomSize); + } + + return; + } + + if (!gEnableCompress || gPagedRom || !gCompressUnpaged) + { + if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO) + Print(ELog, "Writeout uncompressed un-paged and paged sections2\n"); + SetCompressionInfo(KFormatNotCompressed, ALIGN4K(iSizeUsed), ALIGN4K(iUncompressedSize)); + iHeader->iUnpagedCompressedSize = ALIGN4K(iSizeUsed); + iHeader->iUnpagedUncompressedSize = ALIGN4K(iUncompressedSize); + + os.write((char *)iHeader, ALIGN4K(iSizeUsed)); + + if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO) + { + Print(ELog, "iUnpagedCompressedSize :0x%08x (%d)\n", iHeader->iUnpagedCompressedSize); + Print(ELog, "iUnpagedUncompressedSize:0x%08x (%d)\n\n", iHeader->iUnpagedUncompressedSize); + + Print(ELog, "iCompressionType :0x%08x\n", (iExtensionRomHeader ? iExtensionRomHeader->iCompressionType : iHeader->iCompressionType )); + Print(ELog, "iCompressedSize :0x%08x (%d)\n", (iExtensionRomHeader ? iExtensionRomHeader->iCompressedSize : iHeader->iCompressedSize ), (iExtensionRomHeader ? iExtensionRomHeader->iCompressedSize : iHeader->iCompressedSize )); + Print(ELog, "iUncompressedSize :0x%08x (%d)\n\n", (iExtensionRomHeader ? iExtensionRomHeader->iUncompressedSize: iHeader->iUncompressedSize ), (iExtensionRomHeader ? iExtensionRomHeader->iUncompressedSize: iHeader->iUncompressedSize )); + + Print(ELog, "iPageableRomStart :0x%08x (%d)\n", iHeader->iPageableRomStart, iHeader->iPageableRomStart ); + Print(ELog, "iPageableRomSize :0x%08x (%d)\n", iHeader->iPageableRomSize, iHeader->iPageableRomSize ); + Print(ELog, "iRomPageIndex :0x%08x (%d)\n", iHeader->iRomPageIndex, iHeader->iRomPageIndex ); + } + + return; + } + + // compressed image without paging section + streampos headerpos=os.tellp(); + int headersize=iExtensionRomHeader ? sizeof(TExtensionRomHeader) : sizeof(TRomHeader); + + os.write(reinterpret_cast(iHeader), headersize); // write a dummy header + // compress the rest of the image + int srcsize=iSizeUsed - headersize; + int rawimagelen=DeflateCompressCheck(((char *)iHeader)+headersize,srcsize,os); + // write the compression info into the header + SetCompressionInfo(KUidCompressionDeflate, rawimagelen, iUncompressedSize); // doesn't need to be 4K aligned + iHeader->iCompressedUnpagedStart = headersize; + iHeader->iUnpagedCompressedSize = rawimagelen; + iHeader->iUnpagedUncompressedSize = srcsize; + + #ifdef __TOOLS2__ + os.seekp(headerpos); + #else + os.seekp(headerpos,ios::beg); + #endif + os.write(reinterpret_cast(iHeader), headersize); // write header again with (compressed) size info + + if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO) + Print(ELog, "\tiSizeUsed:%d, iUncompressedSize:%d, headersize:%d, srcsize:%d, rawimagelen:%d \n",iSizeUsed, iUncompressedSize, headersize, srcsize, rawimagelen); + } + +TInt E32Rom::Compare(char *anImage, TInt aHeaderType) + { + if (aHeaderType < 0) + aHeaderType = 1; + ifstream file(anImage, ios::binary); + if (!file) + return Print(EError, "Cannot open Rom image '%s' for verification\n", anImage); + Print(ELog, "\nVerifying ROM against image in %s\n", anImage); + switch (aHeaderType) + { + case 0: + break; + case 1: + default: + Print(ELog, "Skipping repro header\n"); + file.seekg(sizeof(TRomLoaderHeader)); + break; + case 2: + Print(ELog, "Skipping coff header\n"); + file.seekg(0x58); + break; + } + TInt length=ALIGN4K(iSizeUsed); + if (iObey->iSectionStart != 0) + { + length = iObey->iSectionStart-iObey->iRomLinearBase; + Print(ELog, "Verifying first section (%08x bytes)... ", length); + } + + TRomHeader compareHeader; + file.read((char *)&compareHeader, sizeof(TRomHeader)); + // Arrange different settings for TRomHeader and + // TRomSectionHeader in the obey file + // For now just copy across the things that'll change + compareHeader.iVersion=iHeader->iVersion; + compareHeader.iTime=iHeader->iTime; + compareHeader.iTimeHi=(TUint32)(iHeader->iTime >> 32); + compareHeader.iCheckSum=iHeader->iCheckSum; + compareHeader.iLanguage=iHeader->iLanguage; + + if (memcmp(&compareHeader, iHeader, sizeof(TRomHeader))!=0) + return Print(EError, "Verify failed.\nRom headers are different\n"); + + // Now compare the rest of the image (or first section) + + TUint *ptr=(TUint *)(iHeader+1); + TInt i; + for (i=sizeof(TRomHeader); iiRomLinearBase); + ptr++; + } + file.close(); + Print(EAlways, "Verify OK\n"); + return KErrNone; + } + + +char* E32Rom::AllocateRelocationTable(char* aAddr, TReloc*& aRelocTable) + { + if(iObey->SetArea().Count() > 1) + { + aRelocTable = reinterpret_cast(aAddr); + + // Allocate one entry per non default area + 1 sentinel + // (Count() returns number of non default areas + 1 (the + // default area)) + TInt size = iObey->SetArea().Count() * sizeof(TReloc); + aAddr += Align(size); + } + else + { + aRelocTable = 0; + } + + return aAddr; + } + + +void E32Rom::FillInRelocationTable(TReloc* aRelocTable) + { + TReloc* p = aRelocTable; + TInt wastedBytes = 0; + + for (NonDefaultAreasIterator areaIt(iObey->SetArea()); + ! areaIt.IsDone(); + areaIt.GoToNext()) + { + Area& currentArea = areaIt.Current(); + + if (currentArea.UsedSize() > 0) + { + p->iLength = currentArea.UsedSize(); + p->iSrc = currentArea.SrcBaseAddr(); + p->iDest = currentArea.DestBaseAddr(); + ++p; + } + else + { + wastedBytes += sizeof(TReloc); + } + } + + if (aRelocTable != 0) + { + // Last entry acts as a sentinel + memset(p, 0, sizeof(*p)); + } + + if (wastedBytes > 0) + { + Print(EWarning, "Some areas are declared but not used\n"); + Print(EWarning, "%d bytes wasted in relocation table\n", wastedBytes); + } + } + + +/** + Link together the kernel extensions. + + Must be called only after space has been allocated in the ROM image + for the kernel extension. + */ + +void E32Rom::LinkKernelExtensions(TRomBuilderEntry* aExtArray[], TInt aExtCount) + { + /** + * The kernel extensions should never be linked together as part of extension ROMs. + */ + if (!iExtensionRomHeader) + { + TLinAddr* pLastNextExtAddr = &(iHeader->iExtensionFile); + + for (TInt i=0; iRomEntry()); + pLastNextExtAddr = &(curExt->iRomImageHeader->iNextExtension); + } + + *pLastNextExtAddr = 0; + } + } + +void E32Rom::ProcessDllData() + { + DllDataEntry *entry = iObey->GetFirstDllDataEntry(); + TRomBuilderEntry *romEntry; + TLinAddr* aExportTbl; + void *aLocation; + TUint aDataAddr; + while(entry){ + // A Dll data may be patched either via the ordinal number (as in ABIv2), or via + // the address of the data field (as in ABIv1). + romEntry = entry->iRomNode->iRomFile->iRbEntry; + if((TInt)entry->iOrdinal != -1) { + + // const data symbol may belong in the Code section. Get the address of the data field via the + // export table. If the address lies within the Code or data section limits, + // get the corresponding location and update it.While considering the Data section limits don't + // include the Bss section, as it doesn't exist as yet in the image. + if(entry->iOrdinal < 1 || entry->iOrdinal > (TUint32)romEntry->iOrigHdr->iExportDirCount) + { + Print(EWarning, "Invalid ordinal %d specified for DLL %s\n", entry->iOrdinal, romEntry->iName); + entry = entry->NextDllDataEntry(); + continue; + } + aExportTbl = (TLinAddr*)((char*)romEntry->iOrigHdr + romEntry->iOrigHdr->iExportDirOffset); + aDataAddr = (TInt32)(aExportTbl[entry->iOrdinal - 1] + entry->iOffset); + + if( (aDataAddr >= romEntry->iOrigHdr->iCodeBase) && + (aDataAddr <= (TUint)(romEntry->iOrigHdr->iCodeBase + \ + romEntry->iOrigHdr->iCodeSize)) ) + { + char *aCodeSeg = (char*)((char*)romEntry->iOrigHdr + romEntry->iOrigHdr->iCodeOffset); + aLocation = (void*)(aCodeSeg + (aDataAddr - romEntry->iOrigHdr->iCodeBase)); + memcpy(aLocation, &(entry->iNewValue), entry->iSize); + } + else if( (aDataAddr >= romEntry->iOrigHdr->iDataBase) && + (aDataAddr <= (TUint)(romEntry->iOrigHdr->iDataBase + \ + romEntry->iOrigHdr->iDataSize )) ) + { + char *aDataSeg = (char*)((char*)romEntry->iOrigHdr + romEntry->iOrigHdr->iDataOffset); + aLocation = (void*)(aDataSeg + (aDataAddr - romEntry->iOrigHdr->iDataBase)); + memcpy(aLocation, &(entry->iNewValue), entry->iSize); + } + else + { + Print(EWarning, "Patchdata failed as address pointed by ordinal %d of DLL %s doesn't lie within Code or Data section limits\n", entry->iOrdinal, romEntry->iName); + } + + } + else if((TInt)entry->iDataAddress != -1) { + // const data symbol may belong in the Code section. If the address lies within the Code + // or data section limits, get the corresponding location and update it.While considering + // the Data section limits don't include the Bss section, as it doesn't exist as yet in the image. + aDataAddr = (TUint)(entry->iDataAddress + entry->iOffset); + if( (aDataAddr >= romEntry->iOrigHdr->iCodeBase) && + (aDataAddr <= (TUint)(romEntry->iOrigHdr->iCodeBase + \ + romEntry->iOrigHdr->iCodeSize )) ) + { + char *aCodeSeg = (char*)((char*)romEntry->iOrigHdr + romEntry->iOrigHdr->iCodeOffset); + aLocation = (void*)(aCodeSeg + (aDataAddr - romEntry->iOrigHdr->iCodeBase)); + memcpy(aLocation, &(entry->iNewValue), entry->iSize); + } + else if( (aDataAddr >= romEntry->iOrigHdr->iDataBase) && + (aDataAddr <= (TUint)(romEntry->iOrigHdr->iDataBase + \ + romEntry->iOrigHdr->iDataSize )) ) + { + char *aDataSeg = (char*)((char*)romEntry->iOrigHdr + romEntry->iOrigHdr->iDataOffset); + aLocation = (void*)(aDataSeg + (aDataAddr - romEntry->iOrigHdr->iDataBase)); + memcpy(aLocation, &(entry->iNewValue), entry->iSize); + } + else + { + Print(EWarning, "Patchdata failed as address 0x%x specified for DLL %s doesn't lie within Code or Data section limits\n", entry->iOrdinal, romEntry->iName); + } + } + else { + } + entry = entry->NextDllDataEntry(); + } + } + +TInt E32Rom::CheckUnpagedMemSize() + { + + if (H.iVerbose && gPagedRom) + { + Print(EDiagnostic, "iMaxUnpagedMemSize 0x%08x (%d)\n", iObey->iMaxUnpagedMemSize, iObey->iMaxUnpagedMemSize); + } + + // Only check if the iMaxUnpagedMemSize is set + if (iObey->iMaxUnpagedMemSize <= 0) return KErrNone; + + // Only for paged rom + if (!gPagedRom) + { + Print(EWarning, "The unpaged size overflow check is skipped.\n"); + return KErrNone; + } + + if (iHeader->iPageableRomStart > 0) + { + if (iHeader->iPageableRomStart > iObey->iMaxUnpagedMemSize) + { + Print(EError, "Unpaged memory size overflow: require 0x%08x (%d) bytes while the maximum size is 0x%08x (%d) bytes\n", + iHeader->iPageableRomStart, + iHeader->iPageableRomStart, + iObey->iMaxUnpagedMemSize, + iObey->iMaxUnpagedMemSize); + + return KErrNoMemory; + } + } + else + { + Print(EWarning, "The size of unpaged memory is not available. The unpaged memory overflow checking is skipped.\n"); + } + + return KErrNone; + } + +TRomNode* E32Rom::RootDirectory() +{ + return iObey->iRootDirectory; +} + +TText* E32Rom::RomFileName() +{ + return iObey->iRomFileName; +} + +TUint32 E32Rom::RomBase() +{ + return iHeader->iRomBase; +} + +TUint32 E32Rom::RomSize() +{ + return iHeader->iRomSize; +} + +TVersion E32Rom::Version() +{ + return iHeader->iVersion; +} + +TInt64 E32Rom::Time() +{ + return iHeader->iTime; +} + +TUint32 E32Rom::CheckSum() +{ + return iHeader->iCheckSum; +} + +TUint32 E32Rom::DataRunAddress() +{ + return iObey->iDataRunAddress; +} + +TUint32 E32Rom::RomAlign() +{ + return iObey->iRomAlign; +}