Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1237 lines
30 KiB

//----------------------------------------------------------------------------
//
// Memory cache object.
//
// Copyright (C) Microsoft Corporation, 1997-2002.
//
//----------------------------------------------------------------------------
#include "ntsdp.hpp"
#define DBG_CACHE 0
#if DBG_CACHE
#define DPCACHE(Args) g_NtDllCalls.DbgPrint Args
#else
#define DPCACHE(Args)
#endif
typedef struct _CACHE
{
RTL_SPLAY_LINKS SplayLinks;
ULONG64 Offset;
ULONG Length;
USHORT Flags;
union
{
PUCHAR Data;
HRESULT Status;
} u;
} CACHE, *PCACHE;
#define C_ERROR 0x0001 // Cache of error code
#define C_DONTEXTEND 0x0002 // Don't try to extend
#define LARGECACHENODE 1024 // Size of large cache node
//----------------------------------------------------------------------------
//
// MemoryCache.
//
//----------------------------------------------------------------------------
MemoryCache::MemoryCache(ULONG MaxSize)
{
m_Target = NULL;
m_MaxSize = MaxSize;
m_UserSize = m_MaxSize;
m_Reads = 0;
m_CachedReads = 0;
m_UncachedReads = 0;
m_CachedBytes = 0;
m_UncachedBytes = 0;
m_Misses = 0;
m_Size = 0;
m_NodeCount = 0;
m_PurgeOverride = FALSE;
m_DecodePTEs = TRUE;
m_ForceDecodePTEs = FALSE;
m_Suspend = 0;
m_Root = NULL;
}
MemoryCache::~MemoryCache(void)
{
Empty();
}
HRESULT
MemoryCache::Read(IN ULONG64 BaseAddress,
IN PVOID UserBuffer,
IN ULONG TransferCount,
IN PULONG BytesRead)
/*++
This function returns the specified data from the system being debugged
using the current mapping of the processor. If the data is not
in the cache, it will then be read from the target system.
Arguments:
BaseAddress - Supplies the base address of the memory to be
copied into the UserBuffer.
TransferCount - Amount of data to be copied to the UserBuffer.
UserBuffer - Address to copy the requested data.
BytesRead - Number of bytes which could actually be copied
--*/
{
HRESULT Status;
PCACHE Node, Node2;
ULONG NextLength;
ULONG i, SuccRead;
PUCHAR NodeData;
*BytesRead = 0;
if (TransferCount == 0)
{
return S_OK;
}
if (m_MaxSize == 0 || m_Suspend)
{
//
// Cache is off
//
goto ReadDirect;
}
DPCACHE(("CACHE: Read req %s:%x\n",
FormatAddr64(BaseAddress), TransferCount));
m_Reads++;
Node = Lookup(BaseAddress, TransferCount, &NextLength);
Status = S_OK;
for (;;)
{
BOOL Cached = FALSE;
if (Node == NULL || Node->Offset > BaseAddress)
{
//
// We are missing the leading data, read it into the cache
//
if (Node)
{
//
// Only get (exactly) enough data to reach neighboring cache
// node. If an overlapped read occurs between the two nodes,
// the data will be concatenated then.
//
NextLength = (ULONG)(Node->Offset - BaseAddress);
}
NodeData = Alloc(NextLength);
Node = (PCACHE)Alloc(sizeof(CACHE));
if (NodeData == NULL || Node == NULL)
{
//
// Out of memory - just read directly to UserBuffer
//
if (NodeData)
{
Free(NodeData, NextLength);
}
if (Node)
{
Free((PUCHAR)Node, sizeof (CACHE));
}
m_UncachedReads++;
m_UncachedBytes += TransferCount;
goto ReadDirect;
}
//
// Read missing data into cache node
//
Node->Offset = BaseAddress;
Node->u.Data = NodeData;
Node->Flags = 0;
m_Misses++;
m_UncachedReads++;
Status = ReadUncached(BaseAddress, Node->u.Data,
NextLength, &SuccRead);
if (Status == HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT))
{
Free(NodeData, NextLength);
Free((PUCHAR)Node, sizeof (CACHE));
DPCACHE(("CACHE: Read failed, %x\n", Status));
return Status;
}
else if (Status != S_OK)
{
//
// There was an error, cache the error for the starting
// byte of this range
//
Free(NodeData, NextLength);
if (Status != HRESULT_FROM_NT(STATUS_UNSUCCESSFUL) &&
Status != HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY))
{
//
// For now be safe, don't cache this error
//
Free((PUCHAR)Node, sizeof (CACHE));
ErrOut("ReadMemoryError %08lx at %s\n",
Status, FormatAddr64(BaseAddress));
DPCACHE(("CACHE: Read partial %x, status %x\n",
*BytesRead, Status));
return *BytesRead > 0 ? S_OK : Status;
}
Node->Length = 1;
Node->Flags |= C_ERROR;
Node->u.Status = Status;
DPCACHE(("CACHE: Error %x node at %s\n",
Status, FormatAddr64(BaseAddress)));
}
else
{
m_UncachedBytes += SuccRead;
Node->Length = SuccRead;
if (SuccRead != NextLength)
{
//
// Some data was not transfered, cache what was returned
//
Node->Flags |= C_DONTEXTEND;
m_Size -= (NextLength - SuccRead);
}
DPCACHE(("CACHE: Added %s:%x, flags %x\n",
FormatAddr64(BaseAddress),
Node->Length, Node->Flags));
}
//
// Insert cache node into splay tree
//
InsertNode(Node);
}
else
{
Cached = TRUE;
m_CachedReads++;
}
if (Node->Flags & C_ERROR)
{
//
// Hit an error range, we're done
//
DPCACHE(("CACHE: Read partial %x, error node %x\n",
*BytesRead, Node->u.Status));
return *BytesRead > 0 ? S_OK : Node->u.Status;
}
//
// Move available data to UserBuffer
//
i = (ULONG)(BaseAddress - Node->Offset);
NodeData = Node->u.Data + i;
i = (ULONG)Node->Length - i;
if (TransferCount < i)
{
i = TransferCount;
}
memcpy(UserBuffer, NodeData, i);
if (Cached)
{
m_CachedBytes += i;
}
TransferCount -= i;
BaseAddress += i;
UserBuffer = (PVOID)((PUCHAR)UserBuffer + i);
*BytesRead += i;
if (!TransferCount)
{
//
// All of the user's data has been transfered
//
DPCACHE(("CACHE: Read success %x\n", *BytesRead));
return S_OK;
}
//
// Look for another cache node with more data
//
Node2 = Lookup(BaseAddress, TransferCount, &NextLength);
if (Node2)
{
if ((Node2->Flags & C_ERROR) == 0 &&
Node2->Offset == BaseAddress &&
Node2->Length + Node->Length < LARGECACHENODE)
{
//
// Data is continued in node2, adjoin the neigboring
// cached data in node & node2 together.
//
NodeData = Alloc(Node->Length + Node2->Length);
if (NodeData != NULL)
{
DPCACHE(("CACHE: Merge %s:%x with %s:%x\n",
FormatAddr64(Node->Offset), Node->Length,
FormatAddr64(Node2->Offset), Node2->Length));
memcpy(NodeData, Node->u.Data, Node->Length);
memcpy(NodeData + Node->Length, Node2->u.Data,
Node2->Length);
Free(Node->u.Data, Node->Length);
Node->u.Data = NodeData;
Node->Length += Node2->Length;
m_Root = (PCACHE)pRtlDelete((PRTL_SPLAY_LINKS)Node2);
Free (Node2->u.Data, Node2->Length);
Free ((PUCHAR)Node2, sizeof (CACHE));
m_NodeCount--;
continue;
}
}
//
// Only get enough data to reach the neighboring cache Node2
//
NextLength = (ULONG)(Node2->Offset - BaseAddress);
if (NextLength == 0)
{
//
// Data is continued in Node2, go get it.
//
Node = Node2;
continue;
}
}
else
{
if (Node->Length > LARGECACHENODE)
{
//
// Current cache node is already big enough. Don't extend
// it, add another cache node.
//
Node = NULL;
continue;
}
}
//
// Extend the current node to include missing data
//
if (Node->Flags & C_DONTEXTEND)
{
Node = NULL;
continue;
}
NodeData = Alloc(Node->Length + NextLength);
if (!NodeData)
{
Node = NULL;
continue;
}
memcpy(NodeData, Node->u.Data, Node->Length);
Free(Node->u.Data, Node->Length);
Node->u.Data = NodeData;
//
// Add new data to end of this node
//
m_Misses++;
m_UncachedReads++;
Status = ReadUncached(BaseAddress, Node->u.Data + Node->Length,
NextLength, &SuccRead);
if (Status == HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT))
{
m_Size -= NextLength;
DPCACHE(("CACHE: Read add failed, %x\n", Status));
return Status;
}
else if (Status != S_OK)
{
//
// Return to error to the caller
//
Node->Flags |= C_DONTEXTEND;
m_Size -= NextLength;
ErrOut("ReadMemoryError %08lx at %s\n",
Status, FormatAddr64(BaseAddress));
DPCACHE(("CACHE: Read add partial %x, status %x\n",
*BytesRead, Status));
return *BytesRead > 0 ? S_OK : Status;
}
m_UncachedBytes += SuccRead;
if (SuccRead != NextLength)
{
Node->Flags |= C_DONTEXTEND;
m_Size -= (NextLength - SuccRead);
}
Node->Length += SuccRead;
DPCACHE(("CACHE: Extended %s:%x to %x, flags %x\n",
FormatAddr64(BaseAddress),
Node->Length - SuccRead, Node->Length, Node->Flags));
// Loop, and move data to user's buffer
}
ReadDirect:
Status = ReadUncached(BaseAddress, UserBuffer, TransferCount, &SuccRead);
*BytesRead += SuccRead;
if (Status != HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT))
{
Status = *BytesRead > 0 ? S_OK : Status;
}
DPCACHE(("CACHE: Read uncached %x, status %x\n",
*BytesRead, Status));
return Status;
}
HRESULT
MemoryCache::Write(IN ULONG64 BaseAddress,
IN PVOID UserBuffer,
IN ULONG TransferCount,
OUT PULONG BytesWritten)
{
// Remove data from cache before writing through to target system.
Remove(BaseAddress, TransferCount);
return WriteUncached(BaseAddress, UserBuffer,
TransferCount, BytesWritten);
}
PCACHE
MemoryCache::Lookup(ULONG64 Offset,
ULONG Length,
PULONG LengthUsed)
/*++
Routine Description:
Walks the cache tree looking for a matching range closest to
the supplied Offset. The length of the range searched is based on
the past length, but may be adjusted slightly.
This function will always search for the starting byte.
Arguments:
Offset - Starting byte being looked for in cache
Length - Length of range being looked for in cache
LengthUsed - Length of range which was really searched for
Return Value:
NULL - data for returned range was not found
PCACHE - leftmost cachenode which has data for returned range
--*/
{
PCACHE Node, Node2;
ULONG64 SumOffsetLength;
if (Length < 0x80 && m_Misses > 3)
{
// Try to cache more than a tiny amount.
Length = 0x80;
}
SumOffsetLength = Offset + Length;
if (SumOffsetLength < Length)
{
//
// Offset + Length wrapped. Adjust Length to be only
// enough bytes before wrapping.
//
Length = (ULONG)(0 - Offset);
SumOffsetLength = (ULONG64)-1;
}
DPCACHE(("CACHE: Lookup(%s, %x) -> ",
FormatAddr64(Offset), Length));
//
// Find leftmost cache node for BaseAddress through BaseAddress+Length
//
Node2 = NULL;
Node = m_Root;
while (Node != NULL)
{
if (SumOffsetLength <= Node->Offset)
{
Node = (PCACHE)RtlLeftChild(&Node->SplayLinks);
}
else if (Node->Offset + Node->Length <= Offset)
{
Node = (PCACHE)RtlRightChild(&Node->SplayLinks);
}
else
{
if (Node->Offset <= Offset)
{
//
// Found starting byte
//
*LengthUsed = Length;
DPCACHE(("found %s:%x, flags %x, used %x\n",
FormatAddr64(Node->Offset),
Node->Length, Node->Flags, Length));
return Node;
}
//
// Check to see if there's a node which has a match closer
// to the start of the requested range
//
Node2 = Node;
Length = (ULONG)(Node->Offset - Offset);
SumOffsetLength = Node->Offset;
Node = (PCACHE)RtlLeftChild(&Node->SplayLinks);
}
}
#if DBG_CACHE
if (Node2)
{
DPCACHE(("found %s:%x, flags %x, used %x\n",
FormatAddr64(Node2->Offset), Node2->Length,
Node2->Flags, Length));
}
else
{
DPCACHE(("not found\n"));
}
#endif
*LengthUsed = Length;
return Node2;
}
VOID
MemoryCache::InsertNode(IN PCACHE Node)
{
PCACHE Node2;
ULONG64 BaseAddress;
//
// Insert cache node into splay tree
//
RtlInitializeSplayLinks(&Node->SplayLinks);
m_NodeCount++;
if (m_Root == NULL)
{
m_Root = Node;
return;
}
Node2 = m_Root;
BaseAddress = Node->Offset;
for (; ;)
{
if (BaseAddress < Node2->Offset)
{
if (RtlLeftChild(&Node2->SplayLinks))
{
Node2 = (PCACHE) RtlLeftChild(&Node2->SplayLinks);
continue;
}
RtlInsertAsLeftChild(Node2, Node);
break;
}
else
{
if (RtlRightChild(&Node2->SplayLinks))
{
Node2 = (PCACHE) RtlRightChild(&Node2->SplayLinks);
continue;
}
RtlInsertAsRightChild(Node2, Node);
break;
}
}
m_Root = (PCACHE)pRtlSplay((PRTL_SPLAY_LINKS)Node2);
}
VOID
MemoryCache::Add(IN ULONG64 BaseAddress,
IN PVOID UserBuffer,
IN ULONG Length)
/*++
Routine Description:
Insert some data into the cache.
Arguments:
BaseAddress - Virtual address
Length - length to cache
UserBuffer - data to put into cache
Return Value:
--*/
{
PCACHE Node;
PUCHAR NodeData;
if (m_MaxSize == 0)
{
//
// Cache is off
//
return;
}
//
// Delete any cached info which hits range
//
Remove (BaseAddress, Length);
NodeData = Alloc (Length);
Node = (PCACHE) Alloc (sizeof (CACHE));
if (NodeData == NULL || Node == NULL)
{
//
// Out of memory - don't bother
//
if (NodeData)
{
Free (NodeData, Length);
}
if (Node)
{
Free ((PUCHAR)Node, sizeof (CACHE));
}
return;
}
//
// Put data into cache node
//
Node->Offset = BaseAddress;
Node->Length = Length;
Node->u.Data = NodeData;
Node->Flags = 0;
memcpy(NodeData, UserBuffer, Length);
InsertNode(Node);
DPCACHE(("CACHE: Add direct %s:%x\n",
FormatAddr64(Node->Offset), Node->Length));
}
PUCHAR
MemoryCache::Alloc(IN ULONG Length)
/*++
Routine Description:
Allocates memory for virtual cache, and tracks total memory
usage.
Arguments:
Length - Amount of memory to allocate
Return Value:
NULL - too much memory is in use, or memory could not
be allocated
Otherwise, returns to address of the allocated memory
--*/
{
PUCHAR Mem;
if (m_Size + Length > m_MaxSize)
{
return NULL;
}
if (!(Mem = (PUCHAR)malloc (Length)))
{
//
// Out of memory - don't get any larger
//
m_Size = m_MaxSize + 1;
return NULL;
}
m_Size += Length;
return Mem;
}
VOID
MemoryCache::Free(IN PUCHAR Memory,
IN ULONG Length)
/*++
Routine Description:
Free memory allocated with Alloc. Adjusts cache is use totals.
Arguments:
Memory - Address of allocated memory
Length - Length of allocated memory
Return Value:
NONE
--*/
{
m_Size -= Length;
free(Memory);
}
VOID
MemoryCache::Remove(IN ULONG64 BaseAddress,
IN ULONG TransferCount)
/*++
Routine Description:
Invalidates range from the cache.
Arguments:
BaseAddress - Starting address to purge
TransferCount - Length of area to purge
Return Value:
NONE
--*/
{
PCACHE Node;
ULONG Used;
//
// Invalidate any data in the cache which covers this range
//
while (Node = Lookup(BaseAddress, TransferCount, &Used))
{
//
// For now just delete the entire cache node which hits the range
//
DPCACHE(("CACHE: Remove %s:%x, flags %x\n",
FormatAddr64(Node->Offset), Node->Length, Node->Flags));
m_Root = (PCACHE) pRtlDelete (&Node->SplayLinks);
if (!(Node->Flags & C_ERROR))
{
Free (Node->u.Data, Node->Length);
}
Free ((PUCHAR)Node, sizeof (CACHE));
m_NodeCount--;
}
}
VOID
MemoryCache::Empty(void)
/*++
Routine Description:
Purges to entire cache
Arguments:
NONE
Return Value:
NONE
--*/
{
PCACHE Node, Node2;
m_Reads = 0;
m_CachedReads = 0;
m_UncachedReads = 0;
m_CachedBytes = 0;
m_UncachedBytes = 0;
m_Misses = 0;
if (!m_Root)
{
return;
}
if (m_PurgeOverride != 0)
{
WarnOut("WARNING: cache being held\n");
return;
}
DPCACHE(("CACHE: Empty cache\n"));
Node2 = m_Root;
Node2->SplayLinks.Parent = NULL;
while ((Node = Node2) != NULL)
{
if ((Node2 = (PCACHE) Node->SplayLinks.LeftChild) != NULL)
{
Node->SplayLinks.LeftChild = NULL;
continue;
}
if ((Node2 = (PCACHE) Node->SplayLinks.RightChild) != NULL)
{
Node->SplayLinks.RightChild = NULL;
continue;
}
Node2 = (PCACHE) Node->SplayLinks.Parent;
if (!(Node->Flags & C_ERROR))
{
free (Node->u.Data);
}
free (Node);
}
m_Size = 0;
m_NodeCount = 0;
m_Root = NULL;
}
VOID
MemoryCache::PurgeType(ULONG Type)
/*++
Routine Description:
Purges all nodes from the cache which match type in question
Arguments:
Type - type of entries to purge from the cache
0 - entries of errored ranges
1 - plus, node which cache user mode entries
Return Value:
NONE
--*/
{
PCACHE Node, Node2;
if (!m_Root)
{
return;
}
DPCACHE(("CACHCE: Purge type %x\n", Type));
//
// this purges the selected cache entries by copy the all the
// cache nodes except from the ones we don't want
//
Node2 = m_Root;
Node2->SplayLinks.Parent = NULL;
m_Root = NULL;
while ((Node = Node2) != NULL)
{
if ((Node2 = (PCACHE)Node->SplayLinks.LeftChild) != NULL)
{
Node->SplayLinks.LeftChild = NULL;
continue;
}
if ((Node2 = (PCACHE)Node->SplayLinks.RightChild) != NULL)
{
Node->SplayLinks.RightChild = NULL;
continue;
}
Node2 = (PCACHE) Node->SplayLinks.Parent;
m_NodeCount--;
if (Node->Flags & C_ERROR)
{
// remove this one from the tree
Free ((PUCHAR)Node, sizeof (CACHE));
continue;
}
if ((Type == 1) && (Node->Offset < m_Target->m_SystemRangeStart))
{
// remove this one from the tree
Free (Node->u.Data, Node->Length);
Free ((PUCHAR)Node, sizeof (CACHE));
continue;
}
// copy to the new tree
InsertNode(Node);
}
}
VOID
MemoryCache::SetForceDecodePtes(BOOL Enable, TargetInfo* Target)
{
m_ForceDecodePTEs = Enable;
if (Enable)
{
m_MaxSize = 0;
}
else
{
m_MaxSize = m_UserSize;
}
Empty();
if (Target)
{
Target->m_PhysicalCache.ChangeSuspend(Enable);
Target->m_PhysicalCache.Empty();
}
}
void
MemoryCache::ParseCommands(void)
{
ULONG64 Address;
while (*g_CurCmd == ' ')
{
g_CurCmd++;
}
_strlwr(g_CurCmd);
BOOL Parsed = TRUE;
if (IS_KERNEL_TARGET(m_Target))
{
if (strcmp (g_CurCmd, "decodeptes") == 0)
{
PurgeType(0);
m_DecodePTEs = TRUE;
}
else if (strcmp (g_CurCmd, "nodecodeptes") == 0)
{
m_DecodePTEs = FALSE;
}
else if (strcmp (g_CurCmd, "forcedecodeptes") == 0)
{
SetForceDecodePtes(TRUE, m_Target);
}
else if (strcmp (g_CurCmd, "noforcedecodeptes") == 0)
{
SetForceDecodePtes(FALSE, m_Target);
}
else
{
Parsed = FALSE;
}
}
if (Parsed)
{
// Command already handled.
}
else if (strcmp (g_CurCmd, "hold") == 0)
{
m_PurgeOverride = TRUE;
}
else if (strcmp (g_CurCmd, "unhold") == 0)
{
m_PurgeOverride = FALSE;
}
else if (strcmp (g_CurCmd, "flushall") == 0)
{
Empty();
}
else if (strcmp (g_CurCmd, "flushu") == 0)
{
PurgeType(1);
}
else if (strcmp (g_CurCmd, "suspend") == 0)
{
ChangeSuspend(FALSE);
}
else if (strcmp (g_CurCmd, "nosuspend") == 0)
{
ChangeSuspend(TRUE);
}
else if (strcmp (g_CurCmd, "dump") == 0)
{
Dump();
goto Done;
}
else if (*g_CurCmd == 'f')
{
while (*g_CurCmd >= 'a' && *g_CurCmd <= 'z')
{
g_CurCmd++;
}
Address = GetExpression();
Remove(Address, 4096);
dprintf("Cached info for address %s for 4096 bytes was flushed\n",
FormatAddr64(Address));
}
else if (*g_CurCmd)
{
if (*g_CurCmd < '0' || *g_CurCmd > '9')
{
dprintf(".cache [{cachesize} | hold | unhold\n");
dprintf(".cache [flushall | flushu | flush addr]\n");
if (IS_KERNEL_TARGET(m_Target))
{
dprintf(".cache [decodeptes | nodecodeptes]\n");
dprintf(".cache [forcedecodeptes | noforcedecodeptes]\n");
}
goto Done;
}
else
{
ULONG NewSize;
NewSize = (ULONG)GetExpression() * 1024;
if (0 > (LONG)NewSize)
{
dprintf("*** Cache size %ld (%#lx KB) is too large - "
"cache unchanged.\n", NewSize, KBYTES(NewSize));
}
else if (m_ForceDecodePTEs)
{
dprintf("Cache size update deferred until "
"noforcedecodeptes\n");
m_UserSize = NewSize;
}
else
{
m_UserSize = NewSize;
m_MaxSize = m_UserSize;
if (m_MaxSize == 0)
{
Empty();
}
}
}
}
dprintf("\n");
dprintf("Max cache size is : %ld bytes (%#lx KB) %s\n",
m_MaxSize, KBYTES(m_MaxSize),
m_MaxSize ? "" : "(cache is off)");
dprintf("Total memory in cache : %ld bytes (%#lx KB) \n",
m_Size - m_NodeCount * sizeof(CACHE),
KBYTES(m_Size - m_NodeCount * sizeof(CACHE)));
dprintf("Number of regions cached: %ld\n", m_NodeCount);
ULONG TotalPartial;
ULONG64 TotalBytes;
double PerCached;
TotalPartial = m_CachedReads + m_UncachedReads;
TotalBytes = m_CachedBytes + m_UncachedBytes;
dprintf("%d full reads broken into %d partial reads\n",
m_Reads, TotalPartial);
PerCached = TotalPartial ?
(double)m_CachedReads * 100.0 / TotalPartial : 0.0;
dprintf(" counts: %d cached/%d uncached, %.2lf%% cached\n",
m_CachedReads, m_UncachedReads, PerCached);
PerCached = TotalBytes ?
(double)m_CachedBytes * 100.0 / TotalBytes : 0.0;
dprintf(" bytes : %I64d cached/%I64d uncached, %.2lf%% cached\n",
m_CachedBytes, m_UncachedBytes, PerCached);
if (m_DecodePTEs)
{
dprintf ("** Transition PTEs are implicitly decoded\n");
}
if (m_ForceDecodePTEs)
{
dprintf("** Virtual addresses are translated to "
"physical addresses before access\n");
}
if (m_PurgeOverride)
{
dprintf("** Implicit cache flushing disabled **\n");
}
if (m_Suspend)
{
dprintf("** Cache access is suspended\n");
}
Done:
while (*g_CurCmd && *g_CurCmd != ';')
{
g_CurCmd++;
}
}
void
MemoryCache::Dump(void)
{
dprintf("Current size %x, max size %x\n",
m_Size, m_MaxSize);
dprintf("%d nodes:\n", m_NodeCount);
DumpNode(m_Root);
}
void
MemoryCache::DumpNode(PCACHE Node)
{
if (Node->SplayLinks.LeftChild)
{
DumpNode((PCACHE)Node->SplayLinks.LeftChild);
}
dprintf(" offset %s, length %3x, flags %x, status %08x\n",
FormatAddr64(Node->Offset), Node->Length,
Node->Flags, (Node->Flags & C_ERROR) ? Node->u.Status : S_OK);
if (Node->SplayLinks.RightChild)
{
DumpNode((PCACHE)Node->SplayLinks.RightChild);
}
}
//----------------------------------------------------------------------------
//
// VirtualMemoryCache.
//
//----------------------------------------------------------------------------
void
VirtualMemoryCache::SetProcess(ProcessInfo* Process)
{
m_Process = Process;
m_Target = m_Process->m_Target;
}
HRESULT
VirtualMemoryCache::ReadUncached(IN ULONG64 BaseAddress,
IN PVOID UserBuffer,
IN ULONG TransferCount,
OUT PULONG BytesRead)
{
return m_Target->ReadVirtualUncached(m_Process, BaseAddress, UserBuffer,
TransferCount, BytesRead);
}
HRESULT
VirtualMemoryCache::WriteUncached(IN ULONG64 BaseAddress,
IN PVOID UserBuffer,
IN ULONG TransferCount,
OUT PULONG BytesWritten)
{
return m_Target->WriteVirtualUncached(m_Process, BaseAddress, UserBuffer,
TransferCount, BytesWritten);
}
//----------------------------------------------------------------------------
//
// PhysicalMemoryCache.
//
//----------------------------------------------------------------------------
void
PhysicalMemoryCache::SetTarget(TargetInfo* Target)
{
m_Target = Target;
}
HRESULT
PhysicalMemoryCache::ReadUncached(IN ULONG64 BaseAddress,
IN PVOID UserBuffer,
IN ULONG TransferCount,
OUT PULONG BytesRead)
{
return m_Target->ReadPhysicalUncached(BaseAddress, UserBuffer,
TransferCount, PHYS_FLAG_DEFAULT,
BytesRead);
}
HRESULT
PhysicalMemoryCache::WriteUncached(IN ULONG64 BaseAddress,
IN PVOID UserBuffer,
IN ULONG TransferCount,
OUT PULONG BytesWritten)
{
return m_Target->WritePhysicalUncached(BaseAddress, UserBuffer,
TransferCount, PHYS_FLAG_DEFAULT,
BytesWritten);
}