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.

1207 lines
31 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. physical.c
  5. Abstract:
  6. WinDbg Extension Api
  7. Revision History:
  8. --*/
  9. #include "precomp.h"
  10. #pragma hdrstop
  11. /*++
  12. Routine Description:
  13. Reverse sign extension of the value returned by GetExpression()
  14. based on the assumption that no physical address may be bigger
  15. than 0xfffffff00000000.
  16. Arguments:
  17. Val - points to the value to reverse sign extension
  18. Return Value:
  19. None.
  20. --*/
  21. void
  22. ReverseSignExtension(ULONG64* Val)
  23. {
  24. if ((*Val & 0xffffffff00000000) == 0xffffffff00000000)
  25. {
  26. *Val &= 0x00000000ffffffff;
  27. }
  28. }
  29. DECLARE_API( chklowmem )
  30. /*++
  31. Routine Description:
  32. Calls an Mm function that checks if the physical pages
  33. below 4Gb have a required fill pattern for PAE systems
  34. booted with /LOWMEM switch.
  35. Arguments:
  36. None.
  37. Return Value:
  38. None.
  39. --*/
  40. {
  41. UNREFERENCED_PARAMETER (args);
  42. UNREFERENCED_PARAMETER (Client);
  43. dprintf ("Checking the low 4GB of RAM for required fill pattern. \n");
  44. dprintf ("Please wait (verification takes approx. 20s) ...\n");
  45. Ioctl (IG_LOWMEM_CHECK, NULL, 0);
  46. dprintf ("Lowmem check done.\n");
  47. return S_OK;
  48. }
  49. /////////////////////////////////////////////////////////////////////
  50. ///////////////////////////////////////////////////////////// !search
  51. /////////////////////////////////////////////////////////////////////
  52. #define SEARCH_HITS 8192
  53. ULONG64 g_SearchHits[SEARCH_HITS];
  54. //
  55. // Kernel variable modification functions.
  56. //
  57. ULONG
  58. READ_ULONG (
  59. ULONG64 Address
  60. );
  61. VOID
  62. WRITE_ULONG (
  63. ULONG64 Address,
  64. ULONG Value
  65. );
  66. ULONG64
  67. READ_PVOID (
  68. ULONG64 Address
  69. );
  70. ULONG
  71. READ_PHYSICAL_ULONG (
  72. ULONG64 Address
  73. );
  74. ULONG64
  75. READ_PHYSICAL_ULONG64 (
  76. ULONG64 Address
  77. );
  78. ULONG64
  79. SearchGetSystemMemoryDescriptor (
  80. );
  81. ULONG64
  82. SearchConvertPageFrameToVa (
  83. ULONG64 PageFrameIndex,
  84. PULONG Flags,
  85. PULONG64 PteAddress
  86. );
  87. #define SEARCH_VA_PROTOTYPE_ADDRESS 0x0001
  88. #define SEARCH_VA_NORMAL_ADDRESS 0x0002
  89. #define SEARCH_VA_LARGE_PAGE_ADDRESS 0x0004
  90. #define SEARCH_VA_UNKNOWN_TYPE_ADDRESS 0x0008
  91. #define SEARCH_VA_SUPER_PAGE_ADDRESS 0x0010
  92. //
  93. // PAE independent functions from p_i386\pte.c
  94. //
  95. ULONG64
  96. DbgGetPdeAddress(
  97. IN ULONG64 VirtualAddress
  98. );
  99. ULONG64
  100. DbgGetPteAddress(
  101. IN ULONG64 VirtualAddress
  102. );
  103. #define BANG_SEARCH_HELP \
  104. "\n\
  105. !search ADDRESS [DELTA [START_PFN END_PFN]] \n\
  106. \n\
  107. Search the physical pages in range [START_PFN..END_PFN] \n\
  108. for ULONG_PTRs with values in range ADDRESS+/-DELTA or values \n\
  109. that differ in only one bit position from ADDRESS. \n\
  110. \n\
  111. The default value for DELTA is 0. For START/END_PFN the default \n\
  112. values are lowest physical page and highest physical page. \n\
  113. \n\
  114. Examples: \n\
  115. \n\
  116. !search AABBCCDD 0A \n\
  117. \n\
  118. Search all physical memory for values in range AABBCCD3 - \n\
  119. AABBCCE8 or with only one bit different than AABBCCDD. \n\
  120. \n\
  121. !search AABBCCDD 0A 13F 240 \n\
  122. \n\
  123. Search page frames in range 13F - 240 for values in range \n\
  124. AABBCCD3 - AABBCCE8 or with only one bit different \n\
  125. than AABBCCDD. \n\
  126. \n\
  127. By default only the first hit in the page is detected. If all \n\
  128. hits within the page are needed the START_PFN and END_PFN \n\
  129. must have the same value. \n\
  130. \n\
  131. Note that a search through the entire physical memory will find \n\
  132. hits in the search engine structures. By doing a search with a \n\
  133. completely different value it can be deduced what hits can be \n\
  134. ignored. \n\n"
  135. //
  136. // Comment this to get verbose output.
  137. //
  138. // #define _INTERNAL_DEBUG_
  139. //
  140. DECLARE_API( search )
  141. /*++
  142. Routine Description:
  143. This routine triggers a search within a given physical
  144. memory range for a pointer. The hits are defined by
  145. an interval (below and above the pointer value) and also
  146. by a Hamming distance equal to one (only one bit different).
  147. Arguments:
  148. None.
  149. Return Value:
  150. None.
  151. --*/
  152. {
  153. ULONG64 ParamAddress;
  154. ULONG64 ParamDelta;
  155. ULONG64 ParamStart;
  156. ULONG64 ParamEnd;
  157. ULONG64 MmLowestPhysicalPage;
  158. ULONG64 MmHighestPhysicalPage;
  159. ULONG64 PageFrame;
  160. ULONG64 StartPage;
  161. ULONG64 EndPage;
  162. ULONG64 RunStartPage;
  163. ULONG64 RunEndPage;
  164. ULONG RunIndex;
  165. BOOLEAN RequestForInterrupt;
  166. BOOLEAN RequestAllOffsets;
  167. ULONG Hits;
  168. ULONG Index;
  169. ULONG64 PfnHit;
  170. ULONG64 VaHit;
  171. ULONG VaFlags;
  172. ULONG PfnOffset;
  173. ULONG64 AddressStart;
  174. ULONG64 AddressEnd;
  175. ULONG DefaultRange;
  176. ULONG64 MemoryDescriptor;
  177. ULONG64 PageCount, BasePage, NumberOfPages;
  178. ULONG NumberOfRuns;
  179. POINTER_SEARCH_PHYSICAL PtrSearch;
  180. ULONG SizeOfPfnNumber = 0;
  181. ULONG64 PteAddress;
  182. UNREFERENCED_PARAMETER (Client);
  183. SizeOfPfnNumber = GetTypeSize("nt!PFN_NUMBER");
  184. if (SizeOfPfnNumber == 0) {
  185. dprintf ("Search: cannot get size of PFN_NUMBER \n");
  186. return E_INVALIDARG;
  187. }
  188. RequestForInterrupt = FALSE;
  189. RequestAllOffsets = FALSE;
  190. DefaultRange = 128;
  191. ParamAddress = 0;
  192. ParamDelta = 0;
  193. ParamStart = 0;
  194. ParamEnd = 0;
  195. //
  196. // Help requested ?
  197. //
  198. if (strstr (args, "?") != 0) {
  199. dprintf (BANG_SEARCH_HELP);
  200. return S_OK;
  201. }
  202. //
  203. // Get command line arguments.
  204. //
  205. {
  206. PCHAR Current = (PCHAR)args;
  207. CHAR Buffer [64];
  208. ULONG BufferIndex;
  209. //
  210. // Get the 4 numeric arguments.
  211. //
  212. for (Index = 0; Index < 4; Index++) {
  213. //
  214. // Get rid of any leading spaces.
  215. //
  216. while (*Current == ' ' || *Current == '\t') {
  217. Current++;
  218. }
  219. if (*Current == 0) {
  220. if (Index == 0) {
  221. dprintf (BANG_SEARCH_HELP);
  222. return E_INVALIDARG;
  223. }
  224. else {
  225. break;
  226. }
  227. }
  228. //
  229. // Get the digits from the Index-th parameter.
  230. //
  231. Buffer [0] = '0';
  232. Buffer [1] = 'x';
  233. BufferIndex = 2;
  234. while ((*Current >= '0' && *Current <= '9')
  235. || (*Current >= 'a' && *Current <= 'f')
  236. || (*Current >= 'A' && *Current <= 'F')) {
  237. Buffer[BufferIndex] = *Current;
  238. Buffer[BufferIndex + 1] = 0;
  239. Current += 1;
  240. BufferIndex += 1;
  241. }
  242. switch (Index) {
  243. case 0: ParamAddress = GetExpression(Buffer); break;
  244. case 1: ParamDelta = GetExpression(Buffer); break;
  245. case 2: ParamStart = GetExpression(Buffer); break;
  246. case 3: ParamEnd = GetExpression(Buffer); break;
  247. default:
  248. dprintf (BANG_SEARCH_HELP);
  249. return E_INVALIDARG;
  250. }
  251. }
  252. }
  253. //
  254. // Read physical memory limits.
  255. //
  256. MmLowestPhysicalPage = GetExpression ("nt!MmLowestPhysicalPage");
  257. MmHighestPhysicalPage = GetExpression ("nt!MmHighestPhysicalPage");
  258. #ifdef _INTERNAL_DEBUG_
  259. dprintf ("Low: %I64X, High: %I64X \n",
  260. READ_PVOID (MmLowestPhysicalPage),
  261. READ_PVOID (MmHighestPhysicalPage));
  262. #endif // #ifdef _INTERNAL_DEBUG_
  263. //
  264. // Figure out proper search parameters.
  265. //
  266. if (ParamStart == 0) {
  267. StartPage = READ_PVOID (MmLowestPhysicalPage);
  268. ParamStart = StartPage;
  269. }
  270. else {
  271. StartPage = ParamStart;
  272. }
  273. if (ParamEnd == 0) {
  274. EndPage = READ_PVOID (MmHighestPhysicalPage);
  275. ParamEnd = EndPage;
  276. }
  277. else {
  278. EndPage = ParamEnd;
  279. }
  280. //
  281. // Set range of addresses that we want to be searched.
  282. //
  283. AddressStart = ParamAddress - ParamDelta;
  284. AddressEnd = ParamAddress + ParamDelta;
  285. PtrSearch.PointerMin = AddressStart;
  286. PtrSearch.PointerMax = AddressEnd;
  287. PtrSearch.MatchOffsets = g_SearchHits;
  288. PtrSearch.MatchOffsetsSize = SEARCH_HITS;
  289. if (SizeOfPfnNumber == 8) {
  290. dprintf ("Searching PFNs in range %016I64X - %016I64X for [%016I64X - %016I64X]\n\n",
  291. StartPage, EndPage, AddressStart, AddressEnd);
  292. dprintf ("%-16s %-8s %-16s %-16s %-16s \n", "Pfn","Offset", "Hit", "Va", "Pte");
  293. dprintf ("- - - - - - - - - - - - - - - - - - - - - - ");
  294. dprintf ("- - - - - - - - - - - - - - - - - - - - - - - - - - -\n");
  295. }
  296. else {
  297. dprintf ("Searching PFNs in range %08I64X - %08I64X for [%08I64X - %08I64X]\n\n",
  298. StartPage, EndPage, AddressStart, AddressEnd);
  299. dprintf ("%-8s %-8s %-8s %-8s %-8s \n", "Pfn","Offset", "Hit", "Va", "Pte");
  300. dprintf ("- - - - - - - - - - - - - - - - - - - - - - - - - - -\n");
  301. }
  302. //
  303. // Get system memory description to figure out what ranges
  304. // should we skip. This is important for sparse PFN database
  305. // and for pages managed by drivers.
  306. //
  307. MemoryDescriptor = SearchGetSystemMemoryDescriptor ();
  308. if (MemoryDescriptor == 0) {
  309. dprintf ("Search error: cannot allocate system memory descriptor \n");
  310. return E_INVALIDARG;
  311. }
  312. //
  313. // Search all physical memory in the specified range.
  314. //
  315. if (StartPage == EndPage) {
  316. EndPage += 1;
  317. RequestAllOffsets = TRUE;
  318. }
  319. //
  320. // Find out what pages are physically available create
  321. // page search ranges based on that.
  322. //
  323. // SilviuC: I should use ReadField to read all these structures
  324. // so that I do not have to take into account padding myself.
  325. //
  326. NumberOfRuns = READ_ULONG (MemoryDescriptor);
  327. NumberOfPages = READ_PVOID (MemoryDescriptor + SizeOfPfnNumber);
  328. #ifdef _INTERNAL_DEBUG_
  329. dprintf ("Runs: %x, Pages: %I64X \n", NumberOfRuns, NumberOfPages);
  330. for (RunIndex = 0; RunIndex < NumberOfRuns; RunIndex += 1) {
  331. ULONG64 RunAddress;
  332. RunAddress = MemoryDescriptor + 2 * SizeOfPfnNumber
  333. + RunIndex * GetTypeSize("nt!_PHYSICAL_MEMORY_RUN");
  334. BasePage = READ_PVOID (RunAddress);
  335. PageCount = READ_PVOID (RunAddress + SizeOfPfnNumber);
  336. dprintf ("Run[%d]: Base: %I64X, Count: %I64X \n",
  337. RunIndex, BasePage, PageCount);
  338. }
  339. #endif // #if _INTERNAL_DEBUG_
  340. #ifdef _INTERNAL_DEBUG_
  341. dprintf ("StartPage: %I64X, EndPage: %I64X \n", StartPage, EndPage);
  342. #endif // #ifdef _INTERNAL_DEBUG_
  343. for (PageFrame = StartPage; PageFrame < EndPage; PageFrame += DefaultRange) {
  344. for (RunIndex = 0; RunIndex < NumberOfRuns; RunIndex += 1) {
  345. //
  346. // BaseAddress and PageCount for current memory run.
  347. //
  348. ULONG64 RunAddress;
  349. #ifdef _INTERNAL_DEBUG_
  350. // dprintf ("Finding a good range ... \n");
  351. #endif // #ifdef _INTERNAL_DEBUG_
  352. RunAddress = MemoryDescriptor + 2 * SizeOfPfnNumber
  353. + RunIndex * GetTypeSize("nt!_PHYSICAL_MEMORY_RUN");
  354. BasePage = READ_PVOID (RunAddress);
  355. PageCount = READ_PVOID (RunAddress + SizeOfPfnNumber);
  356. //
  357. // Figure out real start and end page.
  358. //
  359. RunStartPage = PageFrame;
  360. RunEndPage = PageFrame + DefaultRange;
  361. if (RunEndPage <= BasePage) {
  362. continue;
  363. }
  364. if (RunStartPage >= BasePage + PageCount) {
  365. continue;
  366. }
  367. if (RunStartPage < BasePage) {
  368. RunStartPage = BasePage;
  369. }
  370. if (RunEndPage > BasePage + PageCount) {
  371. RunEndPage = BasePage + PageCount;
  372. }
  373. PtrSearch.Offset = (ULONG64)RunStartPage * PageSize;
  374. if (RequestAllOffsets) {
  375. //
  376. // If the search is in only one page then we
  377. // will try to get all offsets with a hit.
  378. //
  379. PtrSearch.Length = PageSize;
  380. PtrSearch.Flags = PTR_SEARCH_PHYS_ALL_HITS;
  381. }
  382. else {
  383. PtrSearch.Length = (ULONG64)
  384. (RunEndPage - RunStartPage) * PageSize;
  385. PtrSearch.Flags = 0;
  386. }
  387. #ifdef _INTERNAL_DEBUG_
  388. dprintf ("Start: %I64X, End: %I64X \n",
  389. PtrSearch.Offset,
  390. PtrSearch.Offset + PtrSearch.Length);
  391. #endif // #if _INTERNAL_DEBUG_
  392. PtrSearch.MatchOffsetsCount = 0;
  393. Ioctl (IG_POINTER_SEARCH_PHYSICAL, &PtrSearch, sizeof(PtrSearch));
  394. //
  395. // Display results
  396. //
  397. Hits = PtrSearch.MatchOffsetsCount;
  398. for (Index = 0; Index < Hits; Index++) {
  399. PCHAR VaString = "";
  400. VaFlags = 0;
  401. PfnHit = g_SearchHits[Index] / PageSize;
  402. PfnOffset = (ULONG)(g_SearchHits[Index] & (PageSize - 1));
  403. VaHit = SearchConvertPageFrameToVa (PfnHit, &VaFlags, &PteAddress);
  404. // dprintf ("Hits: %u, Index: %u, Va: %I64X \n", Hits, Index, VaHit);
  405. #if DBG
  406. if ((VaFlags & SEARCH_VA_NORMAL_ADDRESS)) {
  407. VaString = ""; // "normal";
  408. }
  409. else if ((VaFlags & SEARCH_VA_LARGE_PAGE_ADDRESS)) {
  410. VaString = "large page";
  411. }
  412. else if ((VaFlags & SEARCH_VA_PROTOTYPE_ADDRESS)) {
  413. VaString = "prototype";
  414. }
  415. else if ((VaFlags & SEARCH_VA_UNKNOWN_TYPE_ADDRESS)) {
  416. VaString = "unknown";
  417. }
  418. else if ((VaFlags & SEARCH_VA_SUPER_PAGE_ADDRESS)) {
  419. VaString = "super page";
  420. }
  421. #endif // #if DBG
  422. if (SizeOfPfnNumber == 8) {
  423. dprintf ("%016I64X %08X %016I64X %016I64X %016I64X %s\n",
  424. PfnHit,
  425. PfnOffset,
  426. READ_PHYSICAL_ULONG64 (PfnHit * PageSize + PfnOffset),
  427. (VaHit == 0 ? 0 : VaHit + PfnOffset),
  428. PteAddress,
  429. VaString);
  430. }
  431. else {
  432. VaHit &= (ULONG64)0xFFFFFFFF;
  433. PteAddress &= (ULONG64)0xFFFFFFFF;
  434. dprintf ("%08I64X %08X %08X %08I64X %08I64X %s\n",
  435. PfnHit,
  436. PfnOffset,
  437. READ_PHYSICAL_ULONG (PfnHit * PageSize + PfnOffset),
  438. (VaHit == 0 ? 0 : VaHit + PfnOffset),
  439. PteAddress,
  440. VaString);
  441. }
  442. }
  443. //
  444. // check for ctrl-c
  445. //
  446. if (CheckControlC()) {
  447. dprintf ("Search interrupted. \n");
  448. RequestForInterrupt = TRUE;
  449. break;
  450. }
  451. }
  452. if (RequestForInterrupt) {
  453. break;
  454. }
  455. }
  456. if (RequestForInterrupt) {
  457. return E_INVALIDARG;
  458. }
  459. else {
  460. dprintf ("Search done.\n");
  461. }
  462. return S_OK;
  463. }
  464. ULONG64
  465. SearchGetSystemMemoryDescriptor (
  466. )
  467. /*++
  468. Routine Description:
  469. Arguments:
  470. None.
  471. Return Value:
  472. A malloc'd PHYSICAL_MEMORY_DESCRIPTOR structure.
  473. Caller is responsible of freeing.
  474. Environment:
  475. Call triggered only from !search Kd extension.
  476. --*/
  477. {
  478. ULONG64 MemoryDescriptorAddress;
  479. ULONG NumberOfRuns;
  480. MemoryDescriptorAddress = READ_PVOID (GetExpression ("nt!MmPhysicalMemoryBlock"));
  481. NumberOfRuns = READ_ULONG (MemoryDescriptorAddress);
  482. if (NumberOfRuns == 0) {
  483. return 0;
  484. }
  485. return MemoryDescriptorAddress;
  486. }
  487. ULONG64
  488. SearchConvertPageFrameToVa (
  489. ULONG64 PageFrameIndex,
  490. PULONG Flags,
  491. PULONG64 PteAddress
  492. )
  493. /*++
  494. Routine Description:
  495. This routine returnes the virtual address corresponding to a
  496. PFN index if the reverse mapping is easy to figure out. For all
  497. other cases (e.g. prototype PTE) the result is null.
  498. Arguments:
  499. PageFrameIndex - PFN index to convert.
  500. Return Value:
  501. The corresponding virtual address or null in case the PFN index
  502. cannot be easily converted to a virtual address.
  503. Environment:
  504. Call triggered only from Kd extension.
  505. --*/
  506. {
  507. ULONG64 Va;
  508. ULONG64 PfnAddress;
  509. ULONG BytesRead;
  510. MMPFNENTRY u3_e1;
  511. //
  512. // On IA64, if the physical address lies within KSEG0
  513. // it's part of a superpage mapping and the virtual
  514. // address should be computed directly from the KSEG0 base.
  515. //
  516. if (TargetMachine == IMAGE_FILE_MACHINE_IA64) {
  517. UCHAR SuperPageEnabled;
  518. SuperPageEnabled = (UCHAR) GetUlongValue ("nt!MiKseg0Mapping");
  519. if (SuperPageEnabled & 0x1) {
  520. ULONG64 Kseg0Start;
  521. ULONG64 Kseg0StartFrame;
  522. ULONG64 Kseg0EndFrame;
  523. Kseg0Start = GetPointerValue ("nt!MiKseg0Start");
  524. Kseg0StartFrame = GetPointerValue ("nt!MiKseg0StartFrame");
  525. Kseg0EndFrame = GetPointerValue ("nt!MiKseg0EndFrame");
  526. if (PageFrameIndex >= Kseg0StartFrame &&
  527. PageFrameIndex <= Kseg0EndFrame) {
  528. *Flags = SEARCH_VA_SUPER_PAGE_ADDRESS;
  529. // There is no corresponding PTE.
  530. *PteAddress = 0;
  531. return Kseg0Start +
  532. (PageFrameIndex - Kseg0StartFrame) * PageSize;
  533. }
  534. }
  535. }
  536. //
  537. // Get address of PFN structure
  538. //
  539. PfnAddress = READ_PVOID (GetExpression("nt!MmPfnDatabase"))
  540. + PageFrameIndex * GetTypeSize("nt!_MMPFN");
  541. BytesRead = 0;
  542. *Flags = 0;
  543. InitTypeRead(PfnAddress, nt!_MMPFN);
  544. //
  545. // (SilviuC): should check if MI_IS_PFN_DELETED(Pfn) is on.
  546. //
  547. //
  548. // Try to figure out Va if possible.
  549. //
  550. *PteAddress = ((ULONG64)ReadField (PteAddress));
  551. GetFieldValue(PfnAddress, "nt!_MMPFN", "u3.e1", u3_e1);
  552. if (u3_e1.PrototypePte) {
  553. *Flags |= SEARCH_VA_PROTOTYPE_ADDRESS;
  554. return 0;
  555. }
  556. Va = DbgGetVirtualAddressMappedByPte (*PteAddress);
  557. *Flags |= SEARCH_VA_NORMAL_ADDRESS;
  558. return Va;
  559. }
  560. //
  561. // Read/write functions
  562. //
  563. ULONG
  564. READ_ULONG (
  565. ULONG64 Address
  566. )
  567. {
  568. ULONG Value = 0;
  569. ULONG BytesRead;
  570. if (! ReadMemory (Address, &Value, sizeof Value, &BytesRead)) {
  571. dprintf ("Search: READ_ULONG error \n");
  572. }
  573. return Value;
  574. }
  575. VOID
  576. WRITE_ULONG (
  577. ULONG64 Address,
  578. ULONG Value
  579. )
  580. {
  581. ULONG BytesWritten;
  582. if (! WriteMemory (Address, &Value, sizeof Value, &BytesWritten)) {
  583. dprintf ("Search: WRITE_ULONG error \n");
  584. }
  585. }
  586. ULONG64
  587. READ_PVOID (
  588. ULONG64 Address
  589. )
  590. {
  591. ULONG64 Value64 = 0;
  592. if (!ReadPointer(Address, &Value64)) {
  593. dprintf ("Search: READ_PVOID error \n");
  594. }
  595. return Value64;
  596. }
  597. ULONG
  598. READ_PHYSICAL_ULONG (
  599. ULONG64 Address
  600. )
  601. {
  602. ULONG Value = 0;
  603. ULONG Bytes = 0;
  604. ReadPhysical (Address, &Value, sizeof Value, &Bytes);
  605. if (Bytes != sizeof Value) {
  606. dprintf ("Search: READ_PHYSICAL_ULONG error \n");
  607. }
  608. return Value;
  609. }
  610. ULONG64
  611. READ_PHYSICAL_ULONG64 (
  612. ULONG64 Address
  613. )
  614. {
  615. ULONG64 Value = 0;
  616. ULONG Bytes = 0;
  617. ReadPhysical (Address, &Value, sizeof Value, &Bytes);
  618. if (Bytes != sizeof Value) {
  619. dprintf ("Search: READ_PHYSICAL_ULONG64 error \n");
  620. }
  621. return Value;
  622. }
  623. /////////////////////////////////////////////////////////////////////
  624. ////////////////////////////////////////////////////////// !searchpte
  625. /////////////////////////////////////////////////////////////////////
  626. DECLARE_API( searchpte )
  627. {
  628. ULONG64 ParamAddress;
  629. ULONG64 ParamDelta;
  630. ULONG64 ParamStart;
  631. ULONG64 ParamEnd;
  632. ULONG64 MmLowestPhysicalPage;
  633. ULONG64 MmHighestPhysicalPage;
  634. ULONG64 PageFrame;
  635. ULONG64 StartPage;
  636. ULONG64 EndPage;
  637. ULONG64 RunStartPage;
  638. ULONG64 RunEndPage;
  639. ULONG RunIndex;
  640. BOOLEAN RequestForInterrupt = FALSE;
  641. ULONG Hits;
  642. ULONG LastHits;
  643. ULONG Index;
  644. ULONG64 PfnHit;
  645. ULONG64 VaHit;
  646. ULONG VaFlags;
  647. ULONG PfnOffset;
  648. ULONG PfnValue;
  649. ULONG64 AddressStart;
  650. ULONG64 AddressEnd;
  651. ULONG DefaultRange = 128;
  652. ULONG64 MemoryDescriptor;
  653. ULONG64 PageCount, BasePage, NumberOfPages;
  654. ULONG NumberOfRuns;
  655. ULONG SizeOfPfnNumber = 0;
  656. ULONG64 PteAddress;
  657. ULONG64 PfnSearchValue;
  658. ULONG NumberOfHits = 0;
  659. PULONG64 PfnHitsBuffer = NULL;
  660. ULONG PfnHitsBufferIndex = 0;
  661. ULONG PfnHitsBufferSize = 1024;
  662. ULONG PfnIndex;
  663. HRESULT Result;
  664. POINTER_SEARCH_PHYSICAL PtrSearch;
  665. SizeOfPfnNumber = GetTypeSize("nt!PFN_NUMBER");
  666. if (SizeOfPfnNumber == 0) {
  667. dprintf ("Search: cannot get size of PFN_NUMBER \n");
  668. Result = E_INVALIDARG;
  669. goto Exit;
  670. }
  671. ParamAddress = 0;
  672. //
  673. // Help requested ?
  674. //
  675. if (strstr (args, "?") != 0) {
  676. dprintf ("!searchpte FRAME(in hex) \n");
  677. dprintf (" \n");
  678. return S_OK;
  679. }
  680. //
  681. // Get command line arguments.
  682. //
  683. if (!sscanf (args, "%I64X", &ParamAddress))
  684. {
  685. ParamAddress = 0;
  686. }
  687. PfnSearchValue = ParamAddress;
  688. dprintf ("Searching for PTEs containing PFN value %I64X ...\n", PfnSearchValue);
  689. //
  690. // Read physical memory limits.
  691. //
  692. MmLowestPhysicalPage = GetExpression ("nt!MmLowestPhysicalPage");
  693. MmHighestPhysicalPage = GetExpression ("nt!MmHighestPhysicalPage");
  694. //
  695. // Figure out proper search parameters.
  696. //
  697. StartPage = READ_PVOID (MmLowestPhysicalPage);
  698. ParamStart = StartPage;
  699. EndPage = READ_PVOID (MmHighestPhysicalPage);
  700. ParamEnd = EndPage;
  701. //
  702. // Set the range of addresses that we want searched.
  703. //
  704. AddressStart = PfnSearchValue;
  705. AddressEnd = PfnSearchValue;
  706. PtrSearch.PointerMin = PfnSearchValue;
  707. PtrSearch.PointerMax = PfnSearchValue;
  708. PtrSearch.MatchOffsets = g_SearchHits;
  709. PtrSearch.MatchOffsetsSize = SEARCH_HITS;
  710. if (SizeOfPfnNumber == 8) {
  711. dprintf ("Searching PFNs in range %016I64X - %016I64X \n\n",
  712. StartPage, EndPage);
  713. dprintf ("%-16s %-8s %-16s %-16s %-16s \n", "Pfn","Offset", "Hit", "Va", "Pte");
  714. dprintf ("- - - - - - - - - - - - - - - - - - - - - - ");
  715. dprintf ("- - - - - - - - - - - - - - - - - - - - - - - - - - -\n");
  716. }
  717. else {
  718. dprintf ("Searching PFNs in range %08I64X - %08I64X \n\n",
  719. StartPage, EndPage);
  720. dprintf ("%-8s %-8s %-8s %-8s %-8s \n", "Pfn","Offset", "Hit", "Va", "Pte");
  721. dprintf ("- - - - - - - - - - - - - - - - - - - - - - - - - - -\n");
  722. }
  723. //
  724. // Get system memory description to figure out what ranges
  725. // should we skip. This is important for sparse PFN database
  726. // and for pages managed by drivers.
  727. //
  728. MemoryDescriptor = SearchGetSystemMemoryDescriptor ();
  729. if (MemoryDescriptor == 0) {
  730. dprintf ("Search error: cannot allocate system memory descriptor \n");
  731. Result = E_INVALIDARG;
  732. goto Exit;
  733. }
  734. //
  735. // Allocate hits buffer.
  736. //
  737. PfnHitsBuffer = (PULONG64) malloc (PfnHitsBufferSize * sizeof(ULONG64));
  738. if (PfnHitsBuffer == NULL) {
  739. dprintf ("Search error: cannot allocate hits buffer. \n");
  740. Result = E_INVALIDARG;
  741. goto Exit;
  742. }
  743. //
  744. // Find out what pages are physically available create
  745. // page search ranges based on that.
  746. //
  747. // SilviuC: I should use ReadField to read all these structures
  748. // so that I do not have to take into account padding myself.
  749. //
  750. NumberOfRuns = READ_ULONG (MemoryDescriptor);
  751. NumberOfPages = READ_PVOID (MemoryDescriptor + SizeOfPfnNumber);
  752. for (PageFrame = StartPage; PageFrame < EndPage; PageFrame += DefaultRange) {
  753. for (RunIndex = 0; RunIndex < NumberOfRuns; RunIndex += 1) {
  754. //
  755. // BaseAddress and PageCount for current memory run.
  756. //
  757. ULONG64 RunAddress;
  758. RunAddress = MemoryDescriptor + 2 * SizeOfPfnNumber
  759. + RunIndex * GetTypeSize("nt!_PHYSICAL_MEMORY_RUN");
  760. BasePage = READ_PVOID (RunAddress);
  761. PageCount = READ_PVOID (RunAddress + SizeOfPfnNumber);
  762. //
  763. // Figure out real start and end page.
  764. //
  765. RunStartPage = PageFrame;
  766. RunEndPage = PageFrame + DefaultRange;
  767. if (RunEndPage <= BasePage) {
  768. continue;
  769. }
  770. if (RunStartPage >= BasePage + PageCount) {
  771. continue;
  772. }
  773. if (RunStartPage < BasePage) {
  774. RunStartPage = BasePage;
  775. }
  776. if (RunEndPage > BasePage + PageCount) {
  777. RunEndPage = BasePage + PageCount;
  778. }
  779. PtrSearch.Offset = (ULONG64)RunStartPage * PageSize;
  780. PtrSearch.Length = (ULONG64)
  781. (RunEndPage - RunStartPage) * PageSize;
  782. PtrSearch.Flags = PTR_SEARCH_PHYS_PTE;
  783. PtrSearch.MatchOffsetsCount = 0;
  784. Ioctl (IG_POINTER_SEARCH_PHYSICAL, &PtrSearch, sizeof(PtrSearch));
  785. //
  786. // Display results
  787. //
  788. Hits = PtrSearch.MatchOffsetsCount;
  789. for (Index = 0; Index < Hits; Index++) {
  790. NumberOfHits += 1;
  791. dprintf (".");
  792. //
  793. // Add to hits buffer
  794. //
  795. PfnHit = g_SearchHits[Index] / PageSize;
  796. PfnHitsBuffer [PfnHitsBufferIndex] = PfnHit;
  797. PfnHitsBufferIndex += 1;
  798. if (PfnHitsBufferIndex >= PfnHitsBufferSize) {
  799. PVOID NewBuffer;
  800. PfnHitsBufferSize *= 2;
  801. NewBuffer = realloc (PfnHitsBuffer,
  802. PfnHitsBufferSize * sizeof(ULONG64));
  803. if (NewBuffer == NULL) {
  804. dprintf ("Search error: cannot reallocate hits buffer with size %u. \n",
  805. PfnHitsBufferSize);
  806. Result = E_INVALIDARG;
  807. goto Exit;
  808. }
  809. PfnHitsBuffer = NewBuffer;
  810. }
  811. }
  812. //
  813. // check for ctrl-c
  814. //
  815. if (CheckControlC()) {
  816. RequestForInterrupt = TRUE;
  817. break;
  818. }
  819. }
  820. if (RequestForInterrupt) {
  821. break;
  822. }
  823. }
  824. //
  825. // Now find all hits in all pages.
  826. //
  827. dprintf ("\n");
  828. dprintf ("Found %u pages with hits. \n", PfnHitsBufferIndex);
  829. dprintf ("Searching now for all hits in relevant pages ... \n");
  830. NumberOfHits = 0;
  831. for (PfnIndex = 0;
  832. !RequestForInterrupt && PfnIndex < PfnHitsBufferIndex;
  833. PfnIndex += 1) {
  834. PtrSearch.Offset = (ULONG64)PfnHitsBuffer[PfnIndex] * PageSize;
  835. PtrSearch.Length = PageSize;
  836. PtrSearch.Flags = PTR_SEARCH_PHYS_ALL_HITS | PTR_SEARCH_PHYS_PTE;
  837. PtrSearch.MatchOffsetsCount = 0;
  838. Ioctl (IG_POINTER_SEARCH_PHYSICAL, &PtrSearch, sizeof(PtrSearch));
  839. Hits = PtrSearch.MatchOffsetsCount;
  840. for (Index = 0; Index < Hits; Index++) {
  841. NumberOfHits += 1;
  842. PfnHit = g_SearchHits[Index] / PageSize;
  843. PfnOffset = (ULONG)(g_SearchHits[Index] & (PageSize - 1));
  844. VaHit = SearchConvertPageFrameToVa (PfnHit, &VaFlags, &PteAddress);
  845. if (SizeOfPfnNumber == 8) {
  846. dprintf ("%016I64X %08X %016I64X %016I64X %016I64X \n",
  847. PfnHit,
  848. PfnOffset,
  849. READ_PHYSICAL_ULONG64 (PfnHit * PageSize + PfnOffset),
  850. (VaHit == 0 ? 0 : VaHit + PfnOffset),
  851. PteAddress);
  852. }
  853. else {
  854. VaHit &= (ULONG64)0xFFFFFFFF;
  855. PteAddress &= (ULONG64)0xFFFFFFFF;
  856. dprintf ("%08I64X %08X %08X %08I64X %08I64X \n",
  857. PfnHit,
  858. PfnOffset,
  859. READ_PHYSICAL_ULONG (PfnHit * PageSize + PfnOffset),
  860. (VaHit == 0 ? 0 : VaHit + PfnOffset),
  861. PteAddress);
  862. }
  863. if (CheckControlC()) {
  864. RequestForInterrupt = TRUE;
  865. break;
  866. }
  867. }
  868. }
  869. dprintf ("\n");
  870. Result = S_OK;
  871. //
  872. // Exit point
  873. //
  874. Exit:
  875. if (PfnHitsBuffer) {
  876. free (PfnHitsBuffer);
  877. }
  878. if (! RequestForInterrupt) {
  879. dprintf ("Search done (%u hits in %u pages).\n",
  880. NumberOfHits,
  881. PfnHitsBufferIndex);
  882. }
  883. else {
  884. dprintf ("Search interrupted. \n");
  885. }
  886. return Result;
  887. }