windows-nt/Source/XPSP1/NT/base/boot/efi/ia64/memory.c
2020-09-26 16:20:57 +08:00

1089 lines
28 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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