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.

517 lines
14 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. checkpfn.c
  5. Abstract:
  6. This module contains routines for sanity checking the PFN database.
  7. Author:
  8. Lou Perazzoli (loup) 25-Apr-1989
  9. Revision History:
  10. --*/
  11. #include "mi.h"
  12. #if DBG
  13. PRTL_BITMAP CheckPfnBitMap;
  14. VOID
  15. MiCheckPfn (
  16. )
  17. /*++
  18. Routine Description:
  19. This routine checks each physical page in the PFN database to ensure
  20. it is in the proper state.
  21. Arguments:
  22. None.
  23. Return Value:
  24. None.
  25. Environment:
  26. Kernel mode, APCs disabled.
  27. --*/
  28. {
  29. PEPROCESS Process;
  30. PMMPFN Pfn1;
  31. PFN_NUMBER Link, Previous;
  32. ULONG i;
  33. PMMPTE PointerPte;
  34. KIRQL PreviousIrql;
  35. KIRQL OldIrql;
  36. USHORT ValidCheck[4];
  37. USHORT ValidPage[4];
  38. PMMPFN PfnX;
  39. ValidCheck[0] = ValidCheck[1] = ValidCheck[2] = ValidCheck[3] = 0;
  40. ValidPage[0] = ValidPage[1] = ValidPage[2] = ValidPage[3] = 0;
  41. if (CheckPfnBitMap == NULL) {
  42. MiCreateBitMap ( &CheckPfnBitMap, MmNumberOfPhysicalPages, NonPagedPool);
  43. }
  44. RtlClearAllBits (CheckPfnBitMap);
  45. Process = PsGetCurrentProcess ();
  46. //
  47. // Walk free list.
  48. //
  49. KeRaiseIrql (APC_LEVEL, &PreviousIrql);
  50. LOCK_PFN (OldIrql);
  51. Previous = MM_EMPTY_LIST;
  52. Link = MmFreePageListHead.Flink;
  53. for (i=0; i < MmFreePageListHead.Total; i++) {
  54. if (Link == MM_EMPTY_LIST) {
  55. DbgPrint("free list total count wrong\n");
  56. UNLOCK_PFN (OldIrql);
  57. KeLowerIrql (PreviousIrql);
  58. return;
  59. }
  60. RtlSetBits (CheckPfnBitMap, (ULONG)Link, 1L);
  61. Pfn1 = MI_PFN_ELEMENT(Link);
  62. if (Pfn1->u3.e2.ReferenceCount != 0) {
  63. DbgPrint("non zero reference count on free list\n");
  64. MiFormatPfn(Pfn1);
  65. }
  66. if (Pfn1->u3.e1.PageLocation != FreePageList) {
  67. DbgPrint("page location not freelist\n");
  68. MiFormatPfn(Pfn1);
  69. }
  70. if (Pfn1->u2.Blink != Previous) {
  71. DbgPrint("bad blink on free list\n");
  72. MiFormatPfn(Pfn1);
  73. }
  74. Previous = Link;
  75. Link = Pfn1->u1.Flink;
  76. }
  77. if (Link != MM_EMPTY_LIST) {
  78. DbgPrint("free list total count wrong\n");
  79. Pfn1 = MI_PFN_ELEMENT(Link);
  80. MiFormatPfn(Pfn1);
  81. }
  82. //
  83. // Walk zeroed list.
  84. //
  85. Previous = MM_EMPTY_LIST;
  86. Link = MmZeroedPageListHead.Flink;
  87. for (i=0; i < MmZeroedPageListHead.Total; i++) {
  88. if (Link == MM_EMPTY_LIST) {
  89. DbgPrint("zero list total count wrong\n");
  90. UNLOCK_PFN (OldIrql);
  91. KeLowerIrql (PreviousIrql);
  92. return;
  93. }
  94. RtlSetBits (CheckPfnBitMap, (ULONG)Link, 1L);
  95. Pfn1 = MI_PFN_ELEMENT(Link);
  96. if (Pfn1->u3.e2.ReferenceCount != 0) {
  97. DbgPrint("non zero reference count on zero list\n");
  98. MiFormatPfn(Pfn1);
  99. }
  100. if (Pfn1->u3.e1.PageLocation != ZeroedPageList) {
  101. DbgPrint("page location not zerolist\n");
  102. MiFormatPfn(Pfn1);
  103. }
  104. if (Pfn1->u2.Blink != Previous) {
  105. DbgPrint("bad blink on zero list\n");
  106. MiFormatPfn(Pfn1);
  107. }
  108. Previous = Link;
  109. Link = Pfn1->u1.Flink;
  110. }
  111. if (Link != MM_EMPTY_LIST) {
  112. DbgPrint("zero list total count wrong\n");
  113. Pfn1 = MI_PFN_ELEMENT(Link);
  114. MiFormatPfn(Pfn1);
  115. }
  116. //
  117. // Walk Bad list.
  118. //
  119. Previous = MM_EMPTY_LIST;
  120. Link = MmBadPageListHead.Flink;
  121. for (i=0; i < MmBadPageListHead.Total; i++) {
  122. if (Link == MM_EMPTY_LIST) {
  123. DbgPrint("Bad list total count wrong\n");
  124. UNLOCK_PFN (OldIrql);
  125. KeLowerIrql (PreviousIrql);
  126. return;
  127. }
  128. RtlSetBits (CheckPfnBitMap, (ULONG)Link, 1L);
  129. Pfn1 = MI_PFN_ELEMENT(Link);
  130. if (Pfn1->u3.e2.ReferenceCount != 0) {
  131. DbgPrint("non zero reference count on Bad list\n");
  132. MiFormatPfn(Pfn1);
  133. }
  134. if (Pfn1->u3.e1.PageLocation != BadPageList) {
  135. DbgPrint("page location not Badlist\n");
  136. MiFormatPfn(Pfn1);
  137. }
  138. if (Pfn1->u2.Blink != Previous) {
  139. DbgPrint("bad blink on Bad list\n");
  140. MiFormatPfn(Pfn1);
  141. }
  142. Previous = Link;
  143. Link = Pfn1->u1.Flink;
  144. }
  145. if (Link != MM_EMPTY_LIST) {
  146. DbgPrint("Bad list total count wrong\n");
  147. Pfn1 = MI_PFN_ELEMENT(Link);
  148. MiFormatPfn(Pfn1);
  149. }
  150. //
  151. // Walk Standby list.
  152. //
  153. Previous = MM_EMPTY_LIST;
  154. Link = MmStandbyPageListHead.Flink;
  155. for (i=0; i < MmStandbyPageListHead.Total; i++) {
  156. if (Link == MM_EMPTY_LIST) {
  157. DbgPrint("Standby list total count wrong\n");
  158. UNLOCK_PFN (OldIrql);
  159. KeLowerIrql (PreviousIrql);
  160. return;
  161. }
  162. RtlSetBits (CheckPfnBitMap, (ULONG)Link, 1L);
  163. Pfn1 = MI_PFN_ELEMENT(Link);
  164. if (Pfn1->u3.e2.ReferenceCount != 0) {
  165. DbgPrint("non zero reference count on Standby list\n");
  166. MiFormatPfn(Pfn1);
  167. }
  168. if (Pfn1->u3.e1.PageLocation != StandbyPageList) {
  169. DbgPrint("page location not Standbylist\n");
  170. MiFormatPfn(Pfn1);
  171. }
  172. if (Pfn1->u2.Blink != Previous) {
  173. DbgPrint("bad blink on Standby list\n");
  174. MiFormatPfn(Pfn1);
  175. }
  176. //
  177. // Check to see if referenced PTE is okay.
  178. //
  179. if (MI_IS_PFN_DELETED (Pfn1)) {
  180. DbgPrint("Invalid pteaddress in standby list\n");
  181. MiFormatPfn(Pfn1);
  182. } else {
  183. OldIrql = 99;
  184. if ((Pfn1->u3.e1.PrototypePte == 1) &&
  185. (MmIsAddressValid (Pfn1->PteAddress))) {
  186. PointerPte = Pfn1->PteAddress;
  187. } else {
  188. PointerPte = MiMapPageInHyperSpace (Process,
  189. Pfn1->u4.PteFrame,
  190. &OldIrql);
  191. PointerPte = (PMMPTE)((ULONG_PTR)PointerPte +
  192. MiGetByteOffset(Pfn1->PteAddress));
  193. }
  194. if (MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE (PointerPte) != Link) {
  195. DbgPrint("Invalid PFN - PTE address is wrong in standby list\n");
  196. MiFormatPfn(Pfn1);
  197. MiFormatPte(PointerPte);
  198. }
  199. if (PointerPte->u.Soft.Transition == 0) {
  200. DbgPrint("Pte not in transition for page on standby list\n");
  201. MiFormatPfn(Pfn1);
  202. MiFormatPte(PointerPte);
  203. }
  204. if (OldIrql != 99) {
  205. MiUnmapPageInHyperSpace (Process, PointerPte, OldIrql);
  206. OldIrql = 99;
  207. }
  208. }
  209. Previous = Link;
  210. Link = Pfn1->u1.Flink;
  211. }
  212. if (Link != MM_EMPTY_LIST) {
  213. DbgPrint("Standby list total count wrong\n");
  214. Pfn1 = MI_PFN_ELEMENT(Link);
  215. MiFormatPfn(Pfn1);
  216. }
  217. //
  218. // Walk Modified list.
  219. //
  220. Previous = MM_EMPTY_LIST;
  221. Link = MmModifiedPageListHead.Flink;
  222. for (i=0; i < MmModifiedPageListHead.Total; i++) {
  223. if (Link == MM_EMPTY_LIST) {
  224. DbgPrint("Modified list total count wrong\n");
  225. UNLOCK_PFN (OldIrql);
  226. KeLowerIrql (PreviousIrql);
  227. return;
  228. }
  229. RtlSetBits (CheckPfnBitMap, (ULONG)Link, 1L);
  230. Pfn1 = MI_PFN_ELEMENT(Link);
  231. if (Pfn1->u3.e2.ReferenceCount != 0) {
  232. DbgPrint("non zero reference count on Modified list\n");
  233. MiFormatPfn(Pfn1);
  234. }
  235. if (Pfn1->u3.e1.PageLocation != ModifiedPageList) {
  236. DbgPrint("page location not Modifiedlist\n");
  237. MiFormatPfn(Pfn1);
  238. }
  239. if (Pfn1->u2.Blink != Previous) {
  240. DbgPrint("bad blink on Modified list\n");
  241. MiFormatPfn(Pfn1);
  242. }
  243. //
  244. // Check to see if referenced PTE is okay.
  245. //
  246. if (MI_IS_PFN_DELETED (Pfn1)) {
  247. DbgPrint("Invalid pteaddress in modified list\n");
  248. MiFormatPfn(Pfn1);
  249. } else {
  250. if ((Pfn1->u3.e1.PrototypePte == 1) &&
  251. (MmIsAddressValid (Pfn1->PteAddress))) {
  252. PointerPte = Pfn1->PteAddress;
  253. } else {
  254. PointerPte = MiMapPageInHyperSpace (Process,
  255. Pfn1->u4.PteFrame,
  256. &OldIrql);
  257. PointerPte = (PMMPTE)((ULONG_PTR)PointerPte +
  258. MiGetByteOffset(Pfn1->PteAddress));
  259. }
  260. if (MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE (PointerPte) != Link) {
  261. DbgPrint("Invalid PFN - PTE address is wrong in modified list\n");
  262. MiFormatPfn(Pfn1);
  263. MiFormatPte(PointerPte);
  264. }
  265. if (PointerPte->u.Soft.Transition == 0) {
  266. DbgPrint("Pte not in transition for page on modified list\n");
  267. MiFormatPfn(Pfn1);
  268. MiFormatPte(PointerPte);
  269. }
  270. if (OldIrql != 99) {
  271. MiUnmapPageInHyperSpace (Process, PointerPte, OldIrql);
  272. OldIrql = 99;
  273. }
  274. }
  275. Previous = Link;
  276. Link = Pfn1->u1.Flink;
  277. }
  278. if (Link != MM_EMPTY_LIST) {
  279. DbgPrint("Modified list total count wrong\n");
  280. Pfn1 = MI_PFN_ELEMENT(Link);
  281. MiFormatPfn(Pfn1);
  282. }
  283. //
  284. // All non active pages have been scanned. Locate the
  285. // active pages and make sure they are consistent.
  286. //
  287. //
  288. // set bit zero as page zero is reserved for now
  289. //
  290. RtlSetBits (CheckPfnBitMap, 0L, 1L);
  291. Link = RtlFindClearBitsAndSet (CheckPfnBitMap, 1L, 0);
  292. while (Link != 0xFFFFFFFF) {
  293. Pfn1 = MI_PFN_ELEMENT (Link);
  294. //
  295. // Make sure the PTE address is okay
  296. //
  297. if ((Pfn1->PteAddress >= (PMMPTE)HYPER_SPACE)
  298. && (Pfn1->u3.e1.PrototypePte == 0)) {
  299. DbgPrint("Pfn with illegal PTE address\n");
  300. MiFormatPfn(Pfn1);
  301. break;
  302. }
  303. if (Pfn1->PteAddress < (PMMPTE)PTE_BASE) {
  304. DbgPrint("Pfn with illegal PTE address\n");
  305. MiFormatPfn(Pfn1);
  306. break;
  307. }
  308. #if defined(_IA64_)
  309. //
  310. // ignore PTEs mapped to IA64 kernel BAT.
  311. //
  312. if (MI_IS_PHYSICAL_ADDRESS(MiGetVirtualAddressMappedByPte(Pfn1->PteAddress))) {
  313. goto NoCheck;
  314. }
  315. #endif // _IA64_
  316. //
  317. // Check to make sure the referenced PTE is for this page.
  318. //
  319. if ((Pfn1->u3.e1.PrototypePte == 1) &&
  320. (MmIsAddressValid (Pfn1->PteAddress))) {
  321. PointerPte = Pfn1->PteAddress;
  322. } else {
  323. PointerPte = MiMapPageInHyperSpace (Process,
  324. Pfn1->u4.PteFrame,
  325. &OldIrql);
  326. PointerPte = (PMMPTE)((ULONG_PTR)PointerPte +
  327. MiGetByteOffset(Pfn1->PteAddress));
  328. }
  329. if (MI_GET_PAGE_FRAME_FROM_PTE (PointerPte) != Link) {
  330. DbgPrint("Invalid PFN - PTE address is wrong in active list\n");
  331. MiFormatPfn(Pfn1);
  332. MiFormatPte(PointerPte);
  333. }
  334. if (PointerPte->u.Hard.Valid == 0) {
  335. //
  336. // if the page is a page table page it could be out of
  337. // the working set yet a transition page is keeping it
  338. // around in memory (ups the share count).
  339. //
  340. if ((Pfn1->PteAddress < (PMMPTE)PDE_BASE) ||
  341. (Pfn1->PteAddress > (PMMPTE)PDE_TOP)) {
  342. DbgPrint("Pte not valid for page on active list\n");
  343. MiFormatPfn(Pfn1);
  344. MiFormatPte(PointerPte);
  345. }
  346. }
  347. if (Pfn1->u3.e2.ReferenceCount != 1) {
  348. DbgPrint("refcount not 1\n");
  349. MiFormatPfn(Pfn1);
  350. }
  351. //
  352. // Check to make sure the PTE count for the frame is okay.
  353. //
  354. if (Pfn1->u3.e1.PrototypePte == 1) {
  355. PfnX = MI_PFN_ELEMENT(Pfn1->u4.PteFrame);
  356. for (i = 0; i < 4; i++) {
  357. if (ValidPage[i] == 0) {
  358. ValidPage[i] = (USHORT)Pfn1->u4.PteFrame;
  359. }
  360. if (ValidPage[i] == (USHORT)Pfn1->u4.PteFrame) {
  361. ValidCheck[i] += 1;
  362. break;
  363. }
  364. }
  365. }
  366. if (OldIrql != 99) {
  367. MiUnmapPageInHyperSpace (Process, PointerPte, OldIrql);
  368. OldIrql = 99;
  369. }
  370. #if defined(_IA64_)
  371. NoCheck:
  372. #endif
  373. Link = RtlFindClearBitsAndSet (CheckPfnBitMap, 1L, 0);
  374. }
  375. for (i = 0; i < 4; i++) {
  376. if (ValidPage[i] == 0) {
  377. break;
  378. }
  379. PfnX = MI_PFN_ELEMENT(ValidPage[i]);
  380. }
  381. UNLOCK_PFN (OldIrql);
  382. KeLowerIrql (PreviousIrql);
  383. return;
  384. }
  385. VOID
  386. MiDumpPfn ( )
  387. {
  388. ULONG i;
  389. PMMPFN Pfn1;
  390. Pfn1 = MI_PFN_ELEMENT (MmLowestPhysicalPage);
  391. for (i=0; i < MmNumberOfPhysicalPages; i++) {
  392. MiFormatPfn (Pfn1);
  393. Pfn1++;
  394. }
  395. return;
  396. }
  397. VOID
  398. MiFormatPfn (
  399. IN PMMPFN PointerPfn
  400. )
  401. {
  402. MMPFN Pfn;
  403. ULONG i;
  404. Pfn = *PointerPfn;
  405. i = (ULONG)(PointerPfn - MmPfnDatabase);
  406. DbgPrint("***PFN %lx flink %p blink %p ptecount-refcnt %lx\n",
  407. i,
  408. Pfn.u1.Flink,
  409. Pfn.u2.Blink,
  410. Pfn.u3.e2.ReferenceCount);
  411. DbgPrint(" pteaddr %p originalPTE %p flags %lx \n",
  412. Pfn.PteAddress,
  413. Pfn.OriginalPte,
  414. Pfn.u3.e2.ShortFlags);
  415. return;
  416. }
  417. #endif