ReactOS 0.4.15-dev-7934-g1dc8d80
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
20CODE_SEG("INIT")
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
58CODE_SEG("INIT")
59VOID
62{
63 /* FIXME: Support this */
64 DPRINT("PAT support detected but not yet taken advantage of\n");
65}
66
67CODE_SEG("INIT")
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
83 ULONG PagesCount,
84 BOOLEAN InLower4Gb)
85{
86 PHYSICAL_ADDRESS AddressMask;
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
112NTAPI
114 PVOID StartPtr,
116{
117 // TODO: Check whether all pages are below 4GB boundary
118 return MmGetPhysicalAddress(StartPtr);
119}
120
122NTAPI
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
153NTAPI
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
181VOID
182NTAPI
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
197NTAPI
198Ki386CreateIdentityMap(PLARGE_IDENTITY_MAP IdentityMap, PVOID StartPtr, ULONG PagesCount)
199{
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
245VOID
246NTAPI
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++)
256}
#define CODE_SEG(...)
unsigned char BOOLEAN
#define DPRINT1
Definition: precomp.h:8
PVOID NTAPI MmAllocateContiguousMemory(IN SIZE_T NumberOfBytes, IN PHYSICAL_ADDRESS HighestAcceptableAddress)
Definition: contmem.c:626
VOID NTAPI MmFreeContiguousMemory(IN PVOID BaseAddress)
Definition: contmem.c:653
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define ULONG_PTR
Definition: config.h:101
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
_Must_inspect_result_ _In_ PFSRTL_PER_STREAM_CONTEXT Ptr
Definition: fsrtlfuncs.h:898
__INTRIN_INLINE unsigned long __readcr3(void)
Definition: intrin_x86.h:1818
__INTRIN_INLINE unsigned long __readcr4(void)
Definition: intrin_x86.h:1825
__INTRIN_INLINE void __writecr3(unsigned int Data)
Definition: intrin_x86.h:1794
__INTRIN_INLINE void __writecr4(unsigned int Data)
Definition: intrin_x86.h:1799
#define ASSERT(a)
Definition: mode.c:44
#define CR4_PGE
Definition: ketypes.h:152
#define PHARDWARE_PTE
Definition: mmtypes.h:187
#define HARDWARE_PTE
Definition: mmtypes.h:186
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
_In_ ULONGLONG _In_ ULONGLONG _In_ BOOLEAN Enable
Definition: ntddpcm.h:142
FORCEINLINE BOOLEAN KeDisableInterrupts(VOID)
Definition: ke.h:239
FORCEINLINE VOID KeRestoreInterrupts(BOOLEAN WereEnabled)
Definition: ke.h:254
struct _LARGE_IDENTITY_MAP * PLARGE_IDENTITY_MAP
VOID NTAPI Ki386EnableCurrentLargePage(IN ULONG_PTR StartAddress, IN ULONG Cr3)
_In_ PVOID _Out_opt_ BOOLEAN _Out_opt_ PPFN_NUMBER Page
Definition: mm.h:1306
PHYSICAL_ADDRESS NTAPI MmGetPhysicalAddress(IN PVOID Address)
Definition: stubs.c:685
BOOLEAN NTAPI Ki386IdentityMapMakeValid(PLARGE_IDENTITY_MAP IdentityMap, PHARDWARE_PTE Pde, PHARDWARE_PTE *PageTable)
Definition: patpge.c:123
VOID NTAPI KiInitializePAT(VOID)
Definition: patpge.c:61
PHYSICAL_ADDRESS NTAPI Ki386BuildIdentityBuffer(PLARGE_IDENTITY_MAP IdentityMap, PVOID StartPtr, ULONG Length)
Definition: patpge.c:113
ULONG_PTR NTAPI Ki386EnableTargetLargePage(IN ULONG_PTR Context)
Definition: patpge.c:70
PVOID NTAPI Ki386AllocateContiguousMemory(PLARGE_IDENTITY_MAP IdentityMap, ULONG PagesCount, BOOLEAN InLower4Gb)
Definition: patpge.c:82
BOOLEAN NTAPI Ki386MapAddress(PLARGE_IDENTITY_MAP IdentityMap, ULONG_PTR VirtualPtr, PHYSICAL_ADDRESS PhysicalPtr)
Definition: patpge.c:154
VOID NTAPI Ki386ConvertPte(PHARDWARE_PTE Pte)
Definition: patpge.c:183
VOID NTAPI Ki386FreeIdentityMap(PLARGE_IDENTITY_MAP IdentityMap)
Definition: patpge.c:247
ULONG_PTR NTAPI Ki386EnableGlobalPage(IN ULONG_PTR Context)
Definition: patpge.c:23
#define PDE_BITS
Definition: patpge.c:15
#define PTE_BITS
Definition: patpge.c:16
BOOLEAN NTAPI Ki386CreateIdentityMap(PLARGE_IDENTITY_MAP IdentityMap, PVOID StartPtr, ULONG PagesCount)
Definition: patpge.c:198
ULONG PFN_NUMBER
Definition: ke.h:9
#define DPRINT
Definition: sndvol32.h:71
ULONG64 PageFrameNumber
Definition: mmtypes.h:78
ULONG64 Write
Definition: mmtypes.h:67
ULONG64 Valid
Definition: mmtypes.h:66
ULONG_PTR StartAddress
Definition: ke.h:257
PVOID PagesList[30]
Definition: ke.h:259
PHARDWARE_PTE TopLevelDirectory
Definition: ke.h:255
ULONG PagesCount
Definition: ke.h:258
static PMEM_HOOK PageTable[TOTAL_PAGES]
Definition: memory.c:43
#define NTAPI
Definition: typedefs.h:36
void * PVOID
Definition: typedefs.h:50
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
LONGLONG QuadPart
Definition: typedefs.h:114
ULONG LowPart
Definition: typedefs.h:106
_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:409