Source code of Windows XP (NT5)
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.

1168 lines
26 KiB

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