Windows NT 4.0 source code leak
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.

1254 lines
29 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. cache.c
  5. Abstract:
  6. Author:
  7. Wesley Witt (wesw) 8-Mar-1992
  8. Environment:
  9. NT 3.1
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. typedef unsigned long DWORD;
  15. typedef int BOOL;
  16. #define NTINCLUDES
  17. #define MIN_READ_SIZE 0x80
  18. #define MIN_CACHE_MISSES 3
  19. ULONG KdMaxCacheSize = 100*1024;
  20. ULONG KdCacheMisses = 0;
  21. ULONG KdCachePurges = 0;
  22. ULONG KdCacheSize = 0;
  23. ULONG KdNodeCount = 0;
  24. BOOLEAN KdPurgeOverride = FALSE;
  25. BOOLEAN KdCacheDecodePTEs = TRUE;
  26. typedef struct {
  27. RTL_SPLAY_LINKS SplayLinks;
  28. ULONG Offset;
  29. USHORT Length;
  30. USHORT Flags;
  31. union {
  32. PUCHAR Data;
  33. NTSTATUS Status;
  34. } u;
  35. } CACHE, *PCACHE;
  36. #define C_ERROR 0x0001 // Cache of error code
  37. #define C_DONTEXTEND 0x0002 // Don't try to extend
  38. #define C_NONDISCARDABLE 0x0004 // never purge this node
  39. #define LARGECACHENODE 1024 // Size of large cache node
  40. PCACHE VirtCacheRoot; // Root of cache node tree
  41. //
  42. // Prototypes...
  43. //
  44. extern void DebugPrint(char *, ...);
  45. BOOLEAN
  46. KdConvertToPhysicalAddr (
  47. PVOID,
  48. PPHYSICAL_ADDRESS
  49. );
  50. PCACHE
  51. CacheLookup (
  52. ULONG Offset,
  53. ULONG Length,
  54. PULONG LengthUsed
  55. );
  56. VOID
  57. InsertCacheNode (
  58. IN PCACHE node
  59. );
  60. PUCHAR vcmalloc (
  61. IN ULONG Length
  62. );
  63. VOID vcfree (
  64. IN PUCHAR Memory,
  65. IN ULONG Length
  66. );
  67. NTSTATUS
  68. VCReadTranslatePTEAndReadMemory (
  69. IN PVOID TargetBaseAddress,
  70. OUT PVOID UserInterfaceBuffer,
  71. IN ULONG TransferCount,
  72. OUT PULONG ActualBytesRead OPTIONAL
  73. );
  74. VOID
  75. DmKdSetMaxCacheSize(
  76. IN ULONG MaxCacheSize
  77. )
  78. {
  79. KdMaxCacheSize = MaxCacheSize;
  80. }
  81. ULONG
  82. DmKdReadCachedVirtualMemory (
  83. IN ULONG BaseAddress,
  84. IN ULONG TransferCount,
  85. IN PUCHAR UserBuffer,
  86. IN PULONG BytesRead,
  87. IN ULONG NonDiscardable
  88. )
  89. /*++
  90. This function returns the specified data from the system being debugged
  91. using the current mapping of the processor. If the data is not
  92. in the cache, it will then be read from the target system.
  93. Arguments:
  94. TargetBaseAddress - Supplies the base address of the memory to be
  95. copied into the UserBuffer.
  96. TransferCount - Amount of data to be copied to the UserBuffer.
  97. UserBuffer - Address to copy the requested data.
  98. BytesRead - Number of bytes which could actually be copied
  99. Return Value:
  100. STATUS_SUCCESS - The specified read occured.
  101. other (see DmKdReadVirtualMemoryNow).
  102. --*/
  103. {
  104. NTSTATUS st;
  105. PCACHE node, node2;
  106. ULONG nextlength;
  107. ULONG i, br;
  108. PUCHAR p;
  109. *BytesRead = 0;
  110. if (KdMaxCacheSize == 0) {
  111. //
  112. // Cache is off
  113. //
  114. goto ReadDirect;
  115. }
  116. // DebugPrint( "readcache %x %d\n", BaseAddress, TransferCount );
  117. node = CacheLookup(BaseAddress, TransferCount, &nextlength);
  118. st = STATUS_SUCCESS;
  119. while( TRUE ) {
  120. //
  121. // Check if current command has been canceled. If yes, go back to
  122. // kd prompt.
  123. //
  124. if (node == NULL || node->Offset > BaseAddress) {
  125. //
  126. // We are missing the leading data, read it into the cache
  127. //
  128. if (node) {
  129. //
  130. // Only get (exactly) enough data to reach neighboring cache
  131. // node. If an overlapped read occurs between the two nodes,
  132. // the data will be concatenated then.
  133. //
  134. nextlength = node->Offset - BaseAddress;
  135. }
  136. //nextlength = max( nextlength, MIN_READ_SIZE );
  137. p = vcmalloc (nextlength);
  138. node = (PCACHE) vcmalloc (sizeof (CACHE));
  139. if (p == NULL || node == NULL) {
  140. //
  141. // Out of memory - just read directly to UserBuffer
  142. //
  143. if (p) {
  144. vcfree (p, nextlength);
  145. }
  146. if (node) {
  147. vcfree ((PUCHAR)node, sizeof (CACHE));
  148. }
  149. goto ReadDirect;
  150. }
  151. //
  152. // Read missing data into cache node
  153. //
  154. node->Offset = BaseAddress;
  155. node->u.Data = p;
  156. node->Flags = 0;
  157. if (NonDiscardable) {
  158. node->Flags |= C_NONDISCARDABLE;
  159. }
  160. KdCacheMisses++;
  161. while( TRUE ) {
  162. st = DmKdReadVirtualMemoryNow(
  163. (PVOID) BaseAddress,
  164. (PVOID) node->u.Data,
  165. nextlength,
  166. &br
  167. );
  168. if (NT_SUCCESS(st)) {
  169. break;
  170. }
  171. //
  172. // Before accepting the error, make sure request
  173. // didn't fail because it was enlarged for caching.
  174. //
  175. i = nextlength;
  176. //nextlength = TransferCount;
  177. //
  178. // If length crosses possible page boundry, shrink request
  179. // even furture.
  180. //
  181. if ((BaseAddress & ~0xfff) != ((BaseAddress+nextlength) & ~0xfff)) {
  182. nextlength = (BaseAddress | 0xfff) - BaseAddress + 1;
  183. }
  184. //
  185. // If nextlength is shorter then failed request, then loop
  186. // and try again
  187. //
  188. if (nextlength >= i) {
  189. //
  190. // If implicit decode of the pte is requested, go
  191. // try getting this memory by it's physical address
  192. //
  193. if (st == STATUS_UNSUCCESSFUL && KdCacheDecodePTEs) {
  194. st = VCReadTranslatePTEAndReadMemory (
  195. (PVOID) BaseAddress,
  196. (PVOID) node->u.Data,
  197. nextlength,
  198. &br
  199. );
  200. }
  201. break;
  202. }
  203. }
  204. if (!NT_SUCCESS(st)) {
  205. //
  206. // There was an error, cache the error for the starting
  207. // byte of this range
  208. //
  209. vcfree (p, nextlength);
  210. if (st != STATUS_UNSUCCESSFUL) {
  211. //
  212. // For now be safe, don't cache this error
  213. //
  214. vcfree ((PUCHAR)node, sizeof (CACHE));
  215. return *BytesRead ? STATUS_SUCCESS : st;
  216. }
  217. node->Length = 1;
  218. node->Flags |= C_ERROR;
  219. node->u.Status = st;
  220. } else {
  221. node->Length = (USHORT) br;
  222. if (br != nextlength) {
  223. //
  224. // Some data was not transfered, cache what was returned
  225. //
  226. node->Flags |= C_DONTEXTEND;
  227. KdCacheSize -= (nextlength - br);
  228. }
  229. }
  230. //
  231. // Insert cache node into splay tree
  232. //
  233. InsertCacheNode (node);
  234. }
  235. if (node->Flags & C_ERROR) {
  236. //
  237. // Hit an error range, we're done
  238. //
  239. return *BytesRead ? STATUS_SUCCESS : node->u.Status;
  240. }
  241. //
  242. // Move available data to UserBuffer
  243. //
  244. i = BaseAddress - node->Offset;
  245. p = node->u.Data + i;
  246. i = (ULONG) node->Length - i;
  247. if (TransferCount < i) {
  248. i = TransferCount;
  249. }
  250. memcpy (UserBuffer, p, i);
  251. TransferCount -= i;
  252. BaseAddress += i;
  253. UserBuffer += i;
  254. *BytesRead += i;
  255. if (!TransferCount) {
  256. //
  257. // All of the users data has been transfered
  258. //
  259. return STATUS_SUCCESS;
  260. }
  261. //
  262. // Look for another cache node with more data
  263. //
  264. node2 = CacheLookup (BaseAddress, TransferCount, &nextlength);
  265. if (node2) {
  266. if ((node2->Flags & C_ERROR) == 0 &&
  267. node2->Offset == BaseAddress &&
  268. node2->Length + node->Length < LARGECACHENODE) {
  269. //
  270. // Data is continued in node2, adjoin the neigboring
  271. // cached data in node & node2 together.
  272. //
  273. p = vcmalloc (node->Length + node2->Length);
  274. if (p != NULL) {
  275. memcpy (p, node->u.Data, node->Length);
  276. memcpy (p+node->Length, node2->u.Data, node2->Length);
  277. vcfree (node->u.Data, node->Length);
  278. node->u.Data = p;
  279. node->Length += node2->Length;
  280. VirtCacheRoot = (PCACHE) RtlDelete ((PRTL_SPLAY_LINKS)node2);
  281. vcfree ((PUCHAR)node2->u.Data, node2->Length);
  282. vcfree ((PUCHAR)node2, sizeof (CACHE));
  283. KdNodeCount--;
  284. continue;
  285. }
  286. }
  287. //
  288. // Only get enough data to reach the neighboring cache node2
  289. //
  290. nextlength = node2->Offset - BaseAddress;
  291. if (nextlength == 0) {
  292. //
  293. // Data is continued in node2, go get it.
  294. //
  295. node = node2;
  296. continue;
  297. }
  298. } else {
  299. if (node->Length > LARGECACHENODE) {
  300. //
  301. // Current cache node is already big enough. Don't extend
  302. // it, add another cache node.
  303. //
  304. node = NULL;
  305. continue;
  306. }
  307. }
  308. //
  309. // Extend the current node to include missing data
  310. //
  311. if (node->Flags & C_DONTEXTEND) {
  312. node = NULL;
  313. continue;
  314. }
  315. //nextlength = max( nextlength, MIN_READ_SIZE );
  316. p = vcmalloc (node->Length + nextlength);
  317. if (!p) {
  318. node = NULL;
  319. continue;
  320. }
  321. memcpy (p, node->u.Data, node->Length);
  322. vcfree (node->u.Data, node->Length);
  323. node->u.Data = p;
  324. //
  325. // Add new data to end of this node
  326. //
  327. KdCacheMisses++;
  328. while( TRUE ) {
  329. st = DmKdReadVirtualMemoryNow (
  330. (PVOID) BaseAddress,
  331. (PVOID) (node->u.Data + node->Length),
  332. nextlength,
  333. &br
  334. );
  335. if (NT_SUCCESS(st)) {
  336. break;
  337. }
  338. //
  339. // Before accepting the error, make sure request
  340. // didn't fail because it was enlarged for caching.
  341. //
  342. node->Flags |= C_DONTEXTEND;
  343. i = TransferCount;
  344. //
  345. // If length crosses possible page boundry, shrink request
  346. // even furture.
  347. //
  348. if ((BaseAddress & ~0xfff) != ((BaseAddress + i) & ~0xfff)) {
  349. i = (BaseAddress | 0xfff) - BaseAddress + 1;
  350. }
  351. //
  352. // If nextlength is shorter, then loop (try the read again)
  353. //
  354. if (i >= nextlength) {
  355. //
  356. // If implicit decode of the pte is requested, go
  357. // try getting this memory by it's physical address
  358. //
  359. if (st == STATUS_UNSUCCESSFUL && KdCacheDecodePTEs) {
  360. st = VCReadTranslatePTEAndReadMemory (
  361. (PVOID) BaseAddress,
  362. (PVOID) (node->u.Data + node->Length),
  363. nextlength,
  364. &br
  365. );
  366. }
  367. break;
  368. }
  369. //
  370. // Adjust counts for new transfer size
  371. //
  372. KdCacheSize -= (nextlength - i);
  373. nextlength = i;
  374. }
  375. if (!NT_SUCCESS(st)) {
  376. //
  377. // Return to error to the caller
  378. //
  379. node->Flags |= C_DONTEXTEND;
  380. KdCacheSize -= nextlength;
  381. return *BytesRead ? STATUS_SUCCESS : st;
  382. }
  383. if (br != nextlength) {
  384. node->Flags |= C_DONTEXTEND;
  385. KdCacheSize -= (nextlength - br);
  386. }
  387. node->Length += (USHORT) br;
  388. // Loop, and move data to user's buffer
  389. }
  390. ReadDirect:
  391. while (TransferCount) {
  392. nextlength = TransferCount;
  393. while( TRUE ) {
  394. st = DmKdReadVirtualMemoryNow (
  395. (PVOID) BaseAddress,
  396. (PVOID) UserBuffer,
  397. nextlength,
  398. &br
  399. );
  400. if (NT_SUCCESS(st)) {
  401. break;
  402. }
  403. if ((BaseAddress & ~0xfff) != ((BaseAddress+nextlength) & ~0xfff)) {
  404. //
  405. // Before accepting the error, make sure request
  406. // didn't fail because it crossed multiple pages
  407. //
  408. nextlength = (BaseAddress | 0xfff) - BaseAddress + 1;
  409. } else {
  410. if (st == STATUS_UNSUCCESSFUL && KdCacheDecodePTEs) {
  411. //
  412. // Try getting the memory by looking up the physical
  413. // location of the page
  414. //
  415. st = VCReadTranslatePTEAndReadMemory (
  416. (PVOID) BaseAddress,
  417. (PVOID) UserBuffer,
  418. nextlength,
  419. &br
  420. );
  421. if (NT_SUCCESS(st)) {
  422. break;
  423. }
  424. }
  425. //
  426. // Return to error to the caller
  427. //
  428. return *BytesRead ? STATUS_SUCCESS : st;
  429. }
  430. }
  431. TransferCount -= br;
  432. BaseAddress += br;
  433. UserBuffer += br;
  434. *BytesRead += br;
  435. }
  436. return STATUS_SUCCESS;
  437. }
  438. PCACHE
  439. CacheLookup (
  440. ULONG Offset,
  441. ULONG Length,
  442. PULONG LengthUsed
  443. )
  444. /*++
  445. Routine Description:
  446. Walks the cache tree looking for a matching range closest to
  447. the supplied Offset. The length of the range searched is based on
  448. the past length, but may be adjusted slightly.
  449. This function will always search for the starting byte.
  450. Arguments:
  451. Offset - Starting byte being looked for in cache
  452. Length - Length of range being looked for in cache
  453. LengthUsed - Length of range which was really search for
  454. Return Value:
  455. NULL - data for returned range was not found
  456. PCACHE - leftmost cachenode which has data for returned range
  457. --*/
  458. {
  459. PCACHE node, node2;
  460. ULONG SumOffsetLength;
  461. // DebugPrint( "CacheLookup\n" );
  462. if (Length < MIN_READ_SIZE && KdCacheMisses > MIN_CACHE_MISSES) {
  463. // Try to cache more then tiny amount
  464. Length = MIN_READ_SIZE;
  465. }
  466. SumOffsetLength = Offset + Length;
  467. if (SumOffsetLength < Length) {
  468. //
  469. // Offset + Length wrapped. Adjust Length to be only
  470. // enough bytes before wrapping.
  471. //
  472. Length = 0 - Offset;
  473. SumOffsetLength = (ULONG) -1;
  474. }
  475. *LengthUsed = Length;
  476. //
  477. // Find leftmost cache node for BaseAddress thru BaseAddress+Length
  478. //
  479. node2 = NULL;
  480. node = VirtCacheRoot;
  481. while (node != NULL) {
  482. if (SumOffsetLength <= node->Offset) {
  483. node = (PCACHE) RtlLeftChild(&node->SplayLinks);
  484. } else if (node->Offset + node->Length <= Offset) {
  485. node = (PCACHE) RtlRightChild(&node->SplayLinks);
  486. } else {
  487. if (node->Offset <= Offset) {
  488. //
  489. // Found starting byte
  490. //
  491. return node;
  492. }
  493. //
  494. // Check to see if there's a node which has a match closer
  495. // to the start of the requested range
  496. //
  497. node2 = node;
  498. Length = node->Offset - Offset;
  499. node = (PCACHE) RtlLeftChild(&node->SplayLinks);
  500. }
  501. }
  502. return node2;
  503. }
  504. VOID
  505. InsertCacheNode (
  506. IN PCACHE node
  507. )
  508. {
  509. PCACHE node2;
  510. ULONG BaseAddress;
  511. //
  512. // Insert cache node into splay tree
  513. //
  514. // DebugPrint( "insertcache\n" );
  515. RtlInitializeSplayLinks(&node->SplayLinks);
  516. KdNodeCount++;
  517. if (VirtCacheRoot == NULL) {
  518. VirtCacheRoot = node;
  519. return;
  520. }
  521. node2 = VirtCacheRoot;
  522. BaseAddress = node->Offset;
  523. while( TRUE ) {
  524. if (BaseAddress < node2->Offset) {
  525. if (RtlLeftChild(&node2->SplayLinks)) {
  526. node2 = (PCACHE) RtlLeftChild(&node2->SplayLinks);
  527. continue;
  528. }
  529. RtlInsertAsLeftChild(node2, node);
  530. break;
  531. } else {
  532. if (RtlRightChild(&node2->SplayLinks)) {
  533. node2 = (PCACHE) RtlRightChild(&node2->SplayLinks);
  534. continue;
  535. }
  536. RtlInsertAsRightChild(node2, node);
  537. break;
  538. }
  539. }
  540. VirtCacheRoot = (PCACHE) RtlSplay((PRTL_SPLAY_LINKS)node2);
  541. }
  542. VOID
  543. DmKdInitVirtualCacheEntry (
  544. IN ULONG BaseAddress,
  545. IN ULONG Length,
  546. IN PUCHAR UserBuffer,
  547. IN ULONG NonDiscardable
  548. )
  549. /*++
  550. Routine Description:
  551. Insert some data into the virtual cache.
  552. Arguments:
  553. BaseAddress - Virtual address
  554. Length - length to cache
  555. UserBuffer - data to put into cache
  556. Return Value:
  557. --*/
  558. {
  559. PCACHE node;
  560. PUCHAR p;
  561. ULONG LengthUsed;
  562. if (KdMaxCacheSize == 0) {
  563. //
  564. // Cache is off
  565. //
  566. return ;
  567. }
  568. // DebugPrint( "DmKdInitVirtualCacheEntry\n" );
  569. node = CacheLookup( BaseAddress, Length, &LengthUsed );
  570. if (node) {
  571. return;
  572. }
  573. //
  574. // Delete any cached info which hits range
  575. //
  576. DmKdWriteCachedVirtualMemory (BaseAddress, Length, UserBuffer);
  577. p = vcmalloc (Length);
  578. node = (PCACHE) vcmalloc (sizeof (CACHE));
  579. if (p == NULL || node == NULL) {
  580. //
  581. // Out of memory - don't bother
  582. //
  583. if (p) {
  584. vcfree (p, Length);
  585. }
  586. if (node) {
  587. vcfree ((PUCHAR)node, sizeof (CACHE));
  588. }
  589. return ;
  590. }
  591. //
  592. // Put data into cache node
  593. //
  594. node->Offset = BaseAddress;
  595. node->Length = (USHORT) Length;
  596. node->u.Data = p;
  597. node->Flags = 0;
  598. if (NonDiscardable) {
  599. node->Flags |= C_NONDISCARDABLE;
  600. }
  601. memcpy (p, UserBuffer, Length);
  602. InsertCacheNode (node);
  603. }
  604. PUCHAR
  605. vcmalloc (
  606. IN ULONG Length
  607. )
  608. /*++
  609. Routine Description:
  610. Allocates memory for virtual cache, and tracks total memory
  611. usage.
  612. Arguments:
  613. Length - Amount of memory to allocate
  614. Return Value:
  615. NULL - too much memory is in use, or memory could not
  616. be allocated
  617. Otherwise, returns to address of the allocated memory
  618. --*/
  619. {
  620. PUCHAR p;
  621. if (KdCacheSize + Length > KdMaxCacheSize)
  622. return NULL;
  623. if (!(p = (PUCHAR) malloc (Length))) {
  624. //
  625. // Out of memory - don't get any larger
  626. //
  627. KdCacheSize = KdMaxCacheSize+1;
  628. return NULL;
  629. }
  630. KdCacheSize += Length;
  631. return p;
  632. }
  633. VOID
  634. vcfree (
  635. IN PUCHAR Memory,
  636. IN ULONG Length
  637. )
  638. /*++
  639. Routine Description:
  640. Free memory allocated with vcmalloc. Adjusts cache is use totals.
  641. Arguments:
  642. Memory - Address of allocated memory
  643. Length - Length of allocated memory
  644. Return Value:
  645. NONE
  646. --*/
  647. {
  648. KdCacheSize -= Length;
  649. free (Memory);
  650. }
  651. NTSTATUS
  652. VCReadTranslatePTEAndReadMemory (
  653. IN PVOID TargetBaseAddress,
  654. OUT PVOID UserInterfaceBuffer,
  655. IN ULONG TransferCount,
  656. OUT PULONG ActualBytesRead OPTIONAL
  657. )
  658. /*++
  659. --*/
  660. {
  661. static BOOLEAN ConvertingAnAddress;
  662. NTSTATUS status;
  663. BOOLEAN converted;
  664. PHYSICAL_ADDRESS TargetPhysicalAddress;
  665. if (ConvertingAnAddress) {
  666. return STATUS_UNSUCCESSFUL;
  667. }
  668. //
  669. // Memory could not be read, try it's physical address.
  670. //
  671. ConvertingAnAddress = TRUE;
  672. converted = KdConvertToPhysicalAddr (
  673. TargetBaseAddress,
  674. &TargetPhysicalAddress
  675. );
  676. if (converted) {
  677. status = DmKdReadPhysicalMemory (
  678. TargetPhysicalAddress,
  679. UserInterfaceBuffer,
  680. TransferCount,
  681. ActualBytesRead
  682. );
  683. } else {
  684. status = STATUS_UNSUCCESSFUL;
  685. }
  686. ConvertingAnAddress = FALSE;
  687. return NT_SUCCESS(status) ? status : STATUS_UNSUCCESSFUL;
  688. }
  689. VOID
  690. DmKdWriteCachedVirtualMemory (
  691. IN ULONG BaseAddress,
  692. IN ULONG TransferCount,
  693. IN PUCHAR UserBuffer
  694. )
  695. /*++
  696. Routine Description:
  697. Invalidates range from the cache.
  698. Arguments:
  699. BaseAddress - Starting address to purge
  700. TransferCount - Length of area to purge
  701. UserBuffer - not used
  702. Return Value:
  703. NONE
  704. --*/
  705. {
  706. PCACHE node;
  707. ULONG bogus;
  708. //
  709. // Invalidate any data in the cache which covers this range
  710. //
  711. while (node = CacheLookup(BaseAddress, TransferCount, &bogus)) {
  712. //
  713. // For now just delete the entire cache node which hits the range
  714. //
  715. VirtCacheRoot = (PCACHE) RtlDelete (&node->SplayLinks);
  716. if (!(node->Flags & C_ERROR)) {
  717. vcfree (node->u.Data, node->Length);
  718. }
  719. vcfree ((PUCHAR)node, sizeof (CACHE));
  720. KdNodeCount--;
  721. }
  722. }
  723. PCACHE
  724. WalkForDelete(PCACHE node)
  725. {
  726. PCACHE node2;
  727. if (!(node->Flags & C_NONDISCARDABLE)) {
  728. return node;
  729. }
  730. node2 = (PCACHE)RtlRightChild(&node->SplayLinks);
  731. if (node2) {
  732. if (!(node2->Flags & C_NONDISCARDABLE)) {
  733. return node2;
  734. } else {
  735. node2 = WalkForDelete( node2 );
  736. if (node2) {
  737. return node2;
  738. }
  739. }
  740. }
  741. node2 = (PCACHE)RtlLeftChild(&node->SplayLinks);
  742. if (node2) {
  743. if (!(node2->Flags & C_NONDISCARDABLE)) {
  744. return node2;
  745. } else {
  746. node2 = WalkForDelete( node2 );
  747. if (node2) {
  748. return node2;
  749. }
  750. }
  751. }
  752. return NULL;
  753. }
  754. VOID
  755. DmKdPurgeCachedVirtualMemory (
  756. BOOL fPurgeNonDiscardable
  757. )
  758. /*++
  759. Routine Description:
  760. Purges to entire virtual memory cache
  761. Arguments:
  762. NONE
  763. Return Value:
  764. NONE
  765. --*/
  766. {
  767. PCACHE node;
  768. PCACHE node2;
  769. if (KdPurgeOverride) {
  770. DMPrintShellMsg("** Warning: cache being help\n");
  771. return;
  772. }
  773. node = VirtCacheRoot;
  774. KdCacheMisses = 0;
  775. KdCachePurges++;
  776. if (fPurgeNonDiscardable) {
  777. while( node ) {
  778. if (!(node->Flags & C_ERROR)) {
  779. free (node->u.Data);
  780. }
  781. KdNodeCount--;
  782. KdCacheSize -= node->Length;
  783. node = VirtCacheRoot = (PCACHE)RtlDelete((PRTL_SPLAY_LINKS)node);
  784. }
  785. KdCacheSize = 0;
  786. return;
  787. }
  788. while( node ) {
  789. node2 = WalkForDelete( node );
  790. if (node2) {
  791. if (!(node2->Flags & C_ERROR)) {
  792. free (node2->u.Data);
  793. }
  794. KdNodeCount--;
  795. KdCacheSize -= node2->Length;
  796. node = VirtCacheRoot = (PCACHE)RtlDelete((PRTL_SPLAY_LINKS)node2);
  797. } else {
  798. node = node2;
  799. }
  800. }
  801. return;
  802. }
  803. void
  804. WalkForDump(PCACHE node)
  805. {
  806. PCACHE l,r;
  807. r = (PCACHE)RtlRightChild(&node->SplayLinks);
  808. l = (PCACHE)RtlLeftChild(&node->SplayLinks);
  809. DMPrintShellMsg( "%08x %8d (%c)\n", node->Offset, node->Length, (node->Flags&C_NONDISCARDABLE) ? 'Y' : 'N' );
  810. if (r) {
  811. WalkForDump( r );
  812. }
  813. if (l) {
  814. WalkForDump( l );
  815. }
  816. }
  817. BOOLEAN
  818. KdConvertToPhysicalAddr (
  819. IN PVOID uAddress,
  820. OUT PPHYSICAL_ADDRESS PhysicalAddress
  821. )
  822. /*++
  823. Routine Description:
  824. Convert a virtual address to a physical one.
  825. Note: that this function is called from within the virtual memory
  826. cache code. This function can read from the virtual memory cache
  827. so long as it only read's PDE's and PTE's and so long as it fails
  828. to convert a PDE or PTE virtual address.
  829. Arguments:
  830. uAddress - address to convert
  831. PhysicalAddress - returned physical address
  832. Return Value:
  833. TRUE - physical address was returned
  834. otherwise, FALSE
  835. --*/
  836. {
  837. #define PDE_TOP 0xC03FFFFF
  838. #if defined( TARGET_i386 )
  839. #define PTE_BASE 0xC0000000
  840. #define PDE_BASE 0xC0300000
  841. #define MM_PTE_PROTOTYPE_MASK 0x400
  842. #define MM_PTE_TRANSITION_MASK 0x800
  843. #define PTE_CONT 0x1
  844. #elif defined( TARGET_PPC )
  845. #define MM_PTE_PROTOTYPE_MASK 0x1
  846. #define MM_PTE_TRANSITION_MASK 0x2
  847. #define PTE_CONT 0x1
  848. #elif defined( TARGET_MIPS )
  849. #define MM_PTE_PROTOTYPE_MASK 0x4
  850. #define MM_PTE_TRANSITION_MASK 0x100
  851. #define PTE_CONT 0x2
  852. #elif defined( TARGET_ALPHA )
  853. #define MM_PTE_PROTOTYPE_MASK 0x2
  854. #define MM_PTE_TRANSITION_MASK 0x4
  855. #define PTE_CONT 0x1
  856. #endif
  857. #define MiGetPdeAddress(va) ((ULONG)(((((ULONG)(va)) >> 22) << 2) + PDE_BASE))
  858. #define MiGetPteAddress(va) ((ULONG)(((((ULONG)(va)) >> 12) << 2) + PTE_BASE))
  859. ULONG Address;
  860. ULONG Pte;
  861. ULONG Pde;
  862. ULONG PdeContents;
  863. ULONG PteContents;
  864. NTSTATUS status;
  865. ULONG result;
  866. Address = (ULONG) uAddress;
  867. if (Address >= PTE_BASE && Address < PDE_TOP) {
  868. //
  869. // The address is the address of a PTE, rather than
  870. // a virtual address. DO NOT CONVERT IT.
  871. //
  872. return FALSE;
  873. }
  874. Pde = MiGetPdeAddress (Address);
  875. Pte = MiGetPteAddress (Address);
  876. status = DmKdReadVirtualMemoryNow((PVOID)Pde,
  877. &PdeContents,
  878. sizeof(ULONG),
  879. &result);
  880. if ((status != STATUS_SUCCESS) || (result < sizeof(ULONG))) {
  881. return FALSE;
  882. }
  883. if (!(PdeContents & PTE_CONT)) {
  884. return FALSE;
  885. }
  886. status = DmKdReadVirtualMemoryNow((PVOID)Pte,
  887. &PteContents,
  888. sizeof(ULONG),
  889. &result);
  890. if ((status != STATUS_SUCCESS) || (result < sizeof(ULONG))) {
  891. return FALSE;
  892. }
  893. if (!(PteContents & PTE_CONT)) {
  894. if ( (PteContents & MM_PTE_PROTOTYPE_MASK) ||
  895. !(PteContents & MM_PTE_TRANSITION_MASK)) {
  896. return FALSE;
  897. }
  898. }
  899. //
  900. // This is a page which is either present or in transition.
  901. // Return the physical address for the request virtual address.
  902. //
  903. PhysicalAddress->LowPart = (PteContents & ~(0xFFF)) | (Address & 0xFFF);
  904. PhysicalAddress->HighPart = 0;
  905. return TRUE;
  906. }
  907. VOID
  908. ProcessCacheCmd(
  909. LPSTR pchCommand
  910. )
  911. {
  912. ULONG CacheSize;
  913. ULONG Address;
  914. while (*pchCommand == ' ') {
  915. pchCommand++;
  916. }
  917. _strlwr (pchCommand);
  918. if (strcmp (pchCommand, "?") == 0) {
  919. usage:
  920. DMPrintShellMsg("\n.cache [{cachesize} | dump | hold | unhold | decodeptes | nodecodeptes]\n");
  921. DMPrintShellMsg(".cache [flushall | flushu | flush addr]\n\n");
  922. return;
  923. } else
  924. if (strcmp (pchCommand, "dump") == 0) {
  925. if (VirtCacheRoot) {
  926. DMPrintShellMsg("\n Address Length Discardable\n");
  927. WalkForDump( VirtCacheRoot );
  928. }
  929. } else
  930. if (strcmp (pchCommand, "hold") == 0) {
  931. KdPurgeOverride = TRUE;
  932. } else
  933. if (strcmp (pchCommand, "unhold") == 0) {
  934. KdPurgeOverride = FALSE;
  935. } else
  936. if (strcmp (pchCommand, "decodeptes") == 0) {
  937. DmKdPurgeCachedVirtualMemory(TRUE);
  938. KdCacheDecodePTEs = TRUE;
  939. } else
  940. if (strcmp (pchCommand, "nodecodeptes") == 0) {
  941. KdCacheDecodePTEs = FALSE;
  942. } else
  943. if (strcmp (pchCommand, "flushall") == 0) {
  944. DmKdPurgeCachedVirtualMemory(TRUE);
  945. } else
  946. if (strcmp (pchCommand, "flushu") == 0) {
  947. DmKdPurgeCachedVirtualMemory(TRUE);
  948. } else
  949. if (*pchCommand == 'f') {
  950. while (*pchCommand >= 'a' && *pchCommand <= 'z') {
  951. pchCommand++;
  952. }
  953. Address = strtoul(pchCommand,NULL,0);
  954. DmKdWriteCachedVirtualMemory (Address, 4096, NULL); // this is a flush
  955. DMPrintShellMsg("Cached info for address %lx for 4096 bytes was flushed\n", Address);
  956. } else if (*pchCommand) {
  957. if (*pchCommand < '0' || *pchCommand > '9') {
  958. goto usage;
  959. } else {
  960. CacheSize = strtoul(pchCommand,NULL,0);
  961. KdMaxCacheSize = CacheSize * 1024;
  962. if (CacheSize == 0) {
  963. DmKdPurgeCachedVirtualMemory(TRUE);
  964. KdCachePurges = 0;
  965. }
  966. }
  967. }
  968. DMPrintShellMsg("\n");
  969. DMPrintShellMsg("Max cache size is....: %ld %s\n", KdMaxCacheSize,
  970. KdMaxCacheSize ? "" : "(cache is off)");
  971. DMPrintShellMsg("Total memory in cache: %ld\n", KdCacheSize - KdNodeCount * sizeof (CACHE) );
  972. DMPrintShellMsg("No of regions cached.: %ld\n", KdNodeCount);
  973. DMPrintShellMsg("Cache misses.........: %ld\n", KdCacheMisses);
  974. DMPrintShellMsg("Cache purges.........: %ld\n", KdCachePurges);
  975. if (KdCacheDecodePTEs) {
  976. DMPrintShellMsg("** Transition ptes are implicity decoded\n");
  977. }
  978. if (KdPurgeOverride) {
  979. DMPrintShellMsg("** Implicit cache flushing disabled **\n");
  980. }
  981. DMPrintShellMsg("\n");
  982. }