1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kernel/eka/memmodel/epoc/mmubase/kblockmap.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,193 @@
1.4 +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32\memmodel\epoc\mmubase\kblockmap.cpp
1.18 +//
1.19 +//
1.20 +
1.21 +#include <memmodel/epoc/mmubase/kblockmap.h>
1.22 +#include <e32cmn.h>
1.23 +#include <e32cmn_private.h>
1.24 +#include <e32atomics.h>
1.25 +
1.26 +#undef ASSERT
1.27 +
1.28 +#ifdef __KERNEL_MODE__
1.29 +
1.30 +#include <kernel/kernel.h>
1.31 +#define TRACECLASS Kern
1.32 +#undef TRACE
1.33 +#define ASSERT(x) __NK_ASSERT_DEBUG(x)
1.34 +#define FREE(x) Kern::Free(x)
1.35 +
1.36 +#define RETURN_ERROR(err, traceMsg) \
1.37 + { \
1.38 + __KTRACE_OPT(KPAGING,Kern::Printf("DP: %s, returning error %d", traceMsg, err)); \
1.39 + return err; \
1.40 + }
1.41 +
1.42 +#define TRACE_FATAL(x) __KTRACE_OPT(KPANIC, Kern::x)
1.43 +
1.44 +#else
1.45 +
1.46 +#include <e32debug.h>
1.47 +#include <e32test.h>
1.48 +#define TRACECLASS RDebug
1.49 +extern RTest test;
1.50 +#define ASSERT(x) test(x);
1.51 +#define FREE(x) User::Free(x)
1.52 +
1.53 +#define RETURN_ERROR(err, traceMsg) \
1.54 + { \
1.55 + RDebug::Printf("DP: %s, returning error %d", traceMsg, err); \
1.56 + return err; \
1.57 + }
1.58 +
1.59 +#define TRACE_FATAL(x) RDebug::x
1.60 +
1.61 +#endif
1.62 +
1.63 +TInt TBlockMap::Initialise(const SBlockMapInfoBase& aBlockMapInfo,
1.64 + TBlockMapEntryBase* aBlockMapEntries,
1.65 + TInt aBlockMapEntriesSize,
1.66 + TInt aReadUnitShift,
1.67 + TInt aDataLengthInFile)
1.68 + {
1.69 + ASSERT(iExtents == NULL);
1.70 +
1.71 + if (aBlockMapEntriesSize % sizeof(TBlockMapEntryBase) != 0)
1.72 + RETURN_ERROR(KErrArgument, "Size of block map is not multiple of entry size");
1.73 + iExtentCount = aBlockMapEntriesSize / sizeof(TBlockMapEntryBase);
1.74 +
1.75 + TInt blockShift = __e32_find_ms1_32(aBlockMapInfo.iBlockGranularity);
1.76 + if ((1u << blockShift) != aBlockMapInfo.iBlockGranularity)
1.77 + RETURN_ERROR(KErrArgument, "Block granularity not a power of two");
1.78 + if (blockShift < aReadUnitShift)
1.79 + RETURN_ERROR(KErrArgument, "Block size must be greater than or equal to read unit size");
1.80 + TInt blockScaling = blockShift - aReadUnitShift;
1.81 + TInt readUnitMask = (1 << aReadUnitShift) - 1;
1.82 +
1.83 + if ((aBlockMapInfo.iStartBlockAddress & ((1 << aReadUnitShift) - 1)) != 0)
1.84 + RETURN_ERROR(KErrArgument, "Block zero address not a multiple of read unit size");
1.85 + TUint blockZeroNumber = (TUint)(aBlockMapInfo.iStartBlockAddress >> aReadUnitShift); // offset of block zero from start of partition
1.86 +
1.87 + if (aBlockMapInfo.iBlockStartOffset >= aBlockMapInfo.iBlockGranularity)
1.88 + RETURN_ERROR(KErrArgument, "Block start offset must be less than block size");
1.89 +
1.90 + if (aDataLengthInFile <= 0)
1.91 + RETURN_ERROR(KErrArgument, "Length of code data in file must be greater than zero");
1.92 + iDataLength = aDataLengthInFile;
1.93 +
1.94 + // Process block map data into kernel-side reprsentation
1.95 + TInt dataOffset = -(TInt)(aBlockMapInfo.iBlockStartOffset & readUnitMask);
1.96 + SExtent entry;
1.97 + for (TInt i = 0 ; i < iExtentCount ; ++i)
1.98 + {
1.99 + const TBlockMapEntryBase& data = aBlockMapEntries[i];
1.100 + entry.iDataOffset = dataOffset;
1.101 + entry.iBlockNumber = (data.iStartBlock << blockScaling) + blockZeroNumber;
1.102 + dataOffset += data.iNumberOfBlocks << blockShift;
1.103 + if (i == 0)
1.104 + {
1.105 + TInt adjustStartBlock = aBlockMapInfo.iBlockStartOffset >> aReadUnitShift;
1.106 + entry.iBlockNumber += adjustStartBlock;
1.107 + dataOffset -= adjustStartBlock << aReadUnitShift;
1.108 + }
1.109 + (SExtent&)data = entry;
1.110 + }
1.111 +
1.112 + if (dataOffset < iDataLength)
1.113 + RETURN_ERROR(KErrArgument, "Block map too short");
1.114 +
1.115 + // Take ownership of buffer
1.116 + iExtents = (SExtent*) aBlockMapEntries;
1.117 +
1.118 + return KErrNone;
1.119 + }
1.120 +
1.121 +TBlockMap::TBlockMap()
1.122 + : iExtents(NULL)
1.123 + {
1.124 + }
1.125 +
1.126 +TBlockMap::~TBlockMap()
1.127 + {
1.128 + FREE(iExtents);
1.129 + }
1.130 +
1.131 +TInt TBlockMap::FindFirstExtent(TInt aPos) const
1.132 + {
1.133 + if (aPos < 0 || aPos >= iDataLength)
1.134 + return KErrArgument;
1.135 + RArray<SExtent> extents(sizeof(SExtent), iExtents, iExtentCount);
1.136 + SExtent findEntry = { aPos, 0 };
1.137 + TInt i = -1;
1.138 + extents.SpecificFindInSignedKeyOrder(findEntry, i, EArrayFindMode_Last);
1.139 + --i;
1.140 + if (i < 0 || i >= iExtentCount)
1.141 + return KErrArgument;
1.142 + return i;
1.143 + }
1.144 +
1.145 +TInt TBlockMap::Read(TLinAddr aBuffer, TInt aPos, TInt aLength, TInt aReadUnitShift, TReadFunc aReadFunc, TAny* aArg1, TAny* aArg2) const
1.146 + {
1.147 + TInt dataOffset = aPos;
1.148 + TInt remain = aLength;
1.149 + TInt readUnitMask = (1 << aReadUnitShift) - 1;
1.150 +
1.151 + TInt i = FindFirstExtent(dataOffset);
1.152 + if (i < 0)
1.153 + return i;
1.154 + TInt bufferStart = (dataOffset - Extent(i).iDataOffset) & readUnitMask; // start of page in buffer
1.155 + TInt bufferOffset = 0;
1.156 + while (remain > 0)
1.157 + {
1.158 + if (i >= Count())
1.159 + return KErrArgument;
1.160 +
1.161 + const SExtent& extent = Extent(i);
1.162 + TInt blockStartOffset = dataOffset - extent.iDataOffset;
1.163 + TInt blockNumber = extent.iBlockNumber + (blockStartOffset >> aReadUnitShift);
1.164 + TInt nextExtentStart = i == Count() - 1 ? iDataLength : Extent(i + 1).iDataOffset;
1.165 + TInt dataSize = Min(remain, nextExtentStart - dataOffset);
1.166 + TInt blockCount = (dataSize + (blockStartOffset & readUnitMask) + readUnitMask) >> aReadUnitShift;
1.167 +
1.168 + TInt r = aReadFunc(aArg1, aArg2, aBuffer + bufferOffset, blockNumber, blockCount);
1.169 + if (r != KErrNone)
1.170 + {
1.171 + TRACE_FATAL(Printf("TBlockMap::Read: error reading media at %08x + %x: %d", blockNumber << aReadUnitShift, blockCount << aReadUnitShift, r));
1.172 + return r;
1.173 + }
1.174 +
1.175 + bufferOffset += blockCount << aReadUnitShift;
1.176 + dataOffset += dataSize;
1.177 + remain -= dataSize;
1.178 + ++i;
1.179 + }
1.180 +
1.181 + return bufferStart;
1.182 + }
1.183 +
1.184 +#ifdef _DEBUG
1.185 +
1.186 +void TBlockMap::Dump() const
1.187 + {
1.188 + TRACECLASS::Printf("TBlockMap:");
1.189 + for (TInt i = 0 ; i < Count() ; ++i)
1.190 + {
1.191 + TInt nextExtentStart = i == Count() - 1 ? iDataLength : Extent(i + 1).iDataOffset;
1.192 + TRACECLASS::Printf(" %d: %08x -> %08x: %08x", i, Extent(i).iDataOffset, nextExtentStart, Extent(i).iBlockNumber);
1.193 + }
1.194 + }
1.195 +
1.196 +#endif