Refactor real-mode memory allocation and identity mapping for AP trampoline
This commit is contained in:
@@ -85,9 +85,9 @@ XTAPI
|
||||
XTSTATUS
|
||||
HL::Cpu::StartAllProcessors(VOID)
|
||||
{
|
||||
ULONG CpuNumber, Index, MaxCpus, SipiVector, Timeout, TrampolineCodeSize, TrampolinePages;
|
||||
PVOID CpuStructures, TrampolineAddress, TrampolineCode;
|
||||
ULONG_PTR AllocationSize;
|
||||
ULONG ApPages, CpuNumber, Index, MaxCpus, SipiVector, Timeout, TrampolineCodeSize;
|
||||
PVOID ApVirtualAddress, CpuStructures, TrampolineCode;
|
||||
PHYSICAL_ADDRESS ApPhysicalAddress;
|
||||
PPROCESSOR_START_BLOCK StartBlock;
|
||||
PKPROCESSOR_BLOCK ProcessorBlock;
|
||||
PACPI_SYSTEM_INFO SysInfo;
|
||||
@@ -136,27 +136,34 @@ HL::Cpu::StartAllProcessors(VOID)
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
/* Compute trampoline memory allocation size (trampoline + processor start block + temporary stack) */
|
||||
AllocationSize = TrampolineCodeSize + sizeof(PROCESSOR_START_BLOCK) + 512;
|
||||
TrampolinePages = (ULONG)(ROUND_UP(AllocationSize, MM_PAGE_SIZE) / MM_PAGE_SIZE);
|
||||
|
||||
/* Allocate real mode memory for AP trampoline */
|
||||
Status = MM::HardwarePool::AllocateRealModeMemory(TrampolinePages, &TrampolineAddress);
|
||||
/* Allocate low memory for AP trampoline code */
|
||||
Status = MM::HardwarePool::AllocateLowMemory(&ApPhysicalAddress, &ApVirtualAddress);
|
||||
if(Status != STATUS_SUCCESS)
|
||||
{
|
||||
/* Failed to allocate memory, print error message and return error */
|
||||
DebugPrint(L"Failed to allocate %lu pages for AP Trampoline!\n", TrampolinePages);
|
||||
DebugPrint(L"Failed to allocate low memory for AP Trampoline!\n");
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Copy trampoline code to low memory */
|
||||
RTL::Memory::CopyMemory(TrampolineAddress, TrampolineCode, TrampolineCodeSize);
|
||||
RTL::Memory::CopyMemory(ApVirtualAddress, TrampolineCode, TrampolineCodeSize);
|
||||
|
||||
/* Compute number of pages for trampoline */
|
||||
ApPages = MM::HardwarePool::CalculateRealModeAllocationPages(TrampolineCodeSize);
|
||||
|
||||
/* Temporarily identity map trampoline address */
|
||||
Status = MM::HardwarePool::MapRealModeMemory(ApPhysicalAddress, ApPages);
|
||||
if(Status != STATUS_SUCCESS)
|
||||
{
|
||||
/* Failed to map memory, return error */
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Get start block address relative to trampoline address */
|
||||
StartBlock = (PPROCESSOR_START_BLOCK)((PUCHAR)TrampolineAddress + TrampolineCodeSize);
|
||||
StartBlock = (PPROCESSOR_START_BLOCK)((PUCHAR)ApVirtualAddress + TrampolineCodeSize);
|
||||
|
||||
/* Get SIPI vector */
|
||||
SipiVector = (ULONG)((ULONG_PTR)TrampolineAddress >> 12);
|
||||
SipiVector = (ULONG)(ApPhysicalAddress.QuadPart >> 12);
|
||||
|
||||
/* Loop over all CPUs */
|
||||
CpuNumber = 0;
|
||||
@@ -183,8 +190,8 @@ HL::Cpu::StartAllProcessors(VOID)
|
||||
Status = MM::KernelPool::AllocateProcessorStructures(&CpuStructures);
|
||||
if(Status != STATUS_SUCCESS)
|
||||
{
|
||||
/* Failed to allocate memory, unmap memory and return error */
|
||||
MM::HardwarePool::UnmapHardwareMemory(TrampolineAddress, TrampolinePages, TRUE);
|
||||
/* Failed to allocate memory, unmap temporary identity mapping and return error */
|
||||
MM::HardwarePool::UnmapRealModeMemory(ApPhysicalAddress, ApPages);
|
||||
return Status;
|
||||
}
|
||||
|
||||
@@ -242,7 +249,7 @@ HL::Cpu::StartAllProcessors(VOID)
|
||||
}
|
||||
}
|
||||
|
||||
/* Unmap trampoline memory and return success */
|
||||
MM::HardwarePool::UnmapHardwareMemory(TrampolineAddress, TrampolinePages, TRUE);
|
||||
/* Unmap temporary identity mapping and return success */
|
||||
MM::HardwarePool::UnmapRealModeMemory(ApPhysicalAddress, ApPages);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ namespace MM
|
||||
private:
|
||||
STATIC LOADER_MEMORY_DESCRIPTOR HardwareAllocationDescriptors[MM_HARDWARE_ALLOCATION_DESCRIPTORS];
|
||||
STATIC PVOID HardwareHeapStart;
|
||||
STATIC PHYSICAL_ADDRESS LowMemoryPhysicalAddress;
|
||||
STATIC PVOID LowMemoryVirtualAddress;
|
||||
STATIC ULONG UsedHardwareAllocationDescriptors;
|
||||
|
||||
public:
|
||||
@@ -27,12 +29,19 @@ namespace MM
|
||||
IN BOOLEAN Aligned,
|
||||
IN ULONGLONG MaximumAddress,
|
||||
OUT PPHYSICAL_ADDRESS Buffer);
|
||||
STATIC XTAPI XTSTATUS AllocateRealModeMemory(IN PFN_NUMBER PageCount,
|
||||
OUT PVOID *MemoryAddress);
|
||||
STATIC XTAPI XTSTATUS AllocateLowMemory(OUT PPHYSICAL_ADDRESS PhysicalAddress,
|
||||
OUT PVOID *VirtualAddress);
|
||||
STATIC XTAPI ULONG CalculateRealModeAllocationPages(IN ULONG TrampolineCodeSize);
|
||||
STATIC XTAPI XTSTATUS FreeHardwareMemory(IN PHYSICAL_ADDRESS PhysicalAddress,
|
||||
IN PFN_NUMBER PageCount);
|
||||
STATIC XTAPI XTSTATUS FreeRealModeMemory(IN PVOID VirtualAddress,
|
||||
IN PFN_NUMBER PageCount);
|
||||
STATIC XTAPI XTSTATUS MapHardwareMemory(IN PHYSICAL_ADDRESS PhysicalAddress,
|
||||
IN PFN_NUMBER PageCount,
|
||||
IN BOOLEAN FlushTlb,
|
||||
OUT PVOID *VirtualAddress);
|
||||
STATIC XTAPI XTSTATUS MapRealModeMemory(IN PHYSICAL_ADDRESS PhysicalAddress,
|
||||
IN ULONG Size);
|
||||
STATIC XTAPI VOID MarkHardwareMemoryWriteThrough(IN PVOID VirtualAddress,
|
||||
IN PFN_NUMBER PageCount);
|
||||
STATIC XTAPI VOID RemapHardwareMemory(IN PVOID VirtualAddress,
|
||||
@@ -41,6 +50,8 @@ namespace MM
|
||||
STATIC XTAPI XTSTATUS UnmapHardwareMemory(IN PVOID VirtualAddress,
|
||||
IN PFN_NUMBER PageCount,
|
||||
IN BOOLEAN FlushTlb);
|
||||
STATIC XTAPI VOID UnmapRealModeMemory(IN PHYSICAL_ADDRESS PhysicalAddress,
|
||||
IN ULONG Size);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,12 @@ LOADER_MEMORY_DESCRIPTOR MM::HardwarePool::HardwareAllocationDescriptors[MM_HARD
|
||||
/* Live address of kernel's hardware heap */
|
||||
PVOID MM::HardwarePool::HardwareHeapStart = MM_HARDWARE_HEAP_START_ADDRESS;
|
||||
|
||||
/* Physical address of kernel's low memory region */
|
||||
PHYSICAL_ADDRESS MM::HardwarePool::LowMemoryPhysicalAddress;
|
||||
|
||||
/* Virtual address of kernel's low memory region */
|
||||
PVOID MM::HardwarePool::LowMemoryVirtualAddress;
|
||||
|
||||
/* Number of used hardware allocation descriptors */
|
||||
ULONG MM::HardwarePool::UsedHardwareAllocationDescriptors = 0;
|
||||
|
||||
|
||||
@@ -150,8 +150,11 @@ MM::HardwarePool::AllocateHardwareMemory(IN PFN_NUMBER PageCount,
|
||||
/**
|
||||
* Allocates a physical page in low memory (addressable in real-mode) and maps it into the virtual address space.
|
||||
*
|
||||
* @param MemoryAddress
|
||||
* Supplies a pointer to a variable that receives the identity-mapped virtual address of the allocated memory.
|
||||
* @param PhysicalAddress
|
||||
* Supplies a pointer to a variable that receives the physical address of the allocated memory.
|
||||
*
|
||||
* @param VirtualAddress
|
||||
* Supplies a pointer to a variable that receives the virtual address of the allocated memory.
|
||||
*
|
||||
* @return This routine returns a status code indicating the success or failure of the operation.
|
||||
*
|
||||
@@ -159,39 +162,141 @@ MM::HardwarePool::AllocateHardwareMemory(IN PFN_NUMBER PageCount,
|
||||
*/
|
||||
XTAPI
|
||||
XTSTATUS
|
||||
MM::HardwarePool::AllocateRealModeMemory(IN PFN_NUMBER PageCount,
|
||||
OUT PVOID *MemoryAddress)
|
||||
MM::HardwarePool::AllocateLowMemory(OUT PPHYSICAL_ADDRESS PhysicalAddress,
|
||||
OUT PVOID *VirtualAddress)
|
||||
{
|
||||
PHYSICAL_ADDRESS PhysicalAddress;
|
||||
PFN_NUMBER PageFrameNumber;
|
||||
PVOID VirtualAddress;
|
||||
ULONG AllocationPages, TrampolineCodeSize;
|
||||
PVOID TrampolineCode;
|
||||
XTSTATUS Status;
|
||||
|
||||
/* Check if low memory is already allocated and mapped */
|
||||
if(LowMemoryVirtualAddress && LowMemoryPhysicalAddress.QuadPart != 0)
|
||||
{
|
||||
/* Check if the caller requested the allocated addresses */
|
||||
if(PhysicalAddress != NULLPTR && VirtualAddress != NULLPTR)
|
||||
{
|
||||
/* Set the trampoline physical and virtual address and return success */
|
||||
*PhysicalAddress = LowMemoryPhysicalAddress;
|
||||
*VirtualAddress = LowMemoryVirtualAddress;
|
||||
}
|
||||
|
||||
/* Return success */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Get trampoline information */
|
||||
AR::ProcessorSupport::GetTrampolineInformation(TrampolineApStartup, &TrampolineCode, &TrampolineCodeSize);
|
||||
|
||||
/* Verify trampoline information */
|
||||
if(TrampolineCode == NULLPTR || TrampolineCodeSize == 0)
|
||||
{
|
||||
/* Failed to get trampoline information, return error */
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
/* Compute number of pages for real-mode memory allocation (trampoline + processor start block + temporary stack) */
|
||||
AllocationPages = CalculateRealModeAllocationPages(TrampolineCodeSize);
|
||||
|
||||
/* Allocate physical memory in first 1MB */
|
||||
Status = AllocateHardwareMemory(PageCount, TRUE, 0x100000, &PhysicalAddress);
|
||||
Status = AllocateHardwareMemory(AllocationPages, TRUE, 0x100000, &LowMemoryPhysicalAddress);
|
||||
if(Status != STATUS_SUCCESS)
|
||||
{
|
||||
/* Failed to allocate memory, return error */
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Calculate virtual address and page frame number */
|
||||
VirtualAddress = (PVOID)(ULONG_PTR)PhysicalAddress.QuadPart;
|
||||
PageFrameNumber = PhysicalAddress.QuadPart >> MM_PAGE_SHIFT;
|
||||
|
||||
/* Identity map the memory to the virtual address */
|
||||
Status = MM::Paging::MapVirtualAddress(VirtualAddress, PageFrameNumber, MM_PTE_EXECUTE_READWRITE);
|
||||
/* Map the memory to the virtual address */
|
||||
Status = MapHardwareMemory(LowMemoryPhysicalAddress, AllocationPages, FALSE, &LowMemoryVirtualAddress);
|
||||
if(Status != STATUS_SUCCESS)
|
||||
{
|
||||
/* Failed to map memory, return error */
|
||||
/* Failed to map memory, free memory and return error */
|
||||
FreeHardwareMemory(LowMemoryPhysicalAddress, AllocationPages);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Set the trampoline virtual address and return success */
|
||||
*MemoryAddress = VirtualAddress;
|
||||
/* Check if the caller requested the allocated addresses */
|
||||
if(PhysicalAddress != NULLPTR && VirtualAddress != NULLPTR)
|
||||
{
|
||||
/* Set the trampoline physical and virtual address and return success */
|
||||
*PhysicalAddress = LowMemoryPhysicalAddress;
|
||||
*VirtualAddress = LowMemoryVirtualAddress;
|
||||
}
|
||||
|
||||
/* Return success */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the total memory allocation size required for the real-mode trampoline execution environment.
|
||||
*
|
||||
* @param TrampolineCodeSize
|
||||
* Supplies the size of the trampoline code in bytes.
|
||||
*
|
||||
* @return This routine returns the computed allocation size in pages.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
ULONG
|
||||
MM::HardwarePool::CalculateRealModeAllocationPages(IN ULONG TrampolineCodeSize)
|
||||
{
|
||||
ULONG Size;
|
||||
|
||||
/* Compute real-mode memory allocation size (trampoline + processor start block + temporary stack) */
|
||||
Size = TrampolineCodeSize + sizeof(PROCESSOR_START_BLOCK) + 512;
|
||||
|
||||
/* Calculate and return number of pages */
|
||||
return (ULONG)(ROUND_UP(Size, MM_PAGE_SIZE) / MM_PAGE_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases physical memory allocated for kernel hardware layer.
|
||||
*
|
||||
* @param PhysicalAddress
|
||||
* Supplies the physical address of the memory block to be freed.
|
||||
*
|
||||
* @param PageCount
|
||||
* Supplies the number of pages associated with the allocation descriptor.
|
||||
*
|
||||
* @return This routine returns a status code indicating the success or failure of the operation.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
XTSTATUS
|
||||
MM::HardwarePool::FreeHardwareMemory(IN PHYSICAL_ADDRESS PhysicalAddress,
|
||||
IN PFN_NUMBER PageCount)
|
||||
{
|
||||
PLOADER_MEMORY_DESCRIPTOR Descriptor;
|
||||
PFN_NUMBER BasePage;
|
||||
ULONG Index;
|
||||
|
||||
/* Calculate base page from physical address */
|
||||
BasePage = PhysicalAddress.QuadPart >> MM_PAGE_SHIFT;
|
||||
|
||||
/* Iterate through recorded hardware descriptors to find the matching allocation */
|
||||
for(Index = 0; Index < UsedHardwareAllocationDescriptors; Index++)
|
||||
{
|
||||
/* Get current hardware allocation descriptor */
|
||||
Descriptor = &HardwareAllocationDescriptors[Index];
|
||||
|
||||
/* Verify descriptor properties */
|
||||
if(Descriptor->MemoryType == LoaderHardwareCachedMemory &&
|
||||
Descriptor->BasePage == BasePage &&
|
||||
Descriptor->PageCount == PageCount)
|
||||
{
|
||||
/* Make descriptor available again */
|
||||
Descriptor->MemoryType = LoaderFree;
|
||||
|
||||
/* Return success */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* Descriptors not found, return error */
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps physical address to the virtual memory area used by kernel hardware layer.
|
||||
*
|
||||
@@ -291,6 +396,46 @@ MM::HardwarePool::MapHardwareMemory(IN PHYSICAL_ADDRESS PhysicalAddress,
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes a temporary identity mapping for a specified physical memory range to facilitate real-mode execution.
|
||||
*
|
||||
* @param PhysicalAddress
|
||||
* Supplies the physical address of the trampoline memory.
|
||||
*
|
||||
* @param Size
|
||||
* Supplies the size of the trampoline memory allocation.
|
||||
*
|
||||
* @return This routine returns a status code indicating the success or failure of the operation.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
XTSTATUS
|
||||
MM::HardwarePool::MapRealModeMemory(IN PHYSICAL_ADDRESS PhysicalAddress,
|
||||
IN ULONG Pages)
|
||||
{
|
||||
PFN_NUMBER Index;
|
||||
XTSTATUS Status;
|
||||
|
||||
/* Identity map each page of the real-mode memory allocation */
|
||||
for(Index = 0; Index < Pages; Index++)
|
||||
{
|
||||
/* Map the current physical page */
|
||||
Status = MM::Paging::MapVirtualAddress((PVOID)(PhysicalAddress.QuadPart + (Index * MM_PAGE_SIZE)),
|
||||
(PhysicalAddress.QuadPart >> MM_PAGE_SHIFT) + Index,
|
||||
MM_PTE_EXECUTE_READWRITE);
|
||||
if(Status != STATUS_SUCCESS)
|
||||
{
|
||||
/* Failed to map the page, unmap previously mapped pages and return the error code */
|
||||
UnmapRealModeMemory(PhysicalAddress, Index * MM_PAGE_SIZE);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return success */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks existing mapping as CD/WT to avoid delays in write-back cache.
|
||||
*
|
||||
@@ -425,3 +570,34 @@ MM::HardwarePool::UnmapHardwareMemory(IN PVOID VirtualAddress,
|
||||
/* Return success */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the temporary identity mapping for a real-mode memory region.
|
||||
*
|
||||
* @param PhysicalAddress
|
||||
* Supplies the physical address of the trampoline memory.
|
||||
*
|
||||
* @param Size
|
||||
* Supplies the size of the trampoline memory allocation.
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
VOID
|
||||
MM::HardwarePool::UnmapRealModeMemory(IN PHYSICAL_ADDRESS PhysicalAddress,
|
||||
IN ULONG Size)
|
||||
{
|
||||
PFN_NUMBER AllocationPages, Index;
|
||||
|
||||
/* Calculate number of pages to unmap */
|
||||
AllocationPages = (ULONG)(ROUND_UP(Size, MM_PAGE_SIZE) / MM_PAGE_SIZE);
|
||||
|
||||
/* Iterate over the allocation pages to remove the identity mapping */
|
||||
for(Index = 0; Index < AllocationPages; Index++)
|
||||
{
|
||||
/* Clear the page table entry for the current virtual address */
|
||||
MM::Paging::ClearPte(MM::Paging::GetPteAddress((PVOID)(PhysicalAddress.QuadPart + (Index * MM_PAGE_SIZE))));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user