First public contribution.
1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
16 #include <plat_priv.h>
17 #include <kernel/cache.h>
25 #include "maddrcont.h"
27 #include "mlargemappings.h"
29 #include "cache_maintenance.inl"
33 Class representing the resources allocated for a ROM shadow page.
35 A shadow page is a page of RAM which is mapped by the MMU to replace
36 a prior existing page at a particular virtual address.
38 class DShadowPage : public DVirtualPinMapping
42 Create a new #DShadowPage to shadow a specified memory page.
44 On success, #iOriginalPage holds the physical address of the original page
45 and #iNewPage the physical address of the newly allocated RAM page; the
46 contents of this are a copy of the original.
48 No MMU entries for the shadow page are changed - it is the responsibility
49 of the caller to handle this. However, the new #DShadowPage object will
50 have pinned the page table used by \a aMapping which maps the page being
51 shadowed, prevent demand paging from discarding any modifications made to
54 @param aMemory The memory object whose memory is to be shadowed.
55 @param aIndex Page index, within the memory, of the page to shadow.
56 @param aMapping A memory mapping which currently maps the page to be
59 @return The newly created DShadowPage or the null pointer if there was
62 static DShadowPage* New(DMemoryObject* aMemory, TUint aIndex, DMemoryMappingBase* aMapping);
65 Free the allocated shadow page (#iNewPage) and unpin any pages table which
66 was pinned, then free this shadow page object.
68 The called of this function must ensure that all references to the shadow
69 RAM page have been removed from any MMU mappings.
78 Second phase constructor. For arguments, see #New.
80 TInt Construct(DMemoryObject* aMemory, TUint aIndex, DMemoryMappingBase* aMapping);
84 The physical address of the original page being shadowed.
86 TPhysAddr iOriginalPage;
89 The physical address of the allocated shadow page.
96 Specialised manager for the memory object representing the system ROM.
97 This handles demand paging of the ROM contents if it is not stored in a memory
98 device capable of execute-in-place random access. E.g. when stored in NAND
101 class DRomMemoryManager : public DPagedMemoryManager
107 Allocate a shadow page for the specified ROM address.
109 Shadow pages are pages of RAM which are mapped by the MMU so that
110 they replace the original ROM memory. The contents of a shadow page
111 are initially the same as the ROM they replace, but may be modified with
114 @param aRomAddr An virtual address which lies within the ROM.
116 @return KErrNone if successful,
117 KErrAlreadyExists if the specified address already has a show page,
118 otherwise one of the system wide error codes.
120 TInt AllocShadowPage(TLinAddr aRomAddr);
123 Free a shadow page previously allocated with #AllocShadowPage.
125 The original ROM memory page is again mapped at the specified address.
127 @param aRomAddr An virtual address which lies within the ROM.
129 @return KErrNone if successful,
130 otherwise one of the system wide error codes.
132 TInt FreeShadowPage(TLinAddr aRomAddr);
135 Copy data into a shadow page, modifying its contents.
137 @param aDst An virtual address which lies within the ROM for which a shadow
138 page has previously been allocated with #AllocShadowPage.
139 @param aSrc The start address of the data to copy to \a aDst.
140 @param aSize The size, in bytes, of the data to copy.
142 @return KErrNone if successful,
143 KErrNotFound if the specified address didn't have a shadow page,
144 otherwise one of the system wide error codes.
146 TInt CopyToShadowMemory(TLinAddr aDst, TLinAddr aSrc, TUint32 aSize);
150 // from DPagedMemoryManager...
151 virtual TInt PageInPinnedDone(DMemoryObject* aMemory, TUint aIndex, SPageInfo* aPageInfo, TPhysAddr* aPageArrayEntry, TPinArgs& aPinArgs);
154 // from DMemoryManager...
155 virtual void Destruct(DMemoryObject* aMemory);
156 virtual TInt HandleFault( DMemoryObject* aMemory, TUint aIndex, DMemoryMapping* aMapping,
157 TUint aMapInstanceCount, TUint aAccessPermissions);
158 virtual TInt Pin(DMemoryObject* aMemory, DMemoryMappingBase* aMapping, TPinArgs& aPinArgs);
159 virtual void Unpin(DMemoryObject* aMemory, DMemoryMappingBase* aMapping, TPinArgs& aPinArgs);
161 // methods inherited from DPagedMemoryManager
164 @copydoc DPagedMemoryManager::Init3
165 This acts as a second phase constructor for the manager which
166 creates the memory objects and mappings to represent the ROM.
168 virtual void Init3();
170 virtual TInt InstallPagingDevice(DPagingDevice* aDevice);
171 virtual TInt AcquirePageReadRequest(DPageReadRequest*& aRequest, DMemoryObject* aMemory, TUint aIndex, TUint aCount);
172 virtual TInt ReadPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages, DPageReadRequest* aRequest);
173 virtual TBool IsAllocated(DMemoryObject* aMemory, TUint aIndex, TUint aCount);
174 virtual void DoUnpin(DMemoryObject* aMemory, TUint aIndex, TUint aCount, DMemoryMappingBase* aMapping, TPinArgs& aPinArgs);
177 Acquire the mutex used to protect shadow page allocation.
182 Release the mutex used to protect shadow page allocation.
188 The ROM paging device which was passed to #InstallPagingDevice.
190 DPagingDevice* iDevice;
193 The memory object containing the ROM.
195 DMemoryObject* iRomMemory;
198 The memory mapping which maps the ROM into a global visible virtual address.
200 DMemoryMapping* iRomMapping;
203 The virtual address for the start of the ROM in the global memory region.
208 The size, in bytes, of the ROM image.
209 This may not be an exact multiple of a page size.
214 The size, in pages, of the ROM image.
219 The offset from the ROM start, in bytes, for the region of the
220 ROM which is demand paged.
225 The size, in bytes, for the region of the ROM which is demand paged.
230 The address within the ROM for the ROM page index.
231 @see TRomHeader::iRomPageIndex.
233 SRomPageInfo* iRomPageIndex;
236 The mutex used to protect shadow page allocation.
241 Container for all allocated DShadowPage objects.
243 RAddressedContainer iShadowPages;
245 #ifdef __SUPPORT_DEMAND_PAGING_EMULATION__
246 TInt iOriginalRomPageCount;
247 TPhysAddr* iOriginalRomPages;
248 friend void RomOriginalPages(TPhysAddr*& aPages, TUint& aPageCount);
251 friend TBool IsUnpagedRom(TLinAddr aBase, TUint aSize);
255 The single instance of this manager class.
257 static DRomMemoryManager TheManager;
261 DRomMemoryManager DRomMemoryManager::TheManager;
262 DPagedMemoryManager* TheRomMemoryManager = &DRomMemoryManager::TheManager;
265 const TInt KMutexOrdRomMemory = KMutexOrdPageIn+1;
268 #ifdef __SUPPORT_DEMAND_PAGING_EMULATION__
270 For use by the emulated paging device to get the location and size of the ROM.
272 @param aPages A reference to store a pointer to an array of the physical addresses of each ROM page.
273 @param aPageCount A reference to store the number of rom pages.
275 void RomOriginalPages(TPhysAddr*& aPages, TUint& aPageCount)
277 aPages = DRomMemoryManager::TheManager.iOriginalRomPages;
278 aPageCount = DRomMemoryManager::TheManager.iOriginalRomPageCount;
284 TBool IsUnpagedRom(TLinAddr aBase, TUint aSize)
286 TUint offset = aBase-DRomMemoryManager::TheManager.iBase;
287 TUint limit = DRomMemoryManager::TheManager.iPagedStart;
291 if(offset>limit || offset<aSize)
297 TInt PagifyChunk(TLinAddr aAddress)
299 TRACE(("PagifyChunk(0x%08x)",aAddress));
301 aAddress &= ~KChunkMask;
302 TPde* pPde = Mmu::PageDirectoryEntry(KKernelOsAsid,aAddress);
305 // check there is actually some memory mapped...
307 if(pde==KPdeUnallocatedEntry)
309 TRACE(("PagifyChunk returns %d",KErrNotFound));
313 // end if memory is not a section mapping...
314 TPhysAddr pdePhys = Mmu::PdePhysAddr(pde);
315 if(pdePhys==KPhysAddrInvalid)
317 TRACE(("PagifyChunk returns %d",KErrAlreadyExists));
318 return KErrAlreadyExists;
321 // get a new page table...
323 TPte* pt = ::PageTables.Alloc(false);
326 TRACE(("PagifyChunk returns %d",KErrNoMemory));
327 ::PageTables.Unlock();
331 // fill page table so it maps the same physical addresses as the section mapping...
332 TPte pte = Mmu::SectionToPageEntry(pde);
337 TRACE2(("!PTE %x=%x",pPte,pte));
341 while(TLinAddr(pPte)&(KPageTableMask/sizeof(TPte)*sizeof(TPte)));
342 CacheMaintenance::MultiplePtesUpdated((TLinAddr)pt,KPageTableSize);
344 // check memory not changed...
346 if(Mmu::PdePhysAddr(*pPde)!=pdePhys)
348 // pde was changed whilst we were creating a new page table, need to retry...
350 ::PageTables.Free(pt);
351 ::PageTables.Unlock();
355 // update page counts...
356 SPageTableInfo* pti = SPageTableInfo::FromPtPtr(pt);
357 TUint count = pti->IncPageCount(KPageTableSize/sizeof(TPte));
359 TRACE2(("pt %x page count=%d",pt,pti->PageCount()));
360 __NK_ASSERT_DEBUG(pti->CheckPageCount());
362 // swap pde entry to point to new page table...
363 pde |= Mmu::PageTablePhysAddr(pt);
364 TRACE2(("!PDE %x=%x",pPde,pde));
366 SinglePdeUpdated(pPde);
371 ::PageTables.Unlock();
372 TRACE(("PagifyChunk returns %d",KErrNone));
377 void UnmapROM(TLinAddr aStart, TLinAddr aEnd)
379 TRACEB(("UnmapROM 0x%08x..0x%08x",aStart,aEnd));
387 MmuLock::Lock(); // hold MmuLock for long time, shouldn't matter as this is only done during boot
389 TPte* pPte = Mmu::PtePtrFromLinAddr(p,KKernelOsAsid);
390 __NK_ASSERT_ALWAYS(pPte);
391 while(p<aEnd && p&KChunkMask)
393 *pPte++ = KPteUnallocatedEntry;
399 TPde* pPde = Mmu::PageDirectoryEntry(KKernelOsAsid,p);
402 *pPde++ = KPdeUnallocatedEntry;
409 __NK_ASSERT_DEBUG(p==aEnd);
413 DRomMemoryManager::DRomMemoryManager()
414 : iShadowPages(0,iShadowLock)
419 void DRomMemoryManager::Init3()
422 const TRomHeader& romHeader = TheRomHeader();
423 iBase = (TLinAddr)&romHeader;
424 iSize = romHeader.iUncompressedSize;
425 iSizeInPages = MM::RoundToPageCount(iSize);
426 TUint chunkSize = ((iSize+KChunkMask)&~KChunkMask);
427 TUint committedSize = TheSuperPage().iTotalRomSize; // size of memory loaded by bootstrap
428 TRACEB(("DRomMemoryManager::Init3 rom=0x%08x+0x%x",iBase,iSize));
430 // get paged rom info...
431 if(romHeader.iRomPageIndex)
432 iRomPageIndex = (SRomPageInfo*)((TInt)&romHeader+romHeader.iRomPageIndex);
433 iPagedSize = romHeader.iPageableRomSize;
434 iPagedStart = iPagedSize ? romHeader.iPageableRomStart : 0;
437 TRACEB(("DRomMemoryManager::Init3() paged=0x%08x+0x%x",(TLinAddr)&romHeader+iPagedStart,iPagedSize));
438 __NK_ASSERT_ALWAYS(iPagedStart<iSize && iPagedStart+iPagedSize>iPagedStart && iPagedStart+iPagedSize<=iSize);
440 #ifdef __SUPPORT_DEMAND_PAGING_EMULATION__
441 // get physical addresses of ROM pages...
442 iOriginalRomPageCount = iSizeInPages;
443 iOriginalRomPages = new TPhysAddr[iOriginalRomPageCount];
444 __NK_ASSERT_ALWAYS(iOriginalRomPages);
445 MmuLock::Lock(); // hold MmuLock for long time, shouldn't matter as this is only done during boot
447 for(i=0; i<iOriginalRomPageCount; i++)
448 iOriginalRomPages[i] = Mmu::LinearToPhysical(iBase+i*KPageSize);
451 // unmap paged part of ROM as the bootstrap will have left it mapped.
452 // See CFG_SupportEmulatedRomPaging in the bootstrap code.
453 // todo: use FMM for this after memory object created
454 UnmapROM(iBase+iPagedStart,iBase+chunkSize);
455 committedSize = iPagedStart;
459 if(iPagedStart && committedSize!=iPagedStart)
461 // unmap any paged ROM which the bootstrap mapped...
462 TRACEB(("DRomMemoryManager::Init3() unmapping unpaged ROM offsets 0x%x thru 0x%x",iPagedStart,committedSize));
463 // todo: use FMM for this after memory object created
464 UnmapROM(iBase+iPagedStart,iBase+committedSize);
465 committedSize = iPagedStart;
468 // create memory object for ROM...
469 TRACEB(("DRomMemoryManager::Init3() committed ROM memory 0x%x of 0x%x",committedSize,chunkSize));
470 TMemoryCreateFlags flags = (TMemoryCreateFlags)(EMemoryCreateNoWipe | EMemoryCreateReadOnly |
471 EMemoryCreateDemandPaged | EMemoryCreateAllowExecution);
472 iRomMemory = DLargeMappedMemory::New(&DRomMemoryManager::TheManager,chunkSize>>KPageShift,EMemoryAttributeStandard,flags);
473 __NK_ASSERT_ALWAYS(iRomMemory);
474 TInt r = MM::MemoryClaimInitialPages(iRomMemory,iBase,committedSize,EUserExecute,false,true);
475 __NK_ASSERT_ALWAYS(r==KErrNone);
476 r = iRomMemory->iPages.Alloc(committedSize>>KPageShift,(chunkSize-committedSize)>>KPageShift);
477 __NK_ASSERT_ALWAYS(r==KErrNone);
479 // create mapping for ROM...
480 r = MM::MappingNew(iRomMapping, iRomMemory, EUserExecute, KKernelOsAsid, EMappingCreateExactVirtual, iBase);
481 __NK_ASSERT_ALWAYS(r==KErrNone);
482 __NK_ASSERT_ALWAYS(iRomMapping->IsLarge());
484 // Set the paging device to be uninstalled, i.e. NULL.
487 _LIT(KRomMemoryLockName,"RomMemory");
488 r = K::MutexCreate(iShadowLock, KRomMemoryLockName, NULL, EFalse, KMutexOrdRomMemory);
489 __NK_ASSERT_ALWAYS(r==KErrNone);
490 MM::MemorySetLock(iRomMemory,iShadowLock);
494 TInt DRomMemoryManager::InstallPagingDevice(DPagingDevice* aDevice)
496 TRACEB(("DRomMemoryManager::InstallPagingDevice(0x%08x)",aDevice));
500 TRACEB(("ROM is not paged"));
505 if(!__e32_atomic_cas_ord_ptr(&iDevice, &null, aDevice)) // set iDevice=aDevice if it was originally 0
507 // ROM paging device already registered...
508 TRACEB(("DRomMemoryManager::InstallPagingDevice returns ALREADY EXISTS!"));
509 return KErrAlreadyExists;
512 __e32_atomic_ior_ord32(&K::MemModelAttributes, (TUint32)EMemModelAttrRomPaging);
518 TInt DRomMemoryManager::AcquirePageReadRequest(DPageReadRequest*& aRequest, DMemoryObject* aMemory, TUint aIndex, TUint aCount)
520 aRequest = iDevice->iRequestPool->AcquirePageReadRequest(aMemory,aIndex,aCount);
525 void DRomMemoryManager::Destruct(DMemoryObject* aMemory)
527 __NK_ASSERT_DEBUG(0);
531 TInt DRomMemoryManager::ReadPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages, DPageReadRequest* aRequest)
533 __NK_ASSERT_DEBUG(aRequest->CheckUse(aMemory,aIndex,aCount));
535 TLinAddr linAddr = aRequest->MapPages(aIndex,aCount,aPages);
538 const TInt readUnitShift = iDevice->iReadUnitShift;
540 for(; aCount; ++aIndex, --aCount, linAddr+=KPageSize)
542 START_PAGING_BENCHMARK;
545 // ROM not broken into pages, so just read it in directly.
546 // KPageShift > readUnitShift so page size is exact multiple of read
547 // units. Therefore it is ok to just shift offset and KPageSize
549 const TInt dataOffset = aIndex << KPageShift;
550 START_PAGING_BENCHMARK;
551 r = iDevice->Read( const_cast<TThreadMessage*>(&aRequest->iMessage),
552 linAddr, dataOffset >> readUnitShift,
553 KPageSize >> readUnitShift, DPagingDevice::EDriveRomPaging);
554 __NK_ASSERT_DEBUG(r!=KErrNoMemory); // not allowed to allocated memory, therefore can't fail with KErrNoMemory
555 END_PAGING_BENCHMARK(EPagingBmReadMedia);
559 // Work out where data for page is located
560 SRomPageInfo* romPageInfo = iRomPageIndex + aIndex;
561 const TInt dataOffset = romPageInfo->iDataStart;
562 const TInt dataSize = romPageInfo->iDataSize;
565 // empty page, fill it with 0xff...
566 memset((TAny*)linAddr, 0xff, KPageSize);
571 __NK_ASSERT_ALWAYS(romPageInfo->iPagingAttributes & SRomPageInfo::EPageable);
573 // Read data for page...
574 TThreadMessage* msg = const_cast<TThreadMessage*>(&aRequest->iMessage);
575 const TLinAddr buffer = aRequest->iBuffer;
576 const TUint readStart = dataOffset >> readUnitShift;
577 const TUint readSize = ((dataOffset + dataSize - 1) >> readUnitShift) - readStart + 1;
578 __NK_ASSERT_DEBUG((readSize << readUnitShift) <= (DPageReadRequest::EMaxPages << KPageShift));
579 START_PAGING_BENCHMARK;
580 r = iDevice->Read(msg, buffer, readStart, readSize, DPagingDevice::EDriveRomPaging);
581 __NK_ASSERT_DEBUG(r!=KErrNoMemory); // not allowed to allocated memory, therefore can't fail with KErrNoMemory
582 END_PAGING_BENCHMARK(EPagingBmReadMedia);
585 // Decompress data, remembering that the data to decompress may be offset from
586 // the start of the data just read in, due to reads having to be aligned by
588 const TLinAddr data = buffer + dataOffset - (readStart << readUnitShift);
589 __ASSERT_COMPILE(SRomPageInfo::ENoCompression==0); // decompress assumes this
590 r = Decompress(romPageInfo->iCompressionType, linAddr, KPageSize, data, dataSize);
594 __KTRACE_OPT(KPANIC, Kern::Printf("DRomMemoryManager::ReadPage: error decompressing page at %08x + %x: %d", dataOffset, dataSize, r));
595 __NK_ASSERT_ALWAYS(r == KPageSize);
600 __KTRACE_OPT(KPANIC, Kern::Printf("DRomMemoryManager::ReadPage: error reading media at %08x + %x: %d", dataOffset, dataSize, r));
603 END_PAGING_BENCHMARK(EPagingBmReadRomPage);
609 aRequest->UnmapPages(true);
615 TBool DRomMemoryManager::IsAllocated(DMemoryObject* aMemory, TUint aIndex, TUint aCount)
617 // all pages in the ROM memory object are always allocated...
622 TInt DRomMemoryManager::HandleFault(DMemoryObject* aMemory, TUint aIndex, DMemoryMapping* aMapping,
623 TUint aMapInstanceCount, TUint aAccessPermissions)
625 __NK_ASSERT_DEBUG(aMemory==iRomMemory);
627 TUint offset = aIndex*KPageSize;
628 if(offset<iPagedStart || offset>=iPagedStart+iPagedSize)
631 return DPagedMemoryManager::HandleFault(aMemory, aIndex, aMapping, aMapInstanceCount, aAccessPermissions);
635 TInt DRomMemoryManager::Pin(DMemoryObject* aMemory, DMemoryMappingBase* aMapping, TPinArgs& aPinArgs)
637 TRACE(("DRomMemoryManager::Pin %08x %08x", aMemory, aMapping));
638 TUint index = aMapping->iStartIndex;
639 TUint endIndex = index+aMapping->iSizeInPages;
640 if(endIndex>iSizeInPages)
644 TUint pagedIndex = iPagedStart>>KPageShift;
645 if(pagedIndex && pagedIndex<endIndex)
650 r = DoPin(aMemory,start,endIndex-start,aMapping,aPinArgs);
657 TInt DRomMemoryManager::PageInPinnedDone(DMemoryObject* aMemory, TUint aIndex, SPageInfo* aPageInfo, TPhysAddr* aPageArrayEntry, TPinArgs& aPinArgs)
659 TRACE(("DRomMemoryManager::PageInPinnedDone %08x %d", aMemory, aIndex));
661 // Only the paged part of rom should be pinned.
662 __NK_ASSERT_DEBUG(aIndex >= iPagedStart >> KPageShift);
664 TInt r = DoPageInDone(aMemory,aIndex,aPageInfo,aPageArrayEntry,true);
666 // Rom page can't be decommitted so this must succeed.
667 __NK_ASSERT_DEBUG(r >= 0);
669 if (aPageInfo->Type() == SPageInfo::EShadow)
670 {// The page is being shadowed so pin the original page.
671 // This is safe as the original page was physically pinned when shadowed.
672 __NK_ASSERT_DEBUG(RPageArray::IsPresent(*aPageArrayEntry));
673 aPageInfo = aPageInfo->GetOriginalPage();
676 ThePager.PagedInPinned(aPageInfo,aPinArgs);
678 // check page assigned correctly...
680 if(RPageArray::IsPresent(*aPageArrayEntry))
682 SPageInfo* pi = SPageInfo::FromPhysAddr(*aPageArrayEntry);
683 if (pi->Type() != SPageInfo::EShadow)
685 __NK_ASSERT_DEBUG(pi->Type() == SPageInfo::EManaged);
686 __NK_ASSERT_DEBUG(pi->Owner()==aMemory);
687 __NK_ASSERT_DEBUG(pi->Index()==aIndex);
688 __NK_ASSERT_DEBUG(pi->PagedState()==SPageInfo::EPagedPinned);
696 void DRomMemoryManager::Unpin(DMemoryObject* aMemory, DMemoryMappingBase* aMapping, TPinArgs& aPinArgs)
698 TRACE(("DRomMemoryManager::Unpin %08x %08x", aMemory, aMapping));
701 TUint index = aMapping->iStartIndex;
702 TUint endIndex = index+aMapping->iSizeInPages;
703 __NK_ASSERT_DEBUG(endIndex<=iSizeInPages); // Pin() should have already ensured this
705 TUint pagedIndex = iPagedStart>>KPageShift;
706 if(pagedIndex && pagedIndex<endIndex)
711 // unpin pages (but only if they were successfully pinned)...
712 if(aMapping->Flags()&DMemoryMapping::EPagesPinned)
713 DoUnpin(aMemory,start,endIndex-start,aMapping,aPinArgs);
716 __NK_ASSERT_DEBUG((aMapping->Flags()&DMemoryMapping::EPageUnmapVetoed)==0); // we shouldn't have tried to Free paged ROM
720 void DRomMemoryManager::DoUnpin(DMemoryObject* aMemory, TUint aIndex, TUint aCount, DMemoryMappingBase* aMapping, TPinArgs& aPinArgs)
722 TRACE(("DRomMemoryManager::DoUnpin(0x%08x,0x%08x,0x%08x,0x%08x,?)",aMemory, aIndex, aCount, aMapping));
724 // This should only be invoked on the paged part of rom.
725 __NK_ASSERT_DEBUG(iPagedStart && aIndex >= (iPagedStart >> KPageShift));
728 TUint endIndex = aIndex+aCount;
729 for(TUint i = aIndex; i < endIndex; ++i)
731 TPhysAddr page = aMemory->iPages.Page(i);
732 __NK_ASSERT_DEBUG(RPageArray::IsPresent(page));
733 SPageInfo* pi = SPageInfo::FromPhysAddr(page);
734 if(pi->Type() == SPageInfo::EShadow)
736 pi = pi->GetOriginalPage();
738 ThePager.Unpin(pi,aPinArgs);
744 // clear EPagesPinned flag...
745 __e32_atomic_and_ord8(&aMapping->Flags(), TUint8(~DMemoryMapping::EPagesPinned));
749 void DRomMemoryManager::ShadowLock()
751 MM::MemoryLock(iRomMemory);
755 void DRomMemoryManager::ShadowUnlock()
757 MM::MemoryUnlock(iRomMemory);
761 TInt DRomMemoryManager::AllocShadowPage(TLinAddr aRomAddr)
763 TRACE(("DRomMemoryManager::AllocShadowPage %08x", aRomAddr));
765 TUint index = (aRomAddr-iBase)>>KPageShift;
766 if (index >= iSizeInPages)
768 __NK_ASSERT_DEBUG(iRomMemory->CheckRegion(index,1));
774 DShadowPage* shadow = (DShadowPage*)iShadowPages.Find(index);
776 r = KErrAlreadyExists;
779 shadow = DShadowPage::New(iRomMemory,index,iRomMapping);
784 r = iShadowPages.Add(index,shadow);
791 // Remap the shadowed rom page to the shadow page. Update the
792 // page array entry for the page being shadowed, this ensures
793 // that any page moving attempts will remap the shadow page when
794 // they realise that the page is physically pinned.
796 TPhysAddr& pageEntry = *iRomMemory->iPages.PageEntry(index);
797 TPhysAddr newPageAddr = shadow->iNewPage;
798 pageEntry = (pageEntry & KPageMask) | newPageAddr;
800 // Mark the SPageInfo of the shadow page with pointer to the original page's
801 // SPageInfo, this is safe as we've physically pinned the original page
802 // so it can't be freed or reused until this shadow page is destroyed.
803 SPageInfo* origPi = SPageInfo::FromPhysAddr(shadow->iOriginalPage);
804 SPageInfo* newPi = SPageInfo::FromPhysAddr(newPageAddr);
805 newPi->SetOriginalPage(origPi);
808 iRomMemory->RemapPage(pageEntry, index, ETrue);
819 TInt DRomMemoryManager::FreeShadowPage(TLinAddr aRomAddr)
821 TUint index = (aRomAddr-iBase)>>KPageShift;
822 if(!iRomMemory->CheckRegion(index,1))
829 DShadowPage* shadow = (DShadowPage*)iShadowPages.Remove(index);
836 // Remap the rom page and update the page array entry for the page
837 // back to the original rom page. This is safe as the page is physically
838 // pinned until shadow is destroyed.
840 TPhysAddr& pageEntry = *iRomMemory->iPages.PageEntry(index);
841 pageEntry = (pageEntry & KPageMask) | shadow->iOriginalPage;
844 iRomMemory->RemapPage(pageEntry, index, ETrue);
856 TInt DRomMemoryManager::CopyToShadowMemory(TLinAddr aDst, TLinAddr aSrc, TUint32 aSize)
858 TRACE(("DRomMemoryManager::CopyToShadowMemory(0x%08x,0x%08x,0x%x)",aDst,aSrc,aSize));
860 TLinAddr offset = aDst-iBase;
861 TLinAddr end = offset+aSize;
862 if(end<offset || end>iSize)
867 TUint size = KPageSize-(offset&KPageMask); // bytes left in page at 'offset'
875 DShadowPage* shadow = (DShadowPage*)iShadowPages.Find(offset>>KPageShift);
882 RamAllocLock::Lock();
883 TLinAddr dst = m.MapTemp(shadow->iNewPage,offset>>KPageShift);
884 dst += offset&KPageMask;
885 memcpy((TAny*)dst,(TAny*)aSrc,size);
887 RamAllocLock::Unlock();
910 DShadowPage* DShadowPage::New(DMemoryObject* aMemory, TUint aIndex, DMemoryMappingBase* aMapping)
912 TRACE(("DShadowPage::New(0x%08x,0x%x,0x%08x)",aMemory, aIndex, aMapping));
913 __NK_ASSERT_DEBUG(MemoryObjectLock::IsHeld(aMemory));
915 DShadowPage* self = new DShadowPage;
917 if(self->Construct(aMemory,aIndex,aMapping)!=KErrNone)
923 TRACE(("DShadowPage::New(0x%08x,0x%x,0x%08x) returns 0x%08x",aMemory, aIndex, aMapping, self));
928 DShadowPage::DShadowPage()
929 : iOriginalPage(KPhysAddrInvalid), iNewPage(KPhysAddrInvalid)
931 // Set flag so that the rom page that is being shadowed can't be moved,
932 // otherwise iOriginalPage will become invalid if the page is moved.
933 Flags() |= EPhysicalPinningMapping;
939 TInt DShadowPage::Construct(DMemoryObject* aMemory, TUint aIndex, DMemoryMappingBase* aMapping)
941 __NK_ASSERT_DEBUG(MemoryObjectLock::IsHeld(aMemory));
943 // Pin the page. It is ok to get the mapping instance count here without
944 // MmuLock as there is only one permenant mapping used for the ROM.
945 TInt r = Pin(aMemory,aIndex,1,EUserReadOnly,aMapping,aMapping->MapInstanceCount());
949 r = PhysAddr(0,1,iOriginalPage,0);
950 __NK_ASSERT_DEBUG(r>=0);
954 RamAllocLock::Lock();
957 r = m.AllocRam(&iNewPage, 1, aMemory->RamAllocFlags(), EPageFixed);
960 TLinAddr dst = m.MapTemp(iNewPage,aIndex,0);
961 TLinAddr src = m.MapTemp(iOriginalPage,aIndex,1);
962 pagecpy((TAny*)dst,(TAny*)src);
963 CacheMaintenance::CodeChanged(dst,KPageSize); // IMB not needed, just clean to PoU (but we don't have a function to do that)
968 SPageInfo::FromPhysAddr(iNewPage)->SetShadow(aIndex,aMemory->PageInfoFlags());
972 RamAllocLock::Unlock();
981 DShadowPage::~DShadowPage()
986 void DShadowPage::Destroy()
988 TRACE2(("DShadowPage[%x]::Destroy()",this));
989 if(iNewPage!=KPhysAddrInvalid)
991 RamAllocLock::Lock();
992 TheMmu.FreeRam(&iNewPage, 1, EPageFixed);
993 RamAllocLock::Unlock();
1002 Replace a page of the system's execute-in-place (XIP) ROM image with a page of
1003 RAM having the same contents. This RAM can subsequently be written to in order
1004 to apply patches to the XIP ROM or to insert software breakpoints for debugging
1006 Call Epoc::FreeShadowPage() when you wish to revert to the original ROM page.
1008 @param aRomAddr The virtual address of the ROM page to be replaced.
1009 @return KErrNone if the operation completed successfully.
1010 KErrArgument if the specified address is not a valid XIP ROM address.
1011 KErrNoMemory if the operation failed due to insufficient free RAM.
1012 KErrAlreadyExists if the XIP ROM page at the specified address has
1013 already been shadowed by a RAM page.
1015 @pre Calling thread must be in a critical section.
1016 @pre Interrupts must be enabled.
1017 @pre Kernel must be unlocked.
1018 @pre No fast mutex can be held.
1019 @pre Call in a thread context.
1021 EXPORT_C TInt Epoc::AllocShadowPage(TLinAddr aRomAddr)
1023 CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"Epoc::AllocShadowPage");
1024 return DRomMemoryManager::TheManager.AllocShadowPage(aRomAddr);
1029 Copies data into shadow memory. Source data is presumed to be in Kernel memory.
1031 @param aSrc Data to copy from.
1032 @param aDest Address to copy into.
1033 @param aLength Number of bytes to copy. Maximum of 32 bytes of data can be copied.
1035 @return KErrNone if the operation completed successfully.
1036 KErrArgument if any part of destination region is not shadow page or
1037 if aLength is greater then 32 bytes.
1039 @pre Calling thread must be in a critical section.
1040 @pre Interrupts must be enabled.
1041 @pre Kernel must be unlocked.
1042 @pre No fast mutex can be held.
1043 @pre Call in a thread context.
1045 EXPORT_C TInt Epoc::CopyToShadowMemory(TLinAddr aDest, TLinAddr aSrc, TUint32 aLength)
1047 CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"Epoc::CopyToShadowMemory");
1048 return DRomMemoryManager::TheManager.CopyToShadowMemory(aDest,aSrc,aLength);
1053 Revert an XIP ROM address which has previously been shadowed to the original
1056 @param aRomAddr The virtual address of the ROM page to be reverted.
1057 @return KErrNone if the operation completed successfully.
1058 KErrArgument if the specified address is not a valid XIP ROM address.
1059 KErrGeneral if the specified address has not previously been shadowed
1060 using Epoc::AllocShadowPage().
1062 @pre Calling thread must be in a critical section.
1063 @pre Interrupts must be enabled.
1064 @pre Kernel must be unlocked.
1065 @pre No fast mutex can be held.
1066 @pre Call in a thread context.
1068 EXPORT_C TInt Epoc::FreeShadowPage(TLinAddr aRomAddr)
1070 return DRomMemoryManager::TheManager.FreeShadowPage(aRomAddr);
1075 Change the permissions on an XIP ROM address which has previously been shadowed
1076 by a RAM page so that the RAM page may no longer be written to.
1078 Note: Shadow page on the latest platforms (that use the reduced set of access permissions:
1079 arm11mpcore, arm1176, cortex) is implemented with read only permissions. Therefore, calling
1080 this function in not necessary, as shadow page is already created as 'frozen'.
1082 @param aRomAddr The virtual address of the shadow RAM page to be frozen.
1083 @return KErrNone if the operation completed successfully.
1084 KErrArgument if the specified address is not a valid XIP ROM address.
1085 KErrGeneral if the specified address has not previously been shadowed
1086 using Epoc::AllocShadowPage().
1088 @pre Calling thread must be in a critical section.
1089 @pre Interrupts must be enabled.
1090 @pre Kernel must be unlocked.
1091 @pre No fast mutex can be held.
1092 @pre Call in a thread context.
1094 EXPORT_C TInt Epoc::FreezeShadowPage(TLinAddr aRomAddr)
1096 // Null operation for flexible memory model...