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.

431 lines
7.3 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. pat.c
  5. Abstract:
  6. This module implements interfaces that set the Page Attribute
  7. Table. These entry points only exist on i386 machines.
  8. Author:
  9. Shivnandan Kaushik (Intel Corp.)
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. --*/
  14. #include "ki.h"
  15. #include "pat.h"
  16. //
  17. // Use lockstep mechanism from mtrr code.
  18. //
  19. #include "mtrr.h"
  20. #if DBG
  21. #define DBGMSG(a) DbgPrint(a)
  22. #else
  23. #define DBGMSG(a)
  24. #endif
  25. //
  26. // Structure used for PAT initialization
  27. //
  28. typedef struct _NEW_PAT {
  29. PAT Attributes;
  30. //
  31. // IPI context to coordinate concurrent PAT update
  32. //
  33. PROCESSOR_LOCKSTEP Synchronize;
  34. } NEW_PAT, *PNEW_PAT;
  35. // Prototypes
  36. VOID
  37. KeRestorePAT (
  38. VOID
  39. );
  40. VOID
  41. KiInitializePAT (
  42. VOID
  43. );
  44. VOID
  45. KiLoadPAT (
  46. IN PNEW_PAT Context
  47. );
  48. VOID
  49. KiLoadPATTarget (
  50. IN PKIPI_CONTEXT SignalDone,
  51. IN PVOID Context,
  52. IN PVOID Parameter2,
  53. IN PVOID Parameter3
  54. );
  55. #if DBG
  56. VOID
  57. KiDumpPAT (
  58. PUCHAR DebugString,
  59. PAT Attributes
  60. );
  61. #endif
  62. #ifdef ALLOC_PRAGMA
  63. #pragma alloc_text(PAGELK,KiInitializePAT)
  64. #pragma alloc_text(PAGELK,KiLoadPAT)
  65. #pragma alloc_text(PAGELK,KiLoadPATTarget)
  66. #endif
  67. VOID
  68. KeRestorePAT (
  69. VOID
  70. )
  71. /*++
  72. Routine Description:
  73. Reinitialize the Page Attribute Table (PAT) on all processors.
  74. N.B. The caller must have the PAGELK code locked
  75. Arguments:
  76. None.
  77. Return Value:
  78. None.
  79. --*/
  80. {
  81. if (KeFeatureBits & KF_PAT) {
  82. KiInitializePAT();
  83. }
  84. }
  85. VOID
  86. KiInitializePAT (
  87. VOID
  88. )
  89. /*++
  90. Routine Description:
  91. Initialize the Page Attribute Table (PAT) on all processors. PAT
  92. is setup to provide WB, WC, STRONG_UC and WEAK_UC as the memory
  93. types such that mm macros for enabling/disabling/querying caching
  94. (MI_DISABLE_CACHING, MI_ENABLE_CACHING and MI_IS_CACHING_ENABLED)
  95. are unaffected.
  96. PAT_Entry PAT Index PCD PWT Memory Type
  97. 0 0 0 0 WB
  98. 1 0 0 1 WC *
  99. 2 0 1 0 WEAK_UC
  100. 3 0 1 1 STRONG_UC
  101. 4 1 0 0 WB
  102. 5 1 0 1 WC *
  103. 6 1 1 0 WEAK_UC
  104. 7 1 1 1 STRONG_UC
  105. N.B. The caller must have the PAGELK code locked and ensure that the
  106. PAT feature is supported.
  107. Arguments:
  108. None.
  109. Return Value:
  110. None.
  111. --*/
  112. {
  113. PAT PatAttributes;
  114. ULONG Size;
  115. KIRQL OldIrql, NewIrql;
  116. PKPRCB Prcb;
  117. NEW_PAT NewPAT;
  118. KAFFINITY TargetProcessors;
  119. ASSERT ((KeFeatureBits & KF_PAT) != 0);
  120. //
  121. // Initialize the PAT
  122. //
  123. PatAttributes.hw.Pat[0] = PAT_TYPE_WB;
  124. PatAttributes.hw.Pat[1] = PAT_TYPE_USWC;
  125. PatAttributes.hw.Pat[2] = PAT_TYPE_WEAK_UC;
  126. PatAttributes.hw.Pat[3] = PAT_TYPE_STRONG_UC;
  127. PatAttributes.hw.Pat[4] = PAT_TYPE_WB;
  128. PatAttributes.hw.Pat[5] = PAT_TYPE_USWC;
  129. PatAttributes.hw.Pat[6] = PAT_TYPE_WEAK_UC;
  130. PatAttributes.hw.Pat[7] = PAT_TYPE_STRONG_UC;
  131. //
  132. // Synchronize with other IPI functions which may stall
  133. //
  134. KiLockContextSwap(&OldIrql);
  135. Prcb = KeGetCurrentPrcb();
  136. NewPAT.Attributes = PatAttributes;
  137. NewPAT.Synchronize.TargetCount = 0;
  138. NewPAT.Synchronize.TargetPhase = &Prcb->ReverseStall;
  139. NewPAT.Synchronize.Processor = Prcb->Number;
  140. #if !defined(NT_UP)
  141. //
  142. // Collect all the (other) processors
  143. //
  144. TargetProcessors = KeActiveProcessors & ~Prcb->SetMember;
  145. if (TargetProcessors != 0) {
  146. KiIpiSendSynchronousPacket (
  147. Prcb,
  148. TargetProcessors,
  149. KiLoadPATTarget,
  150. (PVOID) (&NewPAT),
  151. NULL,
  152. NULL
  153. );
  154. //
  155. // Wait for all processors to be collected
  156. //
  157. KiIpiStallOnPacketTargets(TargetProcessors);
  158. //
  159. // All processors are now waiting. Raise to high level to
  160. // ensure this processor doesn't enter the debugger due to
  161. // some interrupt service routine.
  162. //
  163. KeRaiseIrql (HIGH_LEVEL, &NewIrql);
  164. //
  165. // There's no reason for any debug events now, so signal
  166. // the other processors that they can all begin the PAT update
  167. //
  168. Prcb->ReverseStall += 1;
  169. }
  170. #endif
  171. //
  172. // Update PAT
  173. //
  174. KiLoadPAT(&NewPAT);
  175. //
  176. // Release ContextSwap lock and lower to initial irql
  177. //
  178. KiUnlockContextSwap(OldIrql);
  179. MmEnablePAT();
  180. return;
  181. }
  182. VOID
  183. KiLoadPATTarget (
  184. IN PKIPI_CONTEXT SignalDone,
  185. IN PVOID NewPAT,
  186. IN PVOID Parameter2,
  187. IN PVOID Parameter3
  188. )
  189. /*++
  190. Routine Description:
  191. Synchronize with target processors prior to PAT modification.
  192. Arguments:
  193. Context - Context which includes the PAT to load
  194. Return Value:
  195. None
  196. --*/
  197. {
  198. PNEW_PAT Context;
  199. Context = (PNEW_PAT) NewPAT;
  200. //
  201. // Wait for all processors to be ready
  202. //
  203. KiIpiSignalPacketDoneAndStall(SignalDone,
  204. Context->Synchronize.TargetPhase);
  205. //
  206. // Update PAT
  207. //
  208. KiLoadPAT (Context);
  209. }
  210. VOID
  211. KiLoadPAT (
  212. IN PNEW_PAT Context
  213. )
  214. /*++
  215. Routine Description:
  216. This function loads the PAT to all processors.
  217. Arguments:
  218. Context - Context which includes new PAT to load
  219. Return Value:
  220. PAT on all processors programmed to new values
  221. --*/
  222. {
  223. BOOLEAN Enable;
  224. ULONG HldCr0, HldCr4, Index;
  225. //
  226. // Disable interrupts
  227. //
  228. Enable = KeDisableInterrupts();
  229. //
  230. // Synchronize all processors
  231. //
  232. KiLockStepExecution (&Context->Synchronize);
  233. _asm {
  234. ;
  235. ; Get current CR0
  236. ;
  237. mov eax, cr0
  238. mov HldCr0, eax
  239. ;
  240. ; Disable caching & line fill
  241. ;
  242. and eax, not CR0_NW
  243. or eax, CR0_CD
  244. mov cr0, eax
  245. ;
  246. ; Flush caches
  247. ;
  248. ;
  249. ; wbinvd
  250. ;
  251. _emit 0Fh
  252. _emit 09h
  253. ;
  254. ; Get current cr4
  255. ;
  256. _emit 0Fh
  257. _emit 20h
  258. _emit 0E0h ; mov eax, cr4
  259. mov HldCr4, eax
  260. ;
  261. ; Disable global page
  262. ;
  263. and eax, not CR4_PGE
  264. _emit 0Fh
  265. _emit 22h
  266. _emit 0E0h ; mov cr4, eax
  267. ;
  268. ; Flush TLB
  269. ;
  270. mov eax, cr3
  271. mov cr3, eax
  272. }
  273. //
  274. // Load new PAT
  275. //
  276. WRMSR (PAT_MSR, Context->Attributes.QuadPart);
  277. _asm {
  278. ;
  279. ; Flush caches.
  280. ;
  281. ;
  282. ; wbinvd
  283. ;
  284. _emit 0Fh
  285. _emit 09h
  286. ;
  287. ; Flush TLBs
  288. ;
  289. mov eax, cr3
  290. mov cr3, eax
  291. }
  292. _asm {
  293. ;
  294. ; Restore CR4 (global page enable)
  295. ;
  296. mov eax, HldCr4
  297. _emit 0Fh
  298. _emit 22h
  299. _emit 0E0h ; mov cr4, eax
  300. ;
  301. ; Restore CR0 (cache enable)
  302. ;
  303. mov eax, HldCr0
  304. mov cr0, eax
  305. }
  306. //
  307. // Wait for all processors to reach the same place,
  308. // restore interrupts and return.
  309. //
  310. KiLockStepExecution (&Context->Synchronize);
  311. KeEnableInterrupts (Enable);
  312. }