sl@0: // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32\memmodel\epoc\mmubase\kblockmap.cpp sl@0: // sl@0: // sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: #undef ASSERT sl@0: sl@0: #ifdef __KERNEL_MODE__ sl@0: sl@0: #include sl@0: #define TRACECLASS Kern sl@0: #undef TRACE sl@0: #define ASSERT(x) __NK_ASSERT_DEBUG(x) sl@0: #define FREE(x) Kern::Free(x) sl@0: sl@0: #define RETURN_ERROR(err, traceMsg) \ sl@0: { \ sl@0: __KTRACE_OPT(KPAGING,Kern::Printf("DP: %s, returning error %d", traceMsg, err)); \ sl@0: return err; \ sl@0: } sl@0: sl@0: #define TRACE_FATAL(x) __KTRACE_OPT(KPANIC, Kern::x) sl@0: sl@0: #else sl@0: sl@0: #include sl@0: #include sl@0: #define TRACECLASS RDebug sl@0: extern RTest test; sl@0: #define ASSERT(x) test(x); sl@0: #define FREE(x) User::Free(x) sl@0: sl@0: #define RETURN_ERROR(err, traceMsg) \ sl@0: { \ sl@0: RDebug::Printf("DP: %s, returning error %d", traceMsg, err); \ sl@0: return err; \ sl@0: } sl@0: sl@0: #define TRACE_FATAL(x) RDebug::x sl@0: sl@0: #endif sl@0: sl@0: TInt TBlockMap::Initialise(const SBlockMapInfoBase& aBlockMapInfo, sl@0: TBlockMapEntryBase* aBlockMapEntries, sl@0: TInt aBlockMapEntriesSize, sl@0: TInt aReadUnitShift, sl@0: TInt aDataLengthInFile) sl@0: { sl@0: ASSERT(iExtents == NULL); sl@0: sl@0: if (aBlockMapEntriesSize % sizeof(TBlockMapEntryBase) != 0) sl@0: RETURN_ERROR(KErrArgument, "Size of block map is not multiple of entry size"); sl@0: iExtentCount = aBlockMapEntriesSize / sizeof(TBlockMapEntryBase); sl@0: sl@0: TInt blockShift = __e32_find_ms1_32(aBlockMapInfo.iBlockGranularity); sl@0: if ((1u << blockShift) != aBlockMapInfo.iBlockGranularity) sl@0: RETURN_ERROR(KErrArgument, "Block granularity not a power of two"); sl@0: if (blockShift < aReadUnitShift) sl@0: RETURN_ERROR(KErrArgument, "Block size must be greater than or equal to read unit size"); sl@0: TInt blockScaling = blockShift - aReadUnitShift; sl@0: TInt readUnitMask = (1 << aReadUnitShift) - 1; sl@0: sl@0: if ((aBlockMapInfo.iStartBlockAddress & ((1 << aReadUnitShift) - 1)) != 0) sl@0: RETURN_ERROR(KErrArgument, "Block zero address not a multiple of read unit size"); sl@0: TUint blockZeroNumber = (TUint)(aBlockMapInfo.iStartBlockAddress >> aReadUnitShift); // offset of block zero from start of partition sl@0: sl@0: if (aBlockMapInfo.iBlockStartOffset >= aBlockMapInfo.iBlockGranularity) sl@0: RETURN_ERROR(KErrArgument, "Block start offset must be less than block size"); sl@0: sl@0: if (aDataLengthInFile <= 0) sl@0: RETURN_ERROR(KErrArgument, "Length of code data in file must be greater than zero"); sl@0: iDataLength = aDataLengthInFile; sl@0: sl@0: // Process block map data into kernel-side reprsentation sl@0: TInt dataOffset = -(TInt)(aBlockMapInfo.iBlockStartOffset & readUnitMask); sl@0: SExtent entry; sl@0: for (TInt i = 0 ; i < iExtentCount ; ++i) sl@0: { sl@0: const TBlockMapEntryBase& data = aBlockMapEntries[i]; sl@0: entry.iDataOffset = dataOffset; sl@0: entry.iBlockNumber = (data.iStartBlock << blockScaling) + blockZeroNumber; sl@0: dataOffset += data.iNumberOfBlocks << blockShift; sl@0: if (i == 0) sl@0: { sl@0: TInt adjustStartBlock = aBlockMapInfo.iBlockStartOffset >> aReadUnitShift; sl@0: entry.iBlockNumber += adjustStartBlock; sl@0: dataOffset -= adjustStartBlock << aReadUnitShift; sl@0: } sl@0: (SExtent&)data = entry; sl@0: } sl@0: sl@0: if (dataOffset < iDataLength) sl@0: RETURN_ERROR(KErrArgument, "Block map too short"); sl@0: sl@0: // Take ownership of buffer sl@0: iExtents = (SExtent*) aBlockMapEntries; sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: TBlockMap::TBlockMap() sl@0: : iExtents(NULL) sl@0: { sl@0: } sl@0: sl@0: TBlockMap::~TBlockMap() sl@0: { sl@0: FREE(iExtents); sl@0: } sl@0: sl@0: TInt TBlockMap::FindFirstExtent(TInt aPos) const sl@0: { sl@0: if (aPos < 0 || aPos >= iDataLength) sl@0: return KErrArgument; sl@0: RArray extents(sizeof(SExtent), iExtents, iExtentCount); sl@0: SExtent findEntry = { aPos, 0 }; sl@0: TInt i = -1; sl@0: extents.SpecificFindInSignedKeyOrder(findEntry, i, EArrayFindMode_Last); sl@0: --i; sl@0: if (i < 0 || i >= iExtentCount) sl@0: return KErrArgument; sl@0: return i; sl@0: } sl@0: sl@0: TInt TBlockMap::Read(TLinAddr aBuffer, TInt aPos, TInt aLength, TInt aReadUnitShift, TReadFunc aReadFunc, TAny* aArg1, TAny* aArg2) const sl@0: { sl@0: TInt dataOffset = aPos; sl@0: TInt remain = aLength; sl@0: TInt readUnitMask = (1 << aReadUnitShift) - 1; sl@0: sl@0: TInt i = FindFirstExtent(dataOffset); sl@0: if (i < 0) sl@0: return i; sl@0: TInt bufferStart = (dataOffset - Extent(i).iDataOffset) & readUnitMask; // start of page in buffer sl@0: TInt bufferOffset = 0; sl@0: while (remain > 0) sl@0: { sl@0: if (i >= Count()) sl@0: return KErrArgument; sl@0: sl@0: const SExtent& extent = Extent(i); sl@0: TInt blockStartOffset = dataOffset - extent.iDataOffset; sl@0: TInt blockNumber = extent.iBlockNumber + (blockStartOffset >> aReadUnitShift); sl@0: TInt nextExtentStart = i == Count() - 1 ? iDataLength : Extent(i + 1).iDataOffset; sl@0: TInt dataSize = Min(remain, nextExtentStart - dataOffset); sl@0: TInt blockCount = (dataSize + (blockStartOffset & readUnitMask) + readUnitMask) >> aReadUnitShift; sl@0: sl@0: TInt r = aReadFunc(aArg1, aArg2, aBuffer + bufferOffset, blockNumber, blockCount); sl@0: if (r != KErrNone) sl@0: { sl@0: TRACE_FATAL(Printf("TBlockMap::Read: error reading media at %08x + %x: %d", blockNumber << aReadUnitShift, blockCount << aReadUnitShift, r)); sl@0: return r; sl@0: } sl@0: sl@0: bufferOffset += blockCount << aReadUnitShift; sl@0: dataOffset += dataSize; sl@0: remain -= dataSize; sl@0: ++i; sl@0: } sl@0: sl@0: return bufferStart; sl@0: } sl@0: sl@0: #ifdef _DEBUG sl@0: sl@0: void TBlockMap::Dump() const sl@0: { sl@0: TRACECLASS::Printf("TBlockMap:"); sl@0: for (TInt i = 0 ; i < Count() ; ++i) sl@0: { sl@0: TInt nextExtentStart = i == Count() - 1 ? iDataLength : Extent(i + 1).iDataOffset; sl@0: TRACECLASS::Printf(" %d: %08x -> %08x: %08x", i, Extent(i).iDataOffset, nextExtentStart, Extent(i).iBlockNumber); sl@0: } sl@0: } sl@0: sl@0: #endif