mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +00:00
[NTOS]
- Implement enabling Large Pages support if it is detected. The Page Size Extension (PSE) bit in CR4 is enabled when paging is disabled. To achieve that, a temporary virtual and physical identity mapping is created, which is discarded after PSE is enabled. svn path=/trunk/; revision=59491
This commit is contained in:
parent
50b0c50023
commit
1f8454cef1
4 changed files with 295 additions and 2 deletions
|
@ -163,6 +163,18 @@ typedef struct _KV8086_STACK_FRAME
|
|||
KV86_FRAME V86Frame;
|
||||
} KV8086_STACK_FRAME, *PKV8086_STACK_FRAME;
|
||||
|
||||
//
|
||||
// Large Pages Support
|
||||
//
|
||||
typedef struct _LARGE_IDENTITY_MAP
|
||||
{
|
||||
PHARDWARE_PTE TopLevelDirectory;
|
||||
ULONG Cr3;
|
||||
ULONG_PTR StartAddress;
|
||||
ULONG PagesCount;
|
||||
PVOID PagesList[30];
|
||||
} LARGE_IDENTITY_MAP, *PLARGE_IDENTITY_MAP;
|
||||
|
||||
/* Diable interrupts and return whether they were enabled before */
|
||||
FORCEINLINE
|
||||
BOOLEAN
|
||||
|
@ -374,6 +386,33 @@ Ki386EnableGlobalPage(
|
|||
IN volatile ULONG_PTR Context
|
||||
);
|
||||
|
||||
ULONG_PTR
|
||||
NTAPI
|
||||
Ki386EnableTargetLargePage(
|
||||
IN volatile ULONG_PTR Context
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
Ki386CreateIdentityMap(
|
||||
IN PLARGE_IDENTITY_MAP IdentityMap,
|
||||
IN PVOID StartPtr,
|
||||
IN ULONG Length
|
||||
);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Ki386FreeIdentityMap(
|
||||
IN PLARGE_IDENTITY_MAP IdentityMap
|
||||
);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Ki386EnableCurrentLargePage(
|
||||
IN ULONG_PTR StartAddress,
|
||||
IN ULONG Cr3
|
||||
);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
KiI386PentiumLockErrataFixup(
|
||||
|
|
|
@ -81,6 +81,61 @@ PUBLIC @KiRetireDpcListInDpcStack@8
|
|||
pop esp
|
||||
ret
|
||||
|
||||
PUBLIC _Ki386EnableCurrentLargePage@8
|
||||
_Ki386EnableCurrentLargePage@8:
|
||||
/* Save StartAddress in eax */
|
||||
mov eax, [esp + 4]
|
||||
|
||||
/* Save new CR3 value in ecx */
|
||||
mov ecx, [esp + 8]
|
||||
|
||||
/* Save flags value */
|
||||
pushfd
|
||||
|
||||
/* Disable interrupts */
|
||||
cli
|
||||
|
||||
/* Compute linear address */
|
||||
sub eax, offset _Ki386EnableCurrentLargePage@8
|
||||
add eax, offset _Ki386LargePageIdentityLabel
|
||||
|
||||
/* Save old CR3 in edx and replace with a new one */
|
||||
mov edx, cr3
|
||||
mov cr3, ecx
|
||||
|
||||
/* Jump to the next instruction but in linear mapping */
|
||||
jmp eax
|
||||
|
||||
_Ki386LargePageIdentityLabel:
|
||||
/* Disable paging */
|
||||
mov eax, cr0
|
||||
and eax, NOT CR0_PG
|
||||
mov cr0, eax
|
||||
|
||||
/* Jump to the next instruction */
|
||||
jmp $+2
|
||||
|
||||
/* Enable Page Size Extension in CR4 */
|
||||
mov ecx, cr4
|
||||
or ecx, CR4_PSE
|
||||
mov cr4, ecx
|
||||
|
||||
/* Done, now re-enable paging */
|
||||
or eax, CR0_PG
|
||||
mov cr0, eax
|
||||
|
||||
/* Jump to virtual address */
|
||||
mov eax, offset VirtualSpace
|
||||
jmp eax
|
||||
|
||||
VirtualSpace:
|
||||
/* Restore CR3 contents */
|
||||
mov cr3, edx
|
||||
|
||||
/* Restore flags */
|
||||
popfd
|
||||
|
||||
ret 8
|
||||
|
||||
/* FIXFIX: Move to C code ****/
|
||||
PUBLIC _Ki386SetupAndExitToV86Mode@4
|
||||
|
|
|
@ -46,12 +46,17 @@ KiInitMachineDependent(VOID)
|
|||
ULONG Dummy;
|
||||
KI_SAMPLE_MAP Samples[4];
|
||||
PKI_SAMPLE_MAP CurrentSample = Samples;
|
||||
LARGE_IDENTITY_MAP IdentityMap;
|
||||
|
||||
/* Check for large page support */
|
||||
if (KeFeatureBits & KF_LARGE_PAGE)
|
||||
{
|
||||
/* FIXME: Support this */
|
||||
DPRINT("Large Page support detected but not yet taken advantage of\n");
|
||||
/* Do an IPI to enable it on all CPUs */
|
||||
if (Ki386CreateIdentityMap(&IdentityMap, Ki386EnableCurrentLargePage, 2))
|
||||
KeIpiGenericCall(Ki386EnableTargetLargePage, (ULONG_PTR)&IdentityMap);
|
||||
|
||||
/* Free the pages allocated for identity map */
|
||||
Ki386FreeIdentityMap(&IdentityMap);
|
||||
}
|
||||
|
||||
/* Check for global page support */
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
#define PDE_BITS 10
|
||||
#define PTE_BITS 10
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
ULONG_PTR
|
||||
|
@ -59,3 +62,194 @@ KiInitializePAT(VOID)
|
|||
/* FIXME: Support this */
|
||||
DPRINT("PAT support detected but not yet taken advantage of\n");
|
||||
}
|
||||
|
||||
ULONG_PTR
|
||||
NTAPI
|
||||
INIT_FUNCTION
|
||||
Ki386EnableTargetLargePage(IN ULONG_PTR Context)
|
||||
{
|
||||
PLARGE_IDENTITY_MAP IdentityMap = (PLARGE_IDENTITY_MAP)Context;
|
||||
|
||||
/* Call helper function with the start address and temporary page table pointer */
|
||||
Ki386EnableCurrentLargePage(IdentityMap->StartAddress, IdentityMap->Cr3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PVOID
|
||||
NTAPI
|
||||
Ki386AllocateContiguousMemory(PLARGE_IDENTITY_MAP IdentityMap,
|
||||
ULONG PagesCount,
|
||||
BOOLEAN InLower4Gb)
|
||||
{
|
||||
PHYSICAL_ADDRESS AddressMask;
|
||||
PVOID Result;
|
||||
ULONG SizeInBytes = PagesCount * PAGE_SIZE;
|
||||
|
||||
/* Initialize acceptable address mask to any possible address */
|
||||
AddressMask.LowPart = 0xFFFFFFFF;
|
||||
AddressMask.HighPart = 0xFFFFFFFF;
|
||||
|
||||
/* Mark out higher 4Gb if caller asked so */
|
||||
if (InLower4Gb) AddressMask.HighPart = 0;
|
||||
|
||||
/* Try to allocate the memory */
|
||||
Result = MmAllocateContiguousMemory(SizeInBytes, AddressMask);
|
||||
if (!Result) return NULL;
|
||||
|
||||
/* Zero it out */
|
||||
RtlZeroMemory(Result, SizeInBytes);
|
||||
|
||||
/* Track allocated pages in the IdentityMap structure */
|
||||
IdentityMap->PagesList[IdentityMap->PagesCount] = Result;
|
||||
IdentityMap->PagesCount++;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
PHYSICAL_ADDRESS
|
||||
NTAPI
|
||||
Ki386BuildIdentityBuffer(PLARGE_IDENTITY_MAP IdentityMap,
|
||||
PVOID StartPtr,
|
||||
ULONG Length)
|
||||
{
|
||||
// TODO: Check whether all pages are below 4GB boundary
|
||||
return MmGetPhysicalAddress(StartPtr);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
Ki386IdentityMapMakeValid(PLARGE_IDENTITY_MAP IdentityMap,
|
||||
PHARDWARE_PTE Pde,
|
||||
PHARDWARE_PTE *PageTable)
|
||||
{
|
||||
ULONG NewPage;
|
||||
|
||||
if (Pde->Valid == 0)
|
||||
{
|
||||
/* Invalid, so allocate a new page for it */
|
||||
NewPage = (ULONG)Ki386AllocateContiguousMemory(IdentityMap, 1, FALSE);
|
||||
if (!NewPage) return FALSE;
|
||||
|
||||
/* Set PFN to its virtual address and mark it as valid */
|
||||
Pde->PageFrameNumber = NewPage >> PAGE_SHIFT;
|
||||
Pde->Valid = 1;
|
||||
|
||||
/* Pass page table address to the caller */
|
||||
if (PageTable) *PageTable = (PHARDWARE_PTE)NewPage;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Valid entry, just pass the page table address to the caller */
|
||||
if (PageTable)
|
||||
*PageTable = (PHARDWARE_PTE)(Pde->PageFrameNumber << PAGE_SHIFT);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
Ki386MapAddress(PLARGE_IDENTITY_MAP IdentityMap,
|
||||
ULONG_PTR VirtualPtr,
|
||||
PHYSICAL_ADDRESS PhysicalPtr)
|
||||
{
|
||||
PHARDWARE_PTE Pde, Pte;
|
||||
PHARDWARE_PTE PageTable;
|
||||
|
||||
/* Allocate page directory on demand */
|
||||
if (!IdentityMap->TopLevelDirectory)
|
||||
{
|
||||
IdentityMap->TopLevelDirectory = Ki386AllocateContiguousMemory(IdentityMap, 1, 1);
|
||||
if (!IdentityMap->TopLevelDirectory) return FALSE;
|
||||
}
|
||||
|
||||
/* Get PDE of VirtualPtr and make it writable and valid */
|
||||
Pde = &IdentityMap->TopLevelDirectory[(VirtualPtr >> 22) & ((1 << PDE_BITS) - 1)];
|
||||
if (!Ki386IdentityMapMakeValid(IdentityMap, Pde, &PageTable)) return FALSE;
|
||||
Pde->Write = 1;
|
||||
|
||||
/* Get PTE of VirtualPtr, make it valid, and map PhysicalPtr there */
|
||||
Pte = &PageTable[(VirtualPtr >> 12) & ((1 << PTE_BITS) - 1)];
|
||||
Pte->Valid = 1;
|
||||
Pte->PageFrameNumber = PhysicalPtr.QuadPart >> PAGE_SHIFT;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Ki386ConvertPte(PHARDWARE_PTE Pte)
|
||||
{
|
||||
PVOID VirtualPtr;
|
||||
PHYSICAL_ADDRESS PhysicalPtr;
|
||||
|
||||
/* Get virtual and physical addresses */
|
||||
VirtualPtr = (PVOID)(Pte->PageFrameNumber << PAGE_SHIFT);
|
||||
PhysicalPtr = MmGetPhysicalAddress(VirtualPtr);
|
||||
|
||||
/* Map its physical address in the page table provided by the caller */
|
||||
Pte->PageFrameNumber = PhysicalPtr.QuadPart >> PAGE_SHIFT;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
Ki386CreateIdentityMap(PLARGE_IDENTITY_MAP IdentityMap, PVOID StartPtr, ULONG PagesCount)
|
||||
{
|
||||
ULONG_PTR Ptr;
|
||||
ULONG PteIndex;
|
||||
PHYSICAL_ADDRESS IdentityPtr;
|
||||
|
||||
/* Zero out the IdentityMap contents */
|
||||
RtlZeroMemory(IdentityMap, sizeof(LARGE_IDENTITY_MAP));
|
||||
|
||||
/* Get the pointer to the physical address and save it in the struct */
|
||||
IdentityPtr = Ki386BuildIdentityBuffer(IdentityMap, StartPtr, PagesCount);
|
||||
IdentityMap->StartAddress = IdentityPtr.LowPart;
|
||||
if (IdentityMap->StartAddress == 0)
|
||||
{
|
||||
DPRINT1("Failed to get buffer for large pages identity mapping\n");
|
||||
return FALSE;
|
||||
}
|
||||
DPRINT("IdentityMap->StartAddress %p\n", IdentityMap->StartAddress);
|
||||
|
||||
/* Map all pages */
|
||||
for (Ptr = (ULONG_PTR)StartPtr;
|
||||
Ptr < (ULONG_PTR)StartPtr + PagesCount * PAGE_SIZE;
|
||||
Ptr += PAGE_SIZE, IdentityPtr.QuadPart += PAGE_SIZE)
|
||||
{
|
||||
/* Map virtual address */
|
||||
if (!Ki386MapAddress(IdentityMap, Ptr, IdentityPtr)) return FALSE;
|
||||
|
||||
/* Map physical address */
|
||||
if (!Ki386MapAddress(IdentityMap, IdentityPtr.LowPart, IdentityPtr)) return FALSE;
|
||||
}
|
||||
|
||||
/* Convert all PTEs in the page directory from virtual to physical,
|
||||
because Ki386IdentityMapMakeValid mapped only virtual addresses */
|
||||
for (PteIndex = 0; PteIndex < (PAGE_SIZE / sizeof(HARDWARE_PTE)); PteIndex++)
|
||||
{
|
||||
if (IdentityMap->TopLevelDirectory[PteIndex].Valid != 0)
|
||||
Ki386ConvertPte(&IdentityMap->TopLevelDirectory[PteIndex]);
|
||||
}
|
||||
|
||||
/* Save the page directory address (allocated by Ki386MapAddress) */
|
||||
IdentityMap->Cr3 = MmGetPhysicalAddress(IdentityMap->TopLevelDirectory).LowPart;
|
||||
|
||||
DPRINT("IdentityMap->Cr3 0x%x\n", IdentityMap->Cr3);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Ki386FreeIdentityMap(PLARGE_IDENTITY_MAP IdentityMap)
|
||||
{
|
||||
ULONG Page;
|
||||
|
||||
DPRINT("Freeing %d pages allocated for identity mapping\n", IdentityMap->PagesCount);
|
||||
|
||||
/* Free all allocated pages, if any */
|
||||
for (Page = 0; Page < IdentityMap->PagesCount; Page++)
|
||||
MmFreeContiguousMemory(IdentityMap->PagesList[Page]);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue