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.

497 lines
9.8 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Copyright (c) 1992 Digital Equipment Corporation
  4. Module Name:
  5. hypermap.c
  6. Abstract:
  7. This module contains the routines which map physical pages into
  8. reserved PTEs within hyper space.
  9. This module is machine dependent. This version is targeted for ALPHA
  10. using KSEG0 (32bit superpage) to map the pages at their physical
  11. addresses.
  12. Author:
  13. Lou Perazzoli (loup) 5-Apr-1989
  14. Joe Notarangelo 23-Apr-1992 ALPHA version from MIPS version
  15. Revision History:
  16. --*/
  17. #include "mi.h"
  18. PVOID
  19. MiMapPageInHyperSpace (
  20. IN ULONG PageFrameIndex,
  21. IN PKIRQL OldIrql
  22. )
  23. /*++
  24. Routine Description:
  25. This routine returns the physical address of the page.
  26. ************************************
  27. * *
  28. * Returns with a spin lock held!!! *
  29. * *
  30. ************************************
  31. Arguments:
  32. PageFrameIndex - Supplies the physical page number to map.
  33. OldIrql - Supplies a pointer in which to return the entry IRQL.
  34. Return Value:
  35. Returns the address where the requested page was mapped.
  36. RETURNS WITH THE HYPERSPACE SPIN LOCK HELD!!!!
  37. The routine MiUnmapHyperSpaceMap MUST be called to release the lock!!!!
  38. Environment:
  39. kernel mode.
  40. --*/
  41. {
  42. PMMPTE PointerPte;
  43. MMPTE TempPte;
  44. ULONG offset;
  45. #if DBG
  46. if (PageFrameIndex == 0) {
  47. DbgPrint("attempt to map physical page 0 in hyper space\n");
  48. KeBugCheck (MEMORY_MANAGEMENT);
  49. }
  50. #endif //DBG
  51. //
  52. // If the page is below 1GB physical, then it can be mapped via
  53. // KSEG0.
  54. //
  55. LOCK_HYPERSPACE (OldIrql);
  56. if (PageFrameIndex < MM_PAGES_IN_KSEG0) {
  57. return (PVOID)(KSEG0_BASE + (PageFrameIndex << PAGE_SHIFT));
  58. }
  59. PointerPte = MmFirstReservedMappingPte;
  60. if (PointerPte->u.Hard.Valid == 1) {
  61. //
  62. // All the reserved PTEs have been used, make
  63. // them all invalid.
  64. //
  65. MI_MAKING_MULTIPLE_PTES_INVALID (FALSE);
  66. RtlZeroMemory (MmFirstReservedMappingPte,
  67. (NUMBER_OF_MAPPING_PTES + 1) * sizeof(MMPTE));
  68. //
  69. // Use the page frame number field of the first PTE as an
  70. // offset into the available mapping PTEs.
  71. //
  72. PointerPte->u.Hard.PageFrameNumber = NUMBER_OF_MAPPING_PTES;
  73. //
  74. // Flush entire TB only on this processor.
  75. //
  76. KeFlushEntireTb (TRUE, FALSE);
  77. }
  78. //
  79. // Get offset to first free PTE.
  80. //
  81. offset = PointerPte->u.Hard.PageFrameNumber;
  82. //
  83. // Change offset for next time through.
  84. //
  85. PointerPte->u.Hard.PageFrameNumber = offset - 1;
  86. //
  87. // Point to free entry and make it valid.
  88. //
  89. PointerPte += offset;
  90. ASSERT (PointerPte->u.Hard.Valid == 0);
  91. TempPte = ValidPtePte;
  92. TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
  93. *PointerPte = TempPte;
  94. //
  95. // Return the VA that maps the page.
  96. //
  97. return MiGetVirtualAddressMappedByPte (PointerPte);
  98. }
  99. PVOID
  100. MiMapPageInHyperSpaceAtDpc (
  101. IN ULONG PageFrameIndex
  102. )
  103. /*++
  104. Routine Description:
  105. This routine returns the physical address of the page.
  106. ************************************
  107. * *
  108. * Returns with a spin lock held!!! *
  109. * *
  110. ************************************
  111. Arguments:
  112. PageFrameIndex - Supplies the physical page number to map.
  113. Return Value:
  114. Returns the address where the requested page was mapped.
  115. RETURNS WITH THE HYPERSPACE SPIN LOCK HELD!!!!
  116. The routine MiUnmapHyperSpaceMap MUST be called to release the lock!!!!
  117. Environment:
  118. Kernel mode, DISPATCH_LEVEL on entry.
  119. --*/
  120. {
  121. PMMPTE PointerPte;
  122. MMPTE TempPte;
  123. ULONG offset;
  124. #if DBG
  125. if (PageFrameIndex == 0) {
  126. DbgPrint("attempt to map physical page 0 in hyper space\n");
  127. KeBugCheck (MEMORY_MANAGEMENT);
  128. }
  129. #endif //DBG
  130. //
  131. // If the page is below 1GB physical, then it can be mapped via
  132. // KSEG0.
  133. //
  134. LOCK_HYPERSPACE_AT_DPC ();
  135. if (PageFrameIndex < MM_PAGES_IN_KSEG0) {
  136. return (PVOID)(KSEG0_BASE + (PageFrameIndex << PAGE_SHIFT));
  137. }
  138. PointerPte = MmFirstReservedMappingPte;
  139. if (PointerPte->u.Hard.Valid == 1) {
  140. //
  141. // All the reserved PTEs have been used, make
  142. // them all invalid.
  143. //
  144. MI_MAKING_MULTIPLE_PTES_INVALID (FALSE);
  145. RtlZeroMemory (MmFirstReservedMappingPte,
  146. (NUMBER_OF_MAPPING_PTES + 1) * sizeof(MMPTE));
  147. //
  148. // Use the page frame number field of the first PTE as an
  149. // offset into the available mapping PTEs.
  150. //
  151. PointerPte->u.Hard.PageFrameNumber = NUMBER_OF_MAPPING_PTES;
  152. //
  153. // Flush entire TB only on this processor.
  154. //
  155. KeFlushEntireTb (TRUE, FALSE);
  156. }
  157. //
  158. // Get offset to first free PTE.
  159. //
  160. offset = PointerPte->u.Hard.PageFrameNumber;
  161. //
  162. // Change offset for next time through.
  163. //
  164. PointerPte->u.Hard.PageFrameNumber = offset - 1;
  165. //
  166. // Point to free entry and make it valid.
  167. //
  168. PointerPte += offset;
  169. ASSERT (PointerPte->u.Hard.Valid == 0);
  170. TempPte = ValidPtePte;
  171. TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
  172. *PointerPte = TempPte;
  173. //
  174. // Return the VA that maps the page.
  175. //
  176. return MiGetVirtualAddressMappedByPte (PointerPte);
  177. }
  178. PVOID
  179. MiMapImageHeaderInHyperSpace (
  180. IN ULONG PageFrameIndex
  181. )
  182. /*++
  183. Routine Description:
  184. The physical address of the specified page is returned.
  185. Arguments:
  186. PageFrameIndex - Supplies the physical page number to map.
  187. Return Value:
  188. Returns the virtual address where the specified physical page was
  189. mapped.
  190. Environment:
  191. Kernel mode.
  192. --*/
  193. {
  194. MMPTE TempPte;
  195. PMMPTE PointerPte;
  196. KIRQL OldIrql;
  197. #if DBG
  198. if (PageFrameIndex == 0) {
  199. DbgPrint("attempt to map physical page 0 in hyper space\n");
  200. KeBugCheck (MEMORY_MANAGEMENT);
  201. }
  202. #endif //DBG
  203. PointerPte = MiGetPteAddress (IMAGE_MAPPING_PTE);
  204. LOCK_PFN (OldIrql);
  205. while (PointerPte->u.Long != 0) {
  206. //
  207. // If there is no event specified, set one up.
  208. //
  209. if (MmWorkingSetList->WaitingForImageMapping == (PKEVENT)NULL) {
  210. //
  211. // Set the global event into the field and wait for it.
  212. //
  213. MmWorkingSetList->WaitingForImageMapping = &MmImageMappingPteEvent;
  214. }
  215. //
  216. // Release the PFN lock and wait on the event in an
  217. // atomic operation.
  218. //
  219. KeEnterCriticalRegion();
  220. UNLOCK_PFN_AND_THEN_WAIT(OldIrql);
  221. KeWaitForSingleObject(MmWorkingSetList->WaitingForImageMapping,
  222. Executive,
  223. KernelMode,
  224. FALSE,
  225. (PLARGE_INTEGER)NULL);
  226. KeLeaveCriticalRegion();
  227. LOCK_PFN (OldIrql);
  228. }
  229. ASSERT (PointerPte->u.Long == 0);
  230. TempPte = ValidPtePte;
  231. TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
  232. *PointerPte = TempPte;
  233. UNLOCK_PFN (OldIrql);
  234. return (PVOID)MiGetVirtualAddressMappedByPte (PointerPte);
  235. }
  236. VOID
  237. MiUnmapImageHeaderInHyperSpace (
  238. VOID
  239. )
  240. /*++
  241. Routine Description:
  242. This procedure unmaps the PTE reserved for mapping the image
  243. header, flushes the TB, and, if the WaitingForImageMapping field
  244. is not NULL, sets the specified event.
  245. On ALPHA, no action is required as the super-page address of the page
  246. was used.
  247. Arguments:
  248. None.
  249. Return Value:
  250. None.
  251. Environment:
  252. Kernel mode.
  253. --*/
  254. {
  255. MMPTE TempPte;
  256. PMMPTE PointerPte;
  257. KIRQL OldIrql;
  258. PKEVENT Event;
  259. PointerPte = MiGetPteAddress (IMAGE_MAPPING_PTE);
  260. TempPte.u.Long = 0;
  261. LOCK_PFN (OldIrql);
  262. //
  263. // Capture the current state of the event field and clear it out.
  264. //
  265. Event = MmWorkingSetList->WaitingForImageMapping;
  266. MmWorkingSetList->WaitingForImageMapping = (PKEVENT)NULL;
  267. ASSERT (PointerPte->u.Long != 0);
  268. KeFlushSingleTb (IMAGE_MAPPING_PTE, TRUE, FALSE,
  269. (PHARDWARE_PTE)PointerPte, TempPte.u.Hard);
  270. UNLOCK_PFN (OldIrql);
  271. if (Event != (PKEVENT)NULL) {
  272. //
  273. // If there was an event specified, set the event.
  274. //
  275. KePulseEvent (Event, 0, FALSE);
  276. }
  277. return;
  278. }
  279. PVOID
  280. MiMapPageToZeroInHyperSpace (
  281. IN ULONG PageFrameIndex
  282. )
  283. /*++
  284. Routine Description:
  285. This procedure maps the specified physical page into hyper space
  286. and returns the virtual address which maps the page.
  287. NOTE: it maps it into the same location reserved for fork operations!!
  288. This is only to be used by the zeroing page thread.
  289. Arguments:
  290. PageFrameIndex - Supplies the physical page number to map.
  291. Return Value:
  292. Returns the virtual address where the specified physical page was
  293. mapped.
  294. Environment:
  295. Must be holding the PFN lock.
  296. --*/
  297. {
  298. MMPTE TempPte;
  299. PMMPTE PointerPte;
  300. PVOID MappedAddress;
  301. #if DBG
  302. if (PageFrameIndex == 0) {
  303. DbgPrint("attempt to map physical page 0 in hyper space\n");
  304. KeBugCheck (MEMORY_MANAGEMENT);
  305. }
  306. #endif //DBG
  307. //
  308. // If the page is below 1GB physical then it can be mapped via
  309. // KSEG0.
  310. //
  311. if (PageFrameIndex < MM_PAGES_IN_KSEG0) {
  312. return (PVOID)(KSEG0_BASE + (PageFrameIndex << PAGE_SHIFT));
  313. }
  314. MM_PFN_LOCK_ASSERT();
  315. PointerPte = MiGetPteAddress (ZEROING_PAGE_PTE);
  316. MappedAddress = MiGetVirtualAddressMappedByPte (PointerPte);
  317. TempPte.u.Long = 0;
  318. KeFlushSingleTb (MappedAddress,
  319. TRUE,
  320. FALSE,
  321. (PHARDWARE_PTE)PointerPte, TempPte.u.Hard);
  322. TempPte = ValidPtePte;
  323. TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
  324. *PointerPte = TempPte;
  325. return MappedAddress;
  326. }