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

  1. //----------------------------------------------------------------------------
  2. //
  3. // Memory cache object.
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997-2002.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "ntsdp.hpp"
  9. #define DBG_CACHE 0
  10. #if DBG_CACHE
  11. #define DPCACHE(Args) g_NtDllCalls.DbgPrint Args
  12. #else
  13. #define DPCACHE(Args)
  14. #endif
  15. typedef struct _CACHE
  16. {
  17. RTL_SPLAY_LINKS SplayLinks;
  18. ULONG64 Offset;
  19. ULONG Length;
  20. USHORT Flags;
  21. union
  22. {
  23. PUCHAR Data;
  24. HRESULT Status;
  25. } u;
  26. } CACHE, *PCACHE;
  27. #define C_ERROR 0x0001 // Cache of error code
  28. #define C_DONTEXTEND 0x0002 // Don't try to extend
  29. #define LARGECACHENODE 1024 // Size of large cache node
  30. //----------------------------------------------------------------------------
  31. //
  32. // MemoryCache.
  33. //
  34. //----------------------------------------------------------------------------
  35. MemoryCache::MemoryCache(ULONG MaxSize)
  36. {
  37. m_Target = NULL;
  38. m_MaxSize = MaxSize;
  39. m_UserSize = m_MaxSize;
  40. m_Reads = 0;
  41. m_CachedReads = 0;
  42. m_UncachedReads = 0;
  43. m_CachedBytes = 0;
  44. m_UncachedBytes = 0;
  45. m_Misses = 0;
  46. m_Size = 0;
  47. m_NodeCount = 0;
  48. m_PurgeOverride = FALSE;
  49. m_DecodePTEs = TRUE;
  50. m_ForceDecodePTEs = FALSE;
  51. m_Suspend = 0;
  52. m_Root = NULL;
  53. }
  54. MemoryCache::~MemoryCache(void)
  55. {
  56. Empty();
  57. }
  58. HRESULT
  59. MemoryCache::Read(IN ULONG64 BaseAddress,
  60. IN PVOID UserBuffer,
  61. IN ULONG TransferCount,
  62. IN PULONG BytesRead)
  63. /*++
  64. This function returns the specified data from the system being debugged
  65. using the current mapping of the processor. If the data is not
  66. in the cache, it will then be read from the target system.
  67. Arguments:
  68. BaseAddress - Supplies the base address of the memory to be
  69. copied into the UserBuffer.
  70. TransferCount - Amount of data to be copied to the UserBuffer.
  71. UserBuffer - Address to copy the requested data.
  72. BytesRead - Number of bytes which could actually be copied
  73. --*/
  74. {
  75. HRESULT Status;
  76. PCACHE Node, Node2;
  77. ULONG NextLength;
  78. ULONG i, SuccRead;
  79. PUCHAR NodeData;
  80. *BytesRead = 0;
  81. if (TransferCount == 0)
  82. {
  83. return S_OK;
  84. }
  85. if (m_MaxSize == 0 || m_Suspend)
  86. {
  87. //
  88. // Cache is off
  89. //
  90. goto ReadDirect;
  91. }
  92. DPCACHE(("CACHE: Read req %s:%x\n",
  93. FormatAddr64(BaseAddress), TransferCount));
  94. m_Reads++;
  95. Node = Lookup(BaseAddress, TransferCount, &NextLength);
  96. Status = S_OK;
  97. for (;;)
  98. {
  99. BOOL Cached = FALSE;
  100. if (Node == NULL || Node->Offset > BaseAddress)
  101. {
  102. //
  103. // We are missing the leading data, read it into the cache
  104. //
  105. if (Node)
  106. {
  107. //
  108. // Only get (exactly) enough data to reach neighboring cache
  109. // node. If an overlapped read occurs between the two nodes,
  110. // the data will be concatenated then.
  111. //
  112. NextLength = (ULONG)(Node->Offset - BaseAddress);
  113. }
  114. NodeData = Alloc(NextLength);
  115. Node = (PCACHE)Alloc(sizeof(CACHE));
  116. if (NodeData == NULL || Node == NULL)
  117. {
  118. //
  119. // Out of memory - just read directly to UserBuffer
  120. //
  121. if (NodeData)
  122. {
  123. Free(NodeData, NextLength);
  124. }
  125. if (Node)
  126. {
  127. Free((PUCHAR)Node, sizeof (CACHE));
  128. }
  129. m_UncachedReads++;
  130. m_UncachedBytes += TransferCount;
  131. goto ReadDirect;
  132. }
  133. //
  134. // Read missing data into cache node
  135. //
  136. Node->Offset = BaseAddress;
  137. Node->u.Data = NodeData;
  138. Node->Flags = 0;
  139. m_Misses++;
  140. m_UncachedReads++;
  141. Status = ReadUncached(BaseAddress, Node->u.Data,
  142. NextLength, &SuccRead);
  143. if (Status == HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT))
  144. {
  145. Free(NodeData, NextLength);
  146. Free((PUCHAR)Node, sizeof (CACHE));
  147. DPCACHE(("CACHE: Read failed, %x\n", Status));
  148. return Status;
  149. }
  150. else if (Status != S_OK)
  151. {
  152. //
  153. // There was an error, cache the error for the starting
  154. // byte of this range
  155. //
  156. Free(NodeData, NextLength);
  157. if (Status != HRESULT_FROM_NT(STATUS_UNSUCCESSFUL) &&
  158. Status != HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY))
  159. {
  160. //
  161. // For now be safe, don't cache this error
  162. //
  163. Free((PUCHAR)Node, sizeof (CACHE));
  164. ErrOut("ReadMemoryError %08lx at %s\n",
  165. Status, FormatAddr64(BaseAddress));
  166. DPCACHE(("CACHE: Read partial %x, status %x\n",
  167. *BytesRead, Status));
  168. return *BytesRead > 0 ? S_OK : Status;
  169. }
  170. Node->Length = 1;
  171. Node->Flags |= C_ERROR;
  172. Node->u.Status = Status;
  173. DPCACHE(("CACHE: Error %x node at %s\n",
  174. Status, FormatAddr64(BaseAddress)));
  175. }
  176. else
  177. {
  178. m_UncachedBytes += SuccRead;
  179. Node->Length = SuccRead;
  180. if (SuccRead != NextLength)
  181. {
  182. //
  183. // Some data was not transfered, cache what was returned
  184. //
  185. Node->Flags |= C_DONTEXTEND;
  186. m_Size -= (NextLength - SuccRead);
  187. }
  188. DPCACHE(("CACHE: Added %s:%x, flags %x\n",
  189. FormatAddr64(BaseAddress),
  190. Node->Length, Node->Flags));
  191. }
  192. //
  193. // Insert cache node into splay tree
  194. //
  195. InsertNode(Node);
  196. }
  197. else
  198. {
  199. Cached = TRUE;
  200. m_CachedReads++;
  201. }
  202. if (Node->Flags & C_ERROR)
  203. {
  204. //
  205. // Hit an error range, we're done
  206. //
  207. DPCACHE(("CACHE: Read partial %x, error node %x\n",
  208. *BytesRead, Node->u.Status));
  209. return *BytesRead > 0 ? S_OK : Node->u.Status;
  210. }
  211. //
  212. // Move available data to UserBuffer
  213. //
  214. i = (ULONG)(BaseAddress - Node->Offset);
  215. NodeData = Node->u.Data + i;
  216. i = (ULONG)Node->Length - i;
  217. if (TransferCount < i)
  218. {
  219. i = TransferCount;
  220. }
  221. memcpy(UserBuffer, NodeData, i);
  222. if (Cached)
  223. {
  224. m_CachedBytes += i;
  225. }
  226. TransferCount -= i;
  227. BaseAddress += i;
  228. UserBuffer = (PVOID)((PUCHAR)UserBuffer + i);
  229. *BytesRead += i;
  230. if (!TransferCount)
  231. {
  232. //
  233. // All of the user's data has been transfered
  234. //
  235. DPCACHE(("CACHE: Read success %x\n", *BytesRead));
  236. return S_OK;
  237. }
  238. //
  239. // Look for another cache node with more data
  240. //
  241. Node2 = Lookup(BaseAddress, TransferCount, &NextLength);
  242. if (Node2)
  243. {
  244. if ((Node2->Flags & C_ERROR) == 0 &&
  245. Node2->Offset == BaseAddress &&
  246. Node2->Length + Node->Length < LARGECACHENODE)
  247. {
  248. //
  249. // Data is continued in node2, adjoin the neigboring
  250. // cached data in node & node2 together.
  251. //
  252. NodeData = Alloc(Node->Length + Node2->Length);
  253. if (NodeData != NULL)
  254. {
  255. DPCACHE(("CACHE: Merge %s:%x with %s:%x\n",
  256. FormatAddr64(Node->Offset), Node->Length,
  257. FormatAddr64(Node2->Offset), Node2->Length));
  258. memcpy(NodeData, Node->u.Data, Node->Length);
  259. memcpy(NodeData + Node->Length, Node2->u.Data,
  260. Node2->Length);
  261. Free(Node->u.Data, Node->Length);
  262. Node->u.Data = NodeData;
  263. Node->Length += Node2->Length;
  264. m_Root = (PCACHE)pRtlDelete((PRTL_SPLAY_LINKS)Node2);
  265. Free (Node2->u.Data, Node2->Length);
  266. Free ((PUCHAR)Node2, sizeof (CACHE));
  267. m_NodeCount--;
  268. continue;
  269. }
  270. }
  271. //
  272. // Only get enough data to reach the neighboring cache Node2
  273. //
  274. NextLength = (ULONG)(Node2->Offset - BaseAddress);
  275. if (NextLength == 0)
  276. {
  277. //
  278. // Data is continued in Node2, go get it.
  279. //
  280. Node = Node2;
  281. continue;
  282. }
  283. }
  284. else
  285. {
  286. if (Node->Length > LARGECACHENODE)
  287. {
  288. //
  289. // Current cache node is already big enough. Don't extend
  290. // it, add another cache node.
  291. //
  292. Node = NULL;
  293. continue;
  294. }
  295. }
  296. //
  297. // Extend the current node to include missing data
  298. //
  299. if (Node->Flags & C_DONTEXTEND)
  300. {
  301. Node = NULL;
  302. continue;
  303. }
  304. NodeData = Alloc(Node->Length + NextLength);
  305. if (!NodeData)
  306. {
  307. Node = NULL;
  308. continue;
  309. }
  310. memcpy(NodeData, Node->u.Data, Node->Length);
  311. Free(Node->u.Data, Node->Length);
  312. Node->u.Data = NodeData;
  313. //
  314. // Add new data to end of this node
  315. //
  316. m_Misses++;
  317. m_UncachedReads++;
  318. Status = ReadUncached(BaseAddress, Node->u.Data + Node->Length,
  319. NextLength, &SuccRead);
  320. if (Status == HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT))
  321. {
  322. m_Size -= NextLength;
  323. DPCACHE(("CACHE: Read add failed, %x\n", Status));
  324. return Status;
  325. }
  326. else if (Status != S_OK)
  327. {
  328. //
  329. // Return to error to the caller
  330. //
  331. Node->Flags |= C_DONTEXTEND;
  332. m_Size -= NextLength;
  333. ErrOut("ReadMemoryError %08lx at %s\n",
  334. Status, FormatAddr64(BaseAddress));
  335. DPCACHE(("CACHE: Read add partial %x, status %x\n",
  336. *BytesRead, Status));
  337. return *BytesRead > 0 ? S_OK : Status;
  338. }
  339. m_UncachedBytes += SuccRead;
  340. if (SuccRead != NextLength)
  341. {
  342. Node->Flags |= C_DONTEXTEND;
  343. m_Size -= (NextLength - SuccRead);
  344. }
  345. Node->Length += SuccRead;
  346. DPCACHE(("CACHE: Extended %s:%x to %x, flags %x\n",
  347. FormatAddr64(BaseAddress),
  348. Node->Length - SuccRead, Node->Length, Node->Flags));
  349. // Loop, and move data to user's buffer
  350. }
  351. ReadDirect:
  352. Status = ReadUncached(BaseAddress, UserBuffer, TransferCount, &SuccRead);
  353. *BytesRead += SuccRead;
  354. if (Status != HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT))
  355. {
  356. Status = *BytesRead > 0 ? S_OK : Status;
  357. }
  358. DPCACHE(("CACHE: Read uncached %x, status %x\n",
  359. *BytesRead, Status));
  360. return Status;
  361. }
  362. HRESULT
  363. MemoryCache::Write(IN ULONG64 BaseAddress,
  364. IN PVOID UserBuffer,
  365. IN ULONG TransferCount,
  366. OUT PULONG BytesWritten)
  367. {
  368. // Remove data from cache before writing through to target system.
  369. Remove(BaseAddress, TransferCount);
  370. return WriteUncached(BaseAddress, UserBuffer,
  371. TransferCount, BytesWritten);
  372. }
  373. PCACHE
  374. MemoryCache::Lookup(ULONG64 Offset,
  375. ULONG Length,
  376. PULONG LengthUsed)
  377. /*++
  378. Routine Description:
  379. Walks the cache tree looking for a matching range closest to
  380. the supplied Offset. The length of the range searched is based on
  381. the past length, but may be adjusted slightly.
  382. This function will always search for the starting byte.
  383. Arguments:
  384. Offset - Starting byte being looked for in cache
  385. Length - Length of range being looked for in cache
  386. LengthUsed - Length of range which was really searched for
  387. Return Value:
  388. NULL - data for returned range was not found
  389. PCACHE - leftmost cachenode which has data for returned range
  390. --*/
  391. {
  392. PCACHE Node, Node2;
  393. ULONG64 SumOffsetLength;
  394. if (Length < 0x80 && m_Misses > 3)
  395. {
  396. // Try to cache more than a tiny amount.
  397. Length = 0x80;
  398. }
  399. SumOffsetLength = Offset + Length;
  400. if (SumOffsetLength < Length)
  401. {
  402. //
  403. // Offset + Length wrapped. Adjust Length to be only
  404. // enough bytes before wrapping.
  405. //
  406. Length = (ULONG)(0 - Offset);
  407. SumOffsetLength = (ULONG64)-1;
  408. }
  409. DPCACHE(("CACHE: Lookup(%s, %x) -> ",
  410. FormatAddr64(Offset), Length));
  411. //
  412. // Find leftmost cache node for BaseAddress through BaseAddress+Length
  413. //
  414. Node2 = NULL;
  415. Node = m_Root;
  416. while (Node != NULL)
  417. {
  418. if (SumOffsetLength <= Node->Offset)
  419. {
  420. Node = (PCACHE)RtlLeftChild(&Node->SplayLinks);
  421. }
  422. else if (Node->Offset + Node->Length <= Offset)
  423. {
  424. Node = (PCACHE)RtlRightChild(&Node->SplayLinks);
  425. }
  426. else
  427. {
  428. if (Node->Offset <= Offset)
  429. {
  430. //
  431. // Found starting byte
  432. //
  433. *LengthUsed = Length;
  434. DPCACHE(("found %s:%x, flags %x, used %x\n",
  435. FormatAddr64(Node->Offset),
  436. Node->Length, Node->Flags, Length));
  437. return Node;
  438. }
  439. //
  440. // Check to see if there's a node which has a match closer
  441. // to the start of the requested range
  442. //
  443. Node2 = Node;
  444. Length = (ULONG)(Node->Offset - Offset);
  445. SumOffsetLength = Node->Offset;
  446. Node = (PCACHE)RtlLeftChild(&Node->SplayLinks);
  447. }
  448. }
  449. #if DBG_CACHE
  450. if (Node2)
  451. {
  452. DPCACHE(("found %s:%x, flags %x, used %x\n",
  453. FormatAddr64(Node2->Offset), Node2->Length,
  454. Node2->Flags, Length));
  455. }
  456. else
  457. {
  458. DPCACHE(("not found\n"));
  459. }
  460. #endif
  461. *LengthUsed = Length;
  462. return Node2;
  463. }
  464. VOID
  465. MemoryCache::InsertNode(IN PCACHE Node)
  466. {
  467. PCACHE Node2;
  468. ULONG64 BaseAddress;
  469. //
  470. // Insert cache node into splay tree
  471. //
  472. RtlInitializeSplayLinks(&Node->SplayLinks);
  473. m_NodeCount++;
  474. if (m_Root == NULL)
  475. {
  476. m_Root = Node;
  477. return;
  478. }
  479. Node2 = m_Root;
  480. BaseAddress = Node->Offset;
  481. for (; ;)
  482. {
  483. if (BaseAddress < Node2->Offset)
  484. {
  485. if (RtlLeftChild(&Node2->SplayLinks))
  486. {
  487. Node2 = (PCACHE) RtlLeftChild(&Node2->SplayLinks);
  488. continue;
  489. }
  490. RtlInsertAsLeftChild(Node2, Node);
  491. break;
  492. }
  493. else
  494. {
  495. if (RtlRightChild(&Node2->SplayLinks))
  496. {
  497. Node2 = (PCACHE) RtlRightChild(&Node2->SplayLinks);
  498. continue;
  499. }
  500. RtlInsertAsRightChild(Node2, Node);
  501. break;
  502. }
  503. }
  504. m_Root = (PCACHE)pRtlSplay((PRTL_SPLAY_LINKS)Node2);
  505. }
  506. VOID
  507. MemoryCache::Add(IN ULONG64 BaseAddress,
  508. IN PVOID UserBuffer,
  509. IN ULONG Length)
  510. /*++
  511. Routine Description:
  512. Insert some data into the cache.
  513. Arguments:
  514. BaseAddress - Virtual address
  515. Length - length to cache
  516. UserBuffer - data to put into cache
  517. Return Value:
  518. --*/
  519. {
  520. PCACHE Node;
  521. PUCHAR NodeData;
  522. if (m_MaxSize == 0)
  523. {
  524. //
  525. // Cache is off
  526. //
  527. return;
  528. }
  529. //
  530. // Delete any cached info which hits range
  531. //
  532. Remove (BaseAddress, Length);
  533. NodeData = Alloc (Length);
  534. Node = (PCACHE) Alloc (sizeof (CACHE));
  535. if (NodeData == NULL || Node == NULL)
  536. {
  537. //
  538. // Out of memory - don't bother
  539. //
  540. if (NodeData)
  541. {
  542. Free (NodeData, Length);
  543. }
  544. if (Node)
  545. {
  546. Free ((PUCHAR)Node, sizeof (CACHE));
  547. }
  548. return;
  549. }
  550. //
  551. // Put data into cache node
  552. //
  553. Node->Offset = BaseAddress;
  554. Node->Length = Length;
  555. Node->u.Data = NodeData;
  556. Node->Flags = 0;
  557. memcpy(NodeData, UserBuffer, Length);
  558. InsertNode(Node);
  559. DPCACHE(("CACHE: Add direct %s:%x\n",
  560. FormatAddr64(Node->Offset), Node->Length));
  561. }
  562. PUCHAR
  563. MemoryCache::Alloc(IN ULONG Length)
  564. /*++
  565. Routine Description:
  566. Allocates memory for virtual cache, and tracks total memory
  567. usage.
  568. Arguments:
  569. Length - Amount of memory to allocate
  570. Return Value:
  571. NULL - too much memory is in use, or memory could not
  572. be allocated
  573. Otherwise, returns to address of the allocated memory
  574. --*/
  575. {
  576. PUCHAR Mem;
  577. if (m_Size + Length > m_MaxSize)
  578. {
  579. return NULL;
  580. }
  581. if (!(Mem = (PUCHAR)malloc (Length)))
  582. {
  583. //
  584. // Out of memory - don't get any larger
  585. //
  586. m_Size = m_MaxSize + 1;
  587. return NULL;
  588. }
  589. m_Size += Length;
  590. return Mem;
  591. }
  592. VOID
  593. MemoryCache::Free(IN PUCHAR Memory,
  594. IN ULONG Length)
  595. /*++
  596. Routine Description:
  597. Free memory allocated with Alloc. Adjusts cache is use totals.
  598. Arguments:
  599. Memory - Address of allocated memory
  600. Length - Length of allocated memory
  601. Return Value:
  602. NONE
  603. --*/
  604. {
  605. m_Size -= Length;
  606. free(Memory);
  607. }
  608. VOID
  609. MemoryCache::Remove(IN ULONG64 BaseAddress,
  610. IN ULONG TransferCount)
  611. /*++
  612. Routine Description:
  613. Invalidates range from the cache.
  614. Arguments:
  615. BaseAddress - Starting address to purge
  616. TransferCount - Length of area to purge
  617. Return Value:
  618. NONE
  619. --*/
  620. {
  621. PCACHE Node;
  622. ULONG Used;
  623. //
  624. // Invalidate any data in the cache which covers this range
  625. //
  626. while (Node = Lookup(BaseAddress, TransferCount, &Used))
  627. {
  628. //
  629. // For now just delete the entire cache node which hits the range
  630. //
  631. DPCACHE(("CACHE: Remove %s:%x, flags %x\n",
  632. FormatAddr64(Node->Offset), Node->Length, Node->Flags));
  633. m_Root = (PCACHE) pRtlDelete (&Node->SplayLinks);
  634. if (!(Node->Flags & C_ERROR))
  635. {
  636. Free (Node->u.Data, Node->Length);
  637. }
  638. Free ((PUCHAR)Node, sizeof (CACHE));
  639. m_NodeCount--;
  640. }
  641. }
  642. VOID
  643. MemoryCache::Empty(void)
  644. /*++
  645. Routine Description:
  646. Purges to entire cache
  647. Arguments:
  648. NONE
  649. Return Value:
  650. NONE
  651. --*/
  652. {
  653. PCACHE Node, Node2;
  654. m_Reads = 0;
  655. m_CachedReads = 0;
  656. m_UncachedReads = 0;
  657. m_CachedBytes = 0;
  658. m_UncachedBytes = 0;
  659. m_Misses = 0;
  660. if (!m_Root)
  661. {
  662. return;
  663. }
  664. if (m_PurgeOverride != 0)
  665. {
  666. WarnOut("WARNING: cache being held\n");
  667. return;
  668. }
  669. DPCACHE(("CACHE: Empty cache\n"));
  670. Node2 = m_Root;
  671. Node2->SplayLinks.Parent = NULL;
  672. while ((Node = Node2) != NULL)
  673. {
  674. if ((Node2 = (PCACHE) Node->SplayLinks.LeftChild) != NULL)
  675. {
  676. Node->SplayLinks.LeftChild = NULL;
  677. continue;
  678. }
  679. if ((Node2 = (PCACHE) Node->SplayLinks.RightChild) != NULL)
  680. {
  681. Node->SplayLinks.RightChild = NULL;
  682. continue;
  683. }
  684. Node2 = (PCACHE) Node->SplayLinks.Parent;
  685. if (!(Node->Flags & C_ERROR))
  686. {
  687. free (Node->u.Data);
  688. }
  689. free (Node);
  690. }
  691. m_Size = 0;
  692. m_NodeCount = 0;
  693. m_Root = NULL;
  694. }
  695. VOID
  696. MemoryCache::PurgeType(ULONG Type)
  697. /*++
  698. Routine Description:
  699. Purges all nodes from the cache which match type in question
  700. Arguments:
  701. Type - type of entries to purge from the cache
  702. 0 - entries of errored ranges
  703. 1 - plus, node which cache user mode entries
  704. Return Value:
  705. NONE
  706. --*/
  707. {
  708. PCACHE Node, Node2;
  709. if (!m_Root)
  710. {
  711. return;
  712. }
  713. DPCACHE(("CACHCE: Purge type %x\n", Type));
  714. //
  715. // this purges the selected cache entries by copy the all the
  716. // cache nodes except from the ones we don't want
  717. //
  718. Node2 = m_Root;
  719. Node2->SplayLinks.Parent = NULL;
  720. m_Root = NULL;
  721. while ((Node = Node2) != NULL)
  722. {
  723. if ((Node2 = (PCACHE)Node->SplayLinks.LeftChild) != NULL)
  724. {
  725. Node->SplayLinks.LeftChild = NULL;
  726. continue;
  727. }
  728. if ((Node2 = (PCACHE)Node->SplayLinks.RightChild) != NULL)
  729. {
  730. Node->SplayLinks.RightChild = NULL;
  731. continue;
  732. }
  733. Node2 = (PCACHE) Node->SplayLinks.Parent;
  734. m_NodeCount--;
  735. if (Node->Flags & C_ERROR)
  736. {
  737. // remove this one from the tree
  738. Free ((PUCHAR)Node, sizeof (CACHE));
  739. continue;
  740. }
  741. if ((Type == 1) && (Node->Offset < m_Target->m_SystemRangeStart))
  742. {
  743. // remove this one from the tree
  744. Free (Node->u.Data, Node->Length);
  745. Free ((PUCHAR)Node, sizeof (CACHE));
  746. continue;
  747. }
  748. // copy to the new tree
  749. InsertNode(Node);
  750. }
  751. }
  752. VOID
  753. MemoryCache::SetForceDecodePtes(BOOL Enable, TargetInfo* Target)
  754. {
  755. m_ForceDecodePTEs = Enable;
  756. if (Enable)
  757. {
  758. m_MaxSize = 0;
  759. }
  760. else
  761. {
  762. m_MaxSize = m_UserSize;
  763. }
  764. Empty();
  765. if (Target)
  766. {
  767. Target->m_PhysicalCache.ChangeSuspend(Enable);
  768. Target->m_PhysicalCache.Empty();
  769. }
  770. }
  771. void
  772. MemoryCache::ParseCommands(void)
  773. {
  774. ULONG64 Address;
  775. while (*g_CurCmd == ' ')
  776. {
  777. g_CurCmd++;
  778. }
  779. _strlwr(g_CurCmd);
  780. BOOL Parsed = TRUE;
  781. if (IS_KERNEL_TARGET(m_Target))
  782. {
  783. if (strcmp (g_CurCmd, "decodeptes") == 0)
  784. {
  785. PurgeType(0);
  786. m_DecodePTEs = TRUE;
  787. }
  788. else if (strcmp (g_CurCmd, "nodecodeptes") == 0)
  789. {
  790. m_DecodePTEs = FALSE;
  791. }
  792. else if (strcmp (g_CurCmd, "forcedecodeptes") == 0)
  793. {
  794. SetForceDecodePtes(TRUE, m_Target);
  795. }
  796. else if (strcmp (g_CurCmd, "noforcedecodeptes") == 0)
  797. {
  798. SetForceDecodePtes(FALSE, m_Target);
  799. }
  800. else
  801. {
  802. Parsed = FALSE;
  803. }
  804. }
  805. if (Parsed)
  806. {
  807. // Command already handled.
  808. }
  809. else if (strcmp (g_CurCmd, "hold") == 0)
  810. {
  811. m_PurgeOverride = TRUE;
  812. }
  813. else if (strcmp (g_CurCmd, "unhold") == 0)
  814. {
  815. m_PurgeOverride = FALSE;
  816. }
  817. else if (strcmp (g_CurCmd, "flushall") == 0)
  818. {
  819. Empty();
  820. }
  821. else if (strcmp (g_CurCmd, "flushu") == 0)
  822. {
  823. PurgeType(1);
  824. }
  825. else if (strcmp (g_CurCmd, "suspend") == 0)
  826. {
  827. ChangeSuspend(FALSE);
  828. }
  829. else if (strcmp (g_CurCmd, "nosuspend") == 0)
  830. {
  831. ChangeSuspend(TRUE);
  832. }
  833. else if (strcmp (g_CurCmd, "dump") == 0)
  834. {
  835. Dump();
  836. goto Done;
  837. }
  838. else if (*g_CurCmd == 'f')
  839. {
  840. while (*g_CurCmd >= 'a' && *g_CurCmd <= 'z')
  841. {
  842. g_CurCmd++;
  843. }
  844. Address = GetExpression();
  845. Remove(Address, 4096);
  846. dprintf("Cached info for address %s for 4096 bytes was flushed\n",
  847. FormatAddr64(Address));
  848. }
  849. else if (*g_CurCmd)
  850. {
  851. if (*g_CurCmd < '0' || *g_CurCmd > '9')
  852. {
  853. dprintf(".cache [{cachesize} | hold | unhold\n");
  854. dprintf(".cache [flushall | flushu | flush addr]\n");
  855. if (IS_KERNEL_TARGET(m_Target))
  856. {
  857. dprintf(".cache [decodeptes | nodecodeptes]\n");
  858. dprintf(".cache [forcedecodeptes | noforcedecodeptes]\n");
  859. }
  860. goto Done;
  861. }
  862. else
  863. {
  864. ULONG NewSize;
  865. NewSize = (ULONG)GetExpression() * 1024;
  866. if (0 > (LONG)NewSize)
  867. {
  868. dprintf("*** Cache size %ld (%#lx KB) is too large - "
  869. "cache unchanged.\n", NewSize, KBYTES(NewSize));
  870. }
  871. else if (m_ForceDecodePTEs)
  872. {
  873. dprintf("Cache size update deferred until "
  874. "noforcedecodeptes\n");
  875. m_UserSize = NewSize;
  876. }
  877. else
  878. {
  879. m_UserSize = NewSize;
  880. m_MaxSize = m_UserSize;
  881. if (m_MaxSize == 0)
  882. {
  883. Empty();
  884. }
  885. }
  886. }
  887. }
  888. dprintf("\n");
  889. dprintf("Max cache size is : %ld bytes (%#lx KB) %s\n",
  890. m_MaxSize, KBYTES(m_MaxSize),
  891. m_MaxSize ? "" : "(cache is off)");
  892. dprintf("Total memory in cache : %ld bytes (%#lx KB) \n",
  893. m_Size - m_NodeCount * sizeof(CACHE),
  894. KBYTES(m_Size - m_NodeCount * sizeof(CACHE)));
  895. dprintf("Number of regions cached: %ld\n", m_NodeCount);
  896. ULONG TotalPartial;
  897. ULONG64 TotalBytes;
  898. double PerCached;
  899. TotalPartial = m_CachedReads + m_UncachedReads;
  900. TotalBytes = m_CachedBytes + m_UncachedBytes;
  901. dprintf("%d full reads broken into %d partial reads\n",
  902. m_Reads, TotalPartial);
  903. PerCached = TotalPartial ?
  904. (double)m_CachedReads * 100.0 / TotalPartial : 0.0;
  905. dprintf(" counts: %d cached/%d uncached, %.2lf%% cached\n",
  906. m_CachedReads, m_UncachedReads, PerCached);
  907. PerCached = TotalBytes ?
  908. (double)m_CachedBytes * 100.0 / TotalBytes : 0.0;
  909. dprintf(" bytes : %I64d cached/%I64d uncached, %.2lf%% cached\n",
  910. m_CachedBytes, m_UncachedBytes, PerCached);
  911. if (m_DecodePTEs)
  912. {
  913. dprintf ("** Transition PTEs are implicitly decoded\n");
  914. }
  915. if (m_ForceDecodePTEs)
  916. {
  917. dprintf("** Virtual addresses are translated to "
  918. "physical addresses before access\n");
  919. }
  920. if (m_PurgeOverride)
  921. {
  922. dprintf("** Implicit cache flushing disabled **\n");
  923. }
  924. if (m_Suspend)
  925. {
  926. dprintf("** Cache access is suspended\n");
  927. }
  928. Done:
  929. while (*g_CurCmd && *g_CurCmd != ';')
  930. {
  931. g_CurCmd++;
  932. }
  933. }
  934. void
  935. MemoryCache::Dump(void)
  936. {
  937. dprintf("Current size %x, max size %x\n",
  938. m_Size, m_MaxSize);
  939. dprintf("%d nodes:\n", m_NodeCount);
  940. DumpNode(m_Root);
  941. }
  942. void
  943. MemoryCache::DumpNode(PCACHE Node)
  944. {
  945. if (Node->SplayLinks.LeftChild)
  946. {
  947. DumpNode((PCACHE)Node->SplayLinks.LeftChild);
  948. }
  949. dprintf(" offset %s, length %3x, flags %x, status %08x\n",
  950. FormatAddr64(Node->Offset), Node->Length,
  951. Node->Flags, (Node->Flags & C_ERROR) ? Node->u.Status : S_OK);
  952. if (Node->SplayLinks.RightChild)
  953. {
  954. DumpNode((PCACHE)Node->SplayLinks.RightChild);
  955. }
  956. }
  957. //----------------------------------------------------------------------------
  958. //
  959. // VirtualMemoryCache.
  960. //
  961. //----------------------------------------------------------------------------
  962. void
  963. VirtualMemoryCache::SetProcess(ProcessInfo* Process)
  964. {
  965. m_Process = Process;
  966. m_Target = m_Process->m_Target;
  967. }
  968. HRESULT
  969. VirtualMemoryCache::ReadUncached(IN ULONG64 BaseAddress,
  970. IN PVOID UserBuffer,
  971. IN ULONG TransferCount,
  972. OUT PULONG BytesRead)
  973. {
  974. return m_Target->ReadVirtualUncached(m_Process, BaseAddress, UserBuffer,
  975. TransferCount, BytesRead);
  976. }
  977. HRESULT
  978. VirtualMemoryCache::WriteUncached(IN ULONG64 BaseAddress,
  979. IN PVOID UserBuffer,
  980. IN ULONG TransferCount,
  981. OUT PULONG BytesWritten)
  982. {
  983. return m_Target->WriteVirtualUncached(m_Process, BaseAddress, UserBuffer,
  984. TransferCount, BytesWritten);
  985. }
  986. //----------------------------------------------------------------------------
  987. //
  988. // PhysicalMemoryCache.
  989. //
  990. //----------------------------------------------------------------------------
  991. void
  992. PhysicalMemoryCache::SetTarget(TargetInfo* Target)
  993. {
  994. m_Target = Target;
  995. }
  996. HRESULT
  997. PhysicalMemoryCache::ReadUncached(IN ULONG64 BaseAddress,
  998. IN PVOID UserBuffer,
  999. IN ULONG TransferCount,
  1000. OUT PULONG BytesRead)
  1001. {
  1002. return m_Target->ReadPhysicalUncached(BaseAddress, UserBuffer,
  1003. TransferCount, PHYS_FLAG_DEFAULT,
  1004. BytesRead);
  1005. }
  1006. HRESULT
  1007. PhysicalMemoryCache::WriteUncached(IN ULONG64 BaseAddress,
  1008. IN PVOID UserBuffer,
  1009. IN ULONG TransferCount,
  1010. OUT PULONG BytesWritten)
  1011. {
  1012. return m_Target->WritePhysicalUncached(BaseAddress, UserBuffer,
  1013. TransferCount, PHYS_FLAG_DEFAULT,
  1014. BytesWritten);
  1015. }