1089 lines
28 KiB
C
1089 lines
28 KiB
C
|
/*++
|
|||
|
|
|||
|
|
|||
|
Copyright (c) 1990, 1991 Microsoft Corporation
|
|||
|
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
memory.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module sets up the memory subsystem so that virtual addresses map 1:1
|
|||
|
with physical addresses. It also tweaks the EFI-supplied memory map for
|
|||
|
use by the loader. This mapping occurs as follows:
|
|||
|
|
|||
|
Memory Map used by NTLDR:
|
|||
|
|
|||
|
0 - 1MB Legacy BIOS area, marked as unusable
|
|||
|
|
|||
|
16 MB - 32 MB used for loading drivers
|
|||
|
32 MB - 48 MB used for loading drivers
|
|||
|
|
|||
|
48 MB - 64 MB used for loading kernel and hal (the kernel must be loaded on a 16 MB boundary)
|
|||
|
|
|||
|
64 MB - 80 MB used for diamond decompression engine
|
|||
|
|
|||
|
There are not enough TRs to map all memory, so any other memory has a
|
|||
|
straight 1-1 translation. Since we use KSEG for our addresses, this
|
|||
|
means that these ranges are effectively unaddressable.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
John Vert (jvert) 18-Jun-1991
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel Mode
|
|||
|
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
Andrew Ritz (andrewr) 15-Dec-2000 - added comments and major cleanup for
|
|||
|
running under EFI
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "arccodes.h"
|
|||
|
#include "bootia64.h"
|
|||
|
#include "efi.h"
|
|||
|
|
|||
|
extern EFI_SYSTEM_TABLE *EfiST;
|
|||
|
|
|||
|
WCHAR DebugBuffer[512];
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Current heap start pointers (physical addresses)
|
|||
|
// Note that 0x50000 to 0x5ffff is reserved for detection configuration memory
|
|||
|
//
|
|||
|
|
|||
|
#if FW_HEAP
|
|||
|
ULONG_PTR FwPermanentHeap = PERMANENT_HEAP_START * PAGE_SIZE;
|
|||
|
ULONG_PTR FwTemporaryHeap = (TEMPORARY_HEAP_START * PAGE_SIZE) - 0x10000;
|
|||
|
|
|||
|
//
|
|||
|
// Current pool pointers. This is different than the temporary/permanent
|
|||
|
// heaps, because it is not required to be under 1MB. It is used by the
|
|||
|
// SCSI miniports for allocating their extensions and for the dbcs font image.
|
|||
|
//
|
|||
|
|
|||
|
#define FW_POOL_SIZE (0x40000/PAGE_SIZE)
|
|||
|
ULONG_PTR FwPoolStart;
|
|||
|
ULONG_PTR FwPoolEnd;
|
|||
|
|
|||
|
//
|
|||
|
// This gets set to FALSE right before we call into the osloader, so we
|
|||
|
// know that the fw memory descriptors can no longer be changed at will.
|
|||
|
//
|
|||
|
BOOLEAN FwDescriptorsValid = TRUE;
|
|||
|
#endif
|
|||
|
//
|
|||
|
// External function prototypes
|
|||
|
//
|
|||
|
extern
|
|||
|
ARC_STATUS
|
|||
|
MempGoVirtual (
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Private function prototypes
|
|||
|
//
|
|||
|
|
|||
|
ARC_STATUS
|
|||
|
MempAllocDescriptor(
|
|||
|
IN ULONG StartPage,
|
|||
|
IN ULONG EndPage,
|
|||
|
IN TYPE_OF_MEMORY MemoryType
|
|||
|
);
|
|||
|
|
|||
|
ARC_STATUS
|
|||
|
MempSetDescriptorRegion (
|
|||
|
IN ULONG StartPage,
|
|||
|
IN ULONG EndPage,
|
|||
|
IN TYPE_OF_MEMORY MemoryType
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Global - memory management variables.
|
|||
|
//
|
|||
|
|
|||
|
PHARDWARE_PTE PDE;
|
|||
|
PHARDWARE_PTE HalPT;
|
|||
|
|
|||
|
//
|
|||
|
// Global memory array that is used by the loader to construct the
|
|||
|
// MemoryDescriptorList which is passed into the OS.
|
|||
|
//
|
|||
|
PMEMORY_DESCRIPTOR MDArray;
|
|||
|
//
|
|||
|
// These help us keep track of the memory descriptor array and are used
|
|||
|
// in the allocation and insertion routines
|
|||
|
//
|
|||
|
ULONG NumberDescriptors=0;
|
|||
|
ULONG MaxDescriptors=0;
|
|||
|
|
|||
|
extern GoneVirtual;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
ARC_STATUS
|
|||
|
InitializeMemorySubsystem(
|
|||
|
PBOOT_CONTEXT BootContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The initial heap is mapped and allocated. Pointers to the
|
|||
|
Page directory and page tables are initialized.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BootContext - Supplies basic information provided by SU module.
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
ESUCCESS - Memory succesfully initialized.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ARC_STATUS Status = ESUCCESS;
|
|||
|
PMEMORY_DESCRIPTOR SuMemory;
|
|||
|
ULONG PageStart;
|
|||
|
ULONG PageEnd;
|
|||
|
ULONG LoaderStart;
|
|||
|
ULONG LoaderEnd;
|
|||
|
|
|||
|
//
|
|||
|
// We already have memory descriptors that describe the physical memory
|
|||
|
// layout on the system. We must walk this list and do some tweaking
|
|||
|
// to describe our memory layout.
|
|||
|
//
|
|||
|
|
|||
|
SuMemory = MDArray;
|
|||
|
while (SuMemory->PageCount != 0) {
|
|||
|
PageStart = SuMemory->BasePage;
|
|||
|
PageEnd = SuMemory->BasePage+SuMemory->PageCount;
|
|||
|
#if DBG_MEMORY
|
|||
|
wsprintf( DebugBuffer, L"PageStart (%x), PageEnd (%x), Type (%x)\r\n", PageStart, PageEnd, SuMemory->MemoryType);
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
DBG_EFI_PAUSE();
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// we have no TRs for memory under 16MB so we can't use it in
|
|||
|
// the loader -- mark it as off limits
|
|||
|
//
|
|||
|
if ((PageStart < _16MB) &&
|
|||
|
(PageStart >= _1MB) &&
|
|||
|
(SuMemory->MemoryType == MemoryFree)) {
|
|||
|
ULONG TmpPageEnd = (PageEnd > _16MB) ? _16MB : PageEnd;
|
|||
|
|
|||
|
Status = MempAllocDescriptor( PageStart, TmpPageEnd,
|
|||
|
MemoryFirmwareTemporary );
|
|||
|
|
|||
|
if (Status != ESUCCESS) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
PageStart = TmpPageEnd;
|
|||
|
|
|||
|
if (PageStart != PageEnd ) {
|
|||
|
SuMemory->PageCount -= (PageStart - SuMemory->BasePage);
|
|||
|
SuMemory->BasePage = PageStart;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Move to the next memory descriptor
|
|||
|
//
|
|||
|
|
|||
|
++SuMemory;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (Status != ESUCCESS) {
|
|||
|
#if DBG
|
|||
|
wsprintf( DebugBuffer, TEXT("MempSetDescriptorRegion failed %lx\n"),Status);
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
#endif
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Describe the BIOS area. We are essentially burning the 1st Meg so the OS
|
|||
|
// can do legacy INT emulation.
|
|||
|
//
|
|||
|
// Note: EFI marks the 1st Meg as "boot services data" so that it won't
|
|||
|
// touch it. Once we get into the OS, we need to preserve this same
|
|||
|
// hack (for video card frame buffer, etc). We only really need to preserve
|
|||
|
// 640K - 1MB, but there is a dependency in the x86 emulation code in the
|
|||
|
// Hal upon this region being zero-based. So we burn 640K, and that's life.
|
|||
|
//
|
|||
|
|
|||
|
#if DBG_MEMORY
|
|||
|
wsprintf( DebugBuffer, L"Mark 'BIOS' region %x - %x as firmware permanent\r\n", 0, ROM_END_PAGE );
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
#endif
|
|||
|
MempSetDescriptorRegion(0, ROM_END_PAGE, MemoryFirmwarePermanent);
|
|||
|
|
|||
|
//
|
|||
|
// Make 48mb - 64mb reserved for OS loading
|
|||
|
//
|
|||
|
// THIS IS A HACK - there is IA64 code in blmemory.c:BlMemoryInitialize that is dependent on
|
|||
|
// any descriptor which starts less than 48MB not extending beyond 48MB range. So we mark
|
|||
|
// 48-80 as "free" in order to split the existing (much larger) descriptor
|
|||
|
//
|
|||
|
#if DBG_MEMORY
|
|||
|
wsprintf( DebugBuffer, L"Mark region %x - %x for systemblock\r\n", _48MB, _80MB );
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
#endif
|
|||
|
Status = MempAllocDescriptor(_48MB,
|
|||
|
_80MB,
|
|||
|
MemoryFree);
|
|||
|
|
|||
|
if (Status != ESUCCESS) {
|
|||
|
#if DBG
|
|||
|
wsprintf( DebugBuffer, L"Mark systemblock region failed %x\r\n", Status );
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
#endif
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
#if 0
|
|||
|
#if DBG_MEMORY
|
|||
|
|
|||
|
SuMemory = MDArray;
|
|||
|
while (SuMemory->PageCount != 0) {
|
|||
|
PageStart = SuMemory->BasePage;
|
|||
|
PageEnd = SuMemory->BasePage+SuMemory->PageCount;
|
|||
|
|
|||
|
wsprintf( DebugBuffer, L"dumpmem: PageStart (%x), PageEnd (%x), Type (%x)\r\n", PageStart, PageEnd, SuMemory->MemoryType);
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
DBG_EFI_PAUSE();
|
|||
|
|
|||
|
++SuMemory;
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
#endif
|
|||
|
|
|||
|
#if DBG
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, TEXT("About to Go Virtual\r\n") );
|
|||
|
#endif
|
|||
|
|
|||
|
{
|
|||
|
extern BOOLEAN isOSCHOICE;
|
|||
|
if ((BootContext->MediaType == BootMediaTcpip) &&
|
|||
|
(isOSCHOICE == FALSE)) {
|
|||
|
Status = MempSetDescriptorRegion(_16MB,
|
|||
|
_48MB,
|
|||
|
MemoryFree);
|
|||
|
if( Status != ESUCCESS ) {
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, TEXT("Failed to reclaim 16MB to 48MB!!!"));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Setup TR's used by the NT loader and go into virtual addressing mode.
|
|||
|
//
|
|||
|
if ((BootContext->MediaType != BootMediaTcpip) ||
|
|||
|
(isOSCHOICE == TRUE)) {
|
|||
|
#if DBG
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, TEXT("Really going virtual\r\n") );
|
|||
|
#endif
|
|||
|
Status = MempGoVirtual();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
GoneVirtual = TRUE;
|
|||
|
|
|||
|
if (Status != ESUCCESS) {
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
ARC_STATUS
|
|||
|
MempSetDescriptorRegion (
|
|||
|
IN ULONG StartPage,
|
|||
|
IN ULONG EndPage,
|
|||
|
IN TYPE_OF_MEMORY MemoryType
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function sets a range to the corresponding memory type.
|
|||
|
Descriptors will be removed, modified, inserted as needed to
|
|||
|
set the specified range.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
StartPage - Supplies the beginning page of the new memory descriptor
|
|||
|
|
|||
|
EndPage - Supplies the ending page of the new memory descriptor
|
|||
|
|
|||
|
MemoryType - Supplies the type of memory of the new memory descriptor
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ESUCCESS - Memory descriptor succesfully added to MDL array
|
|||
|
|
|||
|
ENOMEM - MDArray is full.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
ULONG sp, ep;
|
|||
|
TYPE_OF_MEMORY mt;
|
|||
|
BOOLEAN RegionAdded;
|
|||
|
|
|||
|
if (EndPage <= StartPage) {
|
|||
|
//
|
|||
|
// This is a completely bogus memory descriptor. Ignore it.
|
|||
|
//
|
|||
|
|
|||
|
#ifdef LOADER_DEBUG
|
|||
|
wsprintf( DebugBuffer, TEXT("Attempt to create invalid memory descriptor %lx - %lx\n"),
|
|||
|
StartPage,EndPage);
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
#endif
|
|||
|
return(ESUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
RegionAdded = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Clip, remove, any descriptors in target area
|
|||
|
//
|
|||
|
|
|||
|
for (i=0; i < NumberDescriptors; i++) {
|
|||
|
sp = MDArray[i].BasePage;
|
|||
|
ep = MDArray[i].BasePage + MDArray[i].PageCount;
|
|||
|
mt = MDArray[i].MemoryType;
|
|||
|
|
|||
|
if (sp < StartPage) {
|
|||
|
if (ep > StartPage && ep <= EndPage) {
|
|||
|
// truncate this descriptor
|
|||
|
ep = StartPage;
|
|||
|
}
|
|||
|
|
|||
|
if (ep > EndPage) {
|
|||
|
//
|
|||
|
// Target area is contained totally within this
|
|||
|
// descriptor. Split the descriptor into two ranges
|
|||
|
//
|
|||
|
|
|||
|
if (NumberDescriptors == MaxDescriptors) {
|
|||
|
#if DBG
|
|||
|
wsprintf( DebugBuffer, TEXT("ENOMEM returned %S %d\n"), __FILE__, __LINE__ );
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
#endif
|
|||
|
return(ENOMEM);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Add descriptor for EndPage - ep
|
|||
|
//
|
|||
|
|
|||
|
MDArray[NumberDescriptors].MemoryType = mt;
|
|||
|
MDArray[NumberDescriptors].BasePage = EndPage;
|
|||
|
MDArray[NumberDescriptors].PageCount = ep - EndPage;
|
|||
|
NumberDescriptors += 1;
|
|||
|
|
|||
|
//
|
|||
|
// Adjust current descriptor for sp - StartPage
|
|||
|
//
|
|||
|
|
|||
|
ep = StartPage;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
// sp >= StartPage
|
|||
|
|
|||
|
if (sp < EndPage) {
|
|||
|
if (ep < EndPage) {
|
|||
|
//
|
|||
|
// This descriptor is totally within the target area -
|
|||
|
// remove it
|
|||
|
//
|
|||
|
|
|||
|
ep = sp;
|
|||
|
|
|||
|
} else {
|
|||
|
// bump begining page of this descriptor
|
|||
|
sp = EndPage;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check if the new range can be appended or prepended to
|
|||
|
// this descriptor
|
|||
|
//
|
|||
|
if (mt == MemoryType && !RegionAdded) {
|
|||
|
if (sp == EndPage) {
|
|||
|
// prepend region being set
|
|||
|
sp = StartPage;
|
|||
|
RegionAdded = TRUE;
|
|||
|
|
|||
|
} else if (ep == StartPage) {
|
|||
|
// append region being set
|
|||
|
ep = EndPage;
|
|||
|
RegionAdded = TRUE;
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (MDArray[i].BasePage == sp && MDArray[i].PageCount == ep-sp) {
|
|||
|
|
|||
|
//
|
|||
|
// Descriptor was not editted
|
|||
|
//
|
|||
|
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Reset this descriptor
|
|||
|
//
|
|||
|
|
|||
|
MDArray[i].BasePage = sp;
|
|||
|
MDArray[i].PageCount = ep - sp;
|
|||
|
|
|||
|
if (ep == sp) {
|
|||
|
|
|||
|
//
|
|||
|
// Descriptor vanished - remove it
|
|||
|
//
|
|||
|
|
|||
|
NumberDescriptors -= 1;
|
|||
|
if (i < NumberDescriptors) {
|
|||
|
MDArray[i] = MDArray[NumberDescriptors];
|
|||
|
}
|
|||
|
|
|||
|
i--; // backup & recheck current position
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If region wasn't already added to a neighboring region, then
|
|||
|
// create a new descriptor now
|
|||
|
//
|
|||
|
|
|||
|
if (!RegionAdded && MemoryType < LoaderMaximum) {
|
|||
|
if (NumberDescriptors == MaxDescriptors) {
|
|||
|
#if DBG
|
|||
|
wsprintf( DebugBuffer, TEXT("ENOMEM returned %S %d\n"), __FILE__, __LINE__ );
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
#endif
|
|||
|
return(ENOMEM);
|
|||
|
}
|
|||
|
|
|||
|
#ifdef LOADER_DEBUG
|
|||
|
wsprintf( DebugBuffer, TEXT("Adding '%lx - %lx, type %x' to descriptor list\n"),
|
|||
|
StartPage << PAGE_SHIFT,
|
|||
|
EndPage << PAGE_SHIFT,
|
|||
|
(USHORT) MemoryType
|
|||
|
);
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
#endif
|
|||
|
|
|||
|
MDArray[NumberDescriptors].MemoryType = MemoryType;
|
|||
|
MDArray[NumberDescriptors].BasePage = StartPage;
|
|||
|
MDArray[NumberDescriptors].PageCount = EndPage - StartPage;
|
|||
|
NumberDescriptors += 1;
|
|||
|
}
|
|||
|
return (ESUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
ARC_STATUS
|
|||
|
MempAllocDescriptor(
|
|||
|
IN ULONG StartPage,
|
|||
|
IN ULONG EndPage,
|
|||
|
IN TYPE_OF_MEMORY MemoryType
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine carves out a specific memory descriptor from the
|
|||
|
memory descriptors that have already been created. The MD array
|
|||
|
is updated to reflect the new state of memory.
|
|||
|
|
|||
|
The new memory descriptor must be completely contained within an
|
|||
|
already existing memory descriptor. (i.e. memory that does not
|
|||
|
exist should never be marked as a certain type)
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
StartPage - Supplies the beginning page of the new memory descriptor
|
|||
|
|
|||
|
EndPage - Supplies the ending page of the new memory descriptor
|
|||
|
|
|||
|
MemoryType - Supplies the type of memory of the new memory descriptor
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ESUCCESS - Memory descriptor succesfully added to MDL array
|
|||
|
|
|||
|
ENOMEM - MDArray is full.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
|
|||
|
//
|
|||
|
// Walk through the memory descriptors until we find one that
|
|||
|
// contains the start of the descriptor.
|
|||
|
//
|
|||
|
for (i=0; i<NumberDescriptors; i++) {
|
|||
|
if ((MDArray[i].MemoryType == MemoryFree) &&
|
|||
|
(MDArray[i].BasePage <= StartPage ) &&
|
|||
|
(MDArray[i].BasePage+MDArray[i].PageCount > StartPage) &&
|
|||
|
(MDArray[i].BasePage+MDArray[i].PageCount >= EndPage)) {
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (i==MaxDescriptors) {
|
|||
|
#if DBG
|
|||
|
wsprintf( DebugBuffer, TEXT("NumDescriptors filled (%x) ENOMEM returned %S %d\r\n"), MaxDescriptors, __FILE__, __LINE__ );
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
#endif
|
|||
|
return(ENOMEM);
|
|||
|
}
|
|||
|
|
|||
|
if (MDArray[i].BasePage == StartPage) {
|
|||
|
|
|||
|
if (MDArray[i].BasePage+MDArray[i].PageCount == EndPage) {
|
|||
|
|
|||
|
//
|
|||
|
// The new descriptor is identical to the existing descriptor.
|
|||
|
// Simply change the memory type of the existing descriptor in
|
|||
|
// place.
|
|||
|
//
|
|||
|
#if DBG_MEMORY
|
|||
|
wsprintf( DebugBuffer, TEXT("descriptor (%x) matched -- change type from %x to %x\r\n"), MDArray[i].BasePage, MDArray[i].MemoryType, MemoryType );
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
#endif
|
|||
|
MDArray[i].MemoryType = MemoryType;
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// The new descriptor starts on the same page, but is smaller
|
|||
|
// than the existing descriptor. Shrink the existing descriptor
|
|||
|
// by moving its start page up, and create a new descriptor.
|
|||
|
//
|
|||
|
if (NumberDescriptors == MaxDescriptors) {
|
|||
|
#if DBG_MEMORY
|
|||
|
wsprintf( DebugBuffer, TEXT("out of descriptors trying to grow (%x) (%x total)\r\n"), MDArray[i].BasePage,NumberDescriptors );
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
#endif
|
|||
|
#if DBG
|
|||
|
wsprintf( DebugBuffer, TEXT("ENOMEM returned %S %d\n"), __FILE__, __LINE__ );
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
#endif
|
|||
|
return(ENOMEM);
|
|||
|
}
|
|||
|
|
|||
|
#if DBG_MEMORY
|
|||
|
wsprintf(
|
|||
|
DebugBuffer,
|
|||
|
TEXT("split descriptor starting at %x into two (%x pagecount into %x (size %x) and %x size %x)\r\n"),
|
|||
|
StartPage,
|
|||
|
MDArray[i].PageCount,
|
|||
|
EndPage,
|
|||
|
MDArray[i].PageCount - (EndPage-StartPage),
|
|||
|
StartPage,
|
|||
|
EndPage-StartPage );
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
#endif
|
|||
|
|
|||
|
MDArray[i].BasePage = EndPage;
|
|||
|
MDArray[i].PageCount -= (EndPage-StartPage);
|
|||
|
|
|||
|
MDArray[NumberDescriptors].BasePage = StartPage;
|
|||
|
MDArray[NumberDescriptors].PageCount = EndPage-StartPage;
|
|||
|
MDArray[NumberDescriptors].MemoryType = MemoryType;
|
|||
|
++NumberDescriptors;
|
|||
|
|
|||
|
}
|
|||
|
} else if (MDArray[i].BasePage+MDArray[i].PageCount == EndPage) {
|
|||
|
|
|||
|
//
|
|||
|
// The new descriptor ends on the same page. Shrink the existing
|
|||
|
// by decreasing its page count, and create a new descriptor.
|
|||
|
//
|
|||
|
if (NumberDescriptors == MaxDescriptors) {
|
|||
|
#if DBG_MEMORY
|
|||
|
wsprintf( DebugBuffer, TEXT("out of descriptors trying to shrink (%x) (%x total)\r\n"), MDArray[i].BasePage,NumberDescriptors );
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
#endif
|
|||
|
#if DBG
|
|||
|
wsprintf( DebugBuffer, TEXT("ENOMEM returned %S %d\n"), __FILE__, __LINE__ );
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
#endif
|
|||
|
return(ENOMEM);
|
|||
|
}
|
|||
|
|
|||
|
#if DBG_MEMORY
|
|||
|
wsprintf(
|
|||
|
DebugBuffer,
|
|||
|
TEXT("shrink descriptor starting at %x into two (%x pagecount into %x (size %x) and %x size %x, type %x)\r\n"),
|
|||
|
MDArray[i].BasePage,
|
|||
|
MDArray[i].PageCount,
|
|||
|
MDArray[i].BasePage,
|
|||
|
StartPage - MDArray[i].BasePage,
|
|||
|
StartPage,
|
|||
|
EndPage-StartPage,
|
|||
|
MemoryType );
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
#endif
|
|||
|
|
|||
|
MDArray[i].PageCount = StartPage - MDArray[i].BasePage;
|
|||
|
|
|||
|
MDArray[NumberDescriptors].BasePage = StartPage;
|
|||
|
MDArray[NumberDescriptors].PageCount = EndPage-StartPage;
|
|||
|
MDArray[NumberDescriptors].MemoryType = MemoryType;
|
|||
|
++NumberDescriptors;
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// The new descriptor is in the middle of the existing descriptor.
|
|||
|
// Shrink the existing descriptor by decreasing its page count, and
|
|||
|
// create two new descriptors.
|
|||
|
//
|
|||
|
|
|||
|
if (NumberDescriptors+1 >= MaxDescriptors) {
|
|||
|
#if DBG_MEMORY
|
|||
|
wsprintf( DebugBuffer, TEXT("out of descriptors trying to shrink (%x) (%x total)\r\n"), MDArray[i].BasePage,NumberDescriptors );
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
#endif
|
|||
|
#if DBG
|
|||
|
wsprintf( DebugBuffer, TEXT("ENOMEM returned %S %d\n"), __FILE__, __LINE__ );
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
#endif
|
|||
|
return(ENOMEM);
|
|||
|
}
|
|||
|
|
|||
|
#if DBG_MEMORY
|
|||
|
wsprintf(
|
|||
|
DebugBuffer,
|
|||
|
TEXT("split descriptor starting at %x into 3 (%x pagecount into %x (size %x), %x size %x (memory free), %x size %x, type %x)\r\n"),
|
|||
|
MDArray[i].BasePage,
|
|||
|
MDArray[i].PageCount,
|
|||
|
MDArray[i].BasePage,
|
|||
|
StartPage-MDArray[i].BasePage,
|
|||
|
EndPage,
|
|||
|
MDArray[i].PageCount - (EndPage-MDArray[i].BasePage),
|
|||
|
StartPage,
|
|||
|
EndPage-StartPage,
|
|||
|
MemoryType );
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
#endif
|
|||
|
|
|||
|
MDArray[NumberDescriptors].BasePage = EndPage;
|
|||
|
MDArray[NumberDescriptors].PageCount = MDArray[i].PageCount -
|
|||
|
(EndPage-MDArray[i].BasePage);
|
|||
|
MDArray[NumberDescriptors].MemoryType = MemoryFree;
|
|||
|
++NumberDescriptors;
|
|||
|
|
|||
|
MDArray[i].PageCount = StartPage - MDArray[i].BasePage;
|
|||
|
|
|||
|
MDArray[NumberDescriptors].BasePage = StartPage;
|
|||
|
MDArray[NumberDescriptors].PageCount = EndPage-StartPage;
|
|||
|
MDArray[NumberDescriptors].MemoryType = MemoryType;
|
|||
|
++NumberDescriptors;
|
|||
|
}
|
|||
|
|
|||
|
return(ESUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
#if FW_HEAP
|
|||
|
PVOID
|
|||
|
FwAllocateHeapPermanent(
|
|||
|
IN ULONG NumberPages
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This allocates pages from the private heap. The memory descriptor for
|
|||
|
the LoaderMemoryData area is grown to include the returned pages, while
|
|||
|
the memory descriptor for the temporary heap is shrunk by the same amount.
|
|||
|
|
|||
|
N.B. DO NOT call this routine after we have passed control to
|
|||
|
BlOsLoader! Once BlOsLoader calls BlMemoryInitialize, the
|
|||
|
firmware memory descriptors are pulled into the OS Loader heap
|
|||
|
and those are the descriptors passed to the kernel. So any
|
|||
|
changes in the firmware private heap will be irrelevant.
|
|||
|
|
|||
|
If you need to allocate permanent memory after the OS Loader
|
|||
|
has initialized, use BlAllocateDescriptor.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
NumberPages - size of memory to allocate (in pages)
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Pointer to block of memory, if successful.
|
|||
|
NULL, if unsuccessful.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PVOID MemoryPointer;
|
|||
|
PMEMORY_DESCRIPTOR Descriptor;
|
|||
|
|
|||
|
if (FwPermanentHeap + (NumberPages << PAGE_SHIFT) > FwTemporaryHeap) {
|
|||
|
|
|||
|
//
|
|||
|
// Our heaps collide, so we are out of memory
|
|||
|
//
|
|||
|
|
|||
|
wsprintf( DebugBuffer, TEXT("Out of permanent heap!\n"));
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
while (1) {
|
|||
|
}
|
|||
|
|
|||
|
return(NULL);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Find the memory descriptor which describes the LoaderMemoryData area,
|
|||
|
// so we can grow it to include the just-allocated pages.
|
|||
|
//
|
|||
|
Descriptor = MDArray;
|
|||
|
while (Descriptor->MemoryType != LoaderMemoryData) {
|
|||
|
++Descriptor;
|
|||
|
if (Descriptor > MDArray+MaxDescriptors) {
|
|||
|
wsprintf( DebugBuffer, TEXT("ERROR - FwAllocateHeapPermanent couldn't find the LoaderMemoryData descriptor!\r\n"));
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
return(NULL);
|
|||
|
}
|
|||
|
}
|
|||
|
Descriptor->PageCount += NumberPages;
|
|||
|
|
|||
|
//
|
|||
|
// We know that the memory descriptor after this one is the firmware
|
|||
|
// temporary heap descriptor. Since it is physically contiguous with our
|
|||
|
// LoaderMemoryData block, we remove the pages from its descriptor.
|
|||
|
//
|
|||
|
|
|||
|
++Descriptor;
|
|||
|
Descriptor->PageCount -= NumberPages;
|
|||
|
Descriptor->BasePage += NumberPages;
|
|||
|
|
|||
|
MemoryPointer = (PVOID)FwPermanentHeap;
|
|||
|
FwPermanentHeap += NumberPages << PAGE_SHIFT;
|
|||
|
|
|||
|
return(MemoryPointer);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
PVOID
|
|||
|
FwAllocateHeap(
|
|||
|
IN ULONG Size
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Allocates memory from the "firmware" temporary heap.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Size - Supplies size of block to allocate
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
PVOID - Pointer to the beginning of the block
|
|||
|
NULL - Out of memory
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
ULONG SizeInPages;
|
|||
|
ULONG StartPage;
|
|||
|
ARC_STATUS Status;
|
|||
|
|
|||
|
if (((FwTemporaryHeap - FwPermanentHeap) < Size) && (FwDescriptorsValid)) {
|
|||
|
//
|
|||
|
// Large allocations get their own descriptor so miniports that
|
|||
|
// have huge device extensions don't pull up all of the heap.
|
|||
|
//
|
|||
|
// Note that we can only do this while running in "firmware" mode.
|
|||
|
// Once we call into the osloader, it pulls all the memory descriptors
|
|||
|
// out of the "firmware" and changes to this list will not show
|
|||
|
// up there.
|
|||
|
//
|
|||
|
// We are looking for a descriptor that is MemoryFree and <16Mb.
|
|||
|
//
|
|||
|
SizeInPages = (Size+PAGE_SIZE-1) >> PAGE_SHIFT;
|
|||
|
|
|||
|
for (i=0; i<NumberDescriptors; i++) {
|
|||
|
if ((MDArray[i].MemoryType == MemoryFree) &&
|
|||
|
(MDArray[i].BasePage <= _80MB_BOGUS) &&
|
|||
|
(MDArray[i].PageCount >= SizeInPages)) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (i < NumberDescriptors) {
|
|||
|
StartPage = MDArray[i].BasePage+MDArray[i].PageCount-SizeInPages;
|
|||
|
Status = MempAllocDescriptor(StartPage,
|
|||
|
StartPage+SizeInPages,
|
|||
|
MemoryFirmwareTemporary);
|
|||
|
if (Status==ESUCCESS) {
|
|||
|
return((PVOID)(ULONG_PTR)(StartPage << PAGE_SHIFT));
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
FwTemporaryHeap -= Size;
|
|||
|
|
|||
|
//
|
|||
|
// Round down to 16-byte boundary
|
|||
|
//
|
|||
|
|
|||
|
FwTemporaryHeap &= ~((ULONG)0xf);
|
|||
|
|
|||
|
if (FwTemporaryHeap < FwPermanentHeap) {
|
|||
|
#if DBG
|
|||
|
wsprintf( DebugBuffer, TEXT("Out of temporary heap!\n"));
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
#endif
|
|||
|
return(NULL);
|
|||
|
}
|
|||
|
|
|||
|
return((PVOID)FwTemporaryHeap);
|
|||
|
|
|||
|
}
|
|||
|
#endif // FW_HEAP
|
|||
|
|
|||
|
#if FW_HEAP
|
|||
|
|
|||
|
|
|||
|
PVOID
|
|||
|
FwAllocatePool(
|
|||
|
IN ULONG Size
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine allocates memory from the firmware pool. Note that
|
|||
|
this memory is NOT under the 1MB line, so it cannot be used for
|
|||
|
anything that must be accessed from real mode. It is currently used
|
|||
|
only by the SCSI miniport drivers and dbcs font loader.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Size - Supplies size of block to allocate.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
PVOID - pointer to the beginning of the block
|
|||
|
NULL - out of memory
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PVOID Buffer;
|
|||
|
ULONG NewSize;
|
|||
|
|
|||
|
//
|
|||
|
// round size up to 16 byte boundary
|
|||
|
//
|
|||
|
NewSize = (Size + 15) & ~0xf;
|
|||
|
if ((FwPoolStart + NewSize) <= FwPoolEnd) {
|
|||
|
|
|||
|
Buffer = (PVOID)FwPoolStart;
|
|||
|
FwPoolStart += NewSize;
|
|||
|
return(Buffer);
|
|||
|
|
|||
|
} else {
|
|||
|
//
|
|||
|
// we've used up all our pool, try to allocate from the heap.
|
|||
|
//
|
|||
|
return(BlAllocateHeap(Size));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
PVOID
|
|||
|
FwAllocateHeapAligned(
|
|||
|
IN ULONG Size
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Allocates memory from the "firmware" temporary heap. This memory is
|
|||
|
always allocated on a page boundary, so it can readily be used for
|
|||
|
temporary page tables
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Size - Supplies size of block to allocate
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
PVOID - Pointer to the beginning of the block
|
|||
|
NULL - Out of memory
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
FwTemporaryHeap -= Size;
|
|||
|
|
|||
|
//
|
|||
|
// Round down to a page boundary
|
|||
|
//
|
|||
|
|
|||
|
FwTemporaryHeap &= ~(PAGE_SIZE-1);
|
|||
|
|
|||
|
if (FwTemporaryHeap < FwPermanentHeap) {
|
|||
|
wsprintf( DebugBuffer, TEXT("Out of temporary heap!\n")s);
|
|||
|
EfiST->ConOut->OutputString( EfiST->ConOut, DebugBuffer);
|
|||
|
return(NULL);
|
|||
|
}
|
|||
|
RtlZeroMemory((PVOID)FwTemporaryHeap,Size);
|
|||
|
|
|||
|
return((PVOID)FwTemporaryHeap);
|
|||
|
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
#if !defined(NO_LEGACY_DRIVERS)
|
|||
|
//
|
|||
|
// This isn't used under EFI -- the HalPT is only setup immediately
|
|||
|
// before calling ExitBootServices(), and this routine is really
|
|||
|
// only present if ntbootdd.sys must be used.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
PVOID
|
|||
|
MmMapIoSpace (
|
|||
|
IN PHYSICAL_ADDRESS PhysicalAddress,
|
|||
|
IN SIZE_T NumberOfBytes,
|
|||
|
IN MEMORY_CACHING_TYPE CacheType
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function returns the corresponding virtual address for a
|
|||
|
known physical address.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
PhysicalAddress - Supplies the phiscal address.
|
|||
|
|
|||
|
NumberOfBytes - Unused.
|
|||
|
|
|||
|
CacheType - Unused.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns the corresponding virtual address.
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode. Any IRQL level.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
ULONG j;
|
|||
|
ULONG NumberPages;
|
|||
|
|
|||
|
NumberPages = (ULONG)((NumberOfBytes+PAGE_SIZE-1) >> PAGE_SHIFT);
|
|||
|
|
|||
|
//
|
|||
|
// We use the HAL's PDE for mapping memory buffers.
|
|||
|
// Find enough free PTEs.
|
|||
|
//
|
|||
|
|
|||
|
for (i=0; i<=1024-NumberPages; i++) {
|
|||
|
for (j=0; j < NumberPages; j++) {
|
|||
|
if ((((PULONG)HalPT))[i+j]) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (j == NumberPages) {
|
|||
|
for (j=0; j<NumberPages; j++) {
|
|||
|
HalPT[i+j].PageFrameNumber =
|
|||
|
(PhysicalAddress.LowPart >> PAGE_SHIFT)+j;
|
|||
|
HalPT[i+j].Valid = 1;
|
|||
|
HalPT[i+j].Write = 1;
|
|||
|
}
|
|||
|
|
|||
|
return((PVOID)((ULONG_PTR)(0xffc00000 | (i<<12) | (PhysicalAddress.LowPart & 0xfff))));
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
return(NULL);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
MmUnmapIoSpace (
|
|||
|
IN PVOID BaseAddress,
|
|||
|
IN SIZE_T NumberOfBytes
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function unmaps a range of physical address which were previously
|
|||
|
mapped via an MmMapIoSpace function call.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BaseAddress - Supplies the base virtual address where the physical
|
|||
|
address was previously mapped.
|
|||
|
|
|||
|
NumberOfBytes - Supplies the number of bytes which were mapped.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode, IRQL of DISPATCH_LEVEL or below.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
#endif
|