516 lines
12 KiB
C
516 lines
12 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1997 Microsoft Corporation
|
||
|
Copyright (c) 1992 Intel Corporation
|
||
|
All rights reserved
|
||
|
|
||
|
INTEL CORPORATION PROPRIETARY INFORMATION
|
||
|
|
||
|
This software is supplied to Microsoft under the terms
|
||
|
of a license agreement with Intel Corporation and may not be
|
||
|
copied nor disclosed except in accordance with the terms
|
||
|
of that agreement.
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
mpprocst.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This code has been moved from mpsproc.c so that it
|
||
|
can be included from both the MPS hal and the ACPI hal.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Ken Reneris (kenr) 22-Jan-1991
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
Kernel mode only.
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
Ron Mosgrove (Intel) - Modified to support the PC+MP
|
||
|
|
||
|
Jake Oshins (jakeo) - moved from mpsproc.c
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "halp.h"
|
||
|
#include "pcmp_nt.inc"
|
||
|
#include "apic.inc"
|
||
|
#include "stdio.h"
|
||
|
|
||
|
VOID
|
||
|
HalpMapCR3 (
|
||
|
IN ULONG VirtAddress,
|
||
|
IN PHYSICAL_ADDRESS PhysicalAddress,
|
||
|
IN ULONG Length
|
||
|
);
|
||
|
|
||
|
ULONG
|
||
|
HalpBuildTiledCR3 (
|
||
|
IN PKPROCESSOR_STATE ProcessorState
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
HalpFreeTiledCR3 (
|
||
|
VOID
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
StartPx_PMStub (
|
||
|
VOID
|
||
|
);
|
||
|
|
||
|
ULONG
|
||
|
HalpBuildTiledCR3Ex (
|
||
|
IN PKPROCESSOR_STATE ProcessorState,
|
||
|
IN ULONG ProcNum
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
HalpMapCR3Ex (
|
||
|
IN ULONG VirtAddress,
|
||
|
IN PHYSICAL_ADDRESS PhysicalAddress,
|
||
|
IN ULONG Length,
|
||
|
IN ULONG ProcNum
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
HalpFreeTiledCR3Ex (
|
||
|
ULONG ProcNum
|
||
|
);
|
||
|
|
||
|
#define MAX_PT 16
|
||
|
|
||
|
PVOID HiberFreeCR3[MAX_PROCESSORS][MAX_PT]; // remember pool memory to free
|
||
|
|
||
|
PVOID HalpLowStubPhysicalAddress; // pointer to low memory bootup stub
|
||
|
PUCHAR HalpLowStub; // pointer to low memory bootup stub
|
||
|
|
||
|
|
||
|
#ifdef ALLOC_PRAGMA
|
||
|
#pragma alloc_text(PAGELK,HalpBuildTiledCR3)
|
||
|
#pragma alloc_text(PAGELK,HalpMapCR3)
|
||
|
#pragma alloc_text(PAGELK,HalpFreeTiledCR3)
|
||
|
#pragma alloc_text(PAGELK,HalpBuildTiledCR3Ex)
|
||
|
#pragma alloc_text(PAGELK,HalpMapCR3Ex)
|
||
|
#pragma alloc_text(PAGELK,HalpFreeTiledCR3Ex)
|
||
|
#endif
|
||
|
|
||
|
#define PTES_PER_PAGE (PAGE_SIZE / HalPteSize())
|
||
|
|
||
|
PHARDWARE_PTE
|
||
|
GetPdeAddressEx(
|
||
|
ULONG Va,
|
||
|
ULONG ProcessorNumber
|
||
|
)
|
||
|
{
|
||
|
PHARDWARE_PTE pageDirectories;
|
||
|
PHARDWARE_PTE pageDirectoryEntry;
|
||
|
ULONG pageDirectoryIndex;
|
||
|
|
||
|
pageDirectories = (PHARDWARE_PTE)(HiberFreeCR3[ ProcessorNumber ][0]);
|
||
|
|
||
|
if (HalPaeEnabled() != FALSE) {
|
||
|
|
||
|
//
|
||
|
// Skip over the first page, which contains the page directory pointer
|
||
|
// table.
|
||
|
//
|
||
|
|
||
|
HalpAdvancePte( &pageDirectories, PTES_PER_PAGE );
|
||
|
}
|
||
|
|
||
|
pageDirectoryIndex = Va >> MiGetPdiShift();
|
||
|
|
||
|
//
|
||
|
// Note that in the case of PAE, pageDirectoryIndex includes the PDPT
|
||
|
// bits. This works because we know that the four page directory tables
|
||
|
// are adjacent.
|
||
|
//
|
||
|
|
||
|
pageDirectoryEntry = HalpIndexPteArray( pageDirectories,
|
||
|
pageDirectoryIndex );
|
||
|
return pageDirectoryEntry;
|
||
|
}
|
||
|
|
||
|
PHARDWARE_PTE
|
||
|
GetPteAddress(
|
||
|
IN ULONG Va,
|
||
|
IN PHARDWARE_PTE PageTable
|
||
|
)
|
||
|
{
|
||
|
PHARDWARE_PTE pointerPte;
|
||
|
ULONG index;
|
||
|
|
||
|
index = MiGetPteIndex( (PVOID)Va );
|
||
|
pointerPte = HalpIndexPteArray( PageTable, index );
|
||
|
|
||
|
return pointerPte;
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
HalpBuildTiledCR3 (
|
||
|
IN PKPROCESSOR_STATE ProcessorState
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
When the x86 processor is reset it starts in real-mode.
|
||
|
In order to move the processor from real-mode to protected
|
||
|
mode with flat addressing the segment which loads CR0 needs
|
||
|
to have its linear address mapped to the physical
|
||
|
location of the segment for said instruction so the
|
||
|
processor can continue to execute the following instruction.
|
||
|
|
||
|
This function is called to build such a tiled page directory.
|
||
|
In addition, other flat addresses are tiled to match the
|
||
|
current running flat address for the new state. Once the
|
||
|
processor is in flat mode, we move to a NT tiled page which
|
||
|
can then load up the remaining processor state.
|
||
|
|
||
|
Arguments:
|
||
|
ProcessorState - The state the new processor should start in.
|
||
|
|
||
|
Return Value:
|
||
|
Physical address of Tiled page directory
|
||
|
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
return(HalpBuildTiledCR3Ex(ProcessorState,0));
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
HalpBuildTiledCR3Ex (
|
||
|
IN PKPROCESSOR_STATE ProcessorState,
|
||
|
IN ULONG ProcNum
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
When the x86 processor is reset it starts in real-mode.
|
||
|
In order to move the processor from real-mode to protected
|
||
|
mode with flat addressing the segment which loads CR0 needs
|
||
|
to have its linear address mapped to machine the physical
|
||
|
location of the segment for said instruction so the
|
||
|
processor can continue to execute the following instruction.
|
||
|
|
||
|
This function is called to build such a tiled page directory.
|
||
|
In addition, other flat addresses are tiled to match the
|
||
|
current running flat address for the new state. Once the
|
||
|
processor is in flat mode, we move to a NT tiled page which
|
||
|
can then load up the remaining processor state.
|
||
|
|
||
|
Arguments:
|
||
|
ProcessorState - The state the new processor should start in.
|
||
|
|
||
|
Return Value:
|
||
|
Physical address of Tiled page directory
|
||
|
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ULONG allocationSize;
|
||
|
PHARDWARE_PTE pte;
|
||
|
PHARDWARE_PTE pdpt;
|
||
|
PHARDWARE_PTE pdpte;
|
||
|
PHARDWARE_PTE pageDirectory;
|
||
|
PHYSICAL_ADDRESS physicalAddress;
|
||
|
ULONG i;
|
||
|
|
||
|
if (HalPaeEnabled() != FALSE) {
|
||
|
|
||
|
//
|
||
|
// Need 5 pages for PAE mode: one for the page directory pointer
|
||
|
// table and one for each of the four page directories. Note that
|
||
|
// only the single PDPT page really needs to come from memory below 4GB
|
||
|
// physical.
|
||
|
//
|
||
|
|
||
|
allocationSize = PAGE_SIZE * 5;
|
||
|
physicalAddress.HighPart = 0;
|
||
|
physicalAddress.LowPart = 0xffffffff;
|
||
|
|
||
|
HiberFreeCR3[ProcNum][0] =
|
||
|
MmAllocateContiguousMemory (allocationSize, physicalAddress);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Just one page for the page directory.
|
||
|
//
|
||
|
|
||
|
allocationSize = PAGE_SIZE;
|
||
|
HiberFreeCR3[ProcNum][0] =
|
||
|
ExAllocatePoolWithTag (NonPagedPool, allocationSize, HAL_POOL_TAG);
|
||
|
}
|
||
|
|
||
|
if (!HiberFreeCR3[ProcNum][0]) {
|
||
|
// Failed to allocate memory.
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
RtlZeroMemory (HiberFreeCR3[ProcNum][0], allocationSize);
|
||
|
|
||
|
if (HalPaeEnabled() != FALSE) {
|
||
|
|
||
|
//
|
||
|
// Initialize each of the four page directory pointer table entries
|
||
|
//
|
||
|
|
||
|
pdpt = (PHARDWARE_PTE)HiberFreeCR3[ProcNum][0];
|
||
|
pageDirectory = pdpt;
|
||
|
for (i = 0; i < 4; i++) {
|
||
|
|
||
|
//
|
||
|
// Get a pointer to the page directory pointer table entry
|
||
|
//
|
||
|
|
||
|
pdpte = HalpIndexPteArray( pdpt, i );
|
||
|
|
||
|
//
|
||
|
// Skip to the first (next) page directory.
|
||
|
//
|
||
|
|
||
|
HalpAdvancePte( &pageDirectory, PTES_PER_PAGE );
|
||
|
|
||
|
//
|
||
|
// Find its physical address and update the page directory pointer
|
||
|
// table entry.
|
||
|
//
|
||
|
|
||
|
physicalAddress = MmGetPhysicalAddress( pageDirectory );
|
||
|
pdpte->Valid = 1;
|
||
|
HalpSetPageFrameNumber( pdpte,
|
||
|
physicalAddress.QuadPart >> PAGE_SHIFT );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Map page for real mode stub (one page)
|
||
|
//
|
||
|
|
||
|
HalpMapCR3Ex ((ULONG) HalpLowStubPhysicalAddress,
|
||
|
HalpPtrToPhysicalAddress( HalpLowStubPhysicalAddress ),
|
||
|
PAGE_SIZE,
|
||
|
ProcNum);
|
||
|
|
||
|
//
|
||
|
// Map page for protect mode stub (one page)
|
||
|
//
|
||
|
|
||
|
HalpMapCR3Ex ((ULONG) &StartPx_PMStub,
|
||
|
HalpPtrToPhysicalAddress( NULL ),
|
||
|
PAGE_SIZE,
|
||
|
ProcNum);
|
||
|
|
||
|
//
|
||
|
// Map page(s) for processors GDT
|
||
|
//
|
||
|
|
||
|
HalpMapCR3Ex (ProcessorState->SpecialRegisters.Gdtr.Base,
|
||
|
HalpPtrToPhysicalAddress( NULL ),
|
||
|
ProcessorState->SpecialRegisters.Gdtr.Limit,
|
||
|
ProcNum);
|
||
|
|
||
|
|
||
|
//
|
||
|
// Map page(s) for processors IDT
|
||
|
//
|
||
|
|
||
|
HalpMapCR3Ex (ProcessorState->SpecialRegisters.Idtr.Base,
|
||
|
HalpPtrToPhysicalAddress( NULL ),
|
||
|
ProcessorState->SpecialRegisters.Idtr.Limit,
|
||
|
ProcNum);
|
||
|
|
||
|
ASSERT (MmGetPhysicalAddress (HiberFreeCR3[ProcNum][0]).HighPart == 0);
|
||
|
|
||
|
return MmGetPhysicalAddress (HiberFreeCR3[ProcNum][0]).LowPart;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
HalpMapCR3 (
|
||
|
IN ULONG VirtAddress,
|
||
|
IN PHYSICAL_ADDRESS PhysicalAddress,
|
||
|
IN ULONG Length
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
Called to build a page table entry for the passed page
|
||
|
directory. Used to build a tiled page directory with
|
||
|
real-mode & flat mode.
|
||
|
|
||
|
Arguments:
|
||
|
VirtAddress - Current virtual address
|
||
|
PhysicalAddress - Optional. Physical address to be mapped
|
||
|
to, if passed as a NULL then the physical
|
||
|
address of the passed virtual address
|
||
|
is assumed.
|
||
|
Length - number of bytes to map
|
||
|
|
||
|
Return Value:
|
||
|
none.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
HalpMapCR3Ex(VirtAddress,PhysicalAddress,Length,0);
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
HalpMapCR3Ex (
|
||
|
IN ULONG VirtAddress,
|
||
|
IN PHYSICAL_ADDRESS PhysicalAddress,
|
||
|
IN ULONG Length,
|
||
|
IN ULONG ProcNum
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
Called to build a page table entry for the passed page
|
||
|
directory. Used to build a tiled page directory with
|
||
|
real-mode & flat mode.
|
||
|
|
||
|
Arguments:
|
||
|
VirtAddress - Current virtual address
|
||
|
PhysicalAddress - Optional. Physical address to be mapped
|
||
|
to, if passed as a NULL then the physical
|
||
|
address of the passed virtual address
|
||
|
is assumed.
|
||
|
Length - number of bytes to map
|
||
|
|
||
|
Return Value:
|
||
|
none.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ULONG i;
|
||
|
PHARDWARE_PTE PTE;
|
||
|
PVOID pPageTable;
|
||
|
PHYSICAL_ADDRESS pPhysicalPage;
|
||
|
|
||
|
|
||
|
while (Length) {
|
||
|
PTE = GetPdeAddressEx (VirtAddress,ProcNum);
|
||
|
if (HalpIsPteFree( PTE ) != FALSE) {
|
||
|
pPageTable = ExAllocatePoolWithTag(NonPagedPool,
|
||
|
PAGE_SIZE,
|
||
|
HAL_POOL_TAG);
|
||
|
if (!pPageTable) {
|
||
|
|
||
|
//
|
||
|
// This allocation is critical.
|
||
|
//
|
||
|
|
||
|
KeBugCheckEx(HAL_MEMORY_ALLOCATION,
|
||
|
PAGE_SIZE,
|
||
|
6,
|
||
|
(ULONG)__FILE__,
|
||
|
__LINE__
|
||
|
);
|
||
|
}
|
||
|
RtlZeroMemory (pPageTable, PAGE_SIZE);
|
||
|
|
||
|
for (i=0; i < MAX_PT; i++) {
|
||
|
if (!(HiberFreeCR3[ProcNum][i])) {
|
||
|
HiberFreeCR3[ProcNum][i] = pPageTable;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
ASSERT (i < MAX_PT);
|
||
|
|
||
|
pPhysicalPage = MmGetPhysicalAddress (pPageTable);
|
||
|
HalpSetPageFrameNumber( PTE, pPhysicalPage.QuadPart >> PAGE_SHIFT );
|
||
|
PTE->Valid = 1;
|
||
|
PTE->Write = 1;
|
||
|
}
|
||
|
|
||
|
pPhysicalPage.QuadPart =
|
||
|
HalpGetPageFrameNumber( PTE ) << PAGE_SHIFT;
|
||
|
|
||
|
pPageTable = MmMapIoSpace (pPhysicalPage, PAGE_SIZE, TRUE);
|
||
|
|
||
|
PTE = GetPteAddress (VirtAddress, pPageTable);
|
||
|
|
||
|
if (PhysicalAddress.QuadPart == 0) {
|
||
|
PhysicalAddress = MmGetPhysicalAddress((PVOID)VirtAddress);
|
||
|
}
|
||
|
|
||
|
HalpSetPageFrameNumber( PTE, PhysicalAddress.QuadPart >> PAGE_SHIFT );
|
||
|
PTE->Valid = 1;
|
||
|
PTE->Write = 1;
|
||
|
|
||
|
MmUnmapIoSpace (pPageTable, PAGE_SIZE);
|
||
|
|
||
|
PhysicalAddress.QuadPart = 0;
|
||
|
VirtAddress += PAGE_SIZE;
|
||
|
if (Length > PAGE_SIZE) {
|
||
|
Length -= PAGE_SIZE;
|
||
|
} else {
|
||
|
Length = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
HalpFreeTiledCR3 (
|
||
|
VOID
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
Frees any memory allocated when the tiled page directory
|
||
|
was built.
|
||
|
|
||
|
Arguments:
|
||
|
none
|
||
|
|
||
|
Return Value:
|
||
|
none
|
||
|
--*/
|
||
|
{
|
||
|
HalpFreeTiledCR3Ex(0);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
HalpFreeTiledCR3Ex (
|
||
|
ULONG ProcNum
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
Frees any memory allocated when the tiled page directory
|
||
|
was built.
|
||
|
|
||
|
Arguments:
|
||
|
none
|
||
|
|
||
|
Return Value:
|
||
|
none
|
||
|
--*/
|
||
|
{
|
||
|
ULONG i;
|
||
|
|
||
|
for (i = 0; HiberFreeCR3[ProcNum][i]; i++) {
|
||
|
|
||
|
//
|
||
|
// Only the very first entry for each processor might have been
|
||
|
// allocated via MmAllocateContiguousMemory. So only this one can
|
||
|
// (and MUST) be freed via MmFreeContiguousMemory.
|
||
|
//
|
||
|
|
||
|
if ((i == 0) && (HalPaeEnabled() != FALSE)) {
|
||
|
MmFreeContiguousMemory (HiberFreeCR3[ProcNum][i]);
|
||
|
}
|
||
|
else {
|
||
|
ExFreePool (HiberFreeCR3[ProcNum][i]);
|
||
|
}
|
||
|
HiberFreeCR3[ProcNum][i] = 0;
|
||
|
}
|
||
|
}
|
||
|
|