ReactOS  0.4.13-dev-259-g5ca9c9c
patpge.c
Go to the documentation of this file.
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/i386/patpge.c
5 * PURPOSE: Support for PAT and PGE (Large Pages)
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 #define PDE_BITS 10
16 #define PTE_BITS 10
17 
18 /* FUNCTIONS *****************************************************************/
19 
20 INIT_FUNCTION
22 NTAPI
24 {
25  //PLONG Count;
26 #if defined(_GLOBAL_PAGES_ARE_AWESOME_)
27  ULONG Cr4;
28 #endif
30 
31  /* Disable interrupts */
33 
34  /* Spin until other processors are ready */
35  //Count = (PLONG)Context;
36  //InterlockedDecrement(Count);
37  //while (*Count) YieldProcessor();
38 
39 #if defined(_GLOBAL_PAGES_ARE_AWESOME_)
40 
41  /* Get CR4 and ensure global pages are disabled */
42  Cr4 = __readcr4();
43  ASSERT(!(Cr4 & CR4_PGE));
44 
45  /* Reset CR3 to flush the TLB */
47 
48  /* Now enable PGE */
49  __writecr4(Cr4 | CR4_PGE);
50 
51 #endif
52 
53  /* Restore interrupts and return */
55  return 0;
56 }
57 
58 INIT_FUNCTION
59 VOID
60 NTAPI
62 {
63  /* FIXME: Support this */
64  DPRINT("PAT support detected but not yet taken advantage of\n");
65 }
66 
67 INIT_FUNCTION
69 NTAPI
71 {
73 
74  /* Call helper function with the start address and temporary page table pointer */
75  Ki386EnableCurrentLargePage(IdentityMap->StartAddress, IdentityMap->Cr3);
76 
77  return 0;
78 }
79 
80 PVOID
81 NTAPI
83  ULONG PagesCount,
84  BOOLEAN InLower4Gb)
85 {
86  PHYSICAL_ADDRESS AddressMask;
87  PVOID Result;
88  ULONG SizeInBytes = PagesCount * PAGE_SIZE;
89 
90  /* Initialize acceptable address mask to any possible address */
91  AddressMask.LowPart = 0xFFFFFFFF;
92  AddressMask.HighPart = 0xFFFFFFFF;
93 
94  /* Mark out higher 4Gb if caller asked so */
95  if (InLower4Gb) AddressMask.HighPart = 0;
96 
97  /* Try to allocate the memory */
98  Result = MmAllocateContiguousMemory(SizeInBytes, AddressMask);
99  if (!Result) return NULL;
100 
101  /* Zero it out */
102  RtlZeroMemory(Result, SizeInBytes);
103 
104  /* Track allocated pages in the IdentityMap structure */
105  IdentityMap->PagesList[IdentityMap->PagesCount] = Result;
106  IdentityMap->PagesCount++;
107 
108  return Result;
109 }
110 
112 NTAPI
114  PVOID StartPtr,
115  ULONG Length)
116 {
117  // TODO: Check whether all pages are below 4GB boundary
118  return MmGetPhysicalAddress(StartPtr);
119 }
120 
121 BOOLEAN
122 NTAPI
124  PHARDWARE_PTE Pde,
126 {
127  ULONG NewPage;
128 
129  if (Pde->Valid == 0)
130  {
131  /* Invalid, so allocate a new page for it */
132  NewPage = (ULONG)Ki386AllocateContiguousMemory(IdentityMap, 1, FALSE);
133  if (!NewPage) return FALSE;
134 
135  /* Set PFN to its virtual address and mark it as valid */
136  Pde->PageFrameNumber = NewPage >> PAGE_SHIFT;
137  Pde->Valid = 1;
138 
139  /* Pass page table address to the caller */
140  if (PageTable) *PageTable = (PHARDWARE_PTE)NewPage;
141  }
142  else
143  {
144  /* Valid entry, just pass the page table address to the caller */
145  if (PageTable)
147  }
148 
149  return TRUE;
150 }
151 
152 BOOLEAN
153 NTAPI
155  ULONG_PTR VirtualPtr,
156  PHYSICAL_ADDRESS PhysicalPtr)
157 {
158  PHARDWARE_PTE Pde, Pte;
160 
161  /* Allocate page directory on demand */
162  if (!IdentityMap->TopLevelDirectory)
163  {
164  IdentityMap->TopLevelDirectory = Ki386AllocateContiguousMemory(IdentityMap, 1, 1);
165  if (!IdentityMap->TopLevelDirectory) return FALSE;
166  }
167 
168  /* Get PDE of VirtualPtr and make it writable and valid */
169  Pde = &IdentityMap->TopLevelDirectory[(VirtualPtr >> 22) & ((1 << PDE_BITS) - 1)];
170  if (!Ki386IdentityMapMakeValid(IdentityMap, Pde, &PageTable)) return FALSE;
171  Pde->Write = 1;
172 
173  /* Get PTE of VirtualPtr, make it valid, and map PhysicalPtr there */
174  Pte = &PageTable[(VirtualPtr >> 12) & ((1 << PTE_BITS) - 1)];
175  Pte->Valid = 1;
176  Pte->PageFrameNumber = (PFN_NUMBER)(PhysicalPtr.QuadPart >> PAGE_SHIFT);
177 
178  return TRUE;
179 }
180 
181 VOID
182 NTAPI
184 {
185  PVOID VirtualPtr;
186  PHYSICAL_ADDRESS PhysicalPtr;
187 
188  /* Get virtual and physical addresses */
189  VirtualPtr = (PVOID)(Pte->PageFrameNumber << PAGE_SHIFT);
190  PhysicalPtr = MmGetPhysicalAddress(VirtualPtr);
191 
192  /* Map its physical address in the page table provided by the caller */
193  Pte->PageFrameNumber = (PFN_NUMBER)(PhysicalPtr.QuadPart >> PAGE_SHIFT);
194 }
195 
196 BOOLEAN
197 NTAPI
198 Ki386CreateIdentityMap(PLARGE_IDENTITY_MAP IdentityMap, PVOID StartPtr, ULONG PagesCount)
199 {
200  ULONG_PTR Ptr;
201  ULONG PteIndex;
202  PHYSICAL_ADDRESS IdentityPtr;
203 
204  /* Zero out the IdentityMap contents */
205  RtlZeroMemory(IdentityMap, sizeof(LARGE_IDENTITY_MAP));
206 
207  /* Get the pointer to the physical address and save it in the struct */
208  IdentityPtr = Ki386BuildIdentityBuffer(IdentityMap, StartPtr, PagesCount);
209  IdentityMap->StartAddress = IdentityPtr.LowPart;
210  if (IdentityMap->StartAddress == 0)
211  {
212  DPRINT1("Failed to get buffer for large pages identity mapping\n");
213  return FALSE;
214  }
215  DPRINT("IdentityMap->StartAddress %p\n", IdentityMap->StartAddress);
216 
217  /* Map all pages */
218  for (Ptr = (ULONG_PTR)StartPtr;
219  Ptr < (ULONG_PTR)StartPtr + PagesCount * PAGE_SIZE;
220  Ptr += PAGE_SIZE, IdentityPtr.QuadPart += PAGE_SIZE)
221  {
222  /* Map virtual address */
223  if (!Ki386MapAddress(IdentityMap, Ptr, IdentityPtr)) return FALSE;
224 
225  /* Map physical address */
226  if (!Ki386MapAddress(IdentityMap, IdentityPtr.LowPart, IdentityPtr)) return FALSE;
227  }
228 
229  /* Convert all PTEs in the page directory from virtual to physical,
230  because Ki386IdentityMapMakeValid mapped only virtual addresses */
231  for (PteIndex = 0; PteIndex < (PAGE_SIZE / sizeof(HARDWARE_PTE)); PteIndex++)
232  {
233  if (IdentityMap->TopLevelDirectory[PteIndex].Valid != 0)
234  Ki386ConvertPte(&IdentityMap->TopLevelDirectory[PteIndex]);
235  }
236 
237  /* Save the page directory address (allocated by Ki386MapAddress) */
238  IdentityMap->Cr3 = MmGetPhysicalAddress(IdentityMap->TopLevelDirectory).LowPart;
239 
240  DPRINT("IdentityMap->Cr3 0x%x\n", IdentityMap->Cr3);
241 
242  return TRUE;
243 }
244 
245 VOID
246 NTAPI
248 {
249  ULONG Page;
250 
251  DPRINT("Freeing %lu pages allocated for identity mapping\n", IdentityMap->PagesCount);
252 
253  /* Free all allocated pages, if any */
254  for (Page = 0; Page < IdentityMap->PagesCount; Page++)
255  MmFreeContiguousMemory(IdentityMap->PagesList[Page]);
256 }
ULONG64 Valid
Definition: mmtypes.h:66
__INTRIN_INLINE void __writecr4(unsigned int Data)
Definition: intrin_x86.h:1680
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
#define IN
Definition: typedefs.h:38
#define TRUE
Definition: types.h:120
ULONG_PTR StartAddress
Definition: ke.h:173
static PMEM_HOOK PageTable[TOTAL_PAGES]
Definition: memory.c:40
_Must_inspect_result_ _In_ PFSRTL_PER_STREAM_CONTEXT Ptr
Definition: fsrtlfuncs.h:898
_In_ ULONGLONG _In_ ULONGLONG _In_ BOOLEAN Enable
Definition: ntddpcm.h:140
BOOLEAN NTAPI Ki386CreateIdentityMap(PLARGE_IDENTITY_MAP IdentityMap, PVOID StartPtr, ULONG PagesCount)
Definition: patpge.c:198
INIT_FUNCTION ULONG_PTR NTAPI Ki386EnableGlobalPage(IN ULONG_PTR Context)
Definition: patpge.c:23
__INTRIN_INLINE unsigned long __readcr3(void)
Definition: intrin_x86.h:1706
VOID NTAPI Ki386ConvertPte(PHARDWARE_PTE Pte)
Definition: patpge.c:183
VOID NTAPI MmFreeContiguousMemory(IN PVOID BaseAddress)
Definition: contmem.c:648
uint32_t ULONG_PTR
Definition: typedefs.h:63
#define CR4_PGE
Definition: ketypes.h:91
__INTRIN_INLINE void __writecr3(unsigned int Data)
Definition: intrin_x86.h:1675
BOOLEAN NTAPI Ki386MapAddress(PLARGE_IDENTITY_MAP IdentityMap, ULONG_PTR VirtualPtr, PHYSICAL_ADDRESS PhysicalPtr)
Definition: patpge.c:154
ULONG PFN_NUMBER
Definition: ke.h:8
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
struct _HARDWARE_PTE * PHARDWARE_PTE
ULONG PagesCount
Definition: ke.h:174
struct _HARDWARE_PTE HARDWARE_PTE
INIT_FUNCTION VOID NTAPI KiInitializePAT(VOID)
Definition: patpge.c:61
INIT_FUNCTION ULONG_PTR NTAPI Ki386EnableTargetLargePage(IN ULONG_PTR Context)
Definition: patpge.c:70
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:426
void DPRINT(...)
Definition: polytest.cpp:61
FORCEINLINE BOOLEAN KeDisableInterrupts(VOID)
Definition: ke.h:176
void * PVOID
Definition: retypes.h:9
#define PDE_BITS
Definition: patpge.c:15
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
ULONG64 PageFrameNumber
Definition: mmtypes.h:78
PVOID NTAPI Ki386AllocateContiguousMemory(PLARGE_IDENTITY_MAP IdentityMap, ULONG PagesCount, BOOLEAN InLower4Gb)
Definition: patpge.c:82
ULONG LowPart
Definition: typedefs.h:104
#define PAGE_SIZE
Definition: env_spec_w32.h:49
__INTRIN_INLINE unsigned long __readcr4(void)
Definition: intrin_x86.h:1713
PHARDWARE_PTE TopLevelDirectory
Definition: ke.h:171
PVOID PagesList[30]
Definition: ke.h:175
FORCEINLINE VOID KeRestoreInterrupts(BOOLEAN WereEnabled)
Definition: ke.h:191
PVOID NTAPI MmAllocateContiguousMemory(IN SIZE_T NumberOfBytes, IN PHYSICAL_ADDRESS HighestAcceptableAddress)
Definition: contmem.c:621
#define DPRINT1
Definition: precomp.h:8
ULONG64 Write
Definition: mmtypes.h:67
VOID NTAPI Ki386FreeIdentityMap(PLARGE_IDENTITY_MAP IdentityMap)
Definition: patpge.c:247
VOID NTAPI Ki386EnableCurrentLargePage(IN ULONG_PTR StartAddress, IN ULONG Cr3)
unsigned int ULONG
Definition: retypes.h:1
PHYSICAL_ADDRESS NTAPI Ki386BuildIdentityBuffer(PLARGE_IDENTITY_MAP IdentityMap, PVOID StartPtr, ULONG Length)
Definition: patpge.c:113
struct _LARGE_IDENTITY_MAP * PLARGE_IDENTITY_MAP
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define ULONG_PTR
Definition: config.h:101
PHYSICAL_ADDRESS NTAPI MmGetPhysicalAddress(IN PVOID Address)
Definition: stubs.c:682
#define PTE_BITS
Definition: patpge.c:16
BOOLEAN NTAPI Ki386IdentityMapMakeValid(PLARGE_IDENTITY_MAP IdentityMap, PHARDWARE_PTE Pde, PHARDWARE_PTE *PageTable)
Definition: patpge.c:123
LONGLONG QuadPart
Definition: typedefs.h:112