Mike Beaton abe28e829f OcConsoleLib: Add GopBurstMode quirk
OcMemoryLib: Add additional PAT and MTRR caching support
2023-03-28 07:18:14 +01:00

669 lines
20 KiB
C

/** @file
Copyright (C) 2019, vit9696. All rights reserved.
All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef OC_MEMORY_LIB_H
#define OC_MEMORY_LIB_H
#include <Uefi.h>
#include <Guid/MemoryAttributesTable.h>
#include <IndustryStandard/VirtualMemory.h>
/**
Reverse equivalent of NEXT_MEMORY_DESCRIPTOR.
**/
#define PREV_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
/**
Get last descriptor address.
It is assumed that the descriptor contains pages.
**/
#define LAST_DESCRIPTOR_ADDR(Desc) \
((Desc)->PhysicalStart + (EFI_PAGES_TO_SIZE ((UINTN) (Desc)->NumberOfPages) - 1))
/**
Check if area is within the specified descriptor.
It is assumed that the descriptor contains pages and AreaSize is not 0.
**/
#define AREA_WITHIN_DESCRIPTOR(Desc, Area, AreaSize) \
((Area) >= (Desc)->PhysicalStart && ((Area) + ((AreaSize) - 1)) <= LAST_DESCRIPTOR_ADDR (Desc))
/**
Reasonable default virtual memory page pool size (2 MB).
**/
#define OC_DEFAULT_VMEM_PAGE_COUNT 0x200
/**
Reasonable default memory map size used when allocations are problematic.
Note, that MacPro5,1 is known to have 8880 memory map.
**/
#define OC_DEFAULT_MEMORY_MAP_SIZE (EFI_PAGE_SIZE*3)
#define OC_MEMORY_TYPE_DESC_COUNT 16
typedef struct {
CHAR8 *Name;
EFI_MEMORY_TYPE Type;
} OC_MEMORY_TYPE_DESC;
/**
Lock the legacy region specified to enable modification.
@param[in] LegacyAddress The address of the region to lock.
@param[in] LegacyLength The size of the region to lock.
@retval EFI_SUCCESS The region was locked successfully.
**/
EFI_STATUS
LegacyRegionLock (
IN UINT32 LegacyAddress,
IN UINT32 LegacyLength
);
/**
Unlock the legacy region specified to enable modification.
@param[in] LegacyAddress The address of the region to unlock.
@param[in] LegacyLength The size of the region to unlock.
@retval EFI_SUCCESS The region was unlocked successfully.
**/
EFI_STATUS
LegacyRegionUnlock (
IN UINT32 LegacyAddress,
IN UINT32 LegacyLength
);
/**
Get current memory map allocated on pool with reserved entries.
@param[out] MemoryMapSize Resulting memory map size in bytes.
@param[out] DescriptorSize Resulting memory map descriptor size in bytes.
@param[out] MapKey Memory map key, optional.
@param[out] DescriptorVersion Memory map descriptor version, optional.
@param[out] OriginalMemoryMapSize Actual pool allocation memory, optional.
@param[out] IncludeSplitSpace Allocate memory to permit splitting memory map.
@retval current memory map or NULL.
**/
EFI_MEMORY_DESCRIPTOR *
OcGetCurrentMemoryMap (
OUT UINTN *MemoryMapSize,
OUT UINTN *DescriptorSize,
OUT UINTN *MapKey OPTIONAL,
OUT UINT32 *DescriptorVersion OPTIONAL,
OUT UINTN *OriginalMemoryMapSize OPTIONAL,
IN BOOLEAN IncludeSplitSpace
);
/**
Get current memory map of custom allocation.
@param[out] MemoryMapSize Resulting memory map size in bytes.
@param[out] MemoryMap Resulting memory map.
@param[out] MapKey Memory map key.
@param[out] DescriptorSize Resulting memory map descriptor size in bytes.
@param[out] DescriptorVersion Memory map descriptor version.
@param[in] GetMemoryMap Custom GetMemoryMap implementation to use, optional.
@param[in,out] TopMemory Base top address for OcAllocatePagesFromTop allocation, number of pages after return.
@retval EFI_SUCCESS on success.
**/
EFI_STATUS
OcGetCurrentMemoryMapAlloc (
OUT UINTN *MemoryMapSize,
OUT EFI_MEMORY_DESCRIPTOR **MemoryMap,
OUT UINTN *MapKey,
OUT UINTN *DescriptorSize,
OUT UINT32 *DescriptorVersion,
IN EFI_GET_MEMORY_MAP GetMemoryMap OPTIONAL,
IN OUT EFI_PHYSICAL_ADDRESS *TopMemory OPTIONAL
);
/**
Sort memory map entries based upon PhysicalStart, from low to high.
@param MemoryMapSize Size, in bytes, of the MemoryMap buffer.
@param MemoryMap A pointer to the buffer in which firmware places
the current memory map.
@param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
**/
VOID
OcSortMemoryMap (
IN UINTN MemoryMapSize,
IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
IN UINTN DescriptorSize
);
/**
Shrink memory map by joining non-runtime records.
Requires sorted memory map.
@param[in,out] MemoryMapSize Memory map size in bytes, updated on shrink.
@param[in,out] MemoryMap Memory map to shrink.
@param[in] DescriptorSize Memory map descriptor size in bytes.
@retval EFI_SUCCESS on success.
@retval EFI_NOT_FOUND when cannot join anything.
**/
EFI_STATUS
OcShrinkMemoryMap (
IN OUT UINTN *MemoryMapSize,
IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
IN UINTN DescriptorSize
);
/**
Deduplicate memory descriptors. Requires sorted entry list.
@param[in,out] EntryCount Memory map size in entries, updated on shrink.
@param[in,out] MemoryMap Memory map to shrink.
@param[in] DescriptorSize Memory map descriptor size in bytes.
@retval EFI_SUCCESS on success.
@retval EFI_NOT_FOUND when cannot join anything.
**/
EFI_STATUS
OcDeduplicateDescriptors (
IN OUT UINT32 *EntryCount,
IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
IN UINTN DescriptorSize
);
/**
Check range allocation compatibility callback.
@param[in] Address Starting address.
@param[in] Size Size of memory range.
@retval TRUE when suitable for allocation.
**/
typedef
BOOLEAN
(*CHECK_ALLOCATION_RANGE) (
IN EFI_PHYSICAL_ADDRESS Address,
IN UINTN Size
);
/**
Filter memory map entries.
@param[in] Context Parameterised filter data.
@param[in,out] MemoryMapSize Memory map size in bytes.
@param[in,out] MemoryMap Memory map to filter.
@param[in] DescriptorSize Memory map descriptor size in bytes.
**/
typedef
VOID
(*OC_MEMORY_FILTER) (
IN VOID *Context OPTIONAL,
IN UINTN MemoryMapSize,
IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
IN UINTN DescriptorSize
);
/**
Allocate pages from the top of physical memory up to address specified in Memory.
Unlike AllocateMaxAddress, this method guarantees to choose top most address.
@param[in] MemoryType Allocated memory type.
@param[in] Pages Amount of pages to allocate.
@param[in,out] Memory Top address for input, allocated address for output.
@param[in] GetMemoryMap Custom GetMemoryMap implementation to use, optional.
@param[in] AllocatePages Custom AllocatePages implementation to use, optional.
@param[in] CheckRange Handler allowing to not allocate select ranges, optional.
@retval EFI_SUCCESS on successful allocation.
**/
EFI_STATUS
OcAllocatePagesFromTop (
IN EFI_MEMORY_TYPE MemoryType,
IN UINTN Pages,
IN OUT EFI_PHYSICAL_ADDRESS *Memory,
IN EFI_GET_MEMORY_MAP GetMemoryMap OPTIONAL,
IN EFI_ALLOCATE_PAGES AllocatePages OPTIONAL,
IN CHECK_ALLOCATION_RANGE CheckRange OPTIONAL
);
/**
Calculate number of runtime pages in the memory map.
@param[in] MemoryMapSize Memory map size in bytes.
@param[in] MemoryMap Memory map to inspect.
@param[in] DescriptorSize Memory map descriptor size in bytes.
@param[out] DescriptorCount Number of relevant descriptors, optional.
@retval Number of runtime pages.
**/
UINT64
OcCountRuntimePages (
IN UINTN MemoryMapSize,
IN EFI_MEMORY_DESCRIPTOR *MemoryMap,
IN UINTN DescriptorSize,
OUT UINTN *DescriptorCount OPTIONAL
);
/**
Calculate number of free pages in the memory map.
@param[out] LowerMemory Number of free pages below 4 GB, optional.
@retval Number of free pages.
**/
UINTN
OcCountFreePages (
OUT UINTN *LowerMemory OPTIONAL
);
/**
Print memory attributes table if present.
**/
VOID
OcPrintMemoryAttributesTable (
VOID
);
/**
Print memory map.
@param[in] MemoryMapSize Memory map size in bytes.
@param[in] MemoryMap Memory map to print.
@param[in] DescriptorSize Memory map descriptor size in bytes.
**/
VOID
OcPrintMemoryMap (
IN UINTN MemoryMapSize,
IN EFI_MEMORY_DESCRIPTOR *MemoryMap,
IN UINTN DescriptorSize
);
/**
Refresh memory descriptor containing the specified address.
@param[in] MemoryMapSize Memory map size in bytes.
@param[in] MemoryMap Memory map to refresh.
@param[in] DescriptorSize Memory map descriptor size in bytes.
@param[in] Address Address contained in the updated entry.
@param[in] Type Memory type to assign to the entry.
@param[in] SetAttributes Attributes to set.
@param[in] DropAttributes Attributes to remove.
@retval EFI_SUCCESS on success.
@retval EFI_NOT_FOUND no entry contains the specified address.
@retval EFI_UNSUPPORTED memory attributes are not supported by the platform.
**/
EFI_STATUS
OcUpdateDescriptors (
IN UINTN MemoryMapSize,
IN EFI_MEMORY_DESCRIPTOR *MemoryMap,
IN UINTN DescriptorSize,
IN EFI_PHYSICAL_ADDRESS Address,
IN EFI_MEMORY_TYPE Type,
IN UINT64 SetAttributes,
IN UINT64 DropAttributes
);
/**
Obtain memory attributes table.
@param[out] MemoryAttributesEntry memory descriptor pointer, optional.
@retval pointer to memory attributes table.
@retval NULL if memory attributes table is unsupported.
**/
EFI_MEMORY_ATTRIBUTES_TABLE *
OcGetMemoryAttributes (
OUT EFI_MEMORY_DESCRIPTOR **MemoryAttributesEntry OPTIONAL
);
/**
Refresh memory attributes entry containing the specified address.
@param[in] Address Address contained in the updated entry.
@param[in] GetMemoryMap
@retval EFI_SUCCESS on success.
@retval EFI_NOT_FOUND no entry contains the specified address.
@retval EFI_UNSUPPORTED memory attributes are not supported by the platform.
**/
EFI_STATUS
OcRebuildAttributes (
IN EFI_PHYSICAL_ADDRESS Address,
IN EFI_GET_MEMORY_MAP GetMemoryMap OPTIONAL
);
/**
Count upper bound of split runtime descriptors.
@retval amount of runtime descriptors.
**/
UINTN
OcCountSplitDescriptors (
VOID
);
/**
Split memory map by memory attributes if available.
Requires sorted memory map!
@param[in] MaxMemoryMapSize Upper memory map size bound for growth.
@param[in,out] MemoryMapSize Current memory map size, updated on return.
@param[in,out] MemoryMap Memory map to split.
@param[in] DescriptorSize Memory map descriptor size.
Note, the function is guaranteed to return valid memory map, though not necessarily split.
@retval EFI_SUCCESS on success.
@retval EFI_UNSUPPORTED memory attributes are not supported by the platform.
@retval EFI_OUT_OF_RESOURCES new memory map did not fit.
**/
EFI_STATUS
OcSplitMemoryMapByAttributes (
IN UINTN MaxMemoryMapSize,
IN OUT UINTN *MemoryMapSize,
IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
IN UINTN DescriptorSize
);
/**
Checks if PAT is supported.
@retval TRUE PAT is supported.
@retval FALSE PAT is not supported.
**/
BOOLEAN
OcIsPatSupported (
VOID
);
/**
Return short string representation of MTRR cache type, as used in Intel tables.
@param[in] MtrrType MTRR type.
@retval String representation.
**/
CHAR8 *
OcGetMtrrTypeString (
UINT8 MtrrType
);
/**
Return short string representation of PAT cache type, as used in Intel tables.
@param[in] PatType PAT type.
@retval String representation.
**/
CHAR8 *
OcGetPatTypeString (
UINT8 PatType
);
/**
Return pointer to PML4 table in PageTable and PWT and PCD flags in Flags.
@param[out] Flags Current page table PWT and PCT flags.
@retval Current page table address.
**/
PAGE_MAP_AND_DIRECTORY_POINTER *
OcGetCurrentPageTable (
OUT UINTN *Flags OPTIONAL
);
/**
Return physical address for given virtual address.
@param[in] PageTable Page table to use for solving.
@param[in] VirtualAddr Virtual address to look up.
@param[out] PhysicalAddr Physical address to return.
@retval EFI_SUCCESS on successful lookup.
**/
EFI_STATUS
OcGetPhysicalAddress (
IN PAGE_MAP_AND_DIRECTORY_POINTER *PageTable OPTIONAL,
IN EFI_VIRTUAL_ADDRESS VirtualAddr,
OUT EFI_PHYSICAL_ADDRESS *PhysicalAddr
);
/**
Get page table info for a given virtual address.
Includes option to get or set Page Attribute Table (PAT) index for caching type.
@param[in] PageTable Page table to use for solving, and modify iff SetPat==TRUE.
@param[in] VirtualAddr Virtual address to look up.
@param[out] PhysicalAddr Physical address to return.
@param[out] Level Page table mapping level, 1, 2 or 4 for 1Gb, 2Mb or 4kb.
@param[out] Bits Page table mapping flag bits.
@param[in,out] PatIndex PAT index to get or set.
@param[in] SetPat If TRUE then set PatIndex if present, else get.
@retval EFI_SUCCESS on success.
**/
EFI_STATUS
OcGetSetPageTableInfoForAddress (
IN PAGE_MAP_AND_DIRECTORY_POINTER *PageTable OPTIONAL,
IN EFI_VIRTUAL_ADDRESS VirtualAddr,
OUT EFI_PHYSICAL_ADDRESS *PhysicalAddr OPTIONAL,
OUT UINT8 *Level OPTIONAL,
OUT UINT64 *Bits OPTIONAL,
IN OUT PAT_INDEX *PatIndex OPTIONAL,
IN BOOLEAN SetPat
);
/**
Set Page Attribute Table (PAT) index for an address range.
Assumes UEFI identity mapping between physical and virtual addresses.
@param[in] PageTable Page table to use and modify.
@param[in] VirtualAddr Address range start.
@param[in] Length Address range length.
@param[in] PatIndex PAT index to set.
@retval EFI_SUCCESS on success.
@retval EFI_INVALID_PARAMETER on invalid memory range.
@retval error - other error from called methods.
**/
EFI_STATUS
OcSetPatIndexForAddressRange (
IN PAGE_MAP_AND_DIRECTORY_POINTER *PageTable OPTIONAL,
IN EFI_VIRTUAL_ADDRESS VirtualAddr,
IN UINT64 Length,
IN PAT_INDEX *PatIndex
);
/**
Return EFI memory type for given type description
@param[in] MemoryTypeDesc Memory type string representation.
@param[out] MemoryType EFI memory type to return.
@retval EFI_NOT_FOUND on unsuccessful lookup.
@retval EFI_INVALID_PARAMETER on wrong passed agruments.
@retval EFI_SUCCESS on successful lookup.
**/
EFI_STATUS
OcDescToMemoryType (
IN CHAR8 *MemoryTypeDesc,
OUT EFI_MEMORY_TYPE *MemoryType
);
/**
Attempt to set entire MTRR range which starts with address to new MTRR cache type.
Use with caution - attempting to change cache-type on the fly of any region
used for code or data is likely to hang.
Works successfully to uncache GOP (i.e. WC->UC), producing visibly slower results,
on newer firmware where GOP range is set to WC in the first place.
@param[in] Address Start of range.
@param[in] MtrrType MTRR cache type to assign.
@param[out] Length Length of range converted or attempted to be converted, when non-zero.
@retval EFI_SUCCESS if cache type is set and system is still running.
@retval EFI_UNSUPPORTED if MTRR is unsupported.
@retval error - other error from methods called.
**/
EFI_STATUS
OcModifyMtrrRange (
IN EFI_PHYSICAL_ADDRESS Address,
IN UINT8 MtrrType,
OUT UINT64 *Length OPTIONAL
);
/**
Virtual memory context
**/
typedef struct OC_VMEM_CONTEXT_ {
///
/// Memory pool containing memory to be spread across allocations.
///
UINT8 *MemoryPool;
///
/// Free pages in the memory pool.
///
UINTN FreePages;
} OC_VMEM_CONTEXT;
/**
Allocate EfiBootServicesData virtual memory pool from boot services
in the end of BASE_4GB of RAM. Should be called while boot services are
still usable.
@param[out] Context Virtual memory pool context.
@param[in] NumPages Number of pages to be allocated in the pool.
@param[in] GetMemoryMap Custom GetMemoryMap implementation to use, optional.
@retval EFI_SUCCESS on successful allocation.
**/
EFI_STATUS
VmAllocateMemoryPool (
OUT OC_VMEM_CONTEXT *Context,
IN UINTN NumPages,
IN EFI_GET_MEMORY_MAP GetMemoryMap OPTIONAL
);
/**
Allocate pages for e.g. vm page maps.
@param[in,out] Context Virtual memory pool context.
@param[in] NumPages Number of pages to allocate.
@retval allocated pages or NULL.
**/
VOID *
VmAllocatePages (
IN OUT OC_VMEM_CONTEXT *Context,
IN UINTN NumPages
);
/**
Map (remap) given page at physical address to given virtual address in
the specified page table.
@param[in,out] Context Virtual memory pool context.
@param[in] PageTable Page table to update.
@param[in] VirtualAddr Virtual memory address to map at.
@param[in] PhysicalAddr Physical memory address to map from.
@retval EFI_SUCCESS on success.
**/
EFI_STATUS
VmMapVirtualPage (
IN OUT OC_VMEM_CONTEXT *Context,
IN OUT PAGE_MAP_AND_DIRECTORY_POINTER *PageTable OPTIONAL,
IN EFI_VIRTUAL_ADDRESS VirtualAddr,
IN EFI_PHYSICAL_ADDRESS PhysicalAddr
);
/**
Map (remap) a range of 4K pages at physical address to given virtual address
in the specified page table.
@param[in,out] Context Virtual memory pool context.
@param[in] PageTable Page table to update.
@param[in] VirtualAddr Virtual memory address to map at.
@param[in] NumPages Number of 4K pages to map.
@param[in] PhysicalAddr Physical memory address to map from.
@retval EFI_SUCCESS on success.
**/
EFI_STATUS
VmMapVirtualPages (
IN OUT OC_VMEM_CONTEXT *Context,
IN OUT PAGE_MAP_AND_DIRECTORY_POINTER *PageTable OPTIONAL,
IN EFI_VIRTUAL_ADDRESS VirtualAddr,
IN UINT64 NumPages,
IN EFI_PHYSICAL_ADDRESS PhysicalAddr
);
/**
Flushes TLB caches.
**/
VOID
VmFlushCaches (
VOID
);
/**
Check whether built-in allocator is initialized.
@retval TRUE on success.
**/
BOOLEAN
UmmInitialized (
VOID
);
/**
Initialize built-in allocator.
@param[in] Heap Memory pool used for allocations.
@param[in] Size Memory pool size.
**/
VOID
UmmSetHeap (
IN VOID *Heap,
IN UINT32 Size
);
/**
Perform allocation from built-in allocator.
@param[in] Size Allocation size.
@retval allocated memory on success.
**/
VOID *
UmmMalloc (
IN UINT32 Size
);
/**
Perform free of allocated memory. Accepts NULL pointer
and checks whether memory belongs to itself.
@param[in] Ptr Memory to free.
@retval TRUE on success
**/
BOOLEAN
UmmFree (
IN VOID *Ptr
);
#endif // OC_MEMORY_LIB_H