diff --git a/Include/Library/OcAppleRamDiskLib.h b/Include/Library/OcAppleRamDiskLib.h new file mode 100644 index 00000000..879b4ec5 --- /dev/null +++ b/Include/Library/OcAppleRamDiskLib.h @@ -0,0 +1,54 @@ +/** @file + Apple RAM Disk library. + +Copyright (C) 2019, Download-Fritz. 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_APPLE_RAM_DISK_LIB_H +#define OC_APPLE_RAM_DISK_LIB_H + +#include + +APPLE_RAM_DISK_EXTENT_TABLE * +OcAppleRamDiskAllocate ( + IN UINTN Size, + IN EFI_MEMORY_TYPE MemoryType + ); + +BOOLEAN +OcAppleRamDiskRead ( + IN APPLE_RAM_DISK_EXTENT_TABLE *ExtentTable, + IN UINT64 Offset, + IN UINTN Size, + OUT VOID *Buffer + ); + +BOOLEAN +OcAppleRamDiskWrite ( + IN APPLE_RAM_DISK_EXTENT_TABLE *ExtentTable, + IN UINT64 Offset, + IN UINTN Size, + IN CONST VOID *Buffer + ); + +BOOLEAN +OcAppleRamDiskLoadFile ( + IN OUT APPLE_RAM_DISK_EXTENT_TABLE *ExtentTable, + IN EFI_FILE_PROTOCOL *File, + IN UINTN FileSize + ); + +VOID +OcAppleRamDiskFree ( + IN APPLE_RAM_DISK_EXTENT_TABLE *ExtentTable + ); + +#endif // OC_APPLE_RAM_DISK_LIB_H diff --git a/Library/OcAppleRamDiskLib/OcAppleRamDiskLib.c b/Library/OcAppleRamDiskLib/OcAppleRamDiskLib.c new file mode 100644 index 00000000..07423171 --- /dev/null +++ b/Library/OcAppleRamDiskLib/OcAppleRamDiskLib.c @@ -0,0 +1,525 @@ +/** @file + Apple RAM Disk library. + +Copyright (C) 2019, Download-Fritz. 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. + +**/ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#define INTERNAL_ASSERT_EXTENT_TABLE_VALID(ExtentTable) \ + ASSERT ((ExtentTable)->Signature == APPLE_RAM_DISK_EXTENT_SIGNATURE); \ + ASSERT ((ExtentTable)->Version == APPLE_RAM_DISK_EXTENT_VERSION); \ + ASSERT ((ExtentTable)->Reserved == 0); \ + ASSERT ((ExtentTable)->Signature2 == APPLE_RAM_DISK_EXTENT_SIGNATURE); \ + ASSERT ((ExtentTable)->ExtentCount > 0); \ + ASSERT ((ExtentTable)->ExtentCount <= ARRAY_SIZE ((ExtentTable)->Extents)) + +STATIC +BOOLEAN +InternalAllocateRemaining ( + OUT APPLE_RAM_DISK_EXTENT *Extents, + OUT UINT32 *NumExtents, + IN UINT32 MaxExtents, + IN EFI_MEMORY_DESCRIPTOR *MemoryMap, + IN UINTN MemoryMapSize, + IN UINTN DescriptorSize, + IN UINTN RemainingPages, + IN EFI_MEMORY_TYPE MemoryType + ); + +STATIC +BOOLEAN +InternalAllocateRemainingWorker ( + OUT APPLE_RAM_DISK_EXTENT *Extents, + OUT UINT32 *NumExtents, + IN UINT32 MaxExtents, + IN EFI_MEMORY_DESCRIPTOR *MemoryMap, + IN UINTN MemoryMapSize, + IN UINTN DescriptorSize, + IN UINTN RemainingPages, + IN EFI_MEMORY_TYPE MemoryType, + IN BOOLEAN Above4G + ) +{ + EFI_STATUS Status; + BOOLEAN Result; + + EFI_PHYSICAL_ADDRESS ExtentMemory; + + EFI_MEMORY_DESCRIPTOR *EntryWalker; + EFI_MEMORY_DESCRIPTOR *BiggestEntry; + + UINT32 Index; + + ASSERT (Extents != NULL); + ASSERT (MaxExtents > 0); + ASSERT (NumExtents != NULL); + ASSERT (MemoryMap != NULL); + ASSERT (MemoryMapSize > 0); + ASSERT (DescriptorSize > 0); + ASSERT ((MemoryMapSize % DescriptorSize) == 0); + ASSERT (RemainingPages > 0); + + BiggestEntry = NULL; + + for ( + EntryWalker = MemoryMap; + (UINT8 *)EntryWalker < ((UINT8 *)MemoryMap + MemoryMapSize); + EntryWalker = NEXT_MEMORY_DESCRIPTOR (EntryWalker, DescriptorSize)) { + if ((EntryWalker->Type != EfiConventionalMemory) + || (((Above4G ? 1 : 0) ^ ((EntryWalker->PhysicalStart < BASE_4GB) ? 1 : 0)) == 0)) { + continue; + } + + if ((BiggestEntry == NULL) + || (EntryWalker->NumberOfPages > BiggestEntry->NumberOfPages)) { + BiggestEntry = EntryWalker; + } + } + + if (BiggestEntry == NULL) { + return FALSE; + } + + if (BiggestEntry->NumberOfPages >= RemainingPages) { + // + // Backtracking - potential finish + // + ExtentMemory = BiggestEntry->PhysicalStart; + ExtentMemory += EFI_PAGES_TO_SIZE (BiggestEntry->NumberOfPages - RemainingPages); + Status = gBS->AllocatePages ( + AllocateAddress, + MemoryType, + RemainingPages, + &ExtentMemory + ); + if (!EFI_ERROR (Status)) { + Extents[0].Start = ExtentMemory; + Extents[0].Length = EFI_PAGES_TO_SIZE (RemainingPages); + *NumExtents = 1; + + return TRUE; + } + } + + if (MaxExtents == 1) { + return FALSE; + } + // + // Backtracking - iteration + // + BiggestEntry->Type = MemoryType; + Result = InternalAllocateRemaining ( + &Extents[1], + NumExtents, + (MaxExtents - 1), + MemoryMap, + MemoryMapSize, + DescriptorSize, + (RemainingPages - BiggestEntry->NumberOfPages), + MemoryType + ); + BiggestEntry->Type = EfiConventionalMemory; + + if (!Result) { + return FALSE; + } + + ExtentMemory = BiggestEntry->PhysicalStart; + Status = gBS->AllocatePages ( + AllocateAddress, + MemoryType, + BiggestEntry->NumberOfPages, + &ExtentMemory + ); + if (EFI_ERROR (Status)) { + // + // Clean up all successfully backtracked allocations. + // + for (Index = 0; Index < *NumExtents; ++Index) { + gBS->FreePages ( + Extents[Index + 1].Start, + EFI_SIZE_TO_PAGES (Extents[Index + 1].Length) + ); + } + + *NumExtents = 0; + return FALSE; + } + + Extents[0].Start = ExtentMemory; + Extents[0].Length = EFI_PAGES_TO_SIZE (BiggestEntry->NumberOfPages); + ++(*NumExtents); + + return TRUE; +} + +STATIC +BOOLEAN +InternalAllocateRemaining ( + OUT APPLE_RAM_DISK_EXTENT *Extents, + OUT UINT32 *NumExtents, + IN UINT32 MaxExtents, + IN EFI_MEMORY_DESCRIPTOR *MemoryMap, + IN UINTN MemoryMapSize, + IN UINTN DescriptorSize, + IN UINTN RemainingPages, + IN EFI_MEMORY_TYPE MemoryType + ) +{ + BOOLEAN Result; + // + // Prefer fitting all contents above 4 GB. + // + Result = InternalAllocateRemainingWorker ( + Extents, + NumExtents, + MaxExtents, + MemoryMap, + MemoryMapSize, + DescriptorSize, + RemainingPages, + MemoryType, + TRUE + ); + if (!Result) { + Result = InternalAllocateRemainingWorker ( + Extents, + NumExtents, + MaxExtents, + MemoryMap, + MemoryMapSize, + DescriptorSize, + RemainingPages, + MemoryType, + FALSE + ); + } + + return Result; +} + +APPLE_RAM_DISK_EXTENT_TABLE * +OcAppleRamDiskAllocate ( + IN UINTN Size, + IN EFI_MEMORY_TYPE MemoryType + ) +{ + EFI_STATUS Status; + BOOLEAN Result; + + UINTN MemoryMapSize; + EFI_MEMORY_DESCRIPTOR *MemoryMap; + UINTN MapKey; + UINTN DescriptorSize; + UINT32 DescriptorVersion; + + APPLE_RAM_DISK_EXTENT_TABLE *ExtentTable; + UINT64 ExtentTableMemory; + + Status = gBS->AllocatePages ( + AllocateAnyPages, + MemoryType, + EFI_SIZE_TO_PAGES (sizeof (*ExtentTable)), + &ExtentTableMemory + ); + if (EFI_ERROR (Status)) { + return NULL; + } + + MemoryMapSize = 0; + Status = gBS->GetMemoryMap ( + &MemoryMapSize, + NULL, + &MapKey, + &DescriptorSize, + &DescriptorVersion + ); + if (Status != EFI_BUFFER_TOO_SMALL) { + gBS->FreePages ( + ExtentTableMemory, + EFI_SIZE_TO_PAGES (sizeof (*ExtentTable)) + ); + return NULL; + } + // + // Apple uses 1024 as constant, however it will grow by at least + // DescriptorSize. + // + Result = OcOverflowAddUN ( + MemoryMapSize, + MAX (DescriptorSize, 1024), + &MemoryMapSize + ); + if (Result) { + gBS->FreePages ( + ExtentTableMemory, + EFI_SIZE_TO_PAGES (sizeof (*ExtentTable)) + ); + return NULL; + } + + MemoryMap = AllocatePool (MemoryMapSize); + if (MemoryMap == NULL) { + gBS->FreePages ( + ExtentTableMemory, + EFI_SIZE_TO_PAGES (sizeof (*ExtentTable)) + ); + return NULL; + } + + Status = gBS->GetMemoryMap ( + &MemoryMapSize, + MemoryMap, + &MapKey, + &DescriptorSize, + &DescriptorVersion + ); + if (EFI_ERROR (Status)) { + gBS->FreePages ( + ExtentTableMemory, + EFI_SIZE_TO_PAGES (sizeof (*ExtentTable)) + ); + FreePool (MemoryMap); + return NULL; + } + + ExtentTable = (VOID *)(UINTN)ExtentTableMemory; + ExtentTable->Signature = APPLE_RAM_DISK_EXTENT_SIGNATURE; + ExtentTable->Version = APPLE_RAM_DISK_EXTENT_VERSION; + ExtentTable->Reserved = 0; + ExtentTable->Signature2 = APPLE_RAM_DISK_EXTENT_SIGNATURE; + ExtentTable->ExtentCount = 0; + Result = InternalAllocateRemaining ( + ExtentTable->Extents, + &ExtentTable->ExtentCount, + ARRAY_SIZE (ExtentTable->Extents), + MemoryMap, + MemoryMapSize, + DescriptorSize, + EFI_SIZE_TO_PAGES (Size), + MemoryType + ); + if (!Result) { + gBS->FreePages ( + ExtentTableMemory, + EFI_SIZE_TO_PAGES (sizeof (*ExtentTable)) + ); + ExtentTable = NULL; + } + + FreePool (MemoryMap); + + return ExtentTable; +} + +BOOLEAN +OcAppleRamDiskRead ( + IN APPLE_RAM_DISK_EXTENT_TABLE *ExtentTable, + IN UINT64 Offset, + IN UINTN Size, + OUT VOID *Buffer + ) +{ + UINT8 *BufferBytes; + + UINT32 Index; + APPLE_RAM_DISK_EXTENT *Extent; + + UINT64 CurrentOffset; + UINT64 LocalOffset; + UINTN LocalSize; + + ASSERT (ExtentTable != NULL); + INTERNAL_ASSERT_EXTENT_TABLE_VALID (ExtentTable); + ASSERT (Size > 0); + ASSERT (Buffer != NULL); + + BufferBytes = Buffer; + + for ( + Index = 0, CurrentOffset = 0; + Index < ExtentTable->ExtentCount; + ++Index, CurrentOffset += Extent->Length + ) { + Extent = &ExtentTable->Extents[Index]; + + if (Offset >= CurrentOffset) { + LocalOffset = (Offset - CurrentOffset); + LocalSize = (UINTN)MIN ((Extent->Length - LocalOffset), Size); + CopyMem ( + BufferBytes, + (VOID *)((UINTN)Extent->Start + LocalOffset), + LocalSize + ); + + Size -= LocalSize; + if (Size == 0) { + return TRUE; + } + + BufferBytes += LocalSize; + Offset += LocalSize; + } + } + + return FALSE; +} + +BOOLEAN +OcAppleRamDiskWrite ( + IN APPLE_RAM_DISK_EXTENT_TABLE *ExtentTable, + IN UINT64 Offset, + IN UINTN Size, + IN CONST VOID *Buffer + ) +{ + CONST UINT8 *BufferBytes; + + UINT32 Index; + APPLE_RAM_DISK_EXTENT *Extent; + + UINT64 CurrentOffset; + UINT64 LocalOffset; + UINTN LocalSize; + + ASSERT (ExtentTable != NULL); + INTERNAL_ASSERT_EXTENT_TABLE_VALID (ExtentTable); + ASSERT (Size > 0); + ASSERT (Buffer != NULL); + + BufferBytes = Buffer; + + for ( + Index = 0, CurrentOffset = 0; + Index < ExtentTable->ExtentCount; + ++Index, CurrentOffset += Extent->Length + ) { + Extent = &ExtentTable->Extents[Index]; + + if (Offset >= CurrentOffset) { + LocalOffset = (Offset - CurrentOffset); + LocalSize = (UINTN)MIN ((Extent->Length - LocalOffset), Size); + CopyMem ( + (VOID *)((UINTN)Extent->Start + LocalOffset), + BufferBytes, + LocalSize + ); + + Size -= LocalSize; + if (Size == 0) { + return TRUE; + } + + BufferBytes += LocalSize; + Offset += LocalSize; + } + } + + return FALSE; +} + +BOOLEAN +OcAppleRamDiskLoadFile ( + IN OUT APPLE_RAM_DISK_EXTENT_TABLE *ExtentTable, + IN EFI_FILE_PROTOCOL *File, + IN UINTN FileSize + ) +{ + EFI_STATUS Status; + BOOLEAN Result; + + UINTN FileBufferSize; + VOID *FileBuffer; + + UINTN CurrentSize; + UINT64 FilePosition; + + ASSERT (ExtentTable != NULL); + INTERNAL_ASSERT_EXTENT_TABLE_VALID (ExtentTable); + ASSERT (File != NULL); + ASSERT (FileSize > 0); + + FileBufferSize = FileSize; + + while (TRUE) { + FileBuffer = AllocatePool (FileBufferSize); + if (FileBuffer != NULL) { + break; + } + + if (FileBufferSize <= 2) { + return FALSE; + } + + FileBufferSize = ((FileBufferSize / 2) + 1); + } + + FilePosition = 0; + CurrentSize = FileBufferSize; + do { + Status = GetFileData (File, FilePosition, CurrentSize, FileBuffer); + if (!EFI_ERROR (Status)) { + FreePool (FileBuffer); + return FALSE; + } + + Result = OcAppleRamDiskWrite ( + ExtentTable, + FilePosition, + CurrentSize, + FileBuffer + ); + if (!Result) { + FreePool (FileBuffer); + return FALSE; + } + + FilePosition += CurrentSize; + FileSize -= CurrentSize; + CurrentSize = MIN (FileSize, FileBufferSize); + } while (FileSize != 0); + + return TRUE; +} + +VOID +OcAppleRamDiskFree ( + IN APPLE_RAM_DISK_EXTENT_TABLE *ExtentTable + ) +{ + UINT32 Index; + + ASSERT (ExtentTable != NULL); + INTERNAL_ASSERT_EXTENT_TABLE_VALID (ExtentTable); + + for (Index = 0; Index < ExtentTable->ExtentCount; ++Index) { + gBS->FreePages ( + ExtentTable->Extents[Index].Start, + EFI_SIZE_TO_PAGES (ExtentTable->Extents[Index].Length) + ); + } + + gBS->FreePages ( + (UINTN)ExtentTable, + EFI_SIZE_TO_PAGES (sizeof (*ExtentTable)) + ); +} diff --git a/Library/OcAppleRamDiskLib/OcAppleRamDiskLib.inf b/Library/OcAppleRamDiskLib/OcAppleRamDiskLib.inf new file mode 100644 index 00000000..8cbf8b68 --- /dev/null +++ b/Library/OcAppleRamDiskLib/OcAppleRamDiskLib.inf @@ -0,0 +1,35 @@ +## @file +# Apple RAM Disk library. +# +# Copyright (C) 2019, Download-Fritz. 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. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = OcAppleRamDiskLib + FILE_GUID = 57734401-29DB-49C6-816C-BF333A72BBA3 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = OcAppleRamDiskLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER SMM_CORE UEFI_APPLICATION UEFI_DRIVER + +[Packages] + MdePkg/MdePkg.dec + EfiPkg/EfiPkg.dec + OcSupportPkg/OcSupportPkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + MemoryAllocationLib + UefiBootServicesTableLib + +[Sources] + OcAppleRamDiskLib.c diff --git a/OcSupportPkg.dec b/OcSupportPkg.dec index 88d2fe0c..8ef07e8e 100644 --- a/OcSupportPkg.dec +++ b/OcSupportPkg.dec @@ -68,6 +68,9 @@ ## @libraryclass OcAppleKeysLib|Include/Library/OcAppleKeysLib.h + ## @libraryclass + OcAppleRamDiskLib|Include/Library/OcAppleRamDiskLib.h + ## @libraryclass OcBootManagementLib|Include/Library/OcBootManagementLib.h diff --git a/OcSupportPkg.dsc b/OcSupportPkg.dsc index 4b6489d0..ab240afe 100644 --- a/OcSupportPkg.dsc +++ b/OcSupportPkg.dsc @@ -57,6 +57,7 @@ OcAppleImageVerificationLib|OcSupportPkg/Library/OcAppleImageVerificationLib/OcAppleImageVerificationLib.inf OcAppleKernelLib|OcSupportPkg/Library/OcAppleKernelLib/OcAppleKernelLib.inf OcAppleKeysLib|OcSupportPkg/Library/OcAppleKeysLib/OcAppleKeysLib.inf + OcAppleRamDiskLib|OcSupportPkg/Library/OcAppleRamDiskLib/OcAppleRamDiskLib.inf OcBootManagementLib|OcSupportPkg/Library/OcBootManagementLib/OcBootManagementLib.inf OcConsoleLib|OcSupportPkg/Library/OcConsoleLib/OcConsoleLib.inf OcCpuLib|OcSupportPkg/Library/OcCpuLib/OcCpuLib.inf @@ -87,6 +88,7 @@ OcSupportPkg/Library/OcAppleDiskImageLib/OcAppleDiskImageLib.inf OcSupportPkg/Library/OcAppleImageVerificationLib/OcAppleImageVerificationLib.inf OcSupportPkg/Library/OcAppleKernelLib/OcAppleKernelLib.inf + OcSupportPkg/Library/OcAppleRamDiskLib/OcAppleRamDiskLib.inf OcSupportPkg/Library/OcBootManagementLib/OcBootManagementLib.inf OcSupportPkg/Library/OcConfigurationLib/OcConfigurationLib.inf OcSupportPkg/Library/OcCpuLib/OcCpuLib.inf