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.

435 lines
7.8 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. KIRQL OldIrql;
  115. PKPRCB Prcb;
  116. NEW_PAT NewPAT;
  117. #if !defined(NT_UP)
  118. KIRQL NewIrql;
  119. KAFFINITY TargetProcessors;
  120. #endif
  121. ASSERT ((KeFeatureBits & KF_PAT) != 0);
  122. //
  123. // Initialize the PAT
  124. //
  125. PatAttributes.hw.Pat[0] = PAT_TYPE_WB;
  126. PatAttributes.hw.Pat[1] = PAT_TYPE_USWC;
  127. PatAttributes.hw.Pat[2] = PAT_TYPE_WEAK_UC;
  128. PatAttributes.hw.Pat[3] = PAT_TYPE_STRONG_UC;
  129. PatAttributes.hw.Pat[4] = PAT_TYPE_WB;
  130. PatAttributes.hw.Pat[5] = PAT_TYPE_USWC;
  131. PatAttributes.hw.Pat[6] = PAT_TYPE_WEAK_UC;
  132. PatAttributes.hw.Pat[7] = PAT_TYPE_STRONG_UC;
  133. //
  134. // Synchronize with other IPI functions which may stall
  135. //
  136. KeAcquireSpinLock (&KiReverseStallIpiLock, &OldIrql);
  137. Prcb = KeGetCurrentPrcb();
  138. NewPAT.Attributes = PatAttributes;
  139. NewPAT.Synchronize.TargetCount = 0;
  140. NewPAT.Synchronize.TargetPhase = &Prcb->ReverseStall;
  141. NewPAT.Synchronize.Processor = Prcb->Number;
  142. #if !defined(NT_UP)
  143. //
  144. // Collect all the (other) processors
  145. //
  146. TargetProcessors = KeActiveProcessors & ~Prcb->SetMember;
  147. if (TargetProcessors != 0) {
  148. KiIpiSendSynchronousPacket (
  149. Prcb,
  150. TargetProcessors,
  151. KiLoadPATTarget,
  152. (PVOID) (&NewPAT),
  153. NULL,
  154. NULL
  155. );
  156. //
  157. // Wait for all processors to be collected
  158. //
  159. KiIpiStallOnPacketTargets(TargetProcessors);
  160. //
  161. // All processors are now waiting. Raise to high level to
  162. // ensure this processor doesn't enter the debugger due to
  163. // some interrupt service routine.
  164. //
  165. KeRaiseIrql (HIGH_LEVEL, &NewIrql);
  166. //
  167. // There's no reason for any debug events now, so signal
  168. // the other processors that they can all begin the PAT update
  169. //
  170. Prcb->ReverseStall += 1;
  171. }
  172. #endif
  173. //
  174. // Update PAT
  175. //
  176. KiLoadPAT(&NewPAT);
  177. //
  178. // Release lock and lower to initial irql
  179. //
  180. KeReleaseSpinLock (&KiReverseStallIpiLock, OldIrql);
  181. MmEnablePAT();
  182. return;
  183. }
  184. VOID
  185. KiLoadPATTarget (
  186. IN PKIPI_CONTEXT SignalDone,
  187. IN PVOID NewPAT,
  188. IN PVOID Parameter2,
  189. IN PVOID Parameter3
  190. )
  191. /*++
  192. Routine Description:
  193. Synchronize with target processors prior to PAT modification.
  194. Arguments:
  195. Context - Context which includes the PAT to load
  196. Return Value:
  197. None
  198. --*/
  199. {
  200. PNEW_PAT Context;
  201. UNREFERENCED_PARAMETER (Parameter2);
  202. UNREFERENCED_PARAMETER (Parameter3);
  203. Context = (PNEW_PAT) NewPAT;
  204. //
  205. // Wait for all processors to be ready
  206. //
  207. KiIpiSignalPacketDoneAndStall(SignalDone,
  208. Context->Synchronize.TargetPhase);
  209. //
  210. // Update PAT
  211. //
  212. KiLoadPAT (Context);
  213. }
  214. VOID
  215. KiLoadPAT (
  216. IN PNEW_PAT Context
  217. )
  218. /*++
  219. Routine Description:
  220. This function loads the PAT to all processors.
  221. Arguments:
  222. Context - Context which includes new PAT to load
  223. Return Value:
  224. PAT on all processors programmed to new values
  225. --*/
  226. {
  227. BOOLEAN Enable;
  228. ULONG HldCr0, HldCr4;
  229. //
  230. // Disable interrupts
  231. //
  232. Enable = KeDisableInterrupts();
  233. //
  234. // Synchronize all processors
  235. //
  236. KiLockStepExecution (&Context->Synchronize);
  237. _asm {
  238. ;
  239. ; Get current CR0
  240. ;
  241. mov eax, cr0
  242. mov HldCr0, eax
  243. ;
  244. ; Disable caching & line fill
  245. ;
  246. and eax, not CR0_NW
  247. or eax, CR0_CD
  248. mov cr0, eax
  249. ;
  250. ; Flush caches
  251. ;
  252. ;
  253. ; wbinvd
  254. ;
  255. _emit 0Fh
  256. _emit 09h
  257. ;
  258. ; Get current cr4
  259. ;
  260. _emit 0Fh
  261. _emit 20h
  262. _emit 0E0h ; mov eax, cr4
  263. mov HldCr4, eax
  264. ;
  265. ; Disable global page
  266. ;
  267. and eax, not CR4_PGE
  268. _emit 0Fh
  269. _emit 22h
  270. _emit 0E0h ; mov cr4, eax
  271. ;
  272. ; Flush TLB
  273. ;
  274. mov eax, cr3
  275. mov cr3, eax
  276. }
  277. //
  278. // Load new PAT
  279. //
  280. WRMSR (PAT_MSR, Context->Attributes.QuadPart);
  281. _asm {
  282. ;
  283. ; Flush caches.
  284. ;
  285. ;
  286. ; wbinvd
  287. ;
  288. _emit 0Fh
  289. _emit 09h
  290. ;
  291. ; Flush TLBs
  292. ;
  293. mov eax, cr3
  294. mov cr3, eax
  295. }
  296. _asm {
  297. ;
  298. ; Restore CR4 (global page enable)
  299. ;
  300. mov eax, HldCr4
  301. _emit 0Fh
  302. _emit 22h
  303. _emit 0E0h ; mov cr4, eax
  304. ;
  305. ; Restore CR0 (cache enable)
  306. ;
  307. mov eax, HldCr0
  308. mov cr0, eax
  309. }
  310. //
  311. // Wait for all processors to reach the same place,
  312. // restore interrupts and return.
  313. //
  314. KiLockStepExecution (&Context->Synchronize);
  315. KeEnableInterrupts (Enable);
  316. }