os/kernelhwsrv/kernel/eka/drivers/paging/emulated/emulated_data_paging.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2005-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".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // e32/drivers/paging/emulated/emulated_rom_paging.cpp
    15 // 
    16 //
    17 
    18 #include <kernel/kern_priv.h>
    19 #include <kernel/kernel.h>
    20 #include <memmodel/epoc/platform.h>
    21 
    22 class DEmulatedDataPagingDevice : public DPagingDevice
    23 	{
    24 public:
    25 	static TInt Install();
    26 private:
    27 	TInt Construct();
    28 	TInt Read(TThreadMessage* aReq,TLinAddr aBuffer,TUint aOffset,TUint aSize,TInt);
    29 	TInt Write(TThreadMessage* aReq,TLinAddr aBuffer,TUint aOffset,TUint aSize,TBool aBackground);
    30 
    31 	static void ReadTimerCallback(TAny* aSem);
    32 	static void ReadDfcCallback(TAny* aReq);
    33 	void ReadDfc();
    34 
    35 	static void WriteTimerCallback(TAny* aSem);
    36 	static void WriteDfcCallback(TAny* aReq);
    37 	void WriteDfc();
    38 private:
    39 	TLinAddr iDataStore;
    40 	TDfcQue* iDfcQue;
    41 	DMutex* iMutex;
    42 
    43 	struct TDataRequest
    44 		{
    45 		TLinAddr iBuffer;
    46 		TLinAddr iOffset;
    47 		TUint	 iSize;
    48 		NFastSemaphore* iSemaphore;
    49 		TInt iResult;
    50 		};
    51 
    52 	TDataRequest iReadRequest;
    53 	TInt iAccumulatedReadDelay;
    54 	TInt iReadPageDelay;
    55 	TInt iReadPageCPUDelay;
    56 
    57 	TDataRequest iWriteRequest;
    58 	TInt iAccumulatedWriteDelay;
    59 	TInt iWritePageDelay;
    60 	TInt iWritePageCPUDelay;
    61 	};
    62 
    63 
    64 TInt DEmulatedDataPagingDevice::Install()
    65 	{
    66 	__KTRACE_OPT2(KPAGING,KBOOT,Kern::Printf(">DEmulatedDataPagingDevice::Install"));
    67 	TInt r;
    68 	DEmulatedDataPagingDevice* dataDevice = new DEmulatedDataPagingDevice;
    69 	if(!dataDevice)
    70 		r = KErrNoMemory;
    71 	else
    72 		{
    73 		r = dataDevice->Construct();
    74 		if(r==KErrNone)
    75 			Kern::InstallPagingDevice(dataDevice);
    76 		else
    77 			delete dataDevice;
    78 		}
    79 	__KTRACE_OPT2(KPAGING,KBOOT,Kern::Printf("<DEmulatedDataPagingDevice::Install returns %d",r));
    80 	return r;
    81 	}
    82 
    83 
    84 TInt DEmulatedDataPagingDevice::Construct()
    85 	{
    86 	__KTRACE_OPT2(KPAGING,KBOOT,Kern::Printf(">DEmulatedDataPagingDevice::Construct"));
    87 
    88 	// Initialise DPagingDevice base class
    89 	iType = EData;
    90 	iReadUnitShift = 9; // 512 byte units
    91 	iName = "EmulatedDataPagingDevice";
    92 
    93 	// Calculate swap size
    94 	TInt free = Kern::FreeRamInBytes()>>20; // megabytes free
    95 	TInt swapSize = free/2;
    96 	if(swapSize>256)
    97 		swapSize = 256;
    98 	swapSize <<= 20;
    99 	iSwapSize = swapSize>>iReadUnitShift;
   100 	__KTRACE_OPT2(KPAGING,KBOOT,Kern::Printf("DEmulatedDataPagingDevice::Construct swap size 0x%x",swapSize));
   101 
   102 	TInt r = Kern::MutexCreate(iMutex, _L("EmulDataPageDev"), KMutexOrdNone);
   103 	__NK_ASSERT_ALWAYS(r==KErrNone);
   104 	// Create a shared chunk to map the ROM pages
   105 	TChunkCreateInfo info;
   106 	info.iType = TChunkCreateInfo::ESharedKernelSingle;
   107 	info.iMaxSize = swapSize;
   108 	info.iMapAttr = EMapAttrFullyBlocking;
   109 	info.iOwnsMemory = ETrue;
   110 	DChunk* chunk;
   111 	TUint32 mapAttr;
   112 	r = Kern::ChunkCreate(info,chunk,iDataStore,mapAttr);
   113 	__NK_ASSERT_ALWAYS(r==KErrNone);
   114 	r = Kern::ChunkCommit(chunk,0,swapSize);
   115 	__NK_ASSERT_ALWAYS(r==KErrNone);
   116 
   117 	// create DFC thread for NAND read simulation
   118 	_LIT8(KDemandPagingDelay,"DataPagingDelay");
   119 	r = Kern::DfcQCreate(iDfcQue,24,&KDemandPagingDelay); // DFC thread of same priority as NAND driver
   120 	__NK_ASSERT_ALWAYS(r==KErrNone);
   121 
   122 	// setup delays used for simulation
   123 	SDemandPagingConfig config = Epoc::RomHeader().iDemandPagingConfig;
   124 	iReadPageDelay = config.iSpare[0];
   125 	iReadPageCPUDelay = config.iSpare[1];
   126 	iWritePageDelay = config.iSpare[0]*2;
   127 	iWritePageCPUDelay = config.iSpare[1];
   128 	__KTRACE_OPT2(KPAGING,KBOOT,Kern::Printf("DEmulatedDataPagingDevice::Construct emulated delays=%d,%d",iReadPageDelay,iReadPageCPUDelay));
   129 
   130 	__KTRACE_OPT2(KPAGING,KBOOT,Kern::Printf("<DEmulatedDataPagingDevice::Construct"));
   131 	return KErrNone;
   132 	}
   133 
   134 
   135 TInt DEmulatedDataPagingDevice::Read(TThreadMessage* /*aReq*/,TLinAddr aBuffer,TUint aOffset,TUint aSize,TInt)
   136 	{
   137 	aOffset <<= iReadUnitShift;
   138 	aSize <<= iReadUnitShift;
   139 
   140 	if(iReadPageCPUDelay==0 || KDebugNum(KTESTFAST))
   141 		{
   142 		// don't do emulated NAND delay, just copy it immediately...
   143 		memcpy((TAny*)aBuffer,(TAny*)(iDataStore+aOffset),aSize);
   144 		return KErrNone;
   145 		}
   146 	
   147 	// make sure we are single threaded when we use the DFC.
   148 	Kern::MutexWait(*iMutex);
   149 	
   150 	// get a DFC to do the simulated read
   151 	NFastSemaphore sem;
   152 	NKern::FSSetOwner(&sem,NULL);
   153 	iReadRequest.iBuffer = aBuffer;
   154 	iReadRequest.iOffset = aOffset;
   155 	iReadRequest.iSize = aSize;
   156 	iReadRequest.iSemaphore = &sem;
   157 	TDfc dfc(ReadDfcCallback,this,iDfcQue,0);
   158 	dfc.Enque();
   159 	NKern::FSWait(&sem);
   160 	TInt result = iReadRequest.iResult;
   161 	
   162 	// let any other threads have a go.
   163 	Kern::MutexSignal(*iMutex);
   164 	return result;
   165 	}
   166 
   167 
   168 void DEmulatedDataPagingDevice::ReadTimerCallback(TAny* aSem)
   169 	{
   170 	NKern::FSSignal((NFastSemaphore*)aSem);
   171 	}
   172 
   173 
   174 void DEmulatedDataPagingDevice::ReadDfcCallback(TAny* aSelf)
   175 	{
   176 	((DEmulatedDataPagingDevice*)aSelf)->ReadDfc();
   177 	}
   178 
   179 
   180 void DEmulatedDataPagingDevice::ReadDfc()
   181 	{
   182 	// calculate number of ticks to stall to emulate elapsed time for page read request
   183 	iAccumulatedReadDelay += iReadPageDelay;
   184 	TInt tick = NKern::TickPeriod();
   185 	TInt delay = 0;
   186 	if(iAccumulatedReadDelay>tick)
   187 		{
   188 		delay = iAccumulatedReadDelay/tick;
   189 		iAccumulatedReadDelay -= delay*tick+(tick>>1);
   190 		}
   191 	NFastSemaphore sem;
   192 	NKern::FSSetOwner(&sem,NULL);
   193 	NTimer timer(ReadTimerCallback,&sem);
   194 	if(delay)
   195 		timer.OneShot(delay,ETrue);
   196 
   197 	// emulate CPU load for processing read
   198 	Kern::NanoWait(iReadPageCPUDelay*1000);
   199 
   200 	// get data using memcpy
   201 	memcpy((TAny*)iReadRequest.iBuffer,(TAny*)(iDataStore+iReadRequest.iOffset),iReadRequest.iSize);
   202 
   203 	// wait for delay timer
   204 	if(delay)
   205 		NKern::FSWait(&sem);
   206 
   207 	// signal done
   208 	iReadRequest.iResult = KErrNone;
   209 	NKern::FSSignal(iReadRequest.iSemaphore);
   210 	}
   211 
   212 
   213 TInt DEmulatedDataPagingDevice::Write(TThreadMessage* /*aReq*/,TLinAddr aBuffer,TUint aOffset,TUint aSize,TBool aBackground)
   214 	{
   215 	aOffset <<= iReadUnitShift;
   216 	aSize <<= iReadUnitShift;
   217 
   218 	if(iWritePageCPUDelay==0 || KDebugNum(KTESTFAST))
   219 		{
   220 		// don't do emulated NAND delay, just copy it immediately...
   221 		memcpy((TAny*)(iDataStore+aOffset),(TAny*)aBuffer,aSize);
   222 		return KErrNone;
   223 		}
   224 	
   225 	// make sure we are single threaded when we use the DFC.
   226 	Kern::MutexWait(*iMutex);
   227 	
   228 	// get a DFC to do the simulated write
   229 	NFastSemaphore sem;
   230 	NKern::FSSetOwner(&sem,NULL);
   231 	iWriteRequest.iBuffer = aBuffer;
   232 	iWriteRequest.iOffset = aOffset;
   233 	iWriteRequest.iSize = aSize;
   234 	iWriteRequest.iSemaphore = &sem;
   235 	TDfc dfc(WriteDfcCallback,this,iDfcQue,0);
   236 	dfc.Enque();
   237 	NKern::FSWait(&sem);
   238 	TInt result = iWriteRequest.iResult;
   239 	
   240 	// let any other threads have a go.
   241 	Kern::MutexSignal(*iMutex);
   242 	return result;
   243 	}
   244 
   245 
   246 void DEmulatedDataPagingDevice::WriteTimerCallback(TAny* aSem)
   247 	{
   248 	NKern::FSSignal((NFastSemaphore*)aSem);
   249 	}
   250 
   251 
   252 void DEmulatedDataPagingDevice::WriteDfcCallback(TAny* aSelf)
   253 	{
   254 	((DEmulatedDataPagingDevice*)aSelf)->WriteDfc();
   255 	}
   256 
   257 
   258 void DEmulatedDataPagingDevice::WriteDfc()
   259 	{
   260 	// calculate number of ticks to stall to emulate elapsed time for page read request
   261 	iAccumulatedWriteDelay += iWritePageDelay;
   262 	TInt tick = NKern::TickPeriod();
   263 	TInt delay = 0;
   264 	if(iAccumulatedWriteDelay>tick)
   265 		{
   266 		delay = iAccumulatedWriteDelay/tick;
   267 		iAccumulatedWriteDelay -= delay*tick+(tick>>1);
   268 		}
   269 	NFastSemaphore sem;
   270 	NKern::FSSetOwner(&sem,NULL);
   271 	NTimer timer(WriteTimerCallback,&sem);
   272 	if(delay)
   273 		timer.OneShot(delay,ETrue);
   274 
   275 	// emulate CPU load for processing read
   276 	Kern::NanoWait(iWritePageCPUDelay*1000);
   277 
   278 	// write data using memcpy
   279 	memcpy((TAny*)(iDataStore+iWriteRequest.iOffset),(TAny*)iWriteRequest.iBuffer,iWriteRequest.iSize);
   280 
   281 	// wait for delay timer
   282 	if(delay)
   283 		NKern::FSWait(&sem);
   284 
   285 	// signal done
   286 	iWriteRequest.iResult = KErrNone;
   287 	NKern::FSSignal(iWriteRequest.iSemaphore);
   288 	}
   289 
   290 
   291 DECLARE_STANDARD_EXTENSION()
   292 	{
   293 	return DEmulatedDataPagingDevice::Install();
   294 	}