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.

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