diff -r 000000000000 -r 96e5fb8b040d kernel/eka/include/memmodel/epoc/mmubase/mmubase.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/include/memmodel/epoc/mmubase/mmubase.h Thu Dec 17 09:24:54 2009 +0200 @@ -0,0 +1,725 @@ +// Copyright (c) 1998-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: +// e32\include\memmodel\epoc\mmubase\mmubase.h +// +// WARNING: This file contains some APIs which are internal and are subject +// to change without notice. Such APIs should therefore not be used +// outside the Kernel and Hardware Services package. +// + +#ifndef __MMUBASE_H__ +#define __MMUBASE_H__ +#include +#include + + +/****************************************************************************** + * Definitions common to all MMU memory models + ******************************************************************************/ + +/** +@internalComponent +*/ +struct SPageInfo + { + enum TType + { + EInvalid=0, // No physical RAM exists for this page + EFixed=1, // RAM fixed at boot time, + EUnused=2, // Page is unused + EChunk=3, // iOwner=DChunk* iOffset=index into chunk + ECodeSegMemory=4, // iOwner=DCodeSegMemory* iOffset=index into CodeSeg memory (Multiple Memory Model only) +// EHwChunk=5, // Not used + EPageTable=6, // iOwner=0 iOffset=index into KPageTableBase + EPageDir=7, // iOwner=ASID iOffset=index into Page Directory + EPtInfo=8, // iOwner=0 iOffset=index into KPageTableInfoBase + EShadow=9, // iOwner=phys ROM page iOffset=index into ROM + EPagedROM=10, // iOwner=0, iOffset=index into ROM + EPagedCode=11, // iOwner=DCodeSegMemory* iOffset=index into code chunk (not offset into CodeSeg!) + EPagedData=12, // NOT YET SUPPORTED + EPagedCache=13, // iOwner=DChunk* iOffset=index into chunk + EPagedFree=14, // In demand paging 'live list' but not used for any purpose + }; + + enum TState + { + EStateNormal = 0, // no special state + EStatePagedYoung = 1, // demand paged and is on the young list + EStatePagedOld = 2, // demand paged and is on the old list + EStatePagedDead = 3, // demand paged and is currently being modified + EStatePagedLocked = 4 // demand paged but is temporarily not being demand paged + }; + + inline TType Type() + { + return (TType)iType; + } + inline TState State() + { + return (TState)iState; + } + inline TAny* Owner() + { + return iOwner; + } + inline TUint32 Offset() + { + return iOffset; + } + inline TInt LockCount() + { + return iLockCount; + } + + /** Return the index of the zone the page is in + */ + inline TUint8 Zone() + { + return iZone; + } + +#ifdef _DEBUG + void Set(TType aType, TAny* aOwner, TUint32 aOffset); + void Change(TType aType,TState aState); + void SetState(TState aState); + void SetModifier(TAny* aModifier); + TInt CheckModified(TAny* aModifier); + void SetZone(TUint8 aZoneIndex); +#else + inline void Set(TType aType, TAny* aOwner, TUint32 aOffset) + { + (TUint16&)iType = aType; // also sets iState to EStateNormal + iOwner = aOwner; + iOffset = aOffset; + iModifier = 0; + } + inline void Change(TType aType,TState aState) + { + iType = aType; + iState = aState; + iModifier = 0; + } + inline void SetState(TState aState) + { + iState = aState; + iModifier = 0; + } + inline void SetModifier(TAny* aModifier) + { + iModifier = aModifier; + } + inline TInt CheckModified(TAny* aModifier) + { + return iModifier!=aModifier; + } + + inline void SetZone(TUint8 aZoneIndex) + { + iZone = aZoneIndex; + } +#endif // !_DEBUG + void Lock(); + TInt Unlock(); + + inline void SetFixed() + { + Set(EFixed,0,0); + iLockCount = 1; + } + inline void SetUnused() + { + __NK_ASSERT_DEBUG(0 == LockCount()); + (TUint16&)iType = EUnused; // also sets iState to zero + iModifier = 0; + // do not modify iOffset in this function because cache cleaning operations + // rely on using this value + } + inline void SetChunk(TAny* aChunk, TUint32 aOffset) + { + Set(EChunk,aChunk,aOffset); + } + inline void SetCodeSegMemory(TAny* aCodeSegMemory,TUint32 aOffset) + { + Set(ECodeSegMemory,aCodeSegMemory,aOffset); + } +// inline void SetHwChunk(TAny* aChunk, TUint32 aOffset) +// { +// Set(EHwChunk,aChunk,aOffset); +// } + inline void SetPageTable(TUint32 aId) + { + Set(EPageTable,0,aId); + } + inline void SetPageDir(TUint32 aOsAsid, TInt aOffset) + { + Set(EPageDir,(TAny*)aOsAsid,aOffset); + } + inline void SetPtInfo(TUint32 aOffset) + { + Set(EPtInfo,0,aOffset); + } + inline void SetShadow(TPhysAddr aOrigPhys, TUint32 aOffset) + { + Set(EShadow,(TAny*)aOrigPhys,aOffset); + } + inline void SetPagedROM(TUint32 aOffset) + { + Set(EPagedROM,0,aOffset); + } + inline void SetPagedCode(TAny* aCodeSegMemory, TUint32 aOffset) + { + Set(EPagedCode,aCodeSegMemory,aOffset); + } + + inline static SPageInfo* FromLink(SDblQueLink* aLink) + { return (SPageInfo*)((TInt)aLink-_FOFF(SPageInfo,iLink)); } + + inline TUint& PagedLock() + { return (TUint&)iLink.iPrev; } + + /** + Return the SPageInfo for a given page of physical RAM. + */ + inline static SPageInfo* FromPhysAddr(TPhysAddr aAddress); + + /** + Return physical address of the RAM page which this SPageInfo object is associated. + If the address has no SPageInfo, then a null pointer is returned. + */ + static SPageInfo* SafeFromPhysAddr(TPhysAddr aAddress); + + /** + Return physical address of the RAM page which this SPageInfo object is associated. + */ + inline TPhysAddr PhysAddr(); + +private: + TUint8 iType; // enum TType + TUint8 iState; // enum TState + TUint8 iZone; // The index of the zone the page is in, for use by DRamAllocator + TUint8 iSpare1; + TAny* iOwner; // owning object + TUint32 iOffset; // page offset withing owning object + TAny* iModifier; // pointer to object currently manipulating page + TUint32 iLockCount; // non-zero if page acquired by code outside of the kernel + TUint32 iSpare2; +public: + SDblQueLink iLink; // used for placing page into linked lists + }; + +/****************************************************************************** +Per-page table info + +Page count 0-256 +Usage unused + chunk ptr (26 bits) offset (12 bits) + HW chunk ptr (26 bits) offset (12 bits) + global offset (12 bits) + shadow page offset (12 bits) + + +*******************************************************************************/ +/** +@internalComponent +*/ +struct SPageTableInfo + { + enum TAttribs + { + EUnused=0, + EChunk=1, +// EHwChunk=2, + EGlobal=3, + EShadow=4, + }; + + enum {EAttShift=6, EAttMask=0x3f}; + + inline TInt Attribs() + {return iAttPtr&EAttMask;} + inline TInt Count() + {return iCount;} + inline TUint32 Offset() + {return iOffset;} + inline TUint32 Ptr() + {return iAttPtr>>EAttShift;} + + inline void SetUnused() + {iCount=0; iOffset=0; iAttPtr=0;} + inline void SetChunk(TUint32 aChunk, TUint32 aOffset) + {iOffset=aOffset; iAttPtr=(aChunk<> iPtBlockShift;} + + /** + @return The page table entry for the page table info pages. + */ + inline TPte PtInfoPtePerm() + {return iPtInfoPtePerm;} + +public: + TInt AllocRamPages(TPhysAddr* aPageList, TInt aNumPages, TZonePageType aPageType, TUint aBlockedZoneId=KRamZoneInvalidId, TBool aBlockRest=EFalse); + TInt ZoneAllocRamPages(TUint* aZoneIdList, TUint aZoneIdCount, TPhysAddr* aPageList, TInt aNumPages, TZonePageType aPageType); + TInt AllocContiguousRam(TInt aSize, TPhysAddr& aPhysAddr, TZonePageType aPageType, TInt aAlign, TUint aBlockedZoneId=KRamZoneInvalidId, TBool aBlockRest=EFalse); + TInt ZoneAllocContiguousRam(TUint* aZoneIdList, TUint aZoneIdCount, TInt aSize, TPhysAddr& aPhysAddr, TZonePageType aPageType, TInt aAlign); + +public: + TInt iPageSize; // page size in bytes + TInt iPageMask; // page size - 1 + TInt iPageShift; // log2(page size) + TInt iChunkSize; // PDE size in bytes + TInt iChunkMask; // PDE size - 1 + TInt iChunkShift; // log2(PDE size) + TInt iPageTableSize; // 2nd level page table size in bytes + TInt iPageTableMask; // 2nd level page table size - 1 + TInt iPageTableShift; // log2(2nd level page table size) + TInt iPtClusterSize; // number of page tables per page + TInt iPtClusterMask; // number of page tables per page - 1 + TInt iPtClusterShift; // log2(number of page tables per page) + TInt iPtBlockSize; // number of SPageTableInfo per page + TInt iPtBlockMask; // number of SPageTableInfo per page - 1 + TInt iPtBlockShift; // log2(number of SPageTableInfo per page) + TInt iPtGroupSize; // number of page tables mapped by a page table + TInt iPtGroupMask; // number of page tables mapped by a page table - 1 + TInt iPtGroupShift; // log2(number of page tables mapped by a page table) + TInt iMaxPageTables; // maximum number of page tables (<65536) + TInt* iPtBlockCount; // number of page table pages in each block + TInt* iPtGroupCount; // number of page table pages in each group + TInt iNumPages; // Number of pages being managed + SPageTableInfo* iPtInfo; // per-page table information array + TLinAddr iPageTableLinBase; // base address of page tables + DRamAllocator* iRamPageAllocator; + TBitMapAllocator* iPageTableAllocator; // NULL if page table size = page size + TBitMapAllocator* iPageTableLinearAllocator; + TInt iInitialFreeMemory; + TBool iAllocFailed; + TPte iPtInfoPtePerm; + TPte iPtPtePerm; + TPde iPtPdePerm; + TPte* iTempPte; // PTE used for temporary mappings + TLinAddr iTempAddr; // address corresponding to iTempPte + TLinearSection* iKernelSection; // bitmap used to allocate kernel section addresses + THwChunkAddressAllocator* iHwChunkAllocator; // address allocator for HW chunks in kernel section + TUint32 iMapSizes; // bit mask of supported mapping sizes + TUint iDecommitThreshold; // threshold for selective/global cache flush on decommit for VIPT caches + TLinAddr iRomLinearBase; + TLinAddr iRomLinearEnd; + TPte iShadowPtePerm; + TPde iShadowPdePerm; + + // Page moving and defrag fault handling members. + TLinAddr iAltStackBase; + TLinAddr iDisabledAddr; + TInt iDisabledAddrAsid; + TPte* iDisabledPte; + TPte iDisabledOldVal; + + RamCacheBase* iRamCache; + Defrag* iDefrag; + + static DMutex* HwChunkMutex; // mutex protecting HW chunk address allocators + static DMutex* RamAllocatorMutex; // the main mutex protecting alloc/dealloc and most map/unmap + static MmuBase* TheMmu; // pointer to the single instance of this class + static const SRamZone* RamZoneConfig; /** + { +public: + static THwChunkAddressAllocator* New(TInt aAlign, TLinearSection* aSection); + TLinAddr Alloc(TInt aSize, TInt aAlign, TInt aOffset, TPde aPdePerm); + THwChunkRegion* Free(TLinAddr aAddr, TInt aSize); +public: + THwChunkAddressAllocator(); + TLinAddr SearchExisting(TInt aNumPages, TInt aPageAlign, TInt aPageOffset, TPde aPdePerm); + void Discard(THwChunkRegion* aRegion); + static TInt Order(const THwChunkRegion& a1, const THwChunkRegion& a2); + THwChunkRegion* NewRegion(TInt aIndex, TInt aSize, TPde aPdePerm); + THwChunkPageTable* NewPageTable(TInt aIndex, TPde aPdePerm, TInt aInitB, TInt aInitC); +public: + TInt iAlign; // alignment required for allocated addresses + TLinearSection* iSection; // linear section in which allocation occurs + }; + + +/** Hardware chunk + +@internalComponent +*/ +class DMemModelChunkHw : public DPlatChunkHw + { +public: + virtual TInt Close(TAny* aPtr); +public: + TInt AllocateLinearAddress(TPde aPdePerm); + void DeallocateLinearAddress(); +public: + THwChunkAddressAllocator* iAllocator; + }; + + +/****************************************************************************** + * MMU-specifc code segment data + ******************************************************************************/ + +/** +@internalComponent +*/ +class DMmuCodeSegMemory : public DEpocCodeSegMemory + { +public: + DMmuCodeSegMemory(DEpocCodeSeg* aCodeSeg); + ~DMmuCodeSegMemory(); + virtual TInt Create(TCodeSegCreateInfo& aInfo); + virtual TInt Loaded(TCodeSegCreateInfo& aInfo); + + /** + Apply code relocations and import fixups to one page of code. + @param aBuffer The buffer containg the code + @param aCodeAddress The address the page will be mapped at + */ + void ApplyCodeFixups(TUint32* aBuffer, TLinAddr aCodeAddress); + + /** + Apply code relocations and import fixups to one page of code. + Called by DMemModelCodeSegMemory::Loaded to fixup pages which are already paged-in. + + @param aBuffer The buffer containg the code + @param aCodeAddress The address the page will be mapped at + */ + TInt ApplyCodeFixupsOnLoad(TUint32* aBuffer, TLinAddr aCodeAddress); +private: + TInt ReadBlockMap(const TCodeSegCreateInfo& aInfo); + TInt ReadFixupTables(const TCodeSegCreateInfo& aInfo); +public: + TBool iIsDemandPaged; + + TInt iPageCount; // Number of pages used for code + TInt iDataPageCount; // Number of extra pages used to store data section + TUint8* iCodeRelocTable; // Code relocation information + TInt iCodeRelocTableSize; // Size of code relocation table in bytes + TUint8* iImportFixupTable; // Import fixup information + TInt iImportFixupTableSize; // Size of import fixup table in bytes + TUint32 iCodeDelta; // Code relocation delta + TUint32 iDataDelta; // Data relocation delta + + TInt iCompressionType; // Compression scheme in use + TInt32* iCodePageOffsets; // Array of compressed page offsets within the file + TInt iCodeLocalDrive; // Local drive number + TBlockMap iBlockMap; // Kernel-side representation of block map + TInt iCodeStartInFile; // Offset of (possibly compressed) code from start of file + + TAny* iDataSectionMemory; // pointer to saved copy of data section (when demand paging) + + TInt iCodeAllocBase; + }; + +#endif