Refactor real-mode memory allocation and identity mapping for AP trampoline

This commit is contained in:
2026-06-12 13:16:48 +02:00
parent 81c799e590
commit c702152cca
4 changed files with 236 additions and 36 deletions

View File

@@ -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;
}

View File

@@ -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);
};
}

View File

@@ -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;

View File

@@ -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))));
}
}