Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers into modules, and delete rossubsys.

This commit is contained in:
Colin Finck 2017-10-03 07:45:34 +00:00
parent b94e2d8ca0
commit c2c66aff7d
24198 changed files with 0 additions and 37285 deletions

0
boot/environ/lib/arch/.gitignore vendored Normal file
View file

View file

@ -0,0 +1,305 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/arch/i386/arch.c
* PURPOSE: Boot Library Architectural Initialization for i386
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
BL_ARCH_CONTEXT FirmwareExecutionContext;
BL_ARCH_CONTEXT ApplicationExecutionContext;
PBL_ARCH_CONTEXT CurrentExecutionContext;
/* FUNCTIONS *****************************************************************/
VOID
DECLSPEC_NORETURN
ArchTrapNoProcess (
VOID
)
{
/* Do nothing, this is an unsupported debugging interrupt */
#if defined(__GNUC__)
__asm__ __volatile__ ("iret");
#elif defined (_MSC_VER)
_asm { iret };
#else
#error wtf are you using
#endif
__assume(0);
}
VOID
ArchSwitchContext (
_In_ PBL_ARCH_CONTEXT NewContext,
_In_ PBL_ARCH_CONTEXT OldContext
)
{
/* Are we switching to real mode? */
if (NewContext->Mode == BlRealMode)
{
/* Disable paging */
__writecr0(__readcr0() & ~CR0_PG);
/* Are we coming from PAE mode? */
if ((OldContext != NULL) && (OldContext->TranslationType == BlPae))
{
/* Turn off PAE */
__writecr4(__readcr4() & ~CR4_PAE);
}
/* Enable interrupts */
_enable();
}
else
{
/* Switching to protected mode -- disable interrupts if needed */
if (!(NewContext->ContextFlags & BL_CONTEXT_INTERRUPTS_ON))
{
_disable();
}
/* Are we enabling paging for the first time? */
if (NewContext->ContextFlags & BL_CONTEXT_PAGING_ON)
{
/* In PAE mode? */
if (NewContext->TranslationType == BlPae)
{
/* Turn on PAE */
__writecr4(__readcr4() | CR4_PAE);
}
/* Turn on paging */
__writecr0(__readcr0() | CR0_PG);
}
}
}
NTSTATUS
ArchInitializeContext (
_In_ PBL_ARCH_CONTEXT Context
)
{
NTSTATUS Status = STATUS_SUCCESS;
/* Are we initializing real mode? */
if (Context->Mode == BlRealMode)
{
/* Disable paging, enable interrupts */
Context->ContextFlags &= ~BL_CONTEXT_PAGING_ON;
Context->ContextFlags |= BL_CONTEXT_INTERRUPTS_ON;
}
else if (!(BlpApplicationFlags & BL_APPLICATION_FLAG_CONVERTED_FROM_EFI) ||
(BlpLibraryParameters.TranslationType != BlNone))
{
/* Read the current translation type */
Context->TranslationType = BlpLibraryParameters.TranslationType;
/* Disable paging (it's already on), enable interrupts */
Context->ContextFlags &= ~BL_CONTEXT_PAGING_ON;
Context->ContextFlags |= BL_CONTEXT_INTERRUPTS_ON;
/* Enable FXSR support in the FPU */
__writecr4(__readcr4() | CR4_FXSR);
}
else
{
/* Invalid context */
Status = STATUS_NOT_SUPPORTED;
}
/* Return context status */
return Status;
}
NTSTATUS
ArchInitializeContexts (
VOID
)
{
PBL_ARCH_CONTEXT Context = NULL;
NTSTATUS EfiStatus, AppStatus;
/* No current context */
CurrentExecutionContext = NULL;
/* Setup the EFI and Application modes respectively */
FirmwareExecutionContext.Mode = BlRealMode;
ApplicationExecutionContext.Mode = BlProtectedMode;
/* Initialize application mode */
AppStatus = ArchInitializeContext(&ApplicationExecutionContext);
if (NT_SUCCESS(AppStatus))
{
/* Set it as current if it worked */
Context = &ApplicationExecutionContext;
CurrentExecutionContext = &ApplicationExecutionContext;
}
/* Initialize EFI mode */
EfiStatus = ArchInitializeContext(&FirmwareExecutionContext);
if (NT_SUCCESS(EfiStatus))
{
/* Set it as current if application context failed */
if (!NT_SUCCESS(AppStatus))
{
Context = &FirmwareExecutionContext;
CurrentExecutionContext = &FirmwareExecutionContext;
}
/* Switch to application mode, or EFI if that one failed */
ArchSwitchContext(Context, NULL);
EfiStatus = STATUS_SUCCESS;
}
/* Return initialization state */
return EfiStatus;
}
VOID
BlpArchSwitchContext (
_In_ BL_ARCH_MODE NewMode
)
{
PBL_ARCH_CONTEXT Context;
/* In real mode, use EFI, otherwise, use the application mode */
Context = &FirmwareExecutionContext;
if (NewMode != BlRealMode)
{
Context = &ApplicationExecutionContext;
}
/* Are we in a different mode? */
if (CurrentExecutionContext->Mode != NewMode)
{
/* Switch to the new one */
ArchSwitchContext(Context, CurrentExecutionContext);
CurrentExecutionContext = Context;
}
}
VOID
BlpArchEnableTranslation (
VOID
)
{
PBL_ARCH_CONTEXT Context;
/* Does the current execution context already have paging enabled? */
Context = CurrentExecutionContext;
if (!(Context->ContextFlags & BL_CONTEXT_PAGING_ON))
{
/* No -- does it have interrupts enabled? */
if (Context->ContextFlags & BL_CONTEXT_INTERRUPTS_ON)
{
/* Disable them */
_disable();
Context->ContextFlags &= ~BL_CONTEXT_INTERRUPTS_ON;
}
/* Are we enabling PAE? */
if (Context->TranslationType == BlPae)
{
/* Make sure CR4 reflects this */
__writecr4(__readcr4() | CR4_PAE);
}
/* Enable paging in the CPU */
__writecr0(__readcr0() | CR0_PG);
/* Reflect that paging is enabled */
Context->ContextFlags |= BL_CONTEXT_PAGING_ON;
}
}
/*++
* @name BlpArchInitialize
*
* The BlpArchInitialize function initializes the Boot Library.
*
* @param Phase
* Pointer to the Boot Application Parameter Block.
*
* @return NT_SUCCESS if the boot library was loaded correctly, relevant error
* otherwise.
*
*--*/
NTSTATUS
BlpArchInitialize (
_In_ ULONG Phase
)
{
KDESCRIPTOR Idtr;
USHORT CodeSegment;
NTSTATUS Status;
PKIDTENTRY IdtBase;
/* Assume success */
Status = STATUS_SUCCESS;
/* Is this phase 1? */
if (Phase != 0)
{
/* Get the IDT */
__sidt(&Idtr);
IdtBase = (PKIDTENTRY)Idtr.Base;
/* Get the Code Segment */
#if defined(__GNUC__)
__asm__ __volatile__ ("mov %%cs,%0\n\t" :"=r" (CodeSegment));
#elif defined (_MSC_VER)
_asm { mov CodeSegment, cs };
#else
#error wtf are you using
#endif
/* Set up INT 3, ASSERT, and SECURITY_ASSERT to be no-op (for Rtl) */
IdtBase[3].Offset = (USHORT)(ULONG_PTR)ArchTrapNoProcess;
IdtBase[3].Selector = CodeSegment;
IdtBase[3].Access = 0x8E00u;
IdtBase[3].ExtendedOffset = (ULONG_PTR)ArchTrapNoProcess >> 16;
IdtBase[0x2C].Offset = (USHORT)(ULONG_PTR)ArchTrapNoProcess;
IdtBase[0x2C].Selector = CodeSegment;
IdtBase[0x2C].Access = 0x8E00u;
IdtBase[0x2C].ExtendedOffset = (ULONG_PTR)ArchTrapNoProcess >> 16;
IdtBase[0x2D].Offset = (USHORT)(ULONG_PTR)ArchTrapNoProcess;
IdtBase[0x2D].Selector = CodeSegment;
IdtBase[0x2D].Access = 0x8E00u;
IdtBase[0x2D].ExtendedOffset = (ULONG_PTR)ArchTrapNoProcess >> 16;
/* Write the IDT back */
Idtr.Base = (ULONG)IdtBase;
__lidt(&Idtr);
/* Reset FPU state */
#if defined(__GNUC__)
__asm__ __volatile__ ("fninit");
#elif defined (_MSC_VER)
_asm { fninit };
#else
#error wtf are you using
#endif
}
else
{
/* Reset TSC if needed */
if ((__readmsr(0x10) >> 32) & 0xFFC00000)
{
__writemsr(0x10, 0);
}
/* Initialize all the contexts */
Status = ArchInitializeContexts();
}
/* Return initialization state */
return Status;
}

View file

@ -0,0 +1,82 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/arch/transfer.asm
* PURPOSE: Boot Library i386 Transfer Functions
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <asm.inc>
#include <ks386.inc>
EXTERN _GdtRegister:FWORD
EXTERN _IdtRegister:FWORD
EXTERN _BootAppGdtRegister:FWORD
EXTERN _BootAppIdtRegister:FWORD
EXTERN _BootApp32Stack:DWORD
EXTERN _BootApp32EntryRoutine:DWORD
EXTERN _BootApp32Parameters:DWORD
/* FUNCTIONS ****************************************************************/
.code
ASSUME nothing
PUBLIC _Archx86TransferTo32BitApplicationAsm
_Archx86TransferTo32BitApplicationAsm:
/* Save non-volatile registers */
push ebp
push esi
push edi
push ebx
/* Save data segments */
push es
push ds
/* Save the old stack */
mov ebx, esp
/* Save current GDT/IDT, then load new one */
sgdt _GdtRegister+2
sidt _IdtRegister+2
lgdt _BootAppGdtRegister+2
lidt _BootAppIdtRegister+2
/* Load the new stack */
xor ebp, ebp
mov esp, _BootApp32Stack
/* Push old stack onto new stack */
push ebx
/* Call the entry routine, passing the parameters */
mov eax, _BootApp32Parameters
push eax
mov eax, _BootApp32EntryRoutine
call eax
/* Retore old stack */
pop ebx
mov esp, ebx
/* Restore old GDT/IDT */
lgdt _GdtRegister+2
lidt _IdtRegister+2
/* Retore old segments */
pop ds
pop es
/* Retore non-volatiles */
pop ebx
pop edi
pop esi
pop ebp
/* All done */
ret
END

View file

@ -0,0 +1,52 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/arch/stub/arch.c
* PURPOSE: Boot Library Architectural Initialization Skeleton Code
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
PBL_ARCH_CONTEXT CurrentExecutionContext;
/* FUNCTIONS *****************************************************************/
VOID
BlpArchSwitchContext (
_In_ BL_ARCH_MODE NewMode
)
{
}
/*++
* @name BlpArchInitialize
*
* The BlpArchInitialize function initializes the Boot Library.
*
* @param Phase
* Pointer to the Boot Application Parameter Block.
*
* @return NT_SUCCESS if the boot library was loaded correctly, relevant error
* otherwise.
*
*--*/
NTSTATUS
BlpArchInitialize (
_In_ ULONG Phase
)
{
EfiPrintf(L" BlpArchInitialize NOT IMPLEMENTED for this platform\r\n");
return STATUS_NOT_IMPLEMENTED;
}
VOID
Archx86TransferTo32BitApplicationAsm (VOID)
{
EfiPrintf(L" Archx86TransferTo32BitApplicationAsm NOT IMPLEMENTED for this platform\r\n");
}

0
boot/environ/lib/bd/.gitignore vendored Normal file
View file

480
boot/environ/lib/bootlib.c Normal file
View file

@ -0,0 +1,480 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/bootlib.c
* PURPOSE: Boot Library Initialization
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
BL_LIBRARY_PARAMETERS BlpLibraryParameters;
PBL_DEVICE_DESCRIPTOR BlpBootDevice;
PWCHAR BlpApplicationBaseDirectory;
PBOOT_APPLICATION_PARAMETER_BLOCK BlpApplicationParameters;
BL_LOADED_APPLICATION_ENTRY BlpApplicationEntry;
BOOLEAN BlpLibraryParametersInitialized;
ULONG BlpApplicationFlags;
ULONG PdPersistAllocations;
LIST_ENTRY BlpPdListHead;
/* FUNCTIONS *****************************************************************/
/*++
* @name InitializeLibrary
*
* The InitializeLibrary function initializes the Boot Library.
*
* @param BootParameters
* Pointer to the Boot Application Parameter Block.
*
* @param LibraryParameters
* Pointer to the Boot Library Parameters.
*
* @return NT_SUCCESS if the boot library was loaded correctly, relevant error
* otherwise.
*
*--*/
NTSTATUS
InitializeLibrary (
_In_ PBOOT_APPLICATION_PARAMETER_BLOCK BootAppParameters,
_In_ PBL_LIBRARY_PARAMETERS LibraryParameters
)
{
NTSTATUS Status;
PBL_MEMORY_DATA MemoryData;
PBL_APPLICATION_ENTRY AppEntry;
PBL_FIRMWARE_DESCRIPTOR FirmwareDescriptor;
LARGE_INTEGER BootFrequency;
ULONG_PTR ParamPointer;
/* Validate correct Boot Application data */
ParamPointer = (ULONG_PTR)BootAppParameters;
if (!(BootAppParameters) ||
(BootAppParameters->Signature[0] != BOOT_APPLICATION_SIGNATURE_1) ||
(BootAppParameters->Signature[1] != BOOT_APPLICATION_SIGNATURE_2) ||
(BootAppParameters->Size < sizeof(*BootAppParameters)))
{
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Get sub-structures */
MemoryData = (PBL_MEMORY_DATA)(ParamPointer + BootAppParameters->MemoryDataOffset);
FirmwareDescriptor = (PBL_FIRMWARE_DESCRIPTOR)(ParamPointer + BootAppParameters->FirmwareParametersOffset);
AppEntry = (PBL_APPLICATION_ENTRY)(ParamPointer + BootAppParameters->AppEntryOffset);
BlpBootDevice = (PBL_DEVICE_DESCRIPTOR)(ParamPointer + BootAppParameters->BootDeviceOffset);
BlpApplicationBaseDirectory = LibraryParameters->ApplicationBaseDirectory;
/* Initialize the firmware table */
Status = BlpFwInitialize(0, FirmwareDescriptor);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Find boot application entry */
if (strncmp(AppEntry->Signature, BL_APP_ENTRY_SIGNATURE, 7))
{
Status = STATUS_INVALID_PARAMETER_9;
goto Quickie;
}
/* Read parameters */
BlpApplicationParameters = BootAppParameters;
BlpLibraryParameters = *LibraryParameters;
/* Check if the caller sent us their internal BCD options */
if (AppEntry->Flags & BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL)
{
/* These are external to us now, as far as we are concerned */
AppEntry->Flags &= ~BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL;
AppEntry->Flags |= BL_APPLICATION_ENTRY_BCD_OPTIONS_EXTERNAL;
}
/* Save the application entry flags */
BlpApplicationEntry.Flags = AppEntry->Flags;
/* Copy the GUID and point to the options */
BlpApplicationEntry.Guid = AppEntry->Guid;
BlpApplicationEntry.BcdData = &AppEntry->BcdData;
/* Everything has been captured */
BlpLibraryParametersInitialized = TRUE;
/* Initialize the architecture (PM or RM) switching */
Status = BlpArchInitialize(0);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Initialize the memory manager */
Status = BlpMmInitialize(MemoryData,
BootAppParameters->MemoryTranslationType,
LibraryParameters);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"MM init failed!\r\n");
goto Quickie;
}
/* Initialize firmware now that the heap, etc works */
Status = BlpFwInitialize(1, FirmwareDescriptor);
if (!NT_SUCCESS(Status))
{
/* Destroy memory manager in phase 1 */
//BlpMmDestroy(1);
EfiPrintf(L"Firmware2 init failed!\r\n");
return Status;
}
/* Modern systems have an undocumented BCD system for the boot frequency */
Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
0x15000075,
(PULONGLONG)&BootFrequency.QuadPart);
if (NT_SUCCESS(Status) && (BootFrequency.QuadPart))
{
/* Use it if present */
BlpTimePerformanceFrequency = BootFrequency.QuadPart;
}
else
{
/* Use the TSC for calibration */
Status = BlpTimeCalibratePerformanceCounter();
if (!NT_SUCCESS(Status))
{
/* Destroy memory manager in phase 1 */
EfiPrintf(L"TSC calibration failed\r\n");
//BlpMmDestroy(1);
return Status;
}
}
/* Now setup the rest of the architecture (IDT, etc) */
Status = BlpArchInitialize(1);
if (!NT_SUCCESS(Status))
{
/* Destroy memory manager in phase 1 */
EfiPrintf(L"Arch2 init failed\r\n");
//BlpMmDestroy(1);
return Status;
}
#ifdef BL_TPM_SUPPORT
/* Initialize support for Trusted Platform Module v1.2 */
BlpTpmInitialize();
#endif
#ifdef BL_TPM_SUPPORT
/* Initialize the event manager */
EnSubsystemInitialized = 1;
InitializeListHead(&EnEventNotificationList);
#endif
/* Initialize the I/O Manager */
Status = BlpIoInitialize();
if (!NT_SUCCESS(Status))
{
/* Destroy memory manager in phase 1 and the event manager */
EfiPrintf(L"IO init failed\r\n");
#ifdef BL_TPM_SUPPORT
if (EnSubsystemInitialized)
{
BlpEnDestroy();
}
#endif
//BlpMmDestroy(1);
return Status;
}
#ifdef BL_NET_SUPPORT
/* Initialize the network stack */
Status = BlNetInitialize();
if (!NT_SUCCESS(Status))
{
/* Destroy the I/O, event, and memory managers in phase 1 */
BlpIoDestroy();
#ifdef BL_TPM_SUPPORT
if (EnSubsystemInitialized)
{
BlpEnDestroy();
}
#endif
BlpMmDestroy(1);
return Status;
}
#endif
/* Initialize the utility library */
Status = BlUtlInitialize();
if (!NT_SUCCESS(Status))
{
/* Destroy the network, I/O, event, and memory managers in phase 1 */
#ifdef BL_NET_SUPPORT
BlNetDestroy();
#endif
//BlpIoDestroy();
#ifdef BL_TPM_SUPPORT
if (EnSubsystemInitialized)
{
BlpEnDestroy();
}
#endif
//BlpMmDestroy(1);
EfiPrintf(L"Util init failed\r\n");
return Status;
}
#ifdef BL_KD_SUPPORT
/* Initialize PCI Platform Support */
PltInitializePciConfiguration();
#endif
#ifdef BL_SECURE_BOOT_SUPPORT
/* Read the current SecureBoot Policy*/
Status = BlSecureBootSetActivePolicyFromPersistedData();
if (!NT_SUCCESS(Status))
{
/* Destroy everything that we've currently set up */
#ifdef BL_KD_SUPPORT
PltDestroyPciConfiguration();
#endif
#ifdef BL_NET_SUPPORT
BlNetDestroy();
#endif
BlpIoDestroy();
#ifdef BL_TPM_SUPPORT
if (EnSubsystemInitialized)
{
BlpEnDestroy();
}
#endif
BlpMmDestroy(1);
return Status;
}
#endif
#ifdef BL_TPM_SUPPORT
/* Initialize phase 0 of the security subsystem */
SipInitializePhase0();
#endif
#ifdef BL_KD_SUPPORT
/* Bring up the boot debugger, now that SecureBoot has been processed */
BlBdInitialize();
#endif
#ifdef BL_ETW_SUPPORT
/* Initialize internal logging */
BlpLogInitialize();
#endif
/* Are graphics enabled? */
if (!(LibraryParameters->LibraryFlags & BL_LIBRARY_FLAG_NO_DISPLAY))
{
/* Initialize the graphics library */
BlpDisplayInitialize(LibraryParameters->LibraryFlags);
}
/* Initialize the boot application persistent data */
PdPersistAllocations = 0;
InitializeListHead(&BlpPdListHead);
#ifdef BL_TPM_SUPPORT
/* Now setup the security subsystem in phase 1 */
BlpSiInitialize(1);
#endif
/* Setup the text, UI and font resources */
Status = BlpResourceInitialize();
if (!NT_SUCCESS(Status))
{
/* Tear down everything if this failed */
if (!(LibraryParameters->LibraryFlags & BL_LIBRARY_FLAG_NO_DISPLAY))
{
// BlpDisplayDestroy();
}
#ifdef BL_KD_SUPPORT
BlpBdDestroy();
PltDestroyPciConfiguration();
#endif
#ifdef BL_NET_SUPPORT
BlNetDestroy();
#endif
//BlpIoDestroy();
#ifdef BL_TPM_SUPPORT
if (EnSubsystemInitialized)
{
BlpEnDestroy();
}
#endif
//BlpMmDestroy(1);
return Status;
}
#if BL_BITLOCKER_SUPPORT
/* Setup the boot cryptography library */
g_pEnvironmentData = &SymCryptEnvironmentWindowsBootLibrary;
if (SymCryptEnvWindowsBootLibInit)
{
SymCryptEnvWindowsBootLibInit();
}
#endif
/* We are fully initialized, remember this and exit with success */
BlpLibraryParameters.LibraryFlags |= BL_LIBRARY_FLAG_INITIALIZATION_COMPLETED;
Status = STATUS_SUCCESS;
Quickie:
return Status;
}
/*++
* @name BlInitializeLibrary
*
* The BlInitializeLibrary function initializes, or re-initializes, the
* Boot Library.
*
* @param BootParameters
* Pointer to the Boot Application Parameter Block.
*
* @param LibraryParameters
* Pointer to the Boot Library Parameters.
*
* @return NT_SUCCESS if the boot library was loaded correctly, relevant error
* otherwise.
*
*--*/
NTSTATUS
BlInitializeLibrary(
_In_ PBOOT_APPLICATION_PARAMETER_BLOCK BootAppParameters,
_In_ PBL_LIBRARY_PARAMETERS LibraryParameters
)
{
NTSTATUS Status;
/* Are we re-initializing the library? */
if (LibraryParameters->LibraryFlags & BL_LIBRARY_FLAG_REINITIALIZE)
{
/* From scratch? */
BlpLibraryParameters = *LibraryParameters;
if (LibraryParameters->LibraryFlags & BL_LIBRARY_FLAG_REINITIALIZE_ALL)
{
#ifdef BL_TPM_SUPPORT
/* Reinitialize the TPM security enclave as BCD hash changed */
BlpSiInitialize(1);
#endif
#ifdef BL_KD_SUPPORT
/* Reinitialize the boot debugger as BCD debug options changed */
BlBdInitialize();
#endif
/* Reparse the bad page list now that the BCD has been reloaded */
BlMmRemoveBadMemory();
/* Reparse the low/high physical address limits as well */
BlpMmInitializeConstraints();
/* Redraw the graphics console as needed */
BlpDisplayInitialize(LibraryParameters->LibraryFlags);
/* Reinitialize resources (language may have changed) */
BlpResourceInitialize();
}
/* Nothing to do, we're done */
Status = STATUS_SUCCESS;
}
else
{
/* Nope, this is first time initialization */
Status = InitializeLibrary(BootAppParameters, LibraryParameters);
}
/* Return initialization status */
return Status;
}
VOID
BlDestroyLibrary (
VOID
)
{
EfiPrintf(L"Destroy not yet implemented\r\n");
return;
}
PGUID
BlGetApplicationIdentifier (
VOID
)
{
/* Return the GUID, if one was present */
return (BlpApplicationEntry.Flags & BL_APPLICATION_ENTRY_FLAG_NO_GUID) ?
NULL : &BlpApplicationEntry.Guid;
}
NTSTATUS
BlGetApplicationBaseAndSize (
_Out_ PVOID* ImageBase,
_Out_ PULONG ImageSize
)
{
/* Fail if output parameters are missing */
if (!ImageBase || !ImageSize)
{
return STATUS_INVALID_PARAMETER;
}
/* Return the requested data */
*ImageBase = (PVOID)(ULONG_PTR)BlpApplicationParameters->ImageBase;
*ImageSize = BlpApplicationParameters->ImageSize;
return STATUS_SUCCESS;
}
VOID
BlDestroyBootEntry (
_In_ PBL_LOADED_APPLICATION_ENTRY AppEntry
)
{
/* Check if we had allocated BCD options */
if (AppEntry->Flags & BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL)
{
BlMmFreeHeap(AppEntry->BcdData);
}
/* Free the entry itself */
BlMmFreeHeap(AppEntry);
}
NTSTATUS
BlPdQueryData (
_In_ const GUID* DataGuid,
_In_ PVOID Unknown,
_Inout_ PBL_PD_DATA_BLOB DataBlob
)
{
/* Check for invalid or missing parameters */
if (!(DataBlob) ||
!(DataGuid) ||
((DataBlob->BlobSize) && !(DataBlob->Data)))
{
return STATUS_INVALID_PARAMETER;
}
/* Check if there's no persistent data blobs */
if (IsListEmpty(&BlpPdListHead))
{
return STATUS_NOT_FOUND;
}
/* Not yet handled, TODO */
EfiPrintf(L"Boot persistent data not yet implemented\r\n");
return STATUS_NOT_IMPLEMENTED;
}

0
boot/environ/lib/firmware/.gitignore vendored Normal file
View file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,35 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/firmware/fwutil.c
* PURPOSE: Boot Library Firmware Utility Functions
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
VOID
BlFwReboot (
VOID
)
{
#ifdef BL_KD_SUPPORTED
/* Stop the boot debugger*/
BlBdStop();
#endif
/* Reset the machine */
EfiResetSystem(EfiResetCold);
}
NTSTATUS
MmFwFreePages (
_In_ ULONG BasePage,
_In_ ULONG PageCount
)
{
/* Free the pages */
return EfiFreePages(PageCount, BasePage << PAGE_SHIFT);
}

0
boot/environ/lib/io/.gitignore vendored Normal file
View file

View file

@ -0,0 +1,111 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/io/blkcache.c
* PURPOSE: Boot Library Block Cache Management Routines
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
ULONG BcpBlockAllocatorHandle;
ULONG BcpHashTableId;
/* FUNCTIONS *****************************************************************/
NTSTATUS
BcpDestroy (
VOID
)
{
//BcpPurgeCacheEntries();
//return BlpMmDeleteBlockAllocator(BcpBlockAllocatorHandle);
EfiPrintf(L"Destructor for block cache not yet implemented\r\n");
return STATUS_NOT_IMPLEMENTED;
}
BOOLEAN
BcpCompareKey (
_In_ PBL_HASH_ENTRY Entry1,
_In_ PBL_HASH_ENTRY Entry2
)
{
PULONG Value1, Value2;
Value1 = Entry1->Value;
Value2 = Entry2->Value;
return Entry1->Size == Entry2->Size && Entry1->Flags == Entry2->Flags && *Value1 == *Value2 && Value1[1] == Value2[1] && Value1[2] == Value2[2];
}
ULONG
BcpHashFunction (
_In_ PBL_HASH_ENTRY Entry,
_In_ ULONG TableSize
)
{
ULONG i, j, ValueHash;
PUCHAR ValueBuffer;
j = 0;
ValueHash = 0;
i = 0;
ValueBuffer = Entry->Value;
do
{
ValueHash += ValueBuffer[i++];
} while (i < 8);
do
{
ValueHash += ValueBuffer[j++ + 8];
} while (j < 4);
return ValueHash % TableSize;
}
NTSTATUS
BcInitialize (
VOID
)
{
NTSTATUS Status;
Status = BlHtCreate(50, BcpHashFunction, BcpCompareKey, &BcpHashTableId);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
BcpBlockAllocatorHandle = BlpMmCreateBlockAllocator();
if (BcpBlockAllocatorHandle == -1)
{
Status = STATUS_UNSUCCESSFUL;
goto Quickie;
}
Status = BlpIoRegisterDestroyRoutine(BcpDestroy);
if (Status >= 0)
{
return Status;
}
Quickie:
EfiPrintf(L"Failure path not yet implemented\r\n");
#if 0
if (BcpHashTableId != -1)
{
BlHtDestroy(BcpHashTableId);
}
if (BcpBlockAllocatorHandle != -1)
{
BlpMmDeleteBlockAllocator(BcpBlockAllocatorHandle);
}
#endif
return Status;
}

2312
boot/environ/lib/io/device.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,988 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/platform/display.c
* PURPOSE: Boot Library Display Management Routines
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
#include <bcd.h>
/* DATA VARIABLES ************************************************************/
PVOID BfiCachedStrikeData;
LIST_ENTRY BfiDeferredListHead;
LIST_ENTRY BfiFontFileListHead;
PVOID BfiGraphicsRectangle;
ULONG ConsoleGraphicalResolutionListFlags;
BL_DISPLAY_MODE ConsoleGraphicalResolutionList[3] =
{
{1024, 768, 1024},
{800, 600, 800},
{1024, 600, 1024}
};
ULONG ConsoleGraphicalResolutionListSize = RTL_NUMBER_OF(ConsoleGraphicalResolutionList);
BL_DISPLAY_MODE ConsoleTextResolutionList[1] =
{
{80, 25, 80}
};
PVOID DspRemoteInputConsole;
PVOID DspTextConsole;
PVOID DspGraphicalConsole;
PVOID DspLocalInputConsole;
/* FUNCTIONS *****************************************************************/
BOOLEAN
DsppGraphicsDisabledByBcd (
VOID
)
{
BOOLEAN Disabled;
NTSTATUS Status;
/* Get the boot option, and if present, return the result */
Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
BcdLibraryBoolean_GraphicsModeDisabled,
&Disabled);
return (NT_SUCCESS(Status) && (Disabled));
}
NTSTATUS
DsppLoadFontFile (
_In_ PWCHAR FontFileName
)
{
PBL_DEVICE_DESCRIPTOR FontDevice;
NTSTATUS Status;
ULONG NameLength, DirectoryLength, TotalLength;
PWCHAR FontPath, FontDirectory;
BL_LIBRARY_PARAMETERS LibraryParameters;
BOOLEAN CustomDirectory, CustomDevice;
/* Initialize locals */
CustomDirectory = TRUE;
CustomDevice = TRUE;
FontDevice = NULL;
FontPath = NULL;
FontDirectory = NULL;
/* Check if a custom font path should be used */
Status = BlGetBootOptionString(BlpApplicationEntry.BcdData,
BcdLibraryString_FontPath,
&FontDirectory);
if (!NT_SUCCESS(Status))
{
/* Nope, use the one configured by the library */
CustomDirectory = FALSE;
RtlCopyMemory(&LibraryParameters,
&BlpLibraryParameters,
sizeof(LibraryParameters)),
FontDirectory = LibraryParameters.FontBaseDirectory;
}
/* Do we still not have a font directory? */
if (!FontDirectory)
{
/* Use the boot device and boot directory */
FontDevice = BlpBootDevice;
FontDirectory = L"\\EFI\\Microsoft\\Boot\\Fonts";
CustomDevice = FALSE;
}
else
{
/* Otherwise, if we have a font directory, what device is the app on? */
Status = BlGetBootOptionDevice(BlpApplicationEntry.BcdData,
BcdLibraryDevice_ApplicationDevice,
&FontDevice,
NULL);
if (!NT_SUCCESS(Status))
{
/* If we don't know the device, we can't open the path */
goto Quickie;
}
}
/* Figure out the length of the file name, and of the directory */
NameLength = wcslen(FontFileName);
DirectoryLength = wcslen(FontDirectory);
/* Safely add them up*/
Status = RtlULongAdd(NameLength, DirectoryLength, &TotalLength);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Convert to bytes */
Status = RtlULongLongToULong(TotalLength * sizeof(WCHAR), &TotalLength);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Add a terminating NUL */
Status = RtlULongAdd(TotalLength, sizeof(UNICODE_NULL), &TotalLength);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Allocate the final buffer for it */
FontPath = BlMmAllocateHeap(TotalLength);
if (!FontPath)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Concatenate the directory with the file name */
wcscpy(FontPath, FontDirectory);
wcscat(FontPath, FontFileName);
/* Try to load this font */
Status = BfLoadFontFile(FontDevice, FontPath);
Quickie:
/* Check if we had a custom font device allocated and free it */
if ((CustomDevice) && (FontDevice))
{
BlMmFreeHeap(FontDevice);
}
/* Check if we had a custom font directory allocated and free it */
if ((FontDirectory) && (CustomDirectory))
{
BlMmFreeHeap(FontDirectory);
}
/* Check if we had allocated a font path and free it */
if (FontPath)
{
BlMmFreeHeap(FontPath);
}
/* Return back */
return Status;
}
NTSTATUS
BlpDisplayRegisterLocale (
_In_ PWCHAR Locale
)
{
BOOLEAN StandardLocale;
NTSTATUS Status;
PWCHAR FontFileName;
PBL_DEFERRED_FONT_FILE DeferredFont;
PLIST_ENTRY NextEntry;
WCHAR Prefix[3];
/* Assume custom locale */
StandardLocale = FALSE;
/* Bail out if the locale string seems invalid */
if (wcslen(Locale) < 2)
{
return STATUS_INVALID_PARAMETER;
}
/* Check the prefix first, then traditional vs. simplified */
Prefix[0] = Locale[0];
Prefix[1] = Locale[1];
Prefix[2] = UNICODE_NULL;
if (!_wcsicmp(Prefix, L"ja"))
{
FontFileName = L"\\jpn_boot.ttf";
}
else if (!_wcsicmp(Prefix, L"ko"))
{
FontFileName = L"\\kor_boot.ttf";
}
else if (!(_wcsicmp(Locale, L"zh-CN")) ||
!(_wcsicmp(Locale, L"zh-CHS")) ||
!(_wcsicmp(Locale, L"zh-Hans")))
{
FontFileName = L"\\chs_boot.ttf";
}
else if (!(_wcsicmp(Locale, L"zh-TW")) &&
!(_wcsicmp(Locale, L"zh-CHT")) &&
!(_wcsicmp(Locale, L"zh-HK")) &&
!(_wcsicmp(Locale, L"zh-Hant")))
{
FontFileName = L"\\cht_boot.ttf";
}
else
{
StandardLocale = TRUE;
FontFileName = L"\\wgl4_boot.ttf";
}
/* Parse all the currently deferred fonts*/
NextEntry = BfiDeferredListHead.Flink;
while (NextEntry != &BfiDeferredListHead)
{
/* Grab the font */
DeferredFont = CONTAINING_RECORD(NextEntry, BL_DEFERRED_FONT_FILE, ListEntry);
/* Move to the next entry, and remove this one */
NextEntry = NextEntry->Flink;
RemoveEntryList(&DeferredFont->ListEntry);
/* Free the deferred font, we'll be loading a new one */
BfiFreeDeferredFontFile(DeferredFont);
}
/* Load the primary font */
Status = DsppLoadFontFile(FontFileName);
if (NT_SUCCESS(Status) && !(StandardLocale))
{
/* Also load the standard US one if we loaded a different one */
Status = DsppLoadFontFile(L"\\wgl4_boot.ttf");
}
/* Return back to caller */
return Status;
}
NTSTATUS
DsppInitialize (
_In_ ULONG Flags
)
{
BL_LIBRARY_PARAMETERS LibraryParameters = BlpLibraryParameters;
BOOLEAN NoGraphics, HighestMode;
NTSTATUS Status;
PBL_DISPLAY_MODE DisplayMode;
ULONGLONG GraphicsResolution;
PBL_GRAPHICS_CONSOLE GraphicsConsole;
PBL_TEXT_CONSOLE TextConsole, RemoteConsole;
/* Initialize font data */
BfiCachedStrikeData = 0;
InitializeListHead(&BfiDeferredListHead);
InitializeListHead(&BfiFontFileListHead);
/* Allocate the font rectangle */
BfiGraphicsRectangle = BlMmAllocateHeap(90);
if (!BfiGraphicsRectangle)
{
return STATUS_NO_MEMORY;
}
/* Check if display re-initialization is requested */
if (LibraryParameters.LibraryFlags & BL_LIBRARY_FLAG_REINITIALIZE_ALL)
{
/* Recreate a local input console */
ConsoleCreateLocalInputConsole();
}
/* Check if no graphics console is needed */
if ((Flags & BL_LIBRARY_FLAG_NO_GRAPHICS_CONSOLE) ||
(DsppGraphicsDisabledByBcd()))
{
/* Remember this */
NoGraphics = TRUE;
}
else
{
/* No graphics -- remember this */
NoGraphics = FALSE;
}
/* On first load, we always initialize a graphics display */
GraphicsConsole = NULL;
if (!(Flags & BL_LIBRARY_FLAG_REINITIALIZE_ALL) || !(NoGraphics))
{
/* Default to mode 0 (1024x768) */
DisplayMode = &ConsoleGraphicalResolutionList[0];
/* Check what resolution to use*/
Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
BcdLibraryInteger_GraphicsResolution,
&GraphicsResolution);
if (NT_SUCCESS(Status))
{
ConsoleGraphicalResolutionListFlags |= BL_DISPLAY_GRAPHICS_FORCED_VIDEO_MODE_FLAG;
EfiPrintf(L"Display selection not yet handled\r\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Check if the highest mode should be forced */
Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
BcdLibraryBoolean_GraphicsForceHighestMode,
&HighestMode);
if (NT_SUCCESS(Status))
{
ConsoleGraphicalResolutionListFlags |= BL_DISPLAY_GRAPHICS_FORCED_HIGH_RES_MODE_FLAG;
EfiPrintf(L"High res mode not yet handled\r\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Do we need graphics mode after all? */
if (!NoGraphics)
{
/* Yep -- go allocate it */
GraphicsConsole = BlMmAllocateHeap(sizeof(*GraphicsConsole));
if (GraphicsConsole)
{
/* Construct it */
Status = ConsoleGraphicalConstruct(GraphicsConsole);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"GFX FAILED: %lx\r\n", Status);
BlMmFreeHeap(GraphicsConsole);
GraphicsConsole = NULL;
}
}
}
/* Are we using something else than the default mode? */
if (DisplayMode != &ConsoleGraphicalResolutionList[0])
{
EfiPrintf(L"Display path not handled\r\n");
return STATUS_NOT_SUPPORTED;
}
/* Mask out all the flags now */
ConsoleGraphicalResolutionListFlags &= ~(BL_DISPLAY_GRAPHICS_FORCED_VIDEO_MODE_FLAG |
BL_DISPLAY_GRAPHICS_FORCED_HIGH_RES_MODE_FLAG);
}
/* Do we have a graphics console? */
TextConsole = NULL;
if (!GraphicsConsole)
{
/* Nope -- go allocate a text console */
TextConsole = BlMmAllocateHeap(sizeof(*TextConsole));
if (TextConsole)
{
/* Construct it */
Status = ConsoleTextLocalConstruct(TextConsole, TRUE);
if (!NT_SUCCESS(Status))
{
BlMmFreeHeap(TextConsole);
TextConsole = NULL;
}
}
}
/* Initialize all globals to NULL */
DspRemoteInputConsole = NULL;
DspTextConsole = NULL;
DspGraphicalConsole = NULL;
/* If we don't have a text console, go get a remote console */
RemoteConsole = NULL;
if (!TextConsole)
{
ConsoleCreateRemoteConsole(&RemoteConsole);
}
/* Do we have a remote console? */
if (!RemoteConsole)
{
/* Nope -- what about a graphical one? */
if (GraphicsConsole)
{
/* Yes, use it for both graphics and text */
DspGraphicalConsole = GraphicsConsole;
DspTextConsole = GraphicsConsole;
}
else if (TextConsole)
{
/* Nope, but we have a text console */
DspTextConsole = TextConsole;
}
/* Console has been setup */
return STATUS_SUCCESS;
}
/* We have a remote console -- have to figure out how to use it*/
EfiPrintf(L"Display path not handled\r\n");
return STATUS_NOT_SUPPORTED;
}
NTSTATUS
DsppReinitialize (
_In_ ULONG Flags
)
{
PBL_TEXT_CONSOLE TextConsole;
PBL_GRAPHICS_CONSOLE GraphicsConsole;
NTSTATUS Status;
ULONGLONG GraphicsResolution;
BOOLEAN HighestMode;
BL_DISPLAY_MODE CurrentResolution;
/* Do we have local input yet? */
if (!DspLocalInputConsole)
{
/* Create it now */
ConsoleCreateLocalInputConsole();
}
/* If a graphics console is present without a remote console... */
TextConsole = NULL;
if (!(DspRemoteInputConsole) && (DspGraphicalConsole))
{
/* Try to create a remote console */
ConsoleCreateRemoteConsole(&TextConsole);
}
/* All good for now */
Status = STATUS_SUCCESS;
/* Now check if we were able to create the remote console */
if (TextConsole)
{
EfiPrintf(L"EMS not supported\r\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Set a local for the right cast */
GraphicsConsole = DspGraphicalConsole;
/* Nothing to do without a graphics console being reinitialized */
if (!(Flags & BL_LIBRARY_FLAG_REINITIALIZE_ALL) ||
!(GraphicsConsole) ||
!(((PBL_GRAPHICS_CONSOLE_VTABLE)GraphicsConsole->TextConsole.Callbacks)->IsEnabled(GraphicsConsole)))
{
return Status;
}
/* Check if graphics are disabled in the BCD */
if (DsppGraphicsDisabledByBcd())
{
/* Turn off the graphics console, switching back to text mode */
Status = ((PBL_GRAPHICS_CONSOLE_VTABLE)GraphicsConsole->TextConsole.Callbacks)->Enable(GraphicsConsole, FALSE);
}
/* Check if a custom graphics resolution is set */
if (MiscGetBootOption(BlpApplicationEntry.BcdData,
BcdLibraryInteger_GraphicsResolution))
{
/* Check what it's set to */
Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
BcdLibraryInteger_GraphicsResolution,
&GraphicsResolution);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Now check our current graphical resolution */
Status = ((PBL_GRAPHICS_CONSOLE_VTABLE)GraphicsConsole->TextConsole.Callbacks)->GetGraphicalResolution(GraphicsConsole,
&CurrentResolution);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Remember that we're forcing a video mode */
ConsoleGraphicalResolutionListFlags |= BL_DISPLAY_GRAPHICS_FORCED_VIDEO_MODE_FLAG;
/* Check which resolution to set */
if (!GraphicsResolution)
{
/* 1024x768 */
EfiPrintf(L"Display selection not yet handled\r\n");
return STATUS_NOT_IMPLEMENTED;
}
else if (GraphicsResolution == 1)
{
/* 800x600 */
EfiPrintf(L"Display selection not yet handled\r\n");
return STATUS_NOT_IMPLEMENTED;
}
else if (GraphicsResolution == 2)
{
/* 1024x600 */
EfiPrintf(L"Display selection not yet handled\r\n");
return STATUS_NOT_IMPLEMENTED;
}
}
/* Check if the force highest mode setting is present */
if (MiscGetBootOption(BlpApplicationEntry.BcdData,
BcdLibraryBoolean_GraphicsForceHighestMode))
{
/* Check what it's set to */
Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
BcdLibraryBoolean_GraphicsForceHighestMode,
&HighestMode);
if ((NT_SUCCESS(Status)) && (HighestMode))
{
/* Remember that high rest mode is being forced */
ConsoleGraphicalResolutionListFlags |= BL_DISPLAY_GRAPHICS_FORCED_HIGH_RES_MODE_FLAG;
/* Turn it on */
//((PBL_GRAPHICS_CONSOLE_VTABLE)GraphicsConsole->TextConsole.Callbacks)->SetGraphicalResolution(GraphicsConsole, 0, 0);
/* All done now */
ConsoleGraphicalResolutionListFlags |= ~BL_DISPLAY_GRAPHICS_FORCED_HIGH_RES_MODE_FLAG;
EfiPrintf(L"High res mode not yet handled\r\n");
Status = STATUS_NOT_IMPLEMENTED;
}
}
/* Return back to the caller */
return Status;
}
NTSTATUS
BlpDisplayReinitialize (
VOID
)
{
NTSTATUS Status = STATUS_SUCCESS;
PBL_TEXT_CONSOLE TextConsole;
PBL_INPUT_CONSOLE InputConsole;
/* Do we have a local console? */
InputConsole = DspLocalInputConsole;
if (InputConsole)
{
/* Reinitialize it */
Status = InputConsole->Callbacks->Reinitialize((PBL_TEXT_CONSOLE)InputConsole);
if (!NT_SUCCESS(Status))
{
return Status;
}
}
/* Do we have a text console? */
TextConsole = DspTextConsole;
if (TextConsole)
{
/* Reinitialize it */
Status = TextConsole->Callbacks->Reinitialize(TextConsole);
}
/* Return status */
return Status;
}
NTSTATUS
BlpDisplayInitialize (
_In_ ULONG Flags
)
{
NTSTATUS Status;
/* Are we resetting or initializing? */
if (Flags & BL_LIBRARY_FLAG_REINITIALIZE)
{
/* This is a reset */
Status = DsppReinitialize(Flags);
if (NT_SUCCESS(Status))
{
/* Re-initialize the class as well */
Status = BlpDisplayReinitialize();
}
}
else
{
/* Initialize the display */
Status = DsppInitialize(Flags);
}
/* Return display initialization state */
return Status;
}
VOID
BlDisplayGetTextCellResolution (
_Out_ PULONG TextWidth,
_Out_ PULONG TextHeight
)
{
NTSTATUS Status;
PBL_GRAPHICS_CONSOLE GraphicsConsole;
/* If the caller doesn't want anything, bail out */
if (!(TextWidth) || !(TextHeight))
{
return;
}
/* Do we have a text console? */
Status = STATUS_UNSUCCESSFUL;
if (DspTextConsole)
{
/* Do we have a graphics console? */
GraphicsConsole = DspGraphicalConsole;
if (GraphicsConsole)
{
/* Is it currently active? */
if (((PBL_GRAPHICS_CONSOLE_VTABLE)GraphicsConsole->TextConsole.Callbacks)->IsEnabled(GraphicsConsole))
{
/* Yep -- query it */
EfiPrintf(L"GFX active, not supported query\r\n");
Status = STATUS_NOT_IMPLEMENTED;
//Status = ((PBL_GRAPHICS_CONSOLE_VTABLE)GraphicsConsole->TextConsole.Callbacks)->GetTextCellResolution(GraphicsConsole);
}
}
}
/* Check if we failed to get it from the graphics console */
if (!NT_SUCCESS(Status))
{
/* Set default text size */
*TextWidth = 8;
*TextHeight = 8;
}
}
NTSTATUS
BlDisplaySetScreenResolution (
VOID
)
{
PBL_GRAPHICS_CONSOLE Console;
NTSTATUS Status;
/* Assume success */
Status = STATUS_SUCCESS;
/* Do we have a graphics console? */
Console = DspGraphicalConsole;
if (Console)
{
/* Is it currently active? */
if (((PBL_GRAPHICS_CONSOLE_VTABLE)Console->TextConsole.Callbacks)->IsEnabled(Console))
{
/* If so, disable it */
return ((PBL_GRAPHICS_CONSOLE_VTABLE)Console->TextConsole.Callbacks)->Enable(Console, FALSE);
}
}
/* We should've now fallen back to text mode */
if (!DspTextConsole)
{
/* Then fail, as no display appears active */
Status = STATUS_UNSUCCESSFUL;
}
/* Return back to the caller */
return Status;
}
NTSTATUS
BlDisplayGetScreenResolution (
_Out_ PULONG HRes,
_Out_ PULONG VRes
)
{
NTSTATUS Status;
BL_DISPLAY_MODE Resolution;
PBL_GRAPHICS_CONSOLE GraphicsConsole;
/* Assume failure if no consoles are active */
Status = STATUS_UNSUCCESSFUL;
/* Do we have a text console? */
if (DspTextConsole)
{
/* Do we have an active graphics console? */
GraphicsConsole = DspGraphicalConsole;
if ((GraphicsConsole) &&
(((PBL_GRAPHICS_CONSOLE_VTABLE)GraphicsConsole->TextConsole.Callbacks)->IsEnabled(GraphicsConsole)))
{
/* Get the resolution */
Status = ((PBL_GRAPHICS_CONSOLE_VTABLE)GraphicsConsole->TextConsole.Callbacks)->GetGraphicalResolution(GraphicsConsole, &Resolution);
if (NT_SUCCESS(Status))
{
/* Return it back to the caller */
*HRes = Resolution.HRes;
*VRes = Resolution.VRes;
}
}
else
{
/* Return defaults */
*HRes = 640;
*VRes = 200;
Status = STATUS_SUCCESS;
}
}
/* Return if we got a valid resolution back */
return Status;
}
VOID
BlDisplayInvalidateOemBitmap (
VOID
)
{
PBGRT_TABLE BgrtTable;
NTSTATUS Status;
/* Search for the BGRT */
Status = BlUtlGetAcpiTable((PVOID*)&BgrtTable, BGRT_SIGNATURE);
if (NT_SUCCESS(Status))
{
/* Mark the bitmap as invalid */
BgrtTable->Status &= ~BGRT_STATUS_IMAGE_VALID;
/* Unmap the table */
BlMmUnmapVirtualAddressEx(BgrtTable, BgrtTable->Header.Length);
}
}
PBITMAP
BlDisplayGetOemBitmap (
_In_opt_ PCOORD Offsets,
_Out_opt_ PULONG Flags
)
{
NTSTATUS Status;
ULONG Size;
PHYSICAL_ADDRESS PhysicalAddress;
PBGRT_TABLE BgrtTable;
PBITMAP Bitmap;
PBMP_HEADER Header;
Bitmap = NULL;
BgrtTable = NULL;
/* Search for the BGRT */
Status = BlUtlGetAcpiTable((PVOID*)&BgrtTable, BGRT_SIGNATURE);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Make sure this is really a BGRT */
if (BgrtTable->Header.Signature != BGRT_SIGNATURE)
{
Status = STATUS_ACPI_INVALID_TABLE;
goto Quickie;
}
/* Make sure the BGRT table length is valid */
if (BgrtTable->Header.Length != sizeof(*BgrtTable))
{
Status = STATUS_ACPI_INVALID_TABLE;
goto Quickie;
}
/* Make sure its a bitmap */
if (BgrtTable->ImageType != BgrtImageTypeBitmap)
{
Status = STATUS_ACPI_INVALID_TABLE;
goto Quickie;
}
/* Make sure it's somewhere in RAM */
if (!BgrtTable->LogoAddress)
{
Status = STATUS_ACPI_INVALID_TABLE;
goto Quickie;
}
/* Map the bitmap header only for now */
PhysicalAddress.QuadPart = BgrtTable->LogoAddress;
Status = BlMmMapPhysicalAddressEx((PVOID*)&Header,
0,
sizeof(BMP_HEADER),
PhysicalAddress);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Capture the real size of the header */
Size = Header->Size;
/* Unmap the bitmap header */
BlMmUnmapVirtualAddressEx(BgrtTable, sizeof(BMP_HEADER));
/* If the real size is smaller than at least a V3 bitmap, bail out */
if (Size < sizeof(BITMAP))
{
Status = STATUS_ACPI_INVALID_TABLE;
goto Quickie;
}
/* Map the real size of the header */
Status = BlMmMapPhysicalAddressEx((PVOID*)&Bitmap,
0,
Size,
PhysicalAddress);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Make sure this is a non-compressed 24-bit or 32-bit V3 bitmap */
if ((Bitmap->BmpHeader.Signature != 'MB') ||
(Bitmap->DibHeader.Compression) ||
((Bitmap->DibHeader.BitCount != 24) &&
(Bitmap->DibHeader.BitCount != 32)) ||
(Bitmap->DibHeader.Size != sizeof(DIB_HEADER)))
{
Status = STATUS_ACPI_INVALID_TABLE;
goto Quickie;
}
/* Check if caller wants the offsets back */
if (Offsets)
{
/* Give them away */
Offsets->X = BgrtTable->OffsetX;
Offsets->Y = BgrtTable->OffsetY;
}
/* Check if the caller wants flags */
if (Flags)
{
/* Return if the image is valid */
*Flags = BgrtTable->Status & BGRT_STATUS_IMAGE_VALID;
}
Quickie:
/* Check if we had mapped the BGRT */
if (BgrtTable)
{
/* Unmap it */
BlMmUnmapVirtualAddressEx(BgrtTable, BgrtTable->Header.Length);
}
/* Check if this is the failure path */
if (!NT_SUCCESS(Status))
{
/* Did we have the OEM bitmap mapped? */
if (Bitmap)
{
/* Unmap it */
BlMmUnmapVirtualAddressEx(Bitmap, Bitmap->BmpHeader.Size);
}
/* No bitmap to return */
Bitmap = NULL;
}
/* Return the bitmap back, if any */
return Bitmap;
}
BOOLEAN
BlDisplayValidOemBitmap (
VOID
)
{
PBITMAP Bitmap;
ULONG HRes, VRes, Height, Width, Flags;
COORD Offsets;
BOOLEAN Result;
NTSTATUS Status;
/* First check if mobile graphics are enabled */
Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
BcdLibraryBoolean_MobileGraphics,
&Result);
if ((NT_SUCCESS(Status)) && (Result))
{
/* Yes, so use the firmware image */
return TRUE;
}
/* Nope, so we'll check the ACPI OEM bitmap */
Result = FALSE;
Bitmap = BlDisplayGetOemBitmap(&Offsets, &Flags);
/* Is there one? */
if (Bitmap)
{
/* Is it valid? */
if (Flags & BGRT_STATUS_IMAGE_VALID)
{
/* Get the current screen resolution */
Status = BlDisplayGetScreenResolution(&HRes, &VRes);
if (NT_SUCCESS(Status))
{
/* Is there a valid width? */
Width = Bitmap->DibHeader.Width;
if (Width)
{
/* Is there a valid height? */
Height = Bitmap->DibHeader.Height;
if (Height)
{
/* Will if fit on this screen? */
if (((Width + Offsets.X) <= HRes) &&
((Height + Offsets.Y) <= VRes))
{
/* Then it's all good! */
Result = TRUE;
}
}
}
}
}
/* Unmap the bitmap for now, it will be drawn later */
BlMmUnmapVirtualAddressEx(Bitmap, Bitmap->BmpHeader.Size);
}
/* Return that a valid OEM bitmap exists */
return Result;
}
NTSTATUS
BlDisplayClearScreen (
VOID
)
{
NTSTATUS Status;
PBL_TEXT_CONSOLE TextConsole;
/* Nothing to do if there's no text console */
Status = STATUS_SUCCESS;
TextConsole = DspTextConsole;
if (TextConsole)
{
/* Otherwise, clear the whole screen */
Status = TextConsole->Callbacks->ClearText(TextConsole, FALSE);
if (NT_SUCCESS(Status))
{
/* Invalidate the OEM bitmap at this point */
BlDisplayInvalidateOemBitmap();
}
}
/* All done */
return Status;
};
NTSTATUS
BlDisplaySetCursorType (
_In_ ULONG Type
)
{
NTSTATUS Status;
PBL_TEXT_CONSOLE TextConsole;
BL_DISPLAY_STATE State;
/* Nothing to do if there's no text console */
Status = STATUS_SUCCESS;
TextConsole = DspTextConsole;
if (TextConsole)
{
/* Write visibility state and call the function to change it */
State.CursorVisible = Type;
Status = TextConsole->Callbacks->SetTextState(TextConsole, 8, &State);
}
/* All done */
return Status;
}

View file

@ -0,0 +1,280 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/io/display/efi/gop.c
* PURPOSE: Boot Library EFI GOP Routines
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
/* FUNCTIONS *****************************************************************/
NTSTATUS
ConsoleEfiGopGetGraphicalFormat (
_In_ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *ModeInfo,
_Out_ PULONG PixelDepth
)
{
/* Convert the format to depth */
if (ModeInfo->PixelFormat == PixelBlueGreenRedReserved8BitPerColor)
{
*PixelDepth = 32;
return STATUS_SUCCESS;
}
if (ModeInfo->PixelFormat == PixelBitMask)
{
*PixelDepth = 24;
return STATUS_SUCCESS;
}
return STATUS_UNSUCCESSFUL;
}
BOOLEAN
ConsoleEfiGopIsPixelFormatSupported (
_In_ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Mode
)
{
BOOLEAN Supported;
EFI_PIXEL_BITMASK PixelMask;
Supported = FALSE;
/* Check if it's simple BGR8 */
if (Mode->PixelFormat == PixelBlueGreenRedReserved8BitPerColor)
{
Supported = TRUE;
}
else
{
/* Otherwise, we can check if it's a masked format */
if (Mode->PixelFormat == PixelBitMask)
{
/* Check if the masked format is BGR8 */
PixelMask.BlueMask = 0xFF;
PixelMask.GreenMask = 0xFF00;
PixelMask.RedMask = 0xFF0000;
PixelMask.ReservedMask = 0;
if (RtlEqualMemory(&Mode->PixelInformation,
&PixelMask,
sizeof(PixelMask)))
{
Supported = TRUE;
}
}
}
/* Return if the format was supported */
return Supported;
}
NTSTATUS
ConsoleEfiGopFindModeFromAllowed (
_In_ EFI_GRAPHICS_OUTPUT_PROTOCOL *GopProtocol,
_In_ PBL_DISPLAY_MODE SupportedModes,
_In_ ULONG MaximumIndex,
_Out_ PULONG SupportedMode
)
{
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
ConsoleEfiGopEnable (
_In_ PBL_GRAPHICS_CONSOLE GraphicsConsole
)
{
PVOID FrameBuffer;
UINTN CurrentMode, Dummy;
ULONG Mode, PixelDepth;
UINTN FrameBufferSize;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION ModeInformation;
EFI_GRAPHICS_OUTPUT_PROTOCOL* Protocol;
NTSTATUS Status;
PHYSICAL_ADDRESS FrameBufferPhysical;
/* Capture the current mode and protocol */
Mode = GraphicsConsole->Mode;
Protocol = GraphicsConsole->Protocol;
/* Get the current mode and its information */
Status = EfiGopGetCurrentMode(Protocol, &CurrentMode, &ModeInformation);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Check if we're not in the mode we should be */
if (CurrentMode != Mode)
{
/* Switch modes */
Status = EfiGopSetMode(Protocol, Mode);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Reset the OEM bitmap and get the new more information */
BlDisplayInvalidateOemBitmap();
EfiGopGetCurrentMode(Protocol, &Dummy, &ModeInformation);
}
/* Get the pixel depth for this mode */
Status = ConsoleEfiGopGetGraphicalFormat(&ModeInformation, &PixelDepth);
if (NT_SUCCESS(Status))
{
/* Get the framebuffer for this mode */
EfiGopGetFrameBuffer(Protocol, &FrameBufferPhysical, &FrameBufferSize);
/* Map the framebuffer, try as writeback first */
FrameBuffer = NULL;
Status = BlMmMapPhysicalAddressEx(&FrameBuffer,
BlMemoryWriteBack,
FrameBufferSize,
FrameBufferPhysical);
if (!NT_SUCCESS(Status))
{
/* That didn't work, so try uncached next */
Status = BlMmMapPhysicalAddressEx(&FrameBuffer,
BlMemoryUncached,
FrameBufferSize,
FrameBufferPhysical);
}
}
/* Check if getting all the required information worked out */
if (NT_SUCCESS(Status))
{
/* Capture the resolution, depth, and framebuffer information */
GraphicsConsole->DisplayMode.HRes = ModeInformation.HorizontalResolution;
GraphicsConsole->DisplayMode.VRes = ModeInformation.VerticalResolution;
GraphicsConsole->DisplayMode.HRes2 = ModeInformation.PixelsPerScanLine;
GraphicsConsole->PixelDepth = PixelDepth;
GraphicsConsole->FrameBuffer = FrameBuffer;
GraphicsConsole->FrameBufferSize = FrameBufferSize;
GraphicsConsole->PixelsPerScanLine = ModeInformation.PixelsPerScanLine;
/* All good */
Status = STATUS_SUCCESS;
}
else if (CurrentMode != GraphicsConsole->Mode)
{
/* We failed somewhere, reset the mode and the OEM bitmap back */
EfiGopSetMode(Protocol, CurrentMode);
BlDisplayInvalidateOemBitmap();
}
/* Return back to caller */
return Status;
}
VOID
ConsoleEfiGopClose (
_In_ PBL_GRAPHICS_CONSOLE GraphicsConsole
)
{
ULONG OldMode;
/* Did we switch modes when we turned on the console? */
OldMode = GraphicsConsole->OldMode;
if (GraphicsConsole->Mode != OldMode)
{
/* Restore the old mode and reset the OEM bitmap in ACPI */
EfiGopSetMode(GraphicsConsole->Protocol, OldMode);
BlDisplayInvalidateOemBitmap();
}
/* Close the GOP protocol */
EfiCloseProtocol(GraphicsConsole->Handle,
&EfiGraphicsOutputProtocol);
}
NTSTATUS
ConsoleEfiGopOpen (
_In_ PBL_GRAPHICS_CONSOLE GraphicsConsole
)
{
NTSTATUS Status;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GopProtocol;
ULONG Mode, PixelDepth;
UINTN CurrentMode;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION ModeInformation;
BOOLEAN CurrentModeOk;
/* Open a handle to GOP */
Status = EfiOpenProtocol(GraphicsConsole->Handle,
&EfiGraphicsOutputProtocol,
(PVOID*)&GopProtocol);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"GOP OPEN failed: %lx\r\n", Status);
return STATUS_NOT_SUPPORTED;
}
/* Get the current mode */
Status = EfiGopGetCurrentMode(GopProtocol, &CurrentMode, &ModeInformation);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"GOP mode failed: %lx\r\n", Status);
goto Quickie;
}
Mode = CurrentMode;
/* Check if any custom BCD options were provided */
if (ConsoleGraphicalResolutionListFlags &
(BL_DISPLAY_GRAPHICS_FORCED_VIDEO_MODE_FLAG |
BL_DISPLAY_GRAPHICS_FORCED_HIGH_RES_MODE_FLAG))
{
/* We'll have to find a mode */
CurrentModeOk = FALSE;
}
else
{
/* Then we should be in the default mode, check if the pixel format is OK */
CurrentModeOk = ConsoleEfiGopIsPixelFormatSupported(&ModeInformation);
}
/* Is the mode/format OK? */
if (!CurrentModeOk)
{
/* Nope -- we'll have to go find one */
Status = ConsoleEfiGopFindModeFromAllowed(GopProtocol,
ConsoleGraphicalResolutionList,
ConsoleGraphicalResolutionListSize,
&Mode);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
}
/* Store mode information */
GraphicsConsole->Protocol = GopProtocol;
GraphicsConsole->Mode = Mode;
GraphicsConsole->OldMode = CurrentMode;
/* Get format information */
Status = ConsoleEfiGopGetGraphicalFormat(&ModeInformation, &PixelDepth);
if (NT_SUCCESS(Status))
{
/* Store it */
GraphicsConsole->OldDisplayMode.HRes = ModeInformation.HorizontalResolution;
GraphicsConsole->OldDisplayMode.VRes = ModeInformation.VerticalResolution;
GraphicsConsole->OldDisplayMode.HRes2 = ModeInformation.PixelsPerScanLine;
GraphicsConsole->PixelDepth = PixelDepth;
return STATUS_SUCCESS;
}
Quickie:
/* We failed, close the protocol and return the failure code */
EfiPrintf(L"Get format failed: %lx\r\n", Status);
EfiCloseProtocol(GraphicsConsole->Handle, &EfiGraphicsOutputProtocol);
return Status;
}

View file

@ -0,0 +1,168 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/io/display/efi/guicons.c
* PURPOSE: Boot Library EFI GUI Console Routines
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
/* FUNCTIONS *****************************************************************/
VOID
ConsoleFirmwareGraphicalClose (
_In_ PBL_GRAPHICS_CONSOLE GraphicsConsole
)
{
/* Call the correct close routine based on the console mode */
if (GraphicsConsole->Type == BlUgaConsole)
{
ConsoleEfiUgaClose(GraphicsConsole);
}
else
{
ConsoleEfiGopClose(GraphicsConsole);
}
}
NTSTATUS
ConsoleEfiGraphicalOpenProtocol (
_In_ PBL_GRAPHICS_CONSOLE GraphicsConsole,
_In_ BL_GRAPHICS_CONSOLE_TYPE Type
)
{
ULONG HandleIndex, HandleCount;
EFI_HANDLE* HandleArray;
EFI_HANDLE Handle;
NTSTATUS Status;
PVOID Interface;
/* Find a device handle that implements either GOP or UGA */
HandleCount = 0;
HandleArray = NULL;
Status = EfiLocateHandleBuffer(ByProtocol,
(Type == BlGopConsole) ?
&EfiGraphicsOutputProtocol :
&EfiUgaDrawProtocol,
&HandleCount,
&HandleArray);
if (!NT_SUCCESS(Status))
{
/* Nothing supports this (no video card?) */
EfiPrintf(L"Status: %lx Count: %d\r\n", Status, HandleCount);
return STATUS_UNSUCCESSFUL;
}
/* Scan through the handles we received */
for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++)
{
/* Try to open each one */
GraphicsConsole->Handle = HandleArray[HandleIndex];
Handle = HandleArray[HandleIndex];
Status = EfiOpenProtocol(Handle, &EfiDevicePathProtocol, &Interface);
if (NT_SUCCESS(Status))
{
/* Test worked, close the protocol */
EfiCloseProtocol(Handle, &EfiDevicePathProtocol);
/* Now open the real protocol we want, either UGA or GOP */
Status = Type ? ConsoleEfiUgaOpen(GraphicsConsole) :
ConsoleEfiGopOpen(GraphicsConsole);
if (NT_SUCCESS(Status))
{
/* It worked -- store the type of console this is */
GraphicsConsole->Type = Type;
return STATUS_SUCCESS;
}
}
}
/* We failed to find a working GOP/UGA protocol provider */
return STATUS_UNSUCCESSFUL;
}
NTSTATUS
ConsoleFirmwareGraphicalClear (
_In_ PBL_GRAPHICS_CONSOLE Console,
_In_ ULONG Color
)
{
NTSTATUS Status;
UCHAR Pixel[4] = { 0 };
/* Convert the standard color to a firmware pixel color */
Status = ConsolepConvertColorToPixel(Color, Pixel);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Check if this is GOP or UGA */
if (Console->Type == BlUgaConsole)
{
EfiPrintf(L"Uga not supported\r\n");
Status = STATUS_NOT_IMPLEMENTED;
}
else
{
/* For GOP, just fill the screen */
ConsolepClearBuffer(Console->FrameBuffer,
Console->DisplayMode.HRes,
Pixel,
Console->DisplayMode.VRes,
Console->PixelsPerScanLine,
Console->PixelDepth);
Status = STATUS_SUCCESS;
}
/* All clear */
return Status;
}
NTSTATUS
ConsoleFirmwareGraphicalEnable (
_In_ PBL_GRAPHICS_CONSOLE GraphicsConsole
)
{
NTSTATUS Status;
/* Check what type of console this is */
if (GraphicsConsole->Type == BlUgaConsole)
{
/* Handle UGA */
Status = ConsoleEfiUgaSetResolution(GraphicsConsole,
&GraphicsConsole->DisplayMode,
1);
}
else
{
/* Handle GOP */
Status = ConsoleEfiGopEnable(GraphicsConsole);
}
/* Return back to caller */
return Status;
}
VOID
ConsoleFirmwareGraphicalDisable (
_In_ PBL_GRAPHICS_CONSOLE GraphicsConsole
)
{
/* Is this a GOP console? */
if (GraphicsConsole->Type == BlGopConsole)
{
/* Did we map a framebuffer? */
if (GraphicsConsole->FrameBuffer)
{
/* Unmap it */
BlMmUnmapVirtualAddressEx(GraphicsConsole->FrameBuffer,
GraphicsConsole->FrameBufferSize);
}
}
}

View file

@ -0,0 +1,625 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/io/display/efi/textcons.c
* PURPOSE: Boot Library EFI Text Console Routines
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
/* FUNCTIONS *****************************************************************/
BL_COLOR
ConsoleEfiTextGetColorForeground (
_In_ UINT32 Attributes
)
{
/* Read the foreground color attribute and convert to CGA color index */
switch (Attributes & 0x0F)
{
case EFI_BLACK:
return Black;
case EFI_BLUE:
return Blue;
case EFI_GREEN:
return Green;
case EFI_RED:
return Red;
case EFI_CYAN:
return Cyan;
case EFI_MAGENTA:
return Magenta;
case EFI_BROWN:
return Brown;
case EFI_LIGHTGRAY:
return LtGray;
case EFI_DARKGRAY:
return Gray;
case EFI_LIGHTBLUE:
return LtBlue;
case EFI_LIGHTGREEN:
return LtGreen;
case EFI_LIGHTCYAN:
return LtCyan;
case EFI_LIGHTRED:
return LtRed;
case EFI_LIGHTMAGENTA:
return LtMagenta;
case EFI_YELLOW:
return Yellow;
case EFI_WHITE:
default:
return White;
}
}
BL_COLOR
ConsoleEfiTextGetColorBackground (
_In_ UINT32 Attributes
)
{
/* Read the background color attribute and convert to CGA color index */
switch (Attributes & 0xF0)
{
case EFI_BACKGROUND_MAGENTA:
return Magenta;
case EFI_BACKGROUND_BROWN:
return Brown;
case EFI_BACKGROUND_LIGHTGRAY:
return White;
case EFI_BACKGROUND_BLACK:
default:
return Black;
case EFI_BACKGROUND_RED:
return Red;
case EFI_BACKGROUND_GREEN:
return Green;
case EFI_BACKGROUND_CYAN:
return Cyan;
case EFI_BACKGROUND_BLUE:
return Blue;
}
}
ULONG
ConsoleEfiTextGetEfiColorBackground (
_In_ BL_COLOR Color
)
{
/* Convert the CGA color index into an EFI background attribute */
switch (Color)
{
case Blue:
case LtBlue:
return EFI_BACKGROUND_BLUE;
case Green:
case LtGreen:
return EFI_BACKGROUND_GREEN;
case Cyan:
case LtCyan:
return EFI_BACKGROUND_CYAN;
case Red:
case LtRed:
return EFI_BACKGROUND_RED;
case Magenta:
case LtMagenta:
return EFI_BACKGROUND_MAGENTA;
case Brown:
case Yellow:
return EFI_BACKGROUND_BROWN;
case LtGray:
case White:
return EFI_BACKGROUND_LIGHTGRAY;
case Black:
case Gray:
default:
return EFI_BACKGROUND_BLACK;
}
}
ULONG
ConsoleEfiTextGetEfiColorForeground (
_In_ BL_COLOR Color
)
{
/* Convert the CGA color index into an EFI foreground attribute */
switch (Color)
{
case Black:
return EFI_BLACK;
case Blue:
return EFI_BLUE;
case Green:
return EFI_GREEN;
case Cyan:
return EFI_CYAN;
case Red:
return EFI_RED;
case Magenta:
return EFI_MAGENTA;
case Brown:
return EFI_BROWN;
case LtGray:
return EFI_LIGHTGRAY;
case Gray:
return EFI_DARKGRAY;
case LtBlue:
return EFI_LIGHTBLUE;
case LtGreen:
return EFI_LIGHTGREEN;
case LtCyan:
return EFI_LIGHTCYAN;
case LtRed:
return EFI_LIGHTRED;
case LtMagenta:
return EFI_LIGHTMAGENTA;
case Yellow:
return EFI_YELLOW;
case White:
default:
return EFI_WHITE;
}
}
ULONG
ConsoleEfiTextGetAttribute (
BL_COLOR BgColor,
BL_COLOR FgColor
)
{
/* Convert each part and OR into a single attribute */
return ConsoleEfiTextGetEfiColorBackground(BgColor) |
ConsoleEfiTextGetEfiColorForeground(FgColor);
}
VOID
ConsoleEfiTextGetStateFromMode (
_In_ EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode,
_Out_ PBL_DISPLAY_STATE State
)
{
ULONG TextWidth, TextHeight;
/* Get all the EFI data and convert it into our own structure */
BlDisplayGetTextCellResolution(&TextWidth, &TextHeight);
State->FgColor = ConsoleEfiTextGetColorForeground(Mode->Attribute);
State->BgColor = ConsoleEfiTextGetColorBackground(Mode->Attribute);
State->XPos = Mode->CursorColumn * TextWidth;
State->YPos = Mode->CursorRow * TextHeight;
State->CursorVisible = Mode->CursorVisible != FALSE;
}
NTSTATUS
ConsoleFirmwareTextSetState (
_In_ PBL_TEXT_CONSOLE TextConsole,
_In_ UCHAR Mask,
_In_ PBL_DISPLAY_STATE State
)
{
NTSTATUS Status;
ULONG FgColor, BgColor, Attribute, XPos, YPos, TextHeight, TextWidth;
BOOLEAN Visible;
/* Check if foreground state is being set */
if (Mask & 1)
{
/* Check if there's a difference from current */
FgColor = State->FgColor;
if (TextConsole->State.FgColor != FgColor)
{
/* Ignore invalid color */
if (FgColor > White)
{
return STATUS_INVALID_PARAMETER;
}
/* Convert from NT/CGA format to EFI, and then set the attribute */
Attribute = ConsoleEfiTextGetAttribute(TextConsole->State.BgColor,
FgColor);
Status = EfiConOutSetAttribute(TextConsole->Protocol, Attribute);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Update cached state */
TextConsole->State.FgColor = FgColor;
}
}
/* Check if background state is being set */
if (Mask & 2)
{
/* Check if there's a difference from current */
BgColor = State->BgColor;
if (TextConsole->State.BgColor != BgColor)
{
/* Ignore invalid color */
if (BgColor > White)
{
return STATUS_INVALID_PARAMETER;
}
/* Convert from NT/CGA format to EFI, and then set the attribute */
Attribute = ConsoleEfiTextGetAttribute(BgColor,
TextConsole->State.FgColor);
Status = EfiConOutSetAttribute(TextConsole->Protocol, Attribute);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Update cached state */
TextConsole->State.BgColor = BgColor;
}
}
/* Check if position state is being set */
if (Mask & 4)
{
/* Check if there's a difference from current */
XPos = State->XPos;
YPos = State->YPos;
if ((TextConsole->State.XPos != XPos) ||
(TextConsole->State.YPos != YPos))
{
/* Set the new cursor position */
BlDisplayGetTextCellResolution(&TextWidth, &TextHeight);
Status = EfiConOutSetCursorPosition(TextConsole->Protocol,
XPos/ TextWidth,
YPos / TextHeight);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Update cached state */
TextConsole->State.XPos = XPos;
TextConsole->State.YPos = YPos;
}
}
/* Check if cursor state is being set */
if (Mask & 8)
{
/* Check if there's a difference from current */
Visible = State->CursorVisible;
if (TextConsole->State.CursorVisible != Visible)
{
/* Ignore invalid state */
if (Visible >= 3)
{
return STATUS_INVALID_PARAMETER;
}
/* Set the new cursor state */
Status = EfiConOutEnableCursor(TextConsole->Protocol, Visible);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Update cached status */
TextConsole->State.CursorVisible = Visible;
}
}
/* Return success */
return STATUS_SUCCESS;
}
NTSTATUS
ConsoleEfiTextFindModeFromAllowed (
_In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextProtocol,
_In_ PBL_DISPLAY_MODE SupportedModes,
_In_ ULONG MaxIndex,
_Out_ PULONG SupportedMode
)
{
EFI_SIMPLE_TEXT_OUTPUT_MODE ModeInfo;
ULONG MaxMode, MaxQueriedMode, Mode, i, MatchingMode;
UINTN HRes, VRes;
ULONGLONG ModeListSize;
PBL_DISPLAY_MODE ModeEntry, ModeList, SupportedModeEntry;
NTSTATUS Status;
/* Read information on the current mode */
EfiConOutReadCurrentMode(TextProtocol, &ModeInfo);
/* Figure out the max mode, and how many modes we'll have to read */
MaxMode = ModeInfo.MaxMode;
ModeListSize = sizeof(*ModeEntry) * ModeInfo.MaxMode;
if (ModeListSize > MAXULONG)
{
return STATUS_INTEGER_OVERFLOW;
}
/* Allocate a list for all the supported EFI modes */
ModeList = BlMmAllocateHeap(ModeListSize);
if (!ModeList)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Scan all the EFI modes */
EfiPrintf(L"Scanning through %d modes\r\n", MaxMode);
for (MaxQueriedMode = 0, Mode = 0; Mode < MaxMode; Mode++)
{
/* Query information on this mode */
ModeEntry = &ModeList[MaxQueriedMode];
if (NT_SUCCESS(EfiConOutQueryMode(TextProtocol,
Mode,
&HRes,
&VRes)))
{
/* This mode was successfully queried. Save the data */
EfiPrintf(L"EFI Firmware Supported Mode %d is H: %d V: %d\r\n", Mode, HRes, VRes);
ModeEntry->HRes = HRes;
ModeEntry->VRes = VRes;
ModeEntry->HRes2 = HRes;
MaxQueriedMode = Mode + 1;
}
}
/* Loop all the supported mode entries */
for (i = 0; i < MaxIndex; i++)
{
/* Loop all the UEFI queried modes */
SupportedModeEntry = &SupportedModes[i];
for (MatchingMode = 0; MatchingMode < MaxQueriedMode; MatchingMode++)
{
/* Check if the UEFI mode is compatible with our supported mode */
ModeEntry = &ModeList[MatchingMode];
EfiPrintf(L"H1: %d V1: %d - H2: %d - V2: %d\r\n", ModeEntry->HRes, ModeEntry->VRes, SupportedModeEntry->HRes, SupportedModeEntry->VRes);
if ((ModeEntry->HRes == SupportedModeEntry->HRes) &&
(ModeEntry->VRes == SupportedModeEntry->VRes))
{
/* Yep -- free the mode list and return this mode */
BlMmFreeHeap(ModeList);
*SupportedMode = MatchingMode;
return STATUS_SUCCESS;
}
}
}
/* We can't do anything -- there are no matching modes */
Status = STATUS_UNSUCCESSFUL;
BlMmFreeHeap(ModeList);
return Status;
}
VOID
ConsoleFirmwareTextClose (
_In_ PBL_TEXT_CONSOLE TextConsole
)
{
ULONG Mode;
BL_DISPLAY_STATE DisplayState;
/* Read the original mode, and see if it's different than the one now */
Mode = TextConsole->OldMode.Mode;
if (Mode != TextConsole->Mode)
{
/* Restore to the original mode */
EfiConOutSetMode(TextConsole->Protocol, Mode);
}
/* Read the EFI settings for the original mode */
ConsoleEfiTextGetStateFromMode(&TextConsole->OldMode, &DisplayState);
/* Set the original settings */
ConsoleFirmwareTextSetState(TextConsole, 0xF, &DisplayState);
}
NTSTATUS
ConsoleFirmwareTextOpen (
_In_ PBL_TEXT_CONSOLE TextConsole
)
{
BL_DISPLAY_MODE DisplayMode;
EFI_SIMPLE_TEXT_OUTPUT_MODE CurrentMode, NewMode;
UINTN HRes, VRes;
ULONG Mode;
NTSTATUS Status;
/* Read the current mode and its settings */
EfiConOutReadCurrentMode(EfiConOut, &CurrentMode);
Status = EfiConOutQueryMode(EfiConOut, CurrentMode.Mode, &HRes, &VRes);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Save the current mode and its settings */
NewMode = CurrentMode;
DisplayMode.VRes = VRes;
DisplayMode.HRes = HRes;
DisplayMode.HRes2 = HRes;
/* Check if the current mode is compatible with one of our modes */
if (!ConsolepFindResolution(&DisplayMode, ConsoleTextResolutionList, 1))
{
/* It isn't -- find a matching EFI mode for what we need */
EfiPrintf(L"In incorrect mode, scanning for right one\r\n");
Status = ConsoleEfiTextFindModeFromAllowed(EfiConOut,
ConsoleTextResolutionList,
1,
&Mode);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"Failed to find mode: %lx\r\n", Status);
return Status;
}
/* Set the new EFI mode */
EfiPrintf(L"Setting new mode: %d\r\n", Mode);
Status = EfiConOutSetMode(EfiConOut, Mode);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Read the current mode and its settings */
EfiConOutReadCurrentMode(EfiConOut, &NewMode);
Status = EfiConOutQueryMode(EfiConOut, Mode, &HRes, &VRes);
if (!NT_SUCCESS(Status))
{
EfiConOutSetMode(EfiConOut, CurrentMode.Mode);
return Status;
}
/* Save the current mode and its settings */
DisplayMode.HRes = HRes;
DisplayMode.VRes = VRes;
DisplayMode.HRes2 = HRes;
}
/* Capture all the current settings */
ConsoleEfiTextGetStateFromMode(&NewMode, &TextConsole->State);
TextConsole->Mode = NewMode.Mode;
TextConsole->DisplayMode = DisplayMode;
TextConsole->Protocol = EfiConOut;
TextConsole->OldMode = CurrentMode;
return STATUS_SUCCESS;
}
NTSTATUS
ConsoleInputBaseEraseBuffer (
_In_ PBL_INPUT_CONSOLE Console,
_In_opt_ PULONG FillValue
)
{
ULONG ValueToFill;
PULONG i;
/* Check if we should fill with a particular value */
if (FillValue)
{
/* Use it */
ValueToFill = *FillValue;
}
else
{
/* Otherwise, use default */
ValueToFill = 0x10020;
}
/* Set the input buffer to its last location */
Console->DataStart = Console->DataEnd;
/* Fill the buffer with the value */
for (i = Console->Buffer; i < Console->EndBuffer; i++)
{
*i = ValueToFill;
}
/* All done */
return STATUS_SUCCESS;
}
NTSTATUS
ConsoleInputLocalEraseBuffer (
_In_ PBL_INPUT_CONSOLE Console,
_In_opt_ PULONG FillValue
)
{
NTSTATUS Status, EfiStatus;
/* Erase the software buffer */
Status = ConsoleInputBaseEraseBuffer(Console, FillValue);
/* Reset the hardware console */
EfiStatus = EfiConInEx ? EfiConInExReset() : EfiConInReset();
if (!NT_SUCCESS(EfiStatus))
{
/* Normalize the failure code */
EfiStatus = STATUS_UNSUCCESSFUL;
}
/* Check if software reset worked */
if (NT_SUCCESS(Status))
{
/* Then return the firmware code */
Status = EfiStatus;
}
/* All done */
return Status;
}
NTSTATUS
ConsoleFirmwareTextClear (
_In_ PBL_TEXT_CONSOLE Console,
_In_ BOOLEAN LineOnly
)
{
BL_ARCH_MODE OldMode;
EFI_STATUS EfiStatus;
NTSTATUS Status;
ULONG i, Column, Row, TextWidth, TextHeight;
/* Get the text resolution */
BlDisplayGetTextCellResolution(&TextWidth, &TextHeight);
/* Are we just clearing a line? */
if (LineOnly)
{
/* Get the current column and row */
Column = Console->State.XPos / TextWidth;
Row = Console->State.YPos / TextHeight;
/* Loop over every remaining character */
for (i = 0; i < Console->DisplayMode.HRes - Column - 1; i++)
{
/* Write a space on top of it */
Status = EfiConOutOutputString(Console->Protocol, L" ");
if (!NT_SUCCESS(Status))
{
break;
}
}
/* And reset the cursor back at the initial position */
Status = EfiConOutSetCursorPosition(Console->Protocol,
Column,
Row);
}
else
{
/* Are we in protected mode? */
OldMode = CurrentExecutionContext->Mode;
if (OldMode != BlRealMode)
{
/* FIXME: Not yet implemented */
return STATUS_NOT_IMPLEMENTED;
}
/* Clear the screen */
EfiStatus = Console->Protocol->ClearScreen(Console->Protocol);
/* Switch back to protected mode if we came from there */
if (OldMode != BlRealMode)
{
BlpArchSwitchContext(OldMode);
}
/* Conver to NT status -- did that work? */
Status = EfiGetNtStatusCode(EfiStatus);
if (NT_SUCCESS(Status))
{
/* Reset current positions */
Console->State.XPos = 0;
Console->State.YPos = 0;
}
}
/* All done */
return Status;
}

View file

@ -0,0 +1,42 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/io/display/efi/uga.c
* PURPOSE: Boot Library EFI UGA Routines
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
/* FUNCTIONS *****************************************************************/
NTSTATUS
ConsoleEfiUgaOpen (
_In_ PBL_GRAPHICS_CONSOLE GraphicsConsole
)
{
EfiPrintf(L"UGA not implemented\r\n");
return STATUS_NOT_IMPLEMENTED;
}
VOID
ConsoleEfiUgaClose (
_In_ PBL_GRAPHICS_CONSOLE GraphicsConsole
)
{
return;
}
NTSTATUS
ConsoleEfiUgaSetResolution (
_In_ PBL_GRAPHICS_CONSOLE GraphicsConsole,
_In_ PBL_DISPLAY_MODE DisplayMode,
_In_ ULONG DisplayModeCount
)
{
return STATUS_NOT_IMPLEMENTED;
}

View file

@ -0,0 +1,58 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/io/display/emscons.c
* PURPOSE: Boot Library Remote Console Routines
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
/* FUNCTIONS *****************************************************************/
NTSTATUS
ConsoleRemoteConstruct (
_In_ PBL_REMOTE_CONSOLE RemoteConsole
)
{
#ifdef BL_EMS_SUPPORT
#error Implement me
#else
/* We don't support EMS for now */
return STATUS_NOT_IMPLEMENTED;
#endif
}
NTSTATUS
ConsoleCreateRemoteConsole (
_In_ PBL_TEXT_CONSOLE* TextConsole
)
{
PBL_REMOTE_CONSOLE RemoteConsole;
NTSTATUS Status;
/* Allocate the remote console */
RemoteConsole = BlMmAllocateHeap(sizeof(*RemoteConsole));
if (!RemoteConsole)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Construct it */
Status = ConsoleRemoteConstruct(RemoteConsole);
if (!NT_SUCCESS(Status))
{
/* Failed to construct it, delete it */
BlMmFreeHeap(RemoteConsole);
return Status;
}
/* Save the global pointer and return a pointer to the text console */
DspRemoteInputConsole = RemoteConsole;
*TextConsole = &RemoteConsole->TextConsole;
return STATUS_SUCCESS;
}

View file

@ -0,0 +1,462 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/io/display/guicons.c
* PURPOSE: Boot Library GUI Console Routines
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
BL_GRAPHICS_CONSOLE_VTABLE ConsoleGraphicalVtbl =
{
{
(PCONSOLE_DESTRUCT)ConsoleGraphicalDestruct,
(PCONSOLE_REINITIALIZE)ConsoleGraphicalReinitialize,
ConsoleTextBaseGetTextState,
(PCONSOLE_SET_TEXT_STATE)ConsoleGraphicalSetTextState,
NULL, // GetTextResolution
NULL, // SetTextResolution
(PCONSOLE_CLEAR_TEXT)ConsoleGraphicalClearText
},
ConsoleGraphicalIsEnabled,
ConsoleGraphicalEnable,
NULL,
ConsoleGraphicalGetGraphicalResolution,
ConsoleGraphicalGetOriginalResolution,
NULL,
};
/* FUNCTIONS *****************************************************************/
NTSTATUS
ConsoleGraphicalSetTextState (
_In_ PBL_GRAPHICS_CONSOLE Console,
_In_ ULONG Mask,
_In_ PBL_DISPLAY_STATE TextState
)
{
/* Is the text console active? */
if (Console->TextConsole.Active)
{
/* Let it handle that */
return ConsoleFirmwareTextSetState(&Console->TextConsole,
Mask,
TextState);
}
/* Not yet */
EfiPrintf(L"FFX set not implemented\r\n");
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
ConsoleGraphicalConstruct (
_In_ PBL_GRAPHICS_CONSOLE GraphicsConsole
)
{
NTSTATUS Status;
/* Create a text console */
Status = ConsoleTextLocalConstruct(&GraphicsConsole->TextConsole, FALSE);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"Text failed: %lx\r\n", Status);
return Status;
}
/* But overwrite its callbacks with ours */
GraphicsConsole->TextConsole.Callbacks = &ConsoleGraphicalVtbl.Text;
/* Try to create a GOP console */
Status = ConsoleEfiGraphicalOpenProtocol(GraphicsConsole, BlGopConsole);
if (!NT_SUCCESS(Status))
{
/* That failed, try an older EFI 1.02 UGA console */
EfiPrintf(L"GOP open failed!\r\n", Status);
Status = ConsoleEfiGraphicalOpenProtocol(GraphicsConsole, BlUgaConsole);
if (!NT_SUCCESS(Status))
{
/* That failed too, give up */
EfiPrintf(L"UGA failed!\r\n", Status);
ConsoleTextLocalDestruct(&GraphicsConsole->TextConsole);
return STATUS_UNSUCCESSFUL;
}
}
/* Enable the console */
Status = ConsoleFirmwareGraphicalEnable(GraphicsConsole);
if (!NT_SUCCESS(Status))
{
/* Failed to enable it, undo everything */
EfiPrintf(L"Enable failed\r\n");
ConsoleFirmwareGraphicalClose(GraphicsConsole);
ConsoleTextLocalDestruct(&GraphicsConsole->TextConsole);
return STATUS_UNSUCCESSFUL;
}
/* Save the graphics text color from the text mode text color */
GraphicsConsole->FgColor = GraphicsConsole->TextConsole.State.FgColor;
GraphicsConsole->BgColor = GraphicsConsole->TextConsole.State.BgColor;
return STATUS_SUCCESS;
}
VOID
ConsolepClearBuffer (
_In_ PUCHAR FrameBuffer,
_In_ ULONG Width,
_In_ PUCHAR FillColor,
_In_ ULONG Height,
_In_ ULONG ScanlineWidth,
_In_ ULONG PixelDepth
)
{
PUCHAR Scanline, Current, FrameBufferEnd, LineEnd;
ULONG LineBytes, WidthBytes, BytesPerPixel;
/* Get the BPP */
BytesPerPixel = PixelDepth / 8;
/* Using that, calculate the size of a scan line */
LineBytes = ScanlineWidth * BytesPerPixel;
/* And the size of line we'll have to clear */
WidthBytes = Width * BytesPerPixel;
/* Allocate a scanline */
Scanline = BlMmAllocateHeap(WidthBytes);
if (Scanline)
{
/* For each remaining pixel on the scanline */
Current = Scanline;
while (Width--)
{
/* Copy in the fill color */
RtlCopyMemory(Current, FillColor, BytesPerPixel);
Current += BytesPerPixel;
}
/* For each scanline in the frame buffer */
while (Height--)
{
/* Copy our constructed scanline */
RtlCopyMemory(FrameBuffer, Scanline, WidthBytes);
FrameBuffer += LineBytes;
}
}
else
{
FrameBufferEnd = FrameBuffer + Height * LineBytes;
ScanlineWidth = BytesPerPixel * (ScanlineWidth - Width);
while (FrameBuffer != FrameBufferEnd)
{
if (FrameBuffer != (FrameBuffer + WidthBytes))
{
LineEnd = FrameBuffer + WidthBytes;
do
{
RtlCopyMemory(FrameBuffer, FillColor, BytesPerPixel);
FrameBuffer += BytesPerPixel;
}
while (FrameBuffer != LineEnd);
}
FrameBuffer += ScanlineWidth;
}
}
}
NTSTATUS
ConsolepConvertColorToPixel (
_In_ BL_COLOR Color,
_Out_ PUCHAR Pixel
)
{
NTSTATUS Status;
/* Assume success */
Status = STATUS_SUCCESS;
/* Convert the color to a pixel value */
switch (Color)
{
case Black:
Pixel[1] = 0;
Pixel[2] = 0;
Pixel[0] = 0;
break;
case Blue:
Pixel[1] = 0;
Pixel[2] = 0;
Pixel[0] = 0x7F;
break;
case Green:
Pixel[1] = 0x7F;
Pixel[2] = 0;
Pixel[0] = 0;
break;
case Cyan:
Pixel[1] = 0x7F;
Pixel[2] = 0;
Pixel[0] = 0x7F;
break;
case Red:
Pixel[1] = 0;
Pixel[2] = 0x7F;
Pixel[0] = 0x7F;
break;
case Magenta:
Pixel[1] = 0;
Pixel[2] = 0x7F;
Pixel[0] = 0x7F;
break;
case Brown:
Pixel[1] = 0x3F;
Pixel[2] = 0x7F;
Pixel[0] = 0;
break;
case LtGray:
Pixel[1] = 0xBFu;
Pixel[2] = 0xBFu;
*Pixel = 0xBFu;
break;
case Gray:
Pixel[1] = 0x7F;
Pixel[2] = 0x7F;
Pixel[0] = 0x7F;
break;
case LtBlue:
Pixel[1] = 0;
Pixel[2] = 0;
Pixel[0] = 0xFF;
break;
case LtGreen:
Pixel[1] = 0xFF;
Pixel[2] = 0;
Pixel[0] = 0;
break;
case LtCyan:
Pixel[1] = 0xFF;
Pixel[2] = 0;
Pixel[0] = 0xFF;
break;
case LtRed:
Pixel[1] = 0;
Pixel[2] = 0xFF;
Pixel[0] = 0;
break;
case LtMagenta:
Pixel[1] = 0;
Pixel[2] = 0xFF;
Pixel[0] = 0xFF;
break;
case Yellow:
Pixel[1] = 0xFF;
Pixel[2] = 0xFF;
Pixel[0] = 0;
break;
case White:
Pixel[1] = 0xFF;
Pixel[2] = 0xFF;
Pixel[0] = 0xFF;
break;
default:
Status = STATUS_INVALID_PARAMETER;
break;
}
return Status;
}
NTSTATUS
ConsoleGraphicalClearPixels (
_In_ PBL_GRAPHICS_CONSOLE Console,
_In_ ULONG Color
)
{
NTSTATUS Status;
/* Check if the text console is active */
if (Console->TextConsole.Active)
{
/* We shouldn't be here */
Status = STATUS_UNSUCCESSFUL;
}
else
{
/* Clear it in graphics mode */
Status = ConsoleFirmwareGraphicalClear(Console, Color);
}
/* All good */
return Status;
}
NTSTATUS
ConsoleGraphicalClearText (
_In_ PBL_GRAPHICS_CONSOLE Console,
_In_ BOOLEAN LineOnly
)
{
/* Is the text console active? */
if (Console->TextConsole.Active)
{
/* Let firmware clear do it */
return ConsoleFirmwareTextClear(&Console->TextConsole, LineOnly);
}
/* Are we clearing a line only? */
if (LineOnly)
{
return BfClearToEndOfLine(Console);
}
/* Nope -- the whole screen */
return BfClearScreen(Console);
}
BOOLEAN
ConsoleGraphicalIsEnabled (
_In_ PBL_GRAPHICS_CONSOLE Console
)
{
/* Is the text console active? If so, the graphics console isn't */
return !Console->TextConsole.Active;
}
VOID
ConsoleGraphicalDestruct (
_In_ PBL_GRAPHICS_CONSOLE Console
)
{
/* Is the text console active? */
if (Console->TextConsole.Active)
{
/* Disable it */
ConsoleFirmwareGraphicalDisable(Console);
}
/* Close the firmware protocols */
ConsoleFirmwareGraphicalClose(Console);
/* Destroy the console object */
ConsoleTextLocalDestruct(&Console->TextConsole);
}
NTSTATUS
ConsoleGraphicalReinitialize (
_In_ PBL_GRAPHICS_CONSOLE Console
)
{
/* Is the text console active? */
if (Console->TextConsole.Active)
{
/* Reinitialize it */
ConsoleTextLocalReinitialize(&Console->TextConsole);
}
/* Disable the graphics console */
ConsoleFirmwareGraphicalDisable(Console);
/* Then bring it back again */
return ConsoleFirmwareGraphicalEnable(Console);
}
NTSTATUS
ConsoleGraphicalEnable (
_In_ PBL_GRAPHICS_CONSOLE Console,
_In_ BOOLEAN Enable
)
{
BOOLEAN Active;
NTSTATUS Status;
/* The text mode console state should be the opposite of what we want to do */
Active = Console->TextConsole.Active;
if (Active == Enable)
{
/* Are we trying to enable graphics? */
if (Enable)
{
/* Enable the console */
Status = ConsoleFirmwareGraphicalEnable(Console);
if (NT_SUCCESS(Status))
{
return Status;
}
/* Is the text console active? */
if (Console->TextConsole.Active)
{
/* Turn it off */
ConsoleFirmwareTextClose(&Console->TextConsole);
Console->TextConsole.Active = FALSE;
}
/* Preserve the text colors */
Console->FgColor = Console->TextConsole.State.FgColor;
Console->BgColor = Console->TextConsole.State.BgColor;
}
else
{
/* We are turning off graphics -- is the text console active? */
if (Active != TRUE)
{
/* It isn't, so let's turn it on */
Status = ConsoleFirmwareTextOpen(&Console->TextConsole);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Remember that it's on */
Console->TextConsole.Active = TRUE;
}
/* Disable the graphics console */
ConsoleFirmwareGraphicalDisable(Console);
}
}
/* All good */
return STATUS_SUCCESS;
}
NTSTATUS
ConsoleGraphicalGetGraphicalResolution (
_In_ PBL_GRAPHICS_CONSOLE Console,
_In_ PBL_DISPLAY_MODE DisplayMode
)
{
/* Is the text console active? */
if (Console->TextConsole.Active)
{
/* There's no graphics resolution then */
return STATUS_UNSUCCESSFUL;
}
/* Return the current display mode */
*DisplayMode = Console->DisplayMode;
return STATUS_SUCCESS;
}
NTSTATUS
ConsoleGraphicalGetOriginalResolution (
_In_ PBL_GRAPHICS_CONSOLE Console,
_In_ PBL_DISPLAY_MODE DisplayMode
)
{
/* Is the text console active? */
if (Console->TextConsole.Active)
{
/* There's no graphics resolution then */
return STATUS_UNSUCCESSFUL;
}
/* Return the current display mode */
*DisplayMode = Console->OldDisplayMode;
return STATUS_SUCCESS;
}

View file

@ -0,0 +1,270 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/io/display/textcons.c
* PURPOSE: Boot Library Text Console Routines
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
BL_TEXT_CONSOLE_VTABLE ConsoleTextLocalVtbl =
{
ConsoleTextLocalDestruct,
ConsoleTextLocalReinitialize,
ConsoleTextBaseGetTextState,
ConsoleTextLocalSetTextState,
ConsoleTextBaseGetTextResolution,
ConsoleTextLocalSetTextResolution,
ConsoleTextLocalClearText,
ConsoleTextLocalWriteText
};
/* FUNCTIONS *****************************************************************/
VOID
ConsoleTextLocalDestruct (
_In_ struct _BL_TEXT_CONSOLE* Console
)
{
}
NTSTATUS
ConsoleTextLocalReinitialize (
_In_ struct _BL_TEXT_CONSOLE* Console
)
{
EfiPrintf(L"Not active yet!\r\n");
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
ConsoleTextBaseGetTextState (
_In_ struct _BL_TEXT_CONSOLE* Console,
_Out_ PBL_DISPLAY_STATE TextState
)
{
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
ConsoleTextLocalSetTextState (
_In_ struct _BL_TEXT_CONSOLE* Console,
_In_ ULONG Mask,
_In_ PBL_DISPLAY_STATE TextState
)
{
return ConsoleFirmwareTextSetState(Console, Mask, TextState);
}
NTSTATUS
ConsoleTextBaseGetTextResolution (
_In_ struct _BL_TEXT_CONSOLE* Console,
_Out_ PULONG TextResolution
)
{
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
ConsoleTextLocalSetTextResolution (
_In_ struct _BL_TEXT_CONSOLE* Console,
_In_ ULONG NewTextResolution,
_Out_ PULONG OldTextResolution
)
{
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
ConsoleTextLocalClearText (
_In_ struct _BL_TEXT_CONSOLE* Console,
_In_ BOOLEAN LineOnly
)
{
return ConsoleFirmwareTextClear(Console, LineOnly);
}
NTSTATUS
ConsoleTextLocalWriteText (
_In_ struct _BL_TEXT_CONSOLE* Console,
_In_ PCHAR Text,
_In_ ULONG Attribute
)
{
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
ConsoleTextLocalConstruct (
_In_ PBL_TEXT_CONSOLE TextConsole,
_In_ BOOLEAN Activate
)
{
NTSTATUS Status;
BL_DISPLAY_STATE TextState;
/* Set our callbacks */
TextConsole->Callbacks = &ConsoleTextLocalVtbl;
/* Are we activating this console? */
if (Activate)
{
/* Call firmware to activate it */
Status = ConsoleFirmwareTextOpen(TextConsole);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"Failed to activate console: %lx\r\n", Status);
return Status;
}
}
/* Set default text state */
TextState.BgColor = 0;
TextState.XPos = 0;
TextState.YPos = 0;
TextState.CursorVisible = FALSE;
TextState.FgColor = White;
/* Are we activating? */
if (Activate)
{
/* Call firmware to set it */
Status = ConsoleFirmwareTextSetState(TextConsole, 0xF, &TextState);
if (!NT_SUCCESS(Status))
{
/* We failed, back down */
EfiPrintf(L"Failed to set console state: %lx\r\n", Status);
ConsoleFirmwareTextClose(TextConsole);
return Status;
}
}
else
{
/* Just save the state for now, someone else can activate later */
TextConsole->State = TextState;
}
/* Remember if we activated it */
TextConsole->Active = Activate;
return STATUS_SUCCESS;
}
BOOLEAN
ConsolepFindResolution (
_In_ PBL_DISPLAY_MODE Mode,
_In_ PBL_DISPLAY_MODE List,
_In_ ULONG MaxIndex
)
{
PBL_DISPLAY_MODE ListEnd;
/* Loop until we hit the maximum supported list index */
ListEnd = &List[MaxIndex];
while (List != ListEnd)
{
/* Does this resolution match? */
if ((Mode->HRes == List->HRes) && (Mode->VRes == List->VRes))
{
/* Yep -- we got a match */
return TRUE;
}
/* Try another one*/
List++;
}
/* No matches were found */
return FALSE;
}
BL_INPUT_CONSOLE_VTABLE ConsoleInputLocalVtbl =
{
(PCONSOLE_DESTRUCT)ConsoleInputLocalDestruct,
(PCONSOLE_REINITIALIZE)ConsoleInputBaseReinitialize,
};
VOID
ConsoleInputLocalDestruct (
_In_ PBL_INPUT_CONSOLE Console
)
{
/* Erase the current input buffer, and tear down the console */
ConsoleInputLocalEraseBuffer(Console, NULL);
BlMmFreeHeap(Console->Buffer);
}
NTSTATUS
ConsoleInputBaseConstruct (
_In_ PBL_INPUT_CONSOLE Console
)
{
PULONG Buffer;
/* Allocate a new 512 byte buffer */
Buffer = BlMmAllocateHeap(512);
Console->Buffer = Buffer;
if (!Buffer)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Set the current buffer pointers to it */
Console->DataStart = Buffer;
Console->DataEnd = Buffer;
/* Set the end 128 data entries into the buffer */
Console->EndBuffer = Buffer + 128;
return STATUS_SUCCESS;
}
NTSTATUS
ConsoleInputBaseReinitialize (
_In_ PBL_INPUT_CONSOLE Console
)
{
PULONG Buffer;
/* Reset all the buffer pointers to the current buffer */
Buffer = Console->Buffer;
Console->DataStart = Buffer;
Console->DataEnd = Buffer;
Console->EndBuffer = Buffer + 128;
return STATUS_SUCCESS;
}
NTSTATUS
ConsoleCreateLocalInputConsole (
VOID
)
{
PBL_INPUT_CONSOLE InputConsole;
NTSTATUS Status;
/* Allocate the input console */
InputConsole = BlMmAllocateHeap(sizeof(*InputConsole));
if (!InputConsole)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Construct it */
Status = ConsoleInputBaseConstruct(InputConsole);
if (!NT_SUCCESS(Status))
{
/* Tear down on failure */
BlMmFreeHeap(InputConsole);
return Status;
}
/* Set the callback table, and set us as the local input console */
InputConsole->Callbacks = &ConsoleInputLocalVtbl;
DspLocalInputConsole = InputConsole;
return STATUS_SUCCESS;
}

994
boot/environ/lib/io/etfs.c Normal file
View file

@ -0,0 +1,994 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/io/etfs.c
* PURPOSE: Boot Library El Torito File System Management Routines
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <bl.h>
#include <cdfs_new/cd.h>
typedef struct _RAW_ET_VD
{
UCHAR BootIndicator;
UCHAR StandardId[5];
UCHAR Version;
UCHAR SystemId[32];
UCHAR Reserved[32];
ULONG BootCatalogOffset;
UCHAR Padding[1973];
} RAW_ET_VD, *PRAW_ET_VD;
/* DATA VARIABLES ************************************************************/
typedef struct _BL_ETFS_DEVICE
{
ULONG RootDirOffset;
ULONG RootDirSize;
ULONG BlockSize;
ULONG VolumeSize;
BOOLEAN IsIso;
PUCHAR MemoryBlock;
ULONG Offset;
} BL_ETFS_DEVICE, *PBL_ETFS_DEVICE;
typedef struct _BL_ETFS_FILE
{
ULONG DiskOffset;
ULONG DirOffset;
ULONG DirEntOffset;
BL_FILE_INFORMATION;
ULONG DeviceId;
} BL_ETFS_FILE, *PBL_ETFS_FILE;
ULONG EtfsDeviceTableEntries;
PVOID* EtfsDeviceTable;
NTSTATUS
EtfsOpen (
_In_ PBL_FILE_ENTRY Directory,
_In_ PWCHAR FileName,
_In_ ULONG Flags,
_Out_ PBL_FILE_ENTRY *FileEntry
);
NTSTATUS
EtfsGetInformation (
_In_ PBL_FILE_ENTRY FileEntry,
_Out_ PBL_FILE_INFORMATION FileInfo
);
NTSTATUS
EtfsSetInformation (
_In_ PBL_FILE_ENTRY FileEntry,
_In_ PBL_FILE_INFORMATION FileInfo
);
NTSTATUS
EtfsRead (
_In_ PBL_FILE_ENTRY FileEntry,
_In_ PVOID Buffer,
_In_ ULONG Size,
_Out_opt_ PULONG BytesReturned
);
BL_FILE_CALLBACKS EtfsFunctionTable =
{
EtfsOpen,
NULL,
EtfsRead,
NULL,
NULL,
EtfsGetInformation,
EtfsSetInformation
};
/* FUNCTIONS *****************************************************************/
VOID
EtfspGetDirectoryInfo (
_In_ PBL_ETFS_DEVICE EtfsDevice,
_In_ PRAW_DIR_REC DirEntry,
_Out_ PULONG FileOffset,
_Out_ PULONG FileSize,
_Out_opt_ PBOOLEAN IsDirectory
)
{
ULONG SectorOffset;
BOOLEAN IsDir;
*FileOffset = *(PULONG)DirEntry->FileLoc * EtfsDevice->BlockSize;
*FileOffset += (DirEntry->XarLen * EtfsDevice->BlockSize);
SectorOffset = ALIGN_DOWN_BY(*FileOffset, CD_SECTOR_SIZE);
*FileSize = *(PULONG)DirEntry->DataLen;
IsDir = DE_FILE_FLAGS(EtfsDevice->IsIso, DirEntry) & ISO_ATTR_DIRECTORY;
if (IsDir)
{
*FileSize += ALIGN_UP_BY(SectorOffset, CD_SECTOR_SIZE) - SectorOffset;
}
if (IsDirectory)
{
*IsDirectory = IsDir;
}
}
USHORT
EtfspGetDirentNameLength (
_In_ PRAW_DIR_REC DirEntry
)
{
USHORT Length, RealLength;
PUCHAR Pos;
RealLength = Length = DirEntry->FileIdLen;
for (Pos = DirEntry->FileId + Length - 1; Length; --Pos)
{
--Length;
if (*Pos == ';')
{
RealLength = Length;
break;
}
}
Length = RealLength;
for (Pos = DirEntry->FileId + Length - 1; Length; --Pos)
{
--Length;
if (*Pos != '.')
{
break;
}
RealLength = Length;
}
return RealLength;
}
LONG
EtfspCompareNames (
__in PSTRING Name1,
__in PUNICODE_STRING Name2
)
{
ULONG i, l1, l2, l;
l1 = Name1->Length;
l2 = Name2->Length / sizeof(WCHAR);
l = min(l1, l2);
for (i = 0; i < l; i++)
{
if (toupper(Name1->Buffer[i]) != toupper(Name2->Buffer[i]))
{
return toupper(Name1->Buffer[i]) - toupper(Name2->Buffer[i]);
}
}
if (l2 <= l1)
{
return l2 < l1;
}
else
{
return -1;
}
}
BOOLEAN
EtfspFileMatch (
_In_ PRAW_DIR_REC DirEntry,
_In_ PUNICODE_STRING FileName
)
{
BOOLEAN Match;
USHORT Length;
ANSI_STRING DirName;
if ((DirEntry->FileIdLen != 1) ||
((DirEntry->FileId[0] != 0) && (DirEntry->FileId[0] != 1)))
{
Length = EtfspGetDirentNameLength(DirEntry);
DirName.Length = Length;
DirName.MaximumLength = Length;
DirName.Buffer = (PCHAR)DirEntry->FileId;
Match = EtfspCompareNames(&DirName, FileName);
}
else
{
Match = -1;
}
return Match;
}
NTSTATUS
EtfspGetDirent (
_In_ PBL_FILE_ENTRY DirectoryEntry,
_Out_ PRAW_DIR_REC *DirEntry,
_Inout_ PULONG DirentOffset
)
{
PBL_ETFS_FILE EtfsFile;
ULONG FileOffset, DirectoryOffset, AlignedOffset, RemainderOffset;
ULONG DeviceId, ReadSize, DirLen;
PBL_ETFS_DEVICE EtfsDevice;
BOOLEAN NeedRead, IsMulti;
NTSTATUS result;
PRAW_DIR_REC DirEnt;
PUCHAR MemoryBlock;
EtfsFile = DirectoryEntry->FsSpecificData;
DeviceId = EtfsFile->DeviceId;
FileOffset = EtfsFile->DiskOffset;
EtfsDevice = EtfsDeviceTable[DeviceId];
DirectoryOffset = *DirentOffset;
MemoryBlock = EtfsDevice->MemoryBlock;
IsMulti = 0;
AlignedOffset = (FileOffset + *DirentOffset) & ~CD_SECTOR_SIZE;
RemainderOffset = *DirentOffset + FileOffset - AlignedOffset;
ReadSize = 2048 - RemainderOffset;
NeedRead = AlignedOffset == EtfsDevice->Offset ? 0 : 1;
ReadAgain:
if (DirectoryOffset >= EtfsFile->Size)
{
return STATUS_NO_SUCH_FILE;
}
while (ReadSize < MIN_DIR_REC_SIZE)
{
DirectoryOffset += ReadSize;
AlignedOffset += 2048;
ReadSize = 2048;
RemainderOffset = 0;
NeedRead = 1;
if (DirectoryOffset >= EtfsFile->Size)
{
return STATUS_NO_SUCH_FILE;
}
}
if (NeedRead)
{
result = BlDeviceReadAtOffset(DirectoryEntry->DeviceId,
CD_SECTOR_SIZE,
AlignedOffset,
MemoryBlock,
NULL);
if (!NT_SUCCESS(result))
{
EfiPrintf(L"Device read failed %lx\r\n", result);
return result;
}
NeedRead = FALSE;
EtfsDevice->Offset = AlignedOffset;
}
if (!*(MemoryBlock + RemainderOffset))
{
AlignedOffset += 2048;
NeedRead = TRUE;
RemainderOffset = 0;
DirectoryOffset += ReadSize;
ReadSize = 2048;
goto ReadAgain;
}
DirEnt = (PRAW_DIR_REC)(MemoryBlock + RemainderOffset);
DirLen = DirEnt->DirLen;
if (DirLen > ReadSize)
{
EfiPrintf(L"Dir won't fit %lx %lx\r\n", DirLen, ReadSize);
return STATUS_NO_SUCH_FILE;
}
if (IsMulti)
{
if (!(DE_FILE_FLAGS(EtfsDevice->IsIso, DirEnt) & ISO_ATTR_MULTI))
{
IsMulti = TRUE;
}
}
else if (DE_FILE_FLAGS(EtfsDevice->IsIso, DirEnt) & ISO_ATTR_MULTI)
{
IsMulti = TRUE;
}
else
{
if ((DirEnt->FileIdLen != 1) ||
((DirEnt->FileId[0] != 0) && (DirEnt->FileId[0] != 1)))
{
goto Quickie;
}
}
RemainderOffset += DirLen;
DirectoryOffset += DirLen;
ReadSize -= DirLen;
goto ReadAgain;
Quickie:
*DirEntry = DirEnt;
*DirentOffset = DirectoryOffset;
return STATUS_SUCCESS;
}
NTSTATUS
EtfspSearchForDirent (
_In_ PBL_FILE_ENTRY DirectoryEntry,
_In_ PWCHAR FileName,
_Out_ PRAW_DIR_REC *DirEntry,
_Out_ PULONG DirentOffset
)
{
UNICODE_STRING Name;
ULONG NextOffset;
PRAW_DIR_REC DirEnt;
NTSTATUS Status;
RtlInitUnicodeString(&Name, FileName);
for (NextOffset = *DirentOffset;
;
NextOffset = NextOffset + DirEnt->DirLen)
{
Status = EtfspGetDirent(DirectoryEntry, &DirEnt, &NextOffset);
if (!NT_SUCCESS(Status))
{
return STATUS_NO_SUCH_FILE;
}
if (!EtfspFileMatch(DirEnt, &Name))
{
break;
}
}
*DirEntry = DirEnt;
*DirentOffset = NextOffset;
return 0;
}
NTSTATUS
EtfspCachedSearchForDirent (
_In_ PBL_FILE_ENTRY DirectoryEntry,
_In_ PWCHAR FileName,
_Out_ PRAW_DIR_REC *DirEntry,
_Out_ PULONG DirOffset,
_In_ BOOLEAN KeepOffset
)
{
PBL_ETFS_FILE EtfsFile;
PBL_ETFS_DEVICE EtfsDevice;
NTSTATUS Status;
ULONG DirentOffset;
PRAW_DIR_REC Dirent;
UNICODE_STRING Name;
EtfsFile = DirectoryEntry->FsSpecificData;
EtfsDevice = EtfsDeviceTable[EtfsFile->DeviceId];
RtlInitUnicodeString(&Name, FileName);
DirentOffset = EtfsFile->DirEntOffset;
if ((KeepOffset) ||
(ALIGN_DOWN_BY((DirentOffset + EtfsFile->DiskOffset), CD_SECTOR_SIZE) ==
EtfsDevice->Offset))
{
Status = EtfspGetDirent(DirectoryEntry, &Dirent, &DirentOffset);
if (NT_SUCCESS(Status))
{
if (!EtfspFileMatch(Dirent, &Name))
{
*DirEntry = Dirent;
*DirOffset = DirentOffset;
return STATUS_SUCCESS;
}
}
else
{
DirentOffset = 0;
}
}
else
{
DirentOffset = 0;
}
Status = EtfspSearchForDirent(DirectoryEntry,
FileName,
DirEntry,
&DirentOffset);
if (!(NT_SUCCESS(Status)) && (DirentOffset))
{
DirentOffset = 0;
Status = EtfspSearchForDirent(DirectoryEntry,
FileName,
DirEntry,
&DirentOffset);
}
if (NT_SUCCESS(Status))
{
*DirOffset = DirentOffset;
}
return Status;
}
NTSTATUS
EtfsRead (
_In_ PBL_FILE_ENTRY FileEntry,
_In_ PVOID Buffer,
_In_ ULONG Size,
_Out_opt_ PULONG BytesReturned
)
{
ULONG BytesRead;
PBL_ETFS_FILE EtfsFile;
NTSTATUS Status;
/* Assume failure for now */
BytesRead = 0;
/* Make sure that the read is within the file's boundaries */
EtfsFile = FileEntry->FsSpecificData;
if ((Size + EtfsFile->Offset) > EtfsFile->Size)
{
/* Bail out otherwise */
Status = STATUS_INVALID_PARAMETER;
}
else
{
/* Read the offset that matches this file's offset, on the disk */
Status = BlDeviceReadAtOffset(FileEntry->DeviceId,
Size,
EtfsFile->Offset + EtfsFile->DiskOffset,
Buffer,
&BytesRead);
if (NT_SUCCESS(Status))
{
/* Update the file offset and return the size as having been read */
EtfsFile->Offset += Size;
BytesRead = Size;
}
}
/* Check if caller wanted to know how many bytes were read */
if (BytesReturned)
{
/* Return the value */
*BytesReturned = BytesRead;
}
/* All done */
return Status;
}
NTSTATUS
EtfsSetInformation (
_In_ PBL_FILE_ENTRY FileEntry,
_In_ PBL_FILE_INFORMATION FileInfo
)
{
PBL_ETFS_FILE EtfsFile;
BL_FILE_INFORMATION LocalFileInfo;
/* Get the underlying ETFS file data structure */
EtfsFile = (PBL_ETFS_FILE)FileEntry->FsSpecificData;
/* Make a copy of the incoming attributes, but ignore the new offset */
LocalFileInfo = *FileInfo;
LocalFileInfo.Offset = EtfsFile->Offset;
/* Check if these match exactly the current file */
if (!RtlEqualMemory(&LocalFileInfo, &EtfsFile->Size, sizeof(*FileInfo)))
{
/* Nope -- which means caller is trying to change an immutable */
EfiPrintf(L"Incorrect information change\r\n");
return STATUS_INVALID_PARAMETER;
}
/* Is the offset past the end of the file? */
if (FileInfo->Offset >= EtfsFile->Size)
{
/* Don't allow EOF */
EfiPrintf(L"Offset too large: %lx vs %lx\r\n", FileInfo->Offset, EtfsFile->Size);
return STATUS_INVALID_PARAMETER;
}
/* Update the offset */
EtfsFile->Offset = FileInfo->Offset;
return STATUS_SUCCESS;
}
NTSTATUS
EtfsGetInformation (
_In_ PBL_FILE_ENTRY FileEntry,
_Out_ PBL_FILE_INFORMATION FileInfo
)
{
PBL_ETFS_FILE EtfsFile;
/* Get the underlying ETFS file data structure */
EtfsFile = (PBL_ETFS_FILE)FileEntry->FsSpecificData;
/* Copy the cached information structure within it */
RtlCopyMemory(FileInfo, &EtfsFile->Size, sizeof(*FileInfo));
return STATUS_SUCCESS;
}
NTSTATUS
EtfsOpen (
_In_ PBL_FILE_ENTRY Directory,
_In_ PWCHAR FileName,
_In_ ULONG Flags,
_Out_ PBL_FILE_ENTRY *FileEntry
)
{
PBL_ETFS_DEVICE EtfsDevice;
NTSTATUS Status;
PBL_FILE_ENTRY NewFile;
PWCHAR FilePath, FormatString;
PBL_ETFS_FILE EtfsFile;
ULONG DeviceId, FileSize, DirOffset, FileOffset, Size;
PRAW_DIR_REC DirEntry;
BOOLEAN IsDirectory;
EtfsFile = Directory->FsSpecificData;
DeviceId = EtfsFile->DeviceId;
EtfsDevice = EtfsDeviceTable[DeviceId];
/* Find the given file (or directory) in the given directory */
Status = EtfspCachedSearchForDirent(Directory,
FileName,
&DirEntry,
&DirOffset,
FALSE);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Find out information about the file (or directory) we found */
EtfspGetDirectoryInfo(EtfsDevice,
DirEntry,
&FileOffset,
&FileSize,
&IsDirectory);
/* Allocate a file entry */
NewFile = BlMmAllocateHeap(sizeof(*NewFile));
if (!NewFile)
{
return STATUS_NO_MEMORY;
}
/* Zero it out */
RtlZeroMemory(NewFile, sizeof(*NewFile));
/* Figure out the size of the path and filename plus a slash and NUL */
Size = wcslen(Directory->FilePath) + wcslen(FileName) + 2;
FilePath = BlMmAllocateHeap(Size * sizeof(WCHAR));
if (!FilePath)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Allocate an ETFS file entry */
EtfsFile = (PBL_ETFS_FILE)BlMmAllocateHeap(sizeof(*EtfsFile));
if (!EtfsFile)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Zero it out */
RtlZeroMemory(EtfsFile, sizeof(*EtfsFile));
/* Capture the device ID of the directory */
NewFile->DeviceId = Directory->DeviceId;
/* Check if this is the root or a filename\directory under */
FormatString = L"%ls%ls";
if (Directory->FilePath[1])
{
FormatString = L"%ls\\%ls";
}
/* Combine the paths, and save the final path in the file entry */
_snwprintf(FilePath, Size, FormatString, Directory->FilePath, FileName);
NewFile->FilePath = FilePath;
/* Copy the ETFS function callbacks into the file netry */
RtlCopyMemory(&NewFile->Callbacks,
&EtfsFunctionTable,
sizeof(NewFile->Callbacks));
/* Fill out the rest of the details */
EtfsFile->DiskOffset = FileOffset;
EtfsFile->DirOffset = DirOffset;
EtfsFile->Size = FileSize;
EtfsFile->DeviceId = DeviceId;
/* Check if this is a directory */
if (IsDirectory)
{
EtfsFile->Flags |= BL_ETFS_FILE_ENTRY_DIRECTORY;
NewFile->Flags |= BL_FILE_ENTRY_DIRECTORY;
}
/* Write down the name of the filesystem */
EtfsFile->FsName = L"cdfs";
/* All done, return the file entry, and save the ETFS side */
NewFile->FsSpecificData = EtfsFile;
*FileEntry = NewFile;
return Status;
Quickie:
/* Failure path -- free the file path if we had one */
if (NewFile->FilePath)
{
BlMmFreeHeap(NewFile->FilePath);
}
/* Free the ETFS file entry if we had one */
if (NewFile->FsSpecificData)
{
BlMmFreeHeap(NewFile->FsSpecificData);
}
/* Free the file entry itself, and return the error code */
BlMmFreeHeap(NewFile);
return Status;
}
NTSTATUS
EtfspCheckCdfs (
_In_ PBL_ETFS_DEVICE EtfsDevice,
_In_ ULONG DeviceId,
_Out_ PRAW_ISO_VD *VolumeDescriptor,
_Out_ PBOOLEAN VolumeIsIso
)
{
EfiPrintf(L"Raw Cdfs not implemented\r\n");
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
EtfspCheckEtfs (
_In_ PBL_ETFS_DEVICE EtfsDevice,
_In_ ULONG DeviceId,
_Out_ PRAW_ISO_VD *VolumeDescriptor,
_Out_ PBOOLEAN VolumeIsIso
)
{
PRAW_ISO_VD IsoVd;
PRAW_ET_VD EtVd;
NTSTATUS Status;
BOOLEAN IsIso;
BL_DEVICE_INFORMATION DeviceInformation;
ULONG Unknown, BytesRead;
ANSI_STRING CompareString, String;
/* Save our static buffer pointer */
IsoVd = (PRAW_ISO_VD)EtfsDevice->MemoryBlock;
EtVd = (PRAW_ET_VD)IsoVd;
/* First, read the El Torito Volume Descriptor */
BlDeviceGetInformation(DeviceId, &DeviceInformation);
Unknown = DeviceInformation.BlockDeviceInfo.Unknown;
DeviceInformation.BlockDeviceInfo.Unknown |= 1;
BlDeviceSetInformation(DeviceId, &DeviceInformation);
Status = BlDeviceReadAtOffset(DeviceId,
CD_SECTOR_SIZE,
(FIRST_VD_SECTOR + 1) * CD_SECTOR_SIZE,
EtfsDevice->MemoryBlock,
&BytesRead);
DeviceInformation.BlockDeviceInfo.Unknown = Unknown;
BlDeviceSetInformation(DeviceId, &DeviceInformation);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L" read failed\r\n");
return Status;
}
/* Remember that's where we last read */
EtfsDevice->Offset = (FIRST_VD_SECTOR + 1) * CD_SECTOR_SIZE;
/* Check if it's EL TORITO! */
RtlInitString(&String, "EL TORITO SPECIFICATION");
CompareString.Buffer = (PCHAR)EtVd->SystemId;
CompareString.Length = 23;
CompareString.MaximumLength = 23;
if (!RtlEqualString(&CompareString, &String, TRUE))
{
return STATUS_UNSUCCESSFUL;
}
/* Check the version and boot indicator */
if ((EtVd->Version != 1) || (EtVd->BootIndicator))
{
return STATUS_UNSUCCESSFUL;
}
/* Check if it has the CD0001 identifier */
RtlInitString(&String, ISO_VOL_ID);
CompareString.Buffer = (PCHAR)EtVd->StandardId;
CompareString.Length = 5;
CompareString.MaximumLength = 5;
if (!RtlEqualString(&CompareString, &String, TRUE))
{
return STATUS_UNSUCCESSFUL;
}
/* Step two, we now want to read the ISO Volume Descriptor */
DeviceInformation.BlockDeviceInfo.Unknown |= 1u;
BlDeviceSetInformation(DeviceId, &DeviceInformation);
Status = BlDeviceReadAtOffset(DeviceId,
CD_SECTOR_SIZE,
FIRST_VD_SECTOR * CD_SECTOR_SIZE,
EtfsDevice->MemoryBlock,
&BytesRead);
DeviceInformation.BlockDeviceInfo.Unknown = Unknown;
BlDeviceSetInformation(DeviceId, &DeviceInformation);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Remember where we left off */
EtfsDevice->Offset = FIRST_VD_SECTOR * CD_SECTOR_SIZE;
/* This should also say CD0001 */
CompareString.Buffer = (PCHAR)IsoVd->StandardId;
CompareString.Length = 5;
CompareString.MaximumLength = 5;
IsIso = RtlEqualString(&CompareString, &String, TRUE);
if (!IsIso)
{
return STATUS_UNSUCCESSFUL;
}
/* And should be a version we support */
if ((IsoVd->Version != VERSION_1) || (IsoVd->DescType != VD_PRIMARY))
{
return STATUS_UNSUCCESSFUL;
}
/* Return back to the caller */
*VolumeDescriptor = IsoVd;
*VolumeIsIso = IsIso;
return STATUS_SUCCESS;
}
NTSTATUS
EtfspDeviceContextDestroy (
_In_ PBL_ETFS_DEVICE EtfsDevice
)
{
if (EtfsDevice->MemoryBlock)
{
BlMmFreeHeap(EtfsDevice->MemoryBlock);
}
BlMmFreeHeap(EtfsDevice);
return STATUS_SUCCESS;
}
NTSTATUS
EtfspCreateContext (
_In_ ULONG DeviceId,
_Out_ PBL_ETFS_DEVICE *EtfsDevice
)
{
PBL_ETFS_DEVICE NewContext;
PVOID MemoryBlock;
NTSTATUS Status;
BOOLEAN IsIso;
PRAW_ISO_VD RawVd;
NewContext = (PBL_ETFS_DEVICE)BlMmAllocateHeap(sizeof(*NewContext));
if (!NewContext)
{
return STATUS_NO_MEMORY;
}
RtlZeroMemory(NewContext, sizeof(*NewContext));
MemoryBlock = BlMmAllocateHeap(CD_SECTOR_SIZE);
NewContext->MemoryBlock = MemoryBlock;
if (!MemoryBlock)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
Status = EtfspCheckEtfs(NewContext, DeviceId, &RawVd, &IsIso);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"Drive not EDFS. Checking for CDFS: %lx\r\n");
Status = EtfspCheckCdfs(NewContext, DeviceId, &RawVd, &IsIso);
}
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"Drive not CDFS. Failing: %lx\r\n");
goto Quickie;
}
NewContext->IsIso = IsIso;
NewContext->BlockSize = RVD_LB_SIZE(RawVd, IsIso);
NewContext->VolumeSize = RVD_VOL_SIZE(RawVd, IsIso);
EtfspGetDirectoryInfo(NewContext,
(PRAW_DIR_REC)RVD_ROOT_DE(RawVd, IsIso),
&NewContext->RootDirOffset,
&NewContext->RootDirSize,
0);
Status = STATUS_SUCCESS;
Quickie:
if (!NT_SUCCESS(Status))
{
EtfspDeviceContextDestroy(NewContext);
NewContext = NULL;
}
*EtfsDevice = NewContext;
return Status;
}
NTSTATUS
EtfspDeviceTableDestroyEntry (
_In_ PBL_ETFS_DEVICE EtfsDevice,
_In_ ULONG Index
)
{
EtfspDeviceContextDestroy(EtfsDevice);
EtfsDeviceTable[Index] = NULL;
return STATUS_SUCCESS;
}
NTSTATUS
EtfsMount (
_In_ ULONG DeviceId,
_In_ ULONG Unknown,
_Out_ PBL_FILE_ENTRY* FileEntry
)
{
PBL_ETFS_DEVICE EtfsDevice = NULL;
PBL_FILE_ENTRY RootEntry;
NTSTATUS Status;
PBL_ETFS_FILE EtfsFile;
EfiPrintf(L"Trying to mount as ETFS...\r\n");
Status = EtfspCreateContext(DeviceId, &EtfsDevice);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"ETFS context failed: %lx\r\n");
return Status;
}
Status = BlTblSetEntry(&EtfsDeviceTable,
&EtfsDeviceTableEntries,
EtfsDevice,
&DeviceId,
TblDoNotPurgeEntry);
if (!NT_SUCCESS(Status))
{
EtfspDeviceContextDestroy(EtfsDevice);
return Status;
}
RootEntry = BlMmAllocateHeap(sizeof(*RootEntry));
if (!RootEntry)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
RtlZeroMemory(RootEntry, sizeof(*RootEntry));
RootEntry->FilePath = BlMmAllocateHeap(4);
if (!RootEntry->FilePath)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
wcsncpy(RootEntry->FilePath, L"\\", 1);
RootEntry->DeviceId = DeviceId;
RtlCopyMemory(&RootEntry->Callbacks,
&EtfsFunctionTable,
sizeof(RootEntry->Callbacks));
EtfsFile = (PBL_ETFS_FILE)BlMmAllocateHeap(sizeof(*EtfsFile));
if (!EtfsFile)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
RootEntry->Flags |= 0x10000;
RtlZeroMemory(EtfsFile, sizeof(*EtfsFile));
RootEntry->FsSpecificData = EtfsFile;
EtfsFile->DeviceId = DeviceId;
EtfsFile->Flags |= 1;
EtfsFile->DiskOffset = EtfsDevice->RootDirOffset;
EtfsFile->DirOffset = 0;
EtfsFile->Size = EtfsDevice->RootDirSize;
EtfsFile->FsName = L"cdfs";
*FileEntry = RootEntry;
return STATUS_SUCCESS;
Quickie:
if (RootEntry->FilePath)
{
BlMmFreeHeap(RootEntry->FilePath);
}
if (RootEntry->FsSpecificData)
{
BlMmFreeHeap(RootEntry->FsSpecificData);
}
if (RootEntry)
{
BlMmFreeHeap(RootEntry);
}
EtfspDeviceTableDestroyEntry(EtfsDevice, DeviceId);
return Status;
}
NTSTATUS
EtfsInitialize (
VOID
)
{
NTSTATUS Status;
/* Allocate the device table with 2 entries*/
EtfsDeviceTableEntries = 2;
EtfsDeviceTable = BlMmAllocateHeap(sizeof(PBL_FILE_ENTRY) *
EtfsDeviceTableEntries);
if (EtfsDeviceTable)
{
/* Zero it out */
RtlZeroMemory(EtfsDeviceTable,
sizeof(PBL_FILE_ENTRY) * EtfsDeviceTableEntries);
Status = STATUS_SUCCESS;
}
else
{
/* No memory, fail */
Status = STATUS_NO_MEMORY;
}
/* Return back to caller */
return Status;
}

110
boot/environ/lib/io/fat.c Normal file
View file

@ -0,0 +1,110 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/io/fat.c
* PURPOSE: Boot Library FAT File System Management Routines
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <bl.h>
#include <fs_rec/fs_rec.h>
/* DATA VARIABLES ************************************************************/
PVOID* FatDeviceTable;
ULONG FatDeviceTableEntries;
PWCHAR FatpLongFileName;
/* FUNCTIONS *****************************************************************/
NTSTATUS
FatMount (
_In_ ULONG DeviceId,
_In_ ULONG Unknown,
_Out_ PBL_FILE_ENTRY* FileEntry
)
{
BL_DEVICE_INFORMATION DeviceInformation;
ULONG UnknownFlag;
NTSTATUS Status;
PACKED_BOOT_SECTOR FatBootSector;
BIOS_PARAMETER_BLOCK BiosBlock;
/* Capture thing */
BlDeviceGetInformation(DeviceId, &DeviceInformation);
UnknownFlag = DeviceInformation.BlockDeviceInfo.Unknown;
/* Set thing to 1 */
DeviceInformation.BlockDeviceInfo.Unknown |= 1;
BlDeviceSetInformation(DeviceId, &DeviceInformation);
/* Read the boot sector */
Status = BlDeviceReadAtOffset(DeviceId,
sizeof(FatBootSector),
0,
&FatBootSector,
NULL);
/* Restore thing back */
DeviceInformation.BlockDeviceInfo.Unknown = UnknownFlag;
BlDeviceSetInformation(DeviceId, &DeviceInformation);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"Failed reading drive: %lx\r\n", Status);
return Status;
}
FatUnpackBios(&BiosBlock, &FatBootSector.PackedBpb);
/* For now, quickly fail if this isn't FAT */
if (FatBootSector.Jump[0] != 0xE9)
{
return STATUS_UNSUCCESSFUL;
}
EfiPrintf(L"Jump: %lx Bytes Per Sector: %d Sectors Per Cluster: %d Reserved: %d Fats: %d Sectors: %d Large Sectors: %d Media: %lx RootEntries: %d\r\n",
FatBootSector.Jump[0],
BiosBlock.BytesPerSector,
BiosBlock.SectorsPerCluster,
BiosBlock.ReservedSectors,
BiosBlock.Fats,
BiosBlock.Sectors,
BiosBlock.LargeSectors,
BiosBlock.Media,
BiosBlock.RootEntries);
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
FatInitialize (
VOID
)
{
NTSTATUS Status;
/* Allocate the device table with 2 entries*/
FatDeviceTableEntries = 2;
FatDeviceTable = BlMmAllocateHeap(sizeof(PBL_FILE_ENTRY) *
FatDeviceTableEntries);
if (FatDeviceTable)
{
/* Zero it out */
RtlZeroMemory(FatDeviceTable,
sizeof(PBL_FILE_ENTRY) * FatDeviceTableEntries);
/* Allocate a 512 byte buffer for long file name conversion */
FatpLongFileName = BlMmAllocateHeap(512);
Status = FatpLongFileName != NULL ? STATUS_SUCCESS : STATUS_NO_MEMORY;
}
else
{
/* No memory, fail */
Status = STATUS_NO_MEMORY;
}
/* Return back to caller */
return Status;
}

1004
boot/environ/lib/io/file.c Normal file

File diff suppressed because it is too large Load diff

70
boot/environ/lib/io/io.c Normal file
View file

@ -0,0 +1,70 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/io/io.c
* PURPOSE: Boot Library I/O Management Routines
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
ULONG IoMgrRoutineEntries;
PVOID* IoMgrDestroyRoutineTable;
/* FUNCTIONS *****************************************************************/
NTSTATUS
BlpIoRegisterDestroyRoutine (
_In_ PBL_IO_DESTROY_ROUTINE DestroyRoutine
)
{
ULONG Id;
return BlTblSetEntry(&IoMgrDestroyRoutineTable,
&IoMgrRoutineEntries,
DestroyRoutine,
&Id,
TblDoNotPurgeEntry);
}
NTSTATUS
BlpIoInitialize (
VOID
)
{
NTSTATUS Status;
ULONG Size;
/* Allocate the I/O table */
IoMgrRoutineEntries = 4;
Size = IoMgrRoutineEntries * sizeof(PVOID);
IoMgrDestroyRoutineTable = BlMmAllocateHeap(Size);
if (IoMgrDestroyRoutineTable)
{
/* Zero it out */
RtlZeroMemory(IoMgrDestroyRoutineTable, Size);
/* Initialize the device manager */
Status = BlpDeviceInitialize();
/* Initialize the file manager */
if (NT_SUCCESS(Status))
{
Status = BlpFileInitialize();
}
}
else
{
/* No memory */
Status = STATUS_NO_MEMORY;
}
/* Return initialization status */
return Status;
}

0
boot/environ/lib/mc/.gitignore vendored Normal file
View file

1364
boot/environ/lib/misc/bcd.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,870 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/misc/bcdopt.c
* PURPOSE: Boot Library BCD Option Parsing Routines
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
#include <bcd.h>
/* FUNCTIONS *****************************************************************/
PBL_BCD_OPTION
MiscGetBootOption (
_In_ PBL_BCD_OPTION List,
_In_ ULONG Type
)
{
ULONG_PTR NextOption = 0, ListOption;
PBL_BCD_OPTION Option, FoundOption;
/* No options, bail out */
if (!List)
{
return NULL;
}
/* Loop while we find an option */
FoundOption = NULL;
do
{
/* Get the next option and see if it matches the type */
Option = (PBL_BCD_OPTION)((ULONG_PTR)List + NextOption);
if ((Option->Type == Type) && !(Option->Empty))
{
FoundOption = Option;
break;
}
/* Store the offset of the next option */
NextOption = Option->NextEntryOffset;
/* Failed to match. Check for list options */
ListOption = Option->ListOffset;
if (ListOption)
{
/* Try to get a match in the associated option */
Option = MiscGetBootOption((PBL_BCD_OPTION)((ULONG_PTR)Option +
ListOption),
Type);
if (Option)
{
/* Return it */
FoundOption = Option;
break;
}
}
} while (NextOption);
/* Return the option that was found, if any */
return FoundOption;
}
/*++
* @name BlGetBootOptionListSize
*
* The BlGetBootOptionListSize routine
*
* @param BcdOption
* UEFI Image Handle for the current loaded application.
*
* @return Size of the BCD option
*
*--*/
ULONG
BlGetBootOptionListSize (
_In_ PBL_BCD_OPTION BcdOption
)
{
ULONG Size = 0, NextOffset = 0;
PBL_BCD_OPTION NextOption;
/* Loop all the options*/
do
{
/* Move to the next one */
NextOption = (PBL_BCD_OPTION)((ULONG_PTR)BcdOption + NextOffset);
/* Compute the size of the next one */
Size += BlGetBootOptionSize(NextOption);
/* Update the offset */
NextOffset = NextOption->NextEntryOffset;
} while (NextOffset);
/* Return final computed size */
return Size;
}
/*++
* @name BlGetBootOptionSize
*
* The BlGetBootOptionSize routine
*
* @param BcdOption
* UEFI Image Handle for the current loaded application.
*
* @return Size of the BCD option
*
*--*/
ULONG
BlGetBootOptionSize (
_In_ PBL_BCD_OPTION BcdOption
)
{
ULONG Size, Offset;
/* Check if there's any data */
if (BcdOption->DataOffset)
{
/* Add the size of the data */
Size = BcdOption->DataOffset + BcdOption->DataSize;
}
else
{
/* No data, just the structure itself */
Size = sizeof(*BcdOption);
}
/* Any associated options? */
Offset = BcdOption->ListOffset;
if (Offset)
{
/* Go get those too */
Size += BlGetBootOptionListSize((PVOID)((ULONG_PTR)BcdOption + Offset));
}
/* Return the final size */
return Size;
}
NTSTATUS
BlGetBootOptionString (
_In_ PBL_BCD_OPTION List,
_In_ ULONG Type,
_Out_ PWCHAR* Value
)
{
NTSTATUS Status;
PBL_BCD_OPTION Option;
PWCHAR String, StringCopy;
ULONG StringLength;
BcdElementType ElementType;
//PGUID AppIdentifier;
/* Make sure this is a BCD_STRING */
ElementType.PackedValue = Type;
if (ElementType.Format != BCD_TYPE_STRING)
{
return STATUS_INVALID_PARAMETER;
}
/* Return the data */
Option = MiscGetBootOption(List, Type);
if (Option)
{
/* Extract the string */
String = (PWCHAR)((ULONG_PTR)Option + Option->DataOffset);
Status = STATUS_SUCCESS;
}
else
{
/* No string is present */
String = NULL;
Status = STATUS_NOT_FOUND;
}
/* Compute the data size */
StringLength = Option->DataSize / sizeof(WCHAR);
#ifdef _SECURE_BOOT_
/* Filter out SecureBoot Options */
AppIdentifier = BlGetApplicationIdentifier();
Status = BlpBootOptionCallbackString(AppIdentifier, Type, String, StringLength, &String, &StringLength);
#else
#endif
/* Make sure we have a valid, non-filtered string */
if (NT_SUCCESS(Status))
{
/* Check if we have space for one more character */
Status = RtlULongAdd(StringLength, 1, &StringLength);
if (NT_SUCCESS(Status))
{
/* Check if it's safe to multiply by two */
Status = RtlULongMult(StringLength, sizeof(WCHAR), &StringLength);
if (NT_SUCCESS(Status))
{
/* Allocate a copy for the string */
StringCopy = BlMmAllocateHeap(StringLength);
if (StringCopy)
{
/* NULL-terminate it */
RtlCopyMemory(StringCopy,
String,
StringLength - sizeof(UNICODE_NULL));
StringCopy[StringLength] = UNICODE_NULL;
*Value = StringCopy;
Status = STATUS_SUCCESS;
}
else
{
/* No memory, fail */
Status = STATUS_NO_MEMORY;
}
}
}
}
/* All done */
return Status;
}
NTSTATUS
BlGetBootOptionGuid (
_In_ PBL_BCD_OPTION List,
_In_ ULONG Type,
_Out_ PGUID Value
)
{
NTSTATUS Status;
PBL_BCD_OPTION Option;
PGUID Guid;
BcdElementType ElementType;
/* Make sure this is a BCD_TYPE_OBJECT */
ElementType.PackedValue = Type;
if (ElementType.Format != BCD_TYPE_OBJECT)
{
return STATUS_INVALID_PARAMETER;
}
/* Return the data */
Option = MiscGetBootOption(List, Type);
if (!Option)
{
/* Set failure if no data exists */
Status = STATUS_NOT_FOUND;
}
else
{
/* Copy the GUID */
Guid = (PGUID)((ULONG_PTR)Option + Option->DataOffset);
RtlCopyMemory(Value, Guid, Option->DataSize);
Status = STATUS_SUCCESS;
}
/* All good */
return Status;
}
NTSTATUS
BlGetBootOptionGuidList (
_In_ PBL_BCD_OPTION List,
_In_ ULONG Type,
_Out_ PGUID *Value,
_In_ PULONG Count
)
{
NTSTATUS Status;
PBL_BCD_OPTION Option;
PGUID GuidCopy, Guid;
ULONG GuidCount;
BcdElementType ElementType;
/* Make sure this is a BCD_TYPE_OBJECT_LIST */
ElementType.PackedValue = Type;
if (ElementType.Format != BCD_TYPE_OBJECT_LIST)
{
return STATUS_INVALID_PARAMETER;
}
/* Return the data */
Option = MiscGetBootOption(List, Type);
if (!Option)
{
/* Set failure if no data exists */
Status = STATUS_NOT_FOUND;
}
else
{
/* Get the GUIDs and allocate a copy for them */
Guid = (PGUID)((ULONG_PTR)Option + Option->DataOffset);
GuidCopy = BlMmAllocateHeap(Option->DataSize);
if (GuidCopy)
{
/* Copy the GUIDs */
RtlCopyMemory(GuidCopy, Guid, Option->DataSize);
/* Return the number of GUIDs and the start of the array */
GuidCount = Option->DataSize / sizeof(GUID);
*Value = GuidCopy;
*Count = GuidCount;
Status = STATUS_SUCCESS;
}
else
{
/* No memory for the copy */
Status = STATUS_NO_MEMORY;
}
}
/* All good */
return Status;
}
NTSTATUS
BlGetBootOptionDevice (
_In_ PBL_BCD_OPTION List,
_In_ ULONG Type,
_Out_ PBL_DEVICE_DESCRIPTOR* Value,
_In_opt_ PBL_BCD_OPTION* ExtraOptions
)
{
NTSTATUS Status;
PBL_BCD_OPTION Option, ListData, ListCopy, SecureListData;
PBCD_DEVICE_OPTION BcdDevice;
ULONG DeviceSize, ListOffset, ListSize;
PBL_DEVICE_DESCRIPTOR DeviceDescriptor, SecureDescriptor;
//PGUID AppIdentifier;
BcdElementType ElementType;
/* Make sure this is a BCD_TYPE_DEVICE */
ElementType.PackedValue = Type;
if (ElementType.Format != BCD_TYPE_DEVICE)
{
return STATUS_INVALID_PARAMETER;
}
/* Return the data */
Option = MiscGetBootOption(List, Type);
if (!Option)
{
/* Set failure if no data exists */
Status = STATUS_NOT_FOUND;
}
else
{
/* Otherwise, read the size of the BCD device encoded */
BcdDevice = (PBCD_DEVICE_OPTION)((ULONG_PTR)Option + Option->DataOffset);
DeviceSize = BcdDevice->DeviceDescriptor.Size;
/* Allocate a buffer to copy it into */
DeviceDescriptor = BlMmAllocateHeap(DeviceSize);
if (!DeviceDescriptor)
{
return STATUS_NO_MEMORY;
}
/* Copy it into that buffer */
RtlCopyMemory(DeviceDescriptor, &BcdDevice->DeviceDescriptor, DeviceSize);
Status = STATUS_SUCCESS;
}
/* Check if extra options were requested */
if (ExtraOptions)
{
/* See where they are */
ListOffset = Option->ListOffset;
if (ListOffset)
{
/* See how big they are */
ListData = (PBL_BCD_OPTION)((ULONG_PTR)Option + ListOffset);
ListSize = BlGetBootOptionListSize(ListData);
/* Allocate a buffer to hold them into */
ListCopy = BlMmAllocateHeap(ListSize);
if (!ListCopy)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Copy them in there */
RtlCopyMemory(ListCopy, ListData, ListSize);
}
}
#ifdef _SECURE_BOOT_
/* Filter out SecureBoot Options */
AppIdentifier = BlGetApplicationIdentifier();
if (BlpBootOptionCallbacks)
{
DeviceCallback = BlpBootOptionCallbacks->Device;
if (DeviceCallback)
{
Status = DeviceCallback(BlpBootOptionCallbackCookie,
Status,
0,
AppIdentifier,
Type,
&SecureDescriptor,
PtrOptionData);
}
}
#else
/* No secure boot, so the secure descriptors are the standard ones */
SecureDescriptor = DeviceDescriptor;
SecureListData = ListCopy;
#endif
/* Check if the data was read correctly */
if (NT_SUCCESS(Status))
{
/* Check if we had a new descriptor after filtering */
if (SecureDescriptor != DeviceDescriptor)
{
/* Yep -- if we had an old one, free it */
if (DeviceDescriptor)
{
BlMmFreeHeap(DeviceDescriptor);
}
}
/* Check if we had a new list after filtering */
if (SecureListData != ListCopy)
{
/* Yep -- if we had an old list, free it */
if (ListCopy)
{
BlMmFreeHeap(ListCopy);
}
}
/* Finally, check if the caller wanted extra options */
if (ExtraOptions)
{
/* Yep -- so pass the caller our copy */
*ExtraOptions = ListCopy;
ListCopy = NULL;
}
/* Caller always wants data back, so pass them our copy */
*Value = DeviceDescriptor;
DeviceDescriptor = NULL;
}
Quickie:
/* On the failure path, if these buffers are active, we should free them */
if (ListCopy)
{
BlMmFreeHeap(ListCopy);
}
if (DeviceDescriptor)
{
BlMmFreeHeap(DeviceDescriptor);
}
/* All done */
return Status;
}
NTSTATUS
BlGetBootOptionInteger (
_In_ PBL_BCD_OPTION List,
_In_ ULONG Type,
_Out_ PULONGLONG Value
)
{
NTSTATUS Status;
PBL_BCD_OPTION Option;
//PGUID AppIdentifier;
BcdElementType ElementType;
/* Make sure this is a BCD_TYPE_INTEGER */
ElementType.PackedValue = Type;
if (ElementType.Format != BCD_TYPE_INTEGER)
{
return STATUS_INVALID_PARAMETER;
}
/* Return the data */
Option = MiscGetBootOption(List, Type);
if (Option)
{
*Value = *(PULONGLONG)((ULONG_PTR)Option + Option->DataOffset);
}
#ifdef _SECURE_BOOT_
/* Filter out SecureBoot Options */
AppIdentifier = BlGetApplicationIdentifier();
Status = BlpBootOptionCallbackULongLong(AppIdentifier, Type, Value);
#else
/* Option found */
Status = Option ? STATUS_SUCCESS : STATUS_NOT_FOUND;
#endif
return Status;
}
NTSTATUS
BlGetBootOptionBoolean (
_In_ PBL_BCD_OPTION List,
_In_ ULONG Type,
_Out_ PBOOLEAN Value
)
{
NTSTATUS Status;
PBL_BCD_OPTION Option;
//PGUID AppIdentifier;
BcdElementType ElementType;
/* Make sure this is a BCD_TYPE_BOOLEAN */
ElementType.PackedValue = Type;
if (ElementType.Format != BCD_TYPE_BOOLEAN)
{
return STATUS_INVALID_PARAMETER;
}
/* Return the data */
Option = MiscGetBootOption(List, Type);
if (Option)
{
*Value = *(PBOOLEAN)((ULONG_PTR)Option + Option->DataOffset);
}
#ifdef _SECURE_BOOT_
/* Filter out SecureBoot Options */
AppIdentifier = BlGetApplicationIdentifier();
Status = BlpBootOptionCallbackBoolean(AppIdentifier, Type, Value);
#else
/* Option found */
Status = Option ? STATUS_SUCCESS : STATUS_NOT_FOUND;
#endif
return Status;
}
NTSTATUS
BlpGetBootOptionIntegerList (
_In_ PBL_BCD_OPTION List,
_In_ ULONG Type,
_Out_ PULONGLONG* Value,
_Out_ PULONGLONG Count,
_In_ BOOLEAN NoCopy
)
{
PBL_BCD_OPTION Option;
BcdElementType ElementType;
PULONGLONG ValueCopy;
/* Make sure this is a BCD_TYPE_INTEGER_LIST */
ElementType.PackedValue = Type;
if (ElementType.Format != BCD_TYPE_INTEGER_LIST)
{
return STATUS_INVALID_PARAMETER;
}
/* Return the data */
Option = MiscGetBootOption(List, Type);
if (!Option)
{
return STATUS_NOT_FOUND;
}
/* Check if a copy should be made of it */
if (NoCopy)
{
/* Nope, return the raw value */
*Value = (PULONGLONG)((ULONG_PTR)Option + Option->DataOffset);
}
else
{
/* Allocate a buffer for the copy */
ValueCopy = BlMmAllocateHeap(Option->DataSize);
if (!ValueCopy)
{
return STATUS_NO_MEMORY;
}
/* Copy the data in */
RtlCopyMemory(ValueCopy,
(PVOID)((ULONG_PTR)Option + Option->DataOffset),
Option->DataSize);
/* Return our copy */
*Value = ValueCopy;
}
/* Return count and success */
*Count = Option->DataSize / sizeof(ULONGLONG);
return STATUS_SUCCESS;
}
NTSTATUS
BlCopyBootOptions (
_In_ PBL_BCD_OPTION OptionList,
_Out_ PBL_BCD_OPTION *CopiedOptions
)
{
NTSTATUS Status;
ULONG OptionSize;
PBL_BCD_OPTION Options;
/* Assume no options */
Status = STATUS_SUCCESS;
*CopiedOptions = NULL;
/* Get the size of the list and allocate a copy for it */
OptionSize = BlGetBootOptionListSize(OptionList);
Options = BlMmAllocateHeap(OptionSize);
if (!Options)
{
return STATUS_NO_MEMORY;
}
/* Make the copy and return it to the caller */
RtlCopyMemory(Options, OptionList, OptionSize);
*CopiedOptions = Options;
return Status;
}
NTSTATUS
BlAppendBootOptionBoolean (
_In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
_In_ ULONG OptionId
)
{
NTSTATUS Status;
PBL_BCD_OPTION Option;
/* Allocate space for the entry -- remember BOOLEANs are USHORTs in BCD */
Option = BlMmAllocateHeap(sizeof(*Option) + sizeof(USHORT));
if (!Option)
{
return STATUS_NO_MEMORY;
}
/* Initialize it and set the boolean to TRUE */
RtlZeroMemory(Option, sizeof(*Option) + sizeof(USHORT));
Option->DataSize = sizeof(USHORT);
Option->Type = OptionId;
Option->DataOffset = sizeof(*Option);
*(PBOOLEAN)(Option + 1) = TRUE;
/* Append it */
Status = BlAppendBootOptions(AppEntry, Option);
/* We're all done, free our initial option */
BlMmFreeHeap(Option);
return Status;
}
NTSTATUS
BlAppendBootOptionInteger (
_In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
_In_ ULONG OptionId,
_In_ ULONGLONG Value
)
{
NTSTATUS Status;
PBL_BCD_OPTION Option;
/* Allocate space for the entry */
Option = BlMmAllocateHeap(sizeof(*Option) + sizeof(Value));
if (!Option)
{
return STATUS_NO_MEMORY;
}
/* Initialize it and set the integer to the given value */
RtlZeroMemory(Option, sizeof(*Option) + sizeof(Value));
Option->DataSize = sizeof(Value);
Option->Type = OptionId;
Option->DataOffset = sizeof(*Option);
*(PULONGLONG)(Option + 1) = Value;
/* Append it */
Status = BlAppendBootOptions(AppEntry, Option);
/* We're all done, free our initial option */
BlMmFreeHeap(Option);
return Status;
}
NTSTATUS
BlAppendBootOptionString (
_In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
_In_ PWCHAR OptionString
)
{
NTSTATUS Status;
ULONG StringSize;
PBL_BCD_OPTION Option;
/* Get the length in bytes */
Status = RtlULongLongToULong(wcslen(OptionString) * sizeof(WCHAR),
&StringSize);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Add a NULL-terminator */
Status = RtlULongAdd(StringSize, sizeof(UNICODE_NULL), &StringSize);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Allocate space for the entry */
Option = BlMmAllocateHeap(sizeof(*Option) + StringSize);
if (!Option)
{
return STATUS_NO_MEMORY;
}
/* Initialize it and copy the string value */
RtlZeroMemory(Option, sizeof(*Option) + StringSize);
Option->DataSize = StringSize;
Option->Type = BcdLibraryString_ApplicationPath;
Option->DataOffset = sizeof(*Option);
wcsncpy((PWCHAR)Option + 1, OptionString, StringSize / sizeof(WCHAR));
/* Append it */
Status = BlAppendBootOptions(AppEntry, Option);
/* We're all done, free our initial option */
BlMmFreeHeap(Option);
return Status;
}
NTSTATUS
BlAppendBootOptions (
_In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
_In_ PBL_BCD_OPTION Options
)
{
ULONG OptionsSize, CurrentSize;
PBL_BCD_OPTION NewOptions, CurrentOptions, NextOption;
NTSTATUS Status;
ULONG CurrentOffset;
/* Get the current options */
CurrentOptions = AppEntry->BcdData;
/* Calculate the size of the current, and the appended options */
CurrentSize = BlGetBootOptionListSize(CurrentOptions);
OptionsSize = BlGetBootOptionListSize(Options);
/* Allocate a buffer for the concatenated (new) options */
NewOptions = BlMmAllocateHeap(CurrentSize + OptionsSize);
if (!NewOptions)
{
return STATUS_NO_MEMORY;
}
/* Copy the old options, and the ones to be added */
RtlCopyMemory(NewOptions, CurrentOptions, CurrentSize);
RtlCopyMemory((PVOID)((ULONG_PTR)NewOptions + CurrentSize),
Options,
OptionsSize);
/* We made it! */
Status = STATUS_SUCCESS;
/* Scan through to the last option in the list */
CurrentOffset = 0;
do
{
NextOption = (PBL_BCD_OPTION)((ULONG_PTR)NewOptions + CurrentOffset);
CurrentOffset = NextOption->NextEntryOffset;
} while (CurrentOffset);
/* Every other option now has to have its offset adjusted */
do
{
NextOption->NextEntryOffset += CurrentSize;
NextOption = (PBL_BCD_OPTION)((ULONG_PTR)NewOptions + NextOption->NextEntryOffset);
} while (NextOption->NextEntryOffset);
/* If we already had internal options, free them */
if (AppEntry->Flags & BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL)
{
BlMmFreeHeap(AppEntry->BcdData);
}
/* Write the new pointer */
AppEntry->BcdData = NewOptions;
/* Options are now internal, not external */
AppEntry->Flags &= ~BL_APPLICATION_ENTRY_BCD_OPTIONS_EXTERNAL;
AppEntry->Flags |= BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL;
return Status;
}
VOID
BlRemoveBootOption (
_In_ PBL_BCD_OPTION List,
_In_ ULONG Type
)
{
PBL_BCD_OPTION Option;
/* Keep going until the option is gone */
while (1)
{
/* Get the BCD option */
Option = MiscGetBootOption(List, Type);
if (!Option)
{
break;
}
/* Pretend it's empty */
Option->Empty = TRUE;
}
}
NTSTATUS
BlReplaceBootOptions (
_In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
_In_ PBL_BCD_OPTION OldOptions
)
{
NTSTATUS Status;
ULONG OptionSize;
PBL_BCD_OPTION NewOptions;
/* Make sure there's something to replace with */
if (!OldOptions)
{
return STATUS_INVALID_PARAMETER;
}
/* Check if we already had allocated internal options */
if (AppEntry->Flags & BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL)
{
/* Free them */
BlMmFreeHeap(AppEntry->BcdData);
}
/* Reset option flags */
AppEntry->Flags &= ~(BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL |
BL_APPLICATION_ENTRY_BCD_OPTIONS_EXTERNAL);
/* Reset the options and set success for now */
Status = STATUS_SUCCESS;
AppEntry->BcdData = NULL;
/* Get the size of the new list of options */
OptionSize = BlGetBootOptionListSize(OldOptions);
/* Allocate a copy of the new list */
NewOptions = BlMmAllocateHeap(OptionSize);
if (!NewOptions)
{
return STATUS_NO_MEMORY;
}
/* Copy it in */
RtlCopyMemory(NewOptions, OldOptions, OptionSize);
/* Set it as the new set of options and return */
AppEntry->Flags |= BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL;
AppEntry->BcdData = NewOptions;
return Status;
}

View file

@ -0,0 +1,947 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/misc/bootreg.c
* PURPOSE: Boot Library Boot Registry Wrapper for CMLIB
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
#include <bcd.h>
/* DEFINITIONS ***************************************************************/
#define BI_FLUSH_HIVE 0x01
#define BI_HIVE_WRITEABLE 0x02
/* DATA STRUCTURES ***********************************************************/
typedef struct _BI_KEY_HIVE
{
PHBASE_BLOCK BaseBlock;
ULONG HiveSize;
PBL_FILE_PATH_DESCRIPTOR FilePath;
CMHIVE Hive;
LONG ReferenceCount;
ULONG Flags;
PCM_KEY_NODE RootNode;
} BI_KEY_HIVE, *PBI_KEY_HIVE;
typedef struct _BI_KEY_OBJECT
{
PBI_KEY_HIVE KeyHive;
PCM_KEY_NODE KeyNode;
HCELL_INDEX KeyCell;
PWCHAR KeyName;
} BI_KEY_OBJECT, *PBI_KEY_OBJECT;
/* GLOBALS *******************************************************************/
BOOLEAN BiHiveHashLibraryInitialized;
ULONGLONG HvSymcryptSeed;
/* FUNCTIONS *****************************************************************/
BOOLEAN
HvIsInPlaceBaseBlockValid (
_In_ PHBASE_BLOCK BaseBlock
)
{
ULONG HiveLength, HeaderSum;
BOOLEAN Valid;
/* Assume failure */
Valid = FALSE;
/* Check for incorrect signature, type, version, or format */
if ((BaseBlock->Signature == 'fger') &&
(BaseBlock->Type == 0) &&
(BaseBlock->Major <= 1) &&
(BaseBlock->Minor <= 5) &&
(BaseBlock->Minor >= 3) &&
(BaseBlock->Format == 1))
{
/* Check for invalid hive size */
HiveLength = BaseBlock->Length;
if (HiveLength)
{
/* Check for misaligned or too large hive size */
if (!(HiveLength & 0xFFF) && HiveLength <= 0x7FFFE000)
{
/* Check for invalid header checksum */
HeaderSum = HvpHiveHeaderChecksum(BaseBlock);
if (HeaderSum == BaseBlock->CheckSum)
{
/* All good */
Valid = TRUE;
}
}
}
}
/* Return validity */
return Valid;
}
PVOID
NTAPI
CmpAllocate (
_In_ SIZE_T Size,
_In_ BOOLEAN Paged,
_In_ ULONG Tag
)
{
UNREFERENCED_PARAMETER(Paged);
UNREFERENCED_PARAMETER(Tag);
/* Call the heap allocator */
return BlMmAllocateHeap(Size);
}
VOID
NTAPI
CmpFree (
_In_ PVOID Ptr,
_In_ ULONG Quota
)
{
UNREFERENCED_PARAMETER(Quota);
/* Call the heap allocator */
BlMmFreeHeap(Ptr);
}
VOID
BiDereferenceHive (
_In_ HANDLE KeyHandle
)
{
PBI_KEY_OBJECT KeyObject;
/* Get the key object */
KeyObject = (PBI_KEY_OBJECT)KeyHandle;
/* Drop a reference on the parent hive */
--KeyObject->KeyHive->ReferenceCount;
}
VOID
BiFlushHive (
_In_ HANDLE KeyHandle
)
{
/* Not yet implemented */
EfiPrintf(L"NO reg flush\r\n");
return;
}
VOID
BiCloseKey (
_In_ HANDLE KeyHandle
)
{
PBI_KEY_HIVE KeyHive;
PBI_KEY_OBJECT KeyObject;
/* Get the key object and hive */
KeyObject = (PBI_KEY_OBJECT)KeyHandle;
KeyHive = KeyObject->KeyHive;
/* Check if we have a hive, or name, or key node */
if ((KeyHive) || (KeyObject->KeyNode) || (KeyObject->KeyName))
{
/* Drop a reference, see if it's the last one */
BiDereferenceHive(KeyHandle);
if (!KeyHive->ReferenceCount)
{
/* Check if we should flush it */
if (KeyHive->Flags & BI_FLUSH_HIVE)
{
BiFlushHive(KeyHandle);
}
/* Unmap the hive */
MmPapFreePages(KeyHive->BaseBlock, BL_MM_INCLUDE_MAPPED_ALLOCATED);
/* Free the hive and hive path */
BlMmFreeHeap(KeyHive->FilePath);
BlMmFreeHeap(KeyHive);
}
/* Check if a key name is present */
if (KeyObject->KeyName)
{
/* Free it */
BlMmFreeHeap(KeyObject->KeyName);
}
}
/* Free the object */
BlMmFreeHeap(KeyObject);
}
NTSTATUS
BiOpenKey(
_In_ HANDLE ParentHandle,
_In_ PWCHAR KeyName,
_Out_ PHANDLE Handle
)
{
PBI_KEY_OBJECT ParentKey, NewKey;
PBI_KEY_HIVE ParentHive;
NTSTATUS Status;
ULONG NameLength, SubNameLength, NameBytes;
PWCHAR NameStart, NameBuffer;
UNICODE_STRING KeyString;
HCELL_INDEX KeyCell;
PHHIVE Hive;
PCM_KEY_NODE ParentNode;
/* Convert from a handle to our key object */
ParentKey = (PBI_KEY_OBJECT)ParentHandle;
/* Extract the hive and node information */
ParentHive = ParentKey->KeyHive;
ParentNode = ParentKey->KeyNode;
Hive = &ParentKey->KeyHive->Hive.Hive;
/* Initialize variables */
KeyCell = HCELL_NIL;
Status = STATUS_SUCCESS;
NameBuffer = NULL;
/* Loop as long as there's still portions of the key name in play */
NameLength = wcslen(KeyName);
while (NameLength)
{
/* Find the first path separator */
NameStart = wcschr(KeyName, OBJ_NAME_PATH_SEPARATOR);
if (NameStart)
{
/* Look only at the key before the separator */
SubNameLength = NameStart - KeyName;
++NameStart;
}
else
{
/* No path separator, this is the final leaf key */
SubNameLength = NameLength;
}
/* Free the name buffer from the previous pass if needed */
if (NameBuffer)
{
BlMmFreeHeap(NameBuffer);
}
/* Allocate a buffer to hold the name of this specific subkey only */
NameBytes = SubNameLength * sizeof(WCHAR);
NameBuffer = BlMmAllocateHeap(NameBytes + sizeof(UNICODE_NULL));
if (!NameBuffer)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Copy and null-terminate the name of the subkey */
RtlCopyMemory(NameBuffer, KeyName, NameBytes);
NameBuffer[SubNameLength] = UNICODE_NULL;
/* Convert it into a UNICODE_STRING and try to find it */
RtlInitUnicodeString(&KeyString, NameBuffer);
KeyCell = CmpFindSubKeyByName(Hive, ParentNode, &KeyString);
if (KeyCell == HCELL_NIL)
{
Status = STATUS_OBJECT_NAME_NOT_FOUND;
goto Quickie;
}
/* We found it -- get the key node out of it */
ParentNode = (PCM_KEY_NODE)HvGetCell(Hive, KeyCell);
if (!ParentNode)
{
Status = STATUS_REGISTRY_CORRUPT;
goto Quickie;
}
/* Update the key name to the next remaining path element */
KeyName = NameStart;
if (NameStart)
{
/* Update the length to the remainder of the path */
NameLength += -1 - SubNameLength;
}
else
{
/* There's nothing left, this was the leaf key */
NameLength = 0;
}
}
/* Allocate a key object */
NewKey = BlMmAllocateHeap(sizeof(*NewKey));
if (!NewKey)
{
/* Bail out if we had no memory for it */
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Fill out the key object data */
NewKey->KeyNode = ParentNode;
NewKey->KeyHive = ParentHive;
NewKey->KeyName = NameBuffer;
NewKey->KeyCell = KeyCell;
/* Add a reference to the hive */
++ParentHive->ReferenceCount;
/* Return the object back to the caller */
*Handle = NewKey;
Quickie:
/* If we had a name buffer, free it */
if (NameBuffer)
{
BlMmFreeHeap(NameBuffer);
}
/* Return status of the open operation */
return Status;
}
NTSTATUS
BiInitializeAndValidateHive (
_In_ PBI_KEY_HIVE Hive
)
{
ULONG HiveSize;
NTSTATUS Status;
/* Make sure the hive is at least the size of a base block */
if (Hive->HiveSize < sizeof(HBASE_BLOCK))
{
return STATUS_REGISTRY_CORRUPT;
}
/* Make sure that the base block accurately describes the size of the hive */
HiveSize = Hive->BaseBlock->Length + sizeof(HBASE_BLOCK);
if ((HiveSize < sizeof(HBASE_BLOCK)) || (HiveSize > Hive->HiveSize))
{
return STATUS_REGISTRY_CORRUPT;
}
/* Initialize a flat memory hive */
RtlZeroMemory(&Hive->Hive, sizeof(Hive->Hive));
Status = HvInitialize(&Hive->Hive.Hive,
HINIT_FLAT,
0,
0,
Hive->BaseBlock,
CmpAllocate,
CmpFree,
NULL,
NULL,
NULL,
NULL,
0,
NULL);
if (NT_SUCCESS(Status))
{
/* Cleanup volatile/old data */
CmPrepareHive(&Hive->Hive.Hive); // CmCheckRegistry
Status = STATUS_SUCCESS;
}
/* Return the final status */
return Status;
}
NTSTATUS
BiLoadHive (
_In_ PBL_FILE_PATH_DESCRIPTOR FilePath,
_Out_ PHANDLE HiveHandle
)
{
ULONG DeviceId;
PHBASE_BLOCK BaseBlock, NewBaseBlock;
PBI_KEY_OBJECT KeyObject;
PBI_KEY_HIVE BcdHive;
PBL_DEVICE_DESCRIPTOR BcdDevice;
ULONG PathLength, DeviceLength, HiveSize, HiveLength, NewHiveSize;
PWCHAR HiveName, LogName;
BOOLEAN HaveWriteAccess;
NTSTATUS Status;
PVOID LogData;
PHHIVE Hive;
UNICODE_STRING KeyString;
PCM_KEY_NODE RootNode;
HCELL_INDEX CellIndex;
/* Initialize variables */
DeviceId = -1;
BaseBlock = NULL;
BcdHive = NULL;
KeyObject = NULL;
LogData = NULL;
LogName = NULL;
/* Initialize the crypto seed */
if (!BiHiveHashLibraryInitialized)
{
HvSymcryptSeed = 0x82EF4D887A4E55C5;
BiHiveHashLibraryInitialized = TRUE;
}
/* Extract and validate the input path */
BcdDevice = (PBL_DEVICE_DESCRIPTOR)&FilePath->Path;
PathLength = FilePath->Length;
DeviceLength = BcdDevice->Size;
HiveName = (PWCHAR)((ULONG_PTR)BcdDevice + BcdDevice->Size);
if (PathLength <= DeviceLength)
{
/* Doesn't make sense, bail out */
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Attempt to open the underlying device for RW access */
HaveWriteAccess = TRUE;
Status = BlpDeviceOpen(BcdDevice,
BL_DEVICE_READ_ACCESS | BL_DEVICE_WRITE_ACCESS,
0,
&DeviceId);
if (!NT_SUCCESS(Status))
{
/* Try for RO access instead */
HaveWriteAccess = FALSE;
Status = BlpDeviceOpen(BcdDevice, BL_DEVICE_READ_ACCESS, 0, &DeviceId);
if (!NT_SUCCESS(Status))
{
/* No access at all -- bail out */
goto Quickie;
}
}
/* Now try to load the hive on disk */
Status = BlImgLoadImageWithProgress2(DeviceId,
BlLoaderRegistry,
HiveName,
(PVOID*)&BaseBlock,
&HiveSize,
0,
FALSE,
NULL,
NULL);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"Hive read failure: % lx\r\n", Status);
goto Quickie;
}
/* Allocate a hive structure */
BcdHive = BlMmAllocateHeap(sizeof(*BcdHive));
if (!BcdHive)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Initialize it */
RtlZeroMemory(BcdHive, sizeof(*BcdHive));
BcdHive->BaseBlock = BaseBlock;
BcdHive->HiveSize = HiveSize;
if (HaveWriteAccess)
{
BcdHive->Flags |= BI_HIVE_WRITEABLE;
}
/* Make sure the hive was at least one bin long */
if (HiveSize < sizeof(*BaseBlock))
{
Status = STATUS_REGISTRY_CORRUPT;
goto Quickie;
}
/* Make sure the hive contents are at least one bin long */
HiveLength = BaseBlock->Length;
if (BaseBlock->Length < sizeof(*BaseBlock))
{
Status = STATUS_REGISTRY_CORRUPT;
goto Quickie;
}
/* Validate the initial bin (the base block) */
if (!HvIsInPlaceBaseBlockValid(BaseBlock))
{
EfiPrintf(L"Recovery not implemented\r\n");
Status = STATUS_REGISTRY_CORRUPT;
goto Quickie;
}
/* Check if there's log recovery that needs to happen */
if (BaseBlock->Sequence1 != BaseBlock->Sequence2)
{
EfiPrintf(L"Log fix not implemented: %lx %lx\r\n");
Status = STATUS_REGISTRY_CORRUPT;
goto Quickie;
}
/*
* Check if the whole hive doesn't fit in the buffer.
* Note: HiveLength does not include the size of the baseblock itself
*/
if (HiveSize < (HiveLength + sizeof(*BaseBlock)))
{
EfiPrintf(L"Need bigger hive buffer path\r\n");
/* Allocate a slightly bigger buffer */
NewHiveSize = HiveLength + sizeof(*BaseBlock);
Status = MmPapAllocatePagesInRange((PVOID*)&NewBaseBlock,
BlLoaderRegistry,
NewHiveSize >> PAGE_SHIFT,
0,
0,
NULL,
0);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Copy the current data in there */
RtlCopyMemory(NewBaseBlock, BaseBlock, HiveSize);
/* Free the old data */
MmPapFreePages(BaseBlock, BL_MM_INCLUDE_MAPPED_ALLOCATED);
/* Update our pointers */
BaseBlock = NewBaseBlock;
HiveSize = NewHiveSize;
BcdHive->BaseBlock = BaseBlock;
BcdHive->HiveSize = HiveSize;
}
/* Check if any log stuff needs to happen */
if (LogData)
{
EfiPrintf(L"Log fix not implemented: %lx %lx\r\n");
Status = STATUS_REGISTRY_CORRUPT;
goto Quickie;
}
/* Call Hv to setup the hive library */
Status = BiInitializeAndValidateHive(BcdHive);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Now get the root node */
Hive = &BcdHive->Hive.Hive;
RootNode = (PCM_KEY_NODE)HvGetCell(Hive, Hive->BaseBlock->RootCell);
if (!RootNode)
{
Status = STATUS_OBJECT_NAME_NOT_FOUND;
goto Quickie;
}
/* Find the Objects subkey under it to see if it's a real BCD hive */
RtlInitUnicodeString(&KeyString, L"Objects");
CellIndex = CmpFindSubKeyByName(Hive, RootNode, &KeyString);
if (CellIndex == HCELL_NIL)
{
EfiPrintf(L"No OBJECTS subkey found!\r\n");
Status = STATUS_OBJECT_NAME_NOT_FOUND;
goto Quickie;
}
/* This is a valid BCD hive, store its root node here */
BcdHive->RootNode = RootNode;
/* Allocate a copy of the file path */
BcdHive->FilePath = BlMmAllocateHeap(FilePath->Length);
if (!BcdHive->FilePath)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Make a copy of it */
RtlCopyMemory(BcdHive->FilePath, FilePath, FilePath->Length);
/* Create a key object to describe the rot */
KeyObject = BlMmAllocateHeap(sizeof(*KeyObject));
if (!KeyObject)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Fill out the details */
KeyObject->KeyNode = RootNode;
KeyObject->KeyHive = BcdHive;
KeyObject->KeyName = NULL;
KeyObject->KeyCell = Hive->BaseBlock->RootCell;
/* One reference for the key object, plus one lifetime reference */
BcdHive->ReferenceCount = 2;
/* This is the hive handle */
*HiveHandle = KeyObject;
/* We're all good */
Status = STATUS_SUCCESS;
Quickie:
/* If we had a log name, free it */
if (LogName)
{
BlMmFreeHeap(LogName);
}
/* If we had logging data, free it */
if (LogData)
{
MmPapFreePages(LogData, BL_MM_INCLUDE_MAPPED_ALLOCATED);
}
/* Check if this is the failure path */
if (!NT_SUCCESS(Status))
{
/* If we mapped the hive, free it */
if (BaseBlock)
{
MmPapFreePages(BaseBlock, BL_MM_INCLUDE_MAPPED_ALLOCATED);
}
/* If we opened the device, close it */
if (DeviceId != -1)
{
BlDeviceClose(DeviceId);
}
/* Did we create a hive object? */
if (BcdHive)
{
/* Free the file path if we made a copy of it */
if (BcdHive->FilePath)
{
BlMmFreeHeap(BcdHive->FilePath);
}
/* Free the hive itself */
BlMmFreeHeap(BcdHive);
}
/* Finally, free the root key object if we created one */
if (KeyObject)
{
BlMmFreeHeap(KeyObject);
}
}
/* Return the final status */
return Status;
}
NTSTATUS
BiGetRegistryValue (
_In_ HANDLE KeyHandle,
_In_ PWCHAR ValueName,
_In_ ULONG Type,
_Out_ PVOID* Buffer,
_Out_ PULONG ValueLength
)
{
PCM_KEY_NODE KeyNode;
PHHIVE KeyHive;
UNICODE_STRING ValueString;
PBI_KEY_OBJECT KeyObject;
PCM_KEY_VALUE KeyValue;
PVOID ValueCopy;
ULONG Size;
HCELL_INDEX CellIndex;
PCELL_DATA ValueData;
/* Get the key object, node,and hive */
KeyObject = (PBI_KEY_OBJECT)KeyHandle;
KeyNode = KeyObject->KeyNode;
KeyHive = &KeyObject->KeyHive->Hive.Hive;
/* Find the value cell index in the list of values */
RtlInitUnicodeString(&ValueString, ValueName);
CmpFindNameInList(KeyHive,
&KeyNode->ValueList,
&ValueString,
NULL,
&CellIndex);
if (CellIndex == HCELL_NIL)
{
return STATUS_OBJECT_NAME_NOT_FOUND;
}
/* Get the cell data for it */
KeyValue = (PCM_KEY_VALUE)HvGetCell(KeyHive, CellIndex);
if (!KeyValue)
{
return STATUS_REGISTRY_CORRUPT;
}
/* Make sure the type matches */
if (KeyValue->Type != Type)
{
return STATUS_OBJECT_TYPE_MISMATCH;
}
/* Now get the data cell */
ValueData = CmpValueToData(KeyHive, KeyValue, &Size);
/* Make a copy of it */
ValueCopy = BlMmAllocateHeap(Size);
if (!ValueCopy)
{
return STATUS_NO_MEMORY;
}
/* Copy it in the buffer, and return it and its size */
RtlCopyMemory(ValueCopy, ValueData, Size);
*Buffer = ValueCopy;
*ValueLength = Size;
return STATUS_SUCCESS;
}
NTSTATUS
BiEnumerateSubKeys (
_In_ HANDLE KeyHandle,
_Out_ PWCHAR** SubKeyList,
_Out_ PULONG SubKeyCount
)
{
PCM_KEY_NODE KeyNode, Node;
PBI_KEY_OBJECT KeyObject;
ULONG KeyCount;
ULONG NameLength, NewTotalNameLength, FinalLength, TotalNameLength;
PHHIVE Hive;
PWCHAR KeyName, NameEnd;
HCELL_INDEX CellIndex;
PWCHAR* SubKeys;
NTSTATUS Status;
ULONG i;
/* Get the key object, node, and hive */
KeyObject = (PBI_KEY_OBJECT)KeyHandle;
KeyNode = KeyObject->KeyNode;
Hive = &KeyObject->KeyHive->Hive.Hive;
/* Assume it's empty */
*SubKeyList = 0;
*SubKeyCount = 0;
/* Initialize locals */
KeyCount = 0;
SubKeys = 0;
TotalNameLength = 0;
/* Find the first subkey cell index */
CellIndex = CmpFindSubKeyByNumber(Hive, KeyNode, KeyCount);
while (CellIndex != HCELL_NIL)
{
/* Move to the next one */
KeyCount++;
/* Get the cell data for it */
Node = (PCM_KEY_NODE)HvGetCell(Hive, CellIndex);
if (!Node)
{
return STATUS_REGISTRY_CORRUPT;
}
/* Check if the value is compressed */
if (Node->Flags & KEY_COMP_NAME)
{
/* Get the compressed name size */
NameLength = CmpCompressedNameSize(Node->Name, Node->NameLength);
}
else
{
/* Get the real size */
NameLength = Node->NameLength;
}
/* Add up the new length, protecting against overflow */
NewTotalNameLength = TotalNameLength + NameLength + sizeof(UNICODE_NULL);
if (NewTotalNameLength < TotalNameLength)
{
Status = STATUS_NAME_TOO_LONG;
goto Quickie;
}
/* We're good, use the new length */
TotalNameLength = NewTotalNameLength;
/* Find the next subkey cell index */
CellIndex = CmpFindSubKeyByNumber(Hive, KeyNode, KeyCount);
}
/* Were there no keys? We're done, if so */
if (!KeyCount)
{
return STATUS_SUCCESS;
}
/* Safely compute the size of the array needed */
Status = RtlULongLongToULong(sizeof(PWCHAR) * KeyCount, &FinalLength);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Safely add that to the name length */
Status = RtlULongAdd(TotalNameLength, FinalLength, &FinalLength);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Allocate an array big enough for the names and pointers */
SubKeys = BlMmAllocateHeap(FinalLength);
if (!SubKeys)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Go over each key again */
NameEnd = (PWCHAR)&SubKeys[KeyCount];
for (i = 0; i < KeyCount; i++)
{
/* Get the cell index for this subkey */
CellIndex = CmpFindSubKeyByNumber(Hive, KeyNode, i);
if (CellIndex == HCELL_NIL)
{
break;
}
/* Get the cell data for it */
Node = HvGetCell(Hive, CellIndex);
if (!Node)
{
Status = STATUS_REGISTRY_CORRUPT;
goto Quickie;
}
/* Check if the value is compressed */
KeyName = Node->Name;
if (Node->Flags & KEY_COMP_NAME)
{
/* Get the compressed name size */
NameLength = CmpCompressedNameSize(KeyName, Node->NameLength);
CmpCopyCompressedName(NameEnd, NameLength, KeyName, Node->NameLength);
}
else
{
/* Get the real size */
NameLength = Node->NameLength;
RtlCopyMemory(NameEnd, KeyName, NameLength);
}
/* Move the name buffer to the next spot, and NULL-terminate */
SubKeys[i] = NameEnd;
NameEnd += (NameLength / sizeof(WCHAR));
*NameEnd = UNICODE_NULL;
/* Keep going */
NameEnd++;
}
/* Check if the subkeys were empty */
if (i == 0)
{
/* They disappeared in the middle of enumeration */
Status = STATUS_OBJECT_NAME_NOT_FOUND;
goto Quickie;
}
/* Return the count and the array of names */
*SubKeyList = SubKeys;
*SubKeyCount = i;
SubKeys = NULL;
Status = STATUS_SUCCESS;
Quickie:
/* On the failure path, free the subkeys if any exist */
if (SubKeys)
{
BlMmFreeHeap(SubKeys);
}
/* All done, return the result */
return Status;
}
NTSTATUS
BiDeleteKey (
_In_ HANDLE KeyHandle
)
{
NTSTATUS Status;
PBI_KEY_OBJECT KeyObject;
PHHIVE Hive;
ULONG SubKeyCount, i;
PWCHAR* SubKeyList;
HANDLE SubKeyHandle;
/* Get the key object and hive */
KeyObject = (PBI_KEY_OBJECT)KeyHandle;
Hive = &KeyObject->KeyHive->Hive.Hive;
/* Make sure the hive is writeable */
if (!(KeyObject->KeyHive->Flags & BI_HIVE_WRITEABLE))
{
return STATUS_MEDIA_WRITE_PROTECTED;
}
/* Enumerate all of the subkeys */
Status = BiEnumerateSubKeys(KeyHandle, &SubKeyList, &SubKeyCount);
if ((NT_SUCCESS(Status)) && (SubKeyCount > 0))
{
/* Loop through each one */
for (i = 0; i < SubKeyCount; i++)
{
/* Open a handle to it */
Status = BiOpenKey(KeyHandle, SubKeyList[i], &SubKeyHandle);
if (NT_SUCCESS(Status))
{
/* Recursively call us to delete it */
Status = BiDeleteKey(SubKeyHandle);
if (Status != STATUS_SUCCESS)
{
/* Close the key on failure */
BiCloseKey(SubKeyHandle);
}
}
}
}
/* Check if we had a list of subkeys */
if (SubKeyList)
{
/* Free it */
BlMmFreeHeap(SubKeyList);
}
/* Delete this key cell */
Status = CmpFreeKeyByCell(Hive, KeyObject->KeyCell, TRUE);
if (NT_SUCCESS(Status))
{
/* Mark the hive as requiring a flush */
KeyObject->KeyHive->Flags |= BI_FLUSH_HIVE;
BiCloseKey(KeyHandle);
}
/* All done */
return Status;
}

View file

@ -0,0 +1,145 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/misc/debug.c
* PURPOSE: Boot Library Debug Routines
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
CHAR AnsiBuffer[1024];
BOOLEAN BdDebuggerNotPresent;
BOOLEAN BdSubsystemInitialized;
BOOLEAN BdArchBlockDebuggerOperation;
/* FUNCTIONS *****************************************************************/
BOOLEAN
BdDebuggerInitialized (
VOID
)
{
/* Check if BD was initialized, and is currently usable */
return BdSubsystemInitialized && !BdArchBlockDebuggerOperation;
}
NTSTATUS
BlBdPullRemoteFile (
_In_ PWCHAR FilePath,
_Out_ PVOID BaseAddress,
_Out_ PULONGLONG FileSize
)
{
/* Is the boot debugger enabled? */
if (!BlBdDebuggerEnabled())
{
/* Nothing to pull */
return STATUS_DEBUGGER_INACTIVE;
}
/* TODO */
EfiPrintf(L"Todo\r\n");
return STATUS_NOT_IMPLEMENTED;
}
BOOLEAN
BlBdDebuggerEnabled (
VOID
)
{
BOOLEAN Initialized, Enabled;
/* Check if the debugger is initialized */
Initialized = BdDebuggerInitialized();
/* Check if it's currently active */
Enabled = FALSE;
if ((Initialized) && !(BdDebuggerNotPresent))
{
/* Yep! */
Enabled = TRUE;
}
/* Return enabled state */
return Enabled;
}
VOID
BlStatusPrint (
_In_ PCWCH Format,
...
)
{
ANSI_STRING AnsiString;
UNICODE_STRING UnicodeString;
va_list va;
NTSTATUS Status;
va_start(va, Format);
/* Check if the boot debugger is enabled */
if (BlBdDebuggerEnabled()
#if (defined(DBG))
|| TRUE
#endif
)
{
/* Print the string out into a buffer */
if (vswprintf(BlScratchBuffer, Format, va) > 0)
{
#if defined(DBG)
EfiPrintf(BlScratchBuffer);
EfiPrintf(L"\r\n");
#endif
/* Make it a UNICODE_STRING */
RtlInitUnicodeString(&UnicodeString, BlScratchBuffer);
/* Then convert it into an ANSI_STRING */
AnsiString.Length = 0;
AnsiString.MaximumLength = sizeof(AnsiBuffer);
AnsiString.Buffer = AnsiBuffer;
Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
if (NT_SUCCESS(Status))
{
/* Print it out to the debugger if that worked */
DbgPrint(AnsiString.Buffer);
}
}
}
va_end(va);
}
VOID
BlStatusError (
_In_ ULONG ErrorCode,
_In_ ULONG Parameter1,
_In_ ULONG_PTR Parameter2,
_In_ ULONG_PTR Parameter3,
_In_ ULONG_PTR Parameter4
)
{
/* Check if the boot debugger is enabled */
if (BlBdDebuggerEnabled())
{
/* Print out the fatal error */
BlStatusPrint(L"\n"
L"*** Fatal Error 0x%08x :\n"
L" (0x%p, 0x%p, 0x%p, 0x%p)\n"
L"\n",
ErrorCode,
Parameter1,
Parameter2,
Parameter3,
Parameter4);
/* Issue a breakpoint */
__debugbreak();
}
}

View file

@ -0,0 +1,196 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/misc/font.c
* PURPOSE: Boot Library Font Functions
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
LIST_ENTRY BfiDeferredListHead;
/* FUNCTIONS *****************************************************************/
NTSTATUS
BfiLoadFontFile (
_In_ PBL_DEVICE_DESCRIPTOR FontDevice,
_In_ PWCHAR FontPath
)
{
EfiPrintf(L"Cannot load font %s, no font loader exists\r\n", FontPath);
return STATUS_NOT_IMPLEMENTED;
}
VOID
BfiFreeDeferredFontFile (
_In_ PBL_DEFERRED_FONT_FILE DeferredFontFile
)
{
/* Free the device copy if there was one */
if (DeferredFontFile->Device)
{
BlMmFreeHeap(DeferredFontFile->Device);
}
/* Free the path copy if there was one */
if (DeferredFontFile->FontPath)
{
BlMmFreeHeap(DeferredFontFile->FontPath);
}
/* Free the whole thing */
BlMmFreeHeap(DeferredFontFile);
}
NTSTATUS
BfLoadFontFile (
_In_ PBL_DEVICE_DESCRIPTOR Device,
_In_ PWCHAR FontPath
)
{
PBL_DEFERRED_FONT_FILE DeferredFont;
ULONG FontPathSize;
/* Allocate the deferred font structure */
DeferredFont = (PBL_DEFERRED_FONT_FILE)BlMmAllocateHeap(sizeof(*DeferredFont));
if (!DeferredFont)
{
return STATUS_NO_MEMORY;
}
/* Zero it out */
RtlZeroMemory(DeferredFont, sizeof(*DeferredFont));
/* Allocate a copy for the file path */
FontPathSize = sizeof(WCHAR) * wcslen(FontPath) + sizeof(UNICODE_NULL);
DeferredFont->FontPath = (PWCHAR)BlMmAllocateHeap(FontPathSize);
if (!DeferredFont->FontPath)
{
BfiFreeDeferredFontFile(DeferredFont);
return STATUS_NO_MEMORY;
}
/* Allocate a copy for the device */
DeferredFont->Device = BlMmAllocateHeap(Device->Size);
if (!DeferredFont->Device)
{
BfiFreeDeferredFontFile(DeferredFont);
return STATUS_NO_MEMORY;
}
/* Copy the path and device */
RtlCopyMemory(DeferredFont->FontPath, FontPath, FontPathSize);
RtlCopyMemory(DeferredFont->Device,Device, Device->Size);
/* Set pending flag? */
DeferredFont->Flags = 1;
/* Insert it into the list */
InsertTailList(&BfiDeferredListHead, &DeferredFont->ListEntry);
return STATUS_SUCCESS;
}
NTSTATUS
BfLoadDeferredFontFiles (
VOID
)
{
PLIST_ENTRY NextEntry;
PBL_DEFERRED_FONT_FILE DeferredFont;
NTSTATUS Status, LoadStatus;
/* Assume empty list */
Status = STATUS_SUCCESS;
/* Parse the list */
NextEntry = BfiDeferredListHead.Flink;
while (NextEntry != &BfiDeferredListHead)
{
/* Get the font */
DeferredFont = CONTAINING_RECORD(NextEntry, BL_DEFERRED_FONT_FILE, ListEntry);
/* Move to the next entry and remove this one */
NextEntry = NextEntry->Flink;
RemoveEntryList(&DeferredFont->ListEntry);
/* Load the font */
LoadStatus = BfiLoadFontFile(DeferredFont->Device,
DeferredFont->FontPath);
if (!NT_SUCCESS(LoadStatus))
{
/* Remember the load failure if there was one */
Status = LoadStatus;
}
/* Free the deferred font */
BfiFreeDeferredFontFile(DeferredFont);
}
/* Return load status */
return Status;
}
NTSTATUS
BfiFlipCursorCharacter (
_In_ PBL_GRAPHICS_CONSOLE Console,
_In_ BOOLEAN Visible
)
{
/* not implemented */
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
BfClearToEndOfLine (
_In_ PBL_GRAPHICS_CONSOLE Console
)
{
/* not implemented */
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
BfClearScreen (
_In_ PBL_GRAPHICS_CONSOLE Console
)
{
NTSTATUS Status;
/* Reset the cursor position */
Console->TextConsole.State.XPos = 0;
Console->TextConsole.State.YPos = 0;
/* Fill the screen with the background color */
Status = ConsoleGraphicalClearPixels(Console,
Console->TextConsole.State.BgColor);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Check if the cursor should be visible */
if (Console->TextConsole.State.CursorVisible)
{
/* Load any fonts at this time */
if (!IsListEmpty(&BfiDeferredListHead))
{
BfLoadDeferredFontFiles();
}
/* Switch the cursor to visible */
Status = BfiFlipCursorCharacter(Console, TRUE);
}
else
{
/* Nothing left to do */
Status = STATUS_SUCCESS;
}
/* Return cursor flip result, if any */
return Status;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,550 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/misc/resource.c
* PURPOSE: Boot Library Resource Functions
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
PVOID ResPeImageBase;
PVOID ResPeImageEnd;
PVOID ResRootDirectory;
PVOID ResPeImageBasePrimary;
PVOID ResPeImageEndPrimary;
PVOID ResRootDirectoryPrimary;
ULONG_PTR ResRootDirectoryPrimaryOffset;
ULONG_PTR ResRootDirectoryOffset;
ULONG_PTR ResRootDirectoryFallbackOffset;
PVOID ResPeImageBaseFallback;
PVOID ResPeImageEndFallback;
PVOID ResRootDirectoryFallback;
BOOLEAN ResLoadedFontFiles;
PVOID ResMuiImageBase;
ULONG_PTR ResMuiImageSize;
PWCHAR ResLocale;
/* FUNCTIONS *****************************************************************/
NTSTATUS
ResSelectLocale (
_In_ BOOLEAN Primary
)
{
NTSTATUS Status;
/* Check if we're using the primary (MUI) or fallback resources */
if (Primary)
{
/* Use the primary ones */
ResRootDirectory = ResRootDirectoryPrimary;
ResRootDirectoryOffset = ResRootDirectoryPrimaryOffset;
ResPeImageBase = ResPeImageBasePrimary;
ResPeImageEnd = ResPeImageEndPrimary;
/* Register the locale with the display */
Status = BlpDisplayRegisterLocale(ResLocale);
}
/* Check if that failed, or if we're using fallback */
if (!(Primary) || !(NT_SUCCESS(Status)))
{
/* Set the fallback pointers */
ResRootDirectory = ResRootDirectoryFallback;
ResRootDirectoryOffset = ResRootDirectoryFallbackOffset;
ResPeImageBase = ResPeImageBaseFallback;
ResPeImageEnd = ResPeImageEndFallback;
/* Register the fallback (America baby!) locale */
Status = BlpDisplayRegisterLocale(L"en-US");
if (!NT_SUCCESS(Status))
{
/* Fallback to text mode (yes, this is the API...) */
return BlDisplaySetScreenResolution();
}
}
/* No fonts loaded -- return failure code */
ResLoadedFontFiles = FALSE;
return Status;
}
PIMAGE_RESOURCE_DIRECTORY_ENTRY
ResFindDirectoryEntry (
_In_ PIMAGE_RESOURCE_DIRECTORY Directory,
_In_opt_ PUSHORT Id,
_In_opt_ PWCHAR Name,
_In_ ULONG_PTR SectionStart
)
{
PIMAGE_RESOURCE_DIRECTORY_ENTRY EntryTable, IdEntryTable;
ULONG i;
SIZE_T NameLength;
PIMAGE_RESOURCE_DIRECTORY_STRING NameString;
/* Are we looking by ID or name? */
if (Id)
{
/* By ID, so were we passed a name? */
if (Name)
{
/* That doesn't make sense */
return NULL;
}
}
else if (!Name)
{
/* By name, but we weren't given one. Also bad. */
return NULL;
}
/* Get the table of names */
EntryTable = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(Directory + 1);
/* Check if we are doing ID lookup instead */
if (Id)
{
/* The IDs come after the names */
IdEntryTable = &EntryTable[Directory->NumberOfNamedEntries];
/* Parse them */
for (i = 0; i < Directory->NumberOfIdEntries; i++)
{
/* Check if the ID matches, or if the wildcard is being used*/
if ((IdEntryTable[i].Id == *Id) || (*Id == 0xFFFF))
{
/* Return a pointer to the data */
return (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(SectionStart + IdEntryTable[i].OffsetToDirectory);
}
}
/* ID was not found */
return NULL;
}
/* Searching by name, so parse them */
for (i = 0; i < Directory->NumberOfNamedEntries; i++)
{
/* Get the name itself and count its length */
NameString = (PIMAGE_RESOURCE_DIRECTORY_STRING)(SectionStart + EntryTable[i].NameOffset);
NameLength = wcslen(Name);
/* If the length matches, compare the bytes */
if ((NameLength == NameString->Length) &&
(RtlCompareMemory(NameString->NameString, Name, NameLength) == NameLength))
{
/* They both match, so this is our entry. Return it */
return (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(SectionStart + EntryTable[i].OffsetToDirectory);
}
}
/* Name was not found */
return NULL;
}
NTSTATUS
ResFindDataEntryFromImage (
_In_opt_ PVOID ImageBase,
_In_opt_ ULONG ImageSize,
_In_ USHORT DirectoryId,
_In_ PUSHORT EntryId,
_In_ PWCHAR Name,
_Out_ PIMAGE_RESOURCE_DATA_ENTRY *DataEntryOut,
_Out_ PVOID* ResourceOut
)
{
NTSTATUS Status;
PIMAGE_SECTION_HEADER ResourceSection;
PIMAGE_RESOURCE_DIRECTORY ResourceDir, RootDir;
PIMAGE_RESOURCE_DIRECTORY_ENTRY DirEntry;
PIMAGE_RESOURCE_DATA_ENTRY DataEntry;
PVOID Data, DataEnd, ImageEnd;
BOOLEAN UseFallbackDirectory;
/* Assume nothing found */
UseFallbackDirectory = TRUE;
Status = STATUS_NOT_FOUND;
/* Are we looking at a particular image? */
if (ImageBase)
{
/* Then make sure we know its size */
if (!ImageSize)
{
return Status;
}
/* Find the resource section for it */
ResourceSection = BlImgFindSection(ImageBase, ImageSize);
if (!ResourceSection)
{
return STATUS_INVALID_IMAGE_FORMAT;
}
/* Remember how big the image is, and find the resource directory */
ImageEnd = (PVOID)((ULONG_PTR)ImageBase + ImageSize);
RootDir = (PIMAGE_RESOURCE_DIRECTORY)((ULONG_PTR)ImageBase +
ResourceSection->VirtualAddress);
if ((PVOID)RootDir < ImageBase)
{
/* It's out of bounds, so bail out */
return STATUS_INVALID_PARAMETER;
}
/* We have a valid directory, don't use fallback for now */
UseFallbackDirectory = FALSE;
}
else
{
/* We are using the current library settings instead */
ImageBase = ResPeImageBase;
RootDir = ResRootDirectory;
ImageEnd = ResPeImageEnd;
}
/* If we don't have a resource directory, there's nothing to find */
if (!RootDir)
{
return Status;
}
/* Try two loops, once for primary, once for fallback */
while (1)
{
/* Find the directory first */
ResourceDir = (PIMAGE_RESOURCE_DIRECTORY)ResFindDirectoryEntry(RootDir,
&DirectoryId,
NULL,
(ULONG_PTR)RootDir);
if (ResourceDir)
{
break;
}
/* We didn't find it -- is it time to use the fallback? */
if (UseFallbackDirectory)
{
/* Were were not using the fallback already? */
if (RootDir != ResRootDirectoryFallback)
{
/* Then attempt with the fallback instead*/
RootDir = ResRootDirectoryFallback;
ImageBase = ResPeImageBaseFallback;
ImageEnd = ResPeImageEndFallback;
/* Making sure we have one... */
if (RootDir)
{
continue;
}
}
}
/* Otherwise, return failure here */
return Status;
}
/* Now that we are in the right directory, lookup the resource */
ResourceDir = (PIMAGE_RESOURCE_DIRECTORY)ResFindDirectoryEntry(ResourceDir,
EntryId,
Name,
(ULONG_PTR)RootDir);
if (!ResourceDir)
{
return Status;
}
/* The entry is right after */
DirEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResourceDir + 1);
if ((PVOID)DirEntry < (PVOID)ResourceDir)
{
return STATUS_INVALID_PARAMETER;
}
/* Get the data entry for it */
DataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)((ULONG_PTR)RootDir +
DirEntry->OffsetToData);
/* Check if the data entry is out of bounds */
if (((PVOID)DataEntry < ImageBase) || ((PVOID)DataEntry > ImageEnd))
{
return STATUS_INVALID_PARAMETER;
}
/* Finally read the data offset */
Data = (PVOID)((ULONG_PTR)ImageBase + DataEntry->OffsetToData);
/* Check if the data is out of bounds */
if (((PVOID)Data < ImageBase) || ((PVOID)Data > ImageEnd))
{
return STATUS_INVALID_PARAMETER;
}
/* Make sure the data end isn't out of bounds either */
DataEnd = (PVOID)((ULONG_PTR)Data + DataEntry->Size);
if (((PVOID)DataEnd < ImageBase) || ((PVOID)DataEnd > ImageEnd))
{
return STATUS_INVALID_PARAMETER;
}
/* We finally made it. Return the entry and the raw data */
*DataEntryOut = DataEntry;
*ResourceOut = Data;
return STATUS_SUCCESS;
}
PWCHAR
BlResourceFindHtml (
VOID
)
{
NTSTATUS Status;
PIMAGE_RESOURCE_DATA_ENTRY HtmlDataEntry;
PWCHAR Stylesheet;
/* Assume failure */
Stylesheet = NULL;
/* Look for an RT_HTML resource called BOOTMGR.XSL */
Status = ResFindDataEntryFromImage(NULL,
0,
23,
NULL,
L"BOOTMGR.XSL",
&HtmlDataEntry,
(PVOID*)&Stylesheet);
if (!NT_SUCCESS(Status))
{
return Stylesheet;
}
/* Check for Unicode BOM */
if (*Stylesheet == 0xFEFF)
{
/* Overwrite it, and NULL-terminate */
RtlMoveMemory(Stylesheet,
Stylesheet + 1,
HtmlDataEntry->Size - sizeof(WCHAR));
Stylesheet[(HtmlDataEntry->Size / sizeof(WCHAR)) - 1] = UNICODE_NULL;
}
else if (Stylesheet[(HtmlDataEntry->Size / sizeof(WCHAR)) - 1] != UNICODE_NULL)
{
/* If it's not NULL-terminated, fail */
Stylesheet = NULL;
}
/* Return it back */
return Stylesheet;
}
PWCHAR
BlResourceFindMessage (
_In_ ULONG MsgId
)
{
PWCHAR Message;
PIMAGE_RESOURCE_DIRECTORY ResourceDir;
PIMAGE_RESOURCE_DATA_ENTRY DataEntry;
PMESSAGE_RESOURCE_DATA MsgData;
PMESSAGE_RESOURCE_ENTRY MsgEntry;
ULONG i, j;
USHORT Id;
PVOID MsgEnd;
NTSTATUS Status;
/* Bail out if there's no resource directory */
Message = NULL;
if (!ResRootDirectory)
{
return Message;
}
/* Check if we've loaded fonts already */
if (!ResLoadedFontFiles)
{
/* Nope, load them now */
Status = BfLoadDeferredFontFiles();
if (!NT_SUCCESS(Status))
{
/* We failed to load fonts, fallback to fallback locale */
Status = ResSelectLocale(FALSE);
if (NT_SUCCESS(Status))
{
/* Try fonts now */
Status = BfLoadDeferredFontFiles();
if (!NT_SUCCESS(Status))
{
/* Still didn't work -- fallback to text mode */
EfiPrintf(L"Font loading failed, falling back to text mode\r\n");
Status = BlDisplaySetScreenResolution();
if (!NT_SUCCESS(Status))
{
/* That didn't work either. F*ck it. */
return Message;
}
}
}
}
/* Now we have a resource directory, and fonts are loaded */
NT_ASSERT(ResRootDirectory != NULL);
ResLoadedFontFiles = TRUE;
}
/* Go look for RT_MESSAGETABLE */
Id = 11;
ResourceDir = (PIMAGE_RESOURCE_DIRECTORY)ResFindDirectoryEntry(ResRootDirectory,
&Id,
NULL,
(ULONG_PTR)ResRootDirectory);
if (!ResourceDir)
{
return Message;
}
/* Go look for the first directory in the table */
Id = 1;
ResourceDir = (PIMAGE_RESOURCE_DIRECTORY)ResFindDirectoryEntry(ResourceDir,
&Id,
NULL,
(ULONG_PTR)ResRootDirectory);
if (!ResourceDir)
{
return Message;
}
/* Go look for any language entry in the table */
Id = -1;
DataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)ResFindDirectoryEntry(ResourceDir,
&Id,
NULL,
(ULONG_PTR)ResRootDirectory);
if (!DataEntry)
{
return Message;
}
/* Get the message data*/
MsgData = (PMESSAGE_RESOURCE_DATA)((ULONG_PTR)ResRootDirectory +
DataEntry->OffsetToData -
ResRootDirectoryOffset);
/* Loop through the message blocks */
for (j = 0; j < MsgData->NumberOfBlocks; j++)
{
/* Check if the ID is within this range */
if ((MsgId >= MsgData->Blocks[j].LowId) &&
(MsgId <= MsgData->Blocks[j].HighId))
{
/* Get the first entry */
MsgEntry = (PMESSAGE_RESOURCE_ENTRY)((ULONG_PTR)MsgData +
MsgData->Blocks[j].OffsetToEntries);
/* Loop till we find the right one */
for (i = MsgId - MsgData->Blocks[j].LowId; i; --i)
{
MsgEntry = (PMESSAGE_RESOURCE_ENTRY)((ULONG_PTR)MsgEntry +
MsgEntry->Length);
}
/* Find where this message ends */
MsgEnd = (PVOID)((ULONG_PTR)MsgEntry + MsgEntry->Length);
/* Now make sure that the message is within bounds */
if ((MsgEnd >= (PVOID)MsgEntry) &&
((PVOID)MsgEntry >= ResPeImageBase) &&
(MsgEnd <= ResPeImageEnd))
{
/* If so, read the text associated with it */
Message = (PWCHAR)MsgEntry->Text;
break;
}
}
}
/* Return the text, if one was found */
return Message;
}
NTSTATUS
BlpResourceInitialize (
VOID
)
{
NTSTATUS Status;
PIMAGE_SECTION_HEADER ResourceSection;
PVOID ImageBase;
ULONG ImageSize, VRes, HRes;
BOOLEAN UsePrimary;
/* Default to using fallback */
UsePrimary = FALSE;
/* Initialize all globals */
ResMuiImageBase = 0;
ResMuiImageSize = 0;
ResRootDirectoryPrimary = 0;
ResRootDirectoryPrimaryOffset = 0;
ResPeImageBasePrimary = 0;
ResPeImageEndPrimary = 0;
ResRootDirectoryFallback = 0;
ResRootDirectoryFallbackOffset = 0;
ResPeImageBaseFallback = 0;
ResPeImageEndFallback = 0;
ResRootDirectory = 0;
ResRootDirectoryOffset = 0;
ResPeImageBase = 0;
ResPeImageEnd = 0;
ResLoadedFontFiles = 0;
/* Check if we had allocated a locale already */
if (ResLocale)
{
/* Free it and reset */
BlMmFreeHeap(ResLocale);
ResLocale = 0;
}
/* Get our base address and size*/
Status = BlGetApplicationBaseAndSize(&ImageBase, &ImageSize);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Find our resource section */
ResourceSection = BlImgFindSection(ImageBase, ImageSize);
if (ResourceSection)
{
/* The resource section will be our fallback. Save down its details */
ResRootDirectoryFallbackOffset = ResourceSection->VirtualAddress;
ResPeImageBaseFallback = ImageBase;
ResPeImageEndFallback = (PVOID)((ULONG_PTR)ImageBase + ImageSize);
ResRootDirectoryFallback = (PIMAGE_RESOURCE_DIRECTORY)((ULONG_PTR)ImageBase +
ResRootDirectoryFallbackOffset);
}
/* Get the current screen resolution and check if we're in graphics mode */
Status = BlDisplayGetScreenResolution(&HRes, &VRes);
if ((NT_SUCCESS(Status)) && ((HRes != 640) || (VRes != 200)))
{
/* We are... we should load MUI data */
Status = STATUS_NOT_IMPLEMENTED;//ResInitializeMuiResources();
if (NT_SUCCESS(Status))
{
/* And not rely on the fallback */
UsePrimary = TRUE;
}
}
/* Load the locale resources */
return ResSelectLocale(UsePrimary);
}

View file

@ -0,0 +1,98 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Manager
* FILE: boot/environ/lib/misc/rtlcompat.c
* PURPOSE: RTL Library Compatibility Routines
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* FUNCTIONS *****************************************************************/
#if DBG
VOID FASTCALL
CHECK_PAGED_CODE_RTL (
char *file,
int line
)
{
// boot-code is always ok
}
#endif
PVOID MmHighestUserAddress = (PVOID)0xFFFFFFFF;
PVOID
NTAPI
RtlpAllocateMemory (
_In_ ULONG Bytes,
_In_ ULONG Tag
)
{
UNREFERENCED_PARAMETER(Tag);
return BlMmAllocateHeap(Bytes);
}
VOID
NTAPI
RtlpFreeMemory (
_In_ PVOID Mem,
_In_ ULONG Tag
)
{
UNREFERENCED_PARAMETER(Tag);
BlMmFreeHeap(Mem);
}
NTSTATUS
NTAPI
RtlpSafeCopyMemory (
_Out_writes_bytes_all_(Length) VOID UNALIGNED *Destination,
_In_reads_bytes_(Length) CONST VOID UNALIGNED *Source,
_In_ SIZE_T Length
)
{
RtlCopyMemory(Destination, Source, Length);
return STATUS_SUCCESS;
}
VOID
NTAPI
RtlAssert (
IN PVOID FailedAssertion,
IN PVOID FileName,
IN ULONG LineNumber,
IN PCHAR Message OPTIONAL
)
{
EfiPrintf(L"*** ASSERTION %s FAILED AT %d in %s (%s) ***\r\n",
FailedAssertion,
LineNumber,
FileName,
Message);
}
ULONG
DbgPrint (
const char *Format,
...
)
{
EfiPrintf(L"%s\r\n", Format);
return 0;
}
VOID
NTAPI
KeBugCheckEx(
_In_ ULONG BugCheckCode,
_In_ ULONG_PTR BugCheckParameter1,
_In_ ULONG_PTR BugCheckParameter2,
_In_ ULONG_PTR BugCheckParameter3,
_In_ ULONG_PTR BugCheckParameter4)
{
__assume(0);
}

View file

@ -0,0 +1,934 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/misc/util.c
* PURPOSE: Boot Library Utility Functions
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
PRSDT UtlRsdt;
PXSDT UtlXsdt;
PVOID UtlMcContext;
PVOID UtlMcDisplayMessageRoutine;
PVOID UtlMcUpdateMessageRoutine;
PVOID UtlProgressRoutine;
PVOID UtlProgressContext;
PVOID UtlProgressInfoRoutine;
ULONG UtlProgressGranularity;
ULONG UtlCurrentPercentComplete;
ULONG UtlNextUpdatePercentage;
BOOLEAN UtlProgressNeedsInfoUpdate;
PVOID UtlProgressInfo;
/* FUNCTIONS *****************************************************************/
NTSTATUS
BlUtlGetAcpiTable (
_Out_ PVOID* TableAddress,
_In_ ULONG Signature
)
{
ULONG i, TableCount, HeaderLength;
NTSTATUS Status;
PRSDT Rsdt;
PXSDT Xsdt;
PHYSICAL_ADDRESS PhysicalAddress;
PDESCRIPTION_HEADER Header;
Header = 0;
/* Make sure there's an output parameter */
if (!TableAddress)
{
return STATUS_INVALID_PARAMETER;
}
/* Get the currently known RSDT and XSDT */
Rsdt = (PRSDT)UtlRsdt;
Xsdt = (PXSDT)UtlXsdt;
/* Is there an RSDT? */
if (!Rsdt)
{
/* No -- is there an XSDT? */
if (!Xsdt)
{
/* No. Look up the RSDT */
Status = EfipGetRsdt(&PhysicalAddress);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"no rsdp found\r\n");
return Status;
}
/* Map the header */
Status = BlMmMapPhysicalAddressEx((PVOID)&Header,
0,
sizeof(*Header),
PhysicalAddress);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Unmap the header */
BlMmUnmapVirtualAddressEx(Header, sizeof(*Header));
/* Map the whole table */
Status = BlMmMapPhysicalAddressEx((PVOID)&Header,
0,
Header->Length,
PhysicalAddress);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Check if its an XSDT or an RSDT */
if (Header->Signature == XSDT_SIGNATURE)
{
/* It's an XSDT */
Xsdt = (PXSDT)Header;
UtlXsdt = Xsdt;
}
else
{
/* It's an RSDT */
Rsdt = (PRSDT)Header;
UtlRsdt = Rsdt;
}
}
}
/* OK, so do we have an XSDT after all? */
if (Xsdt)
{
/* Yes... how big is it? */
HeaderLength = Xsdt->Header.Length;
if (HeaderLength >= sizeof(*Header))
{
HeaderLength = sizeof(*Header);
}
/* Based on that, how many tables are there? */
TableCount = (Xsdt->Header.Length - HeaderLength) / sizeof(PHYSICAL_ADDRESS);
}
else
{
/* Nope, we have an RSDT. How big is it? */
HeaderLength = Rsdt->Header.Length;
if (HeaderLength >= sizeof(*Header))
{
HeaderLength = sizeof(*Header);
}
/* Based on that, how many tables are there? */
TableCount = (Rsdt->Header.Length - HeaderLength) / sizeof(ULONG);
}
/* Loop through the ACPI tables */
for (i = 0; i < TableCount; i++)
{
/* For an XSDT, read the 64-bit address directly */
if (Xsdt)
{
PhysicalAddress = Xsdt->Tables[i];
}
else
{
/* For RSDT, cast it */
PhysicalAddress.QuadPart = Rsdt->Tables[i];
}
/* Map the header */
Status = BlMmMapPhysicalAddressEx((PVOID)&Header,
0,
sizeof(*Header),
PhysicalAddress);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Is it the right one? */
if (Header->Signature == Signature)
{
/* Unmap the header */
BlMmUnmapVirtualAddressEx(Header, sizeof(*Header));
/* Map the whole table */
return BlMmMapPhysicalAddressEx(TableAddress,
0,
Header->Length,
PhysicalAddress);
}
}
/* Requested table does not exist */
return STATUS_NOT_FOUND;
}
VOID
BlUtlUpdateProgress (
_In_ ULONG Percentage,
_Out_opt_ PBOOLEAN Completed
)
{
if (UtlProgressRoutine)
{
EfiPrintf(L"Unimplemented\r\n");
}
else if (*Completed)
{
*Completed = TRUE;
}
}
NTSTATUS
BlUtlInitialize (
VOID
)
{
UtlRsdt = 0;
UtlXsdt = 0;
UtlMcContext = 0;
UtlMcDisplayMessageRoutine = 0;
UtlMcUpdateMessageRoutine = 0;
UtlProgressRoutine = 0;
UtlProgressContext = 0;
UtlProgressInfoRoutine = 0;
UtlProgressGranularity = 0;
UtlCurrentPercentComplete = 0;
UtlNextUpdatePercentage = 0;
UtlProgressNeedsInfoUpdate = 0;
UtlProgressInfo = 0;
return STATUS_SUCCESS;
}
VOID
BmUpdateProgressInfo (
_In_ PVOID Unknown,
_In_ PWCHAR ProgressInfo
)
{
EfiPrintf(L"Progress Info: %s\r\n", ProgressInfo);
}
VOID
BmUpdateProgress (
_In_ PVOID Unknown,
_In_ ULONG Percent,
_Out_ PBOOLEAN Completed
)
{
EfiPrintf(L"Progress: %d\r\n", Percent);
if (Completed)
{
*Completed = TRUE;
}
}
NTSTATUS
BlUtlRegisterProgressRoutine (
VOID
)
{
/* One shouldn't already exist */
if (UtlProgressRoutine)
{
return STATUS_UNSUCCESSFUL;
}
/* Set the routine, and no context */
UtlProgressRoutine = BmUpdateProgress;
UtlProgressContext = NULL;
/* Progress increases by one */
UtlProgressGranularity = 1;
/* Set progress to zero for now */
UtlCurrentPercentComplete = 0;
UtlNextUpdatePercentage = 0;
/* Set the info routine if there is one */
UtlProgressInfoRoutine = BmUpdateProgressInfo;
/* All good */
return STATUS_SUCCESS;
}
PVOID
BlTblFindEntry (
_In_ PVOID *Table,
_In_ ULONG Count,
_Out_ PULONG EntryIndex,
_In_ PBL_TBL_LOOKUP_ROUTINE Callback,
_In_ PVOID Argument1,
_In_ PVOID Argument2,
_In_ PVOID Argument3,
_In_ PVOID Argument4
)
{
PVOID Entry = NULL;
ULONG Index;
BOOLEAN Result;
/* Check for invalid parameters */
if (!(Table) || !(EntryIndex))
{
return Entry;
}
/* Loop each entry in the table */
for (Index = 0; Index < Count; Index++)
{
/* Check if this entry is filled out */
if (Table[Index])
{
/* Call the comparison function */
Result = Callback(Table[Index],
Argument1,
Argument2,
Argument3,
Argument4);
if (Result)
{
/* Entry found return it */
*EntryIndex = Index;
Entry = Table[Index];
break;
}
}
}
/* Return the entry that was (or wasn't) found */
return Entry;
}
NTSTATUS
BlTblSetEntry (
_Inout_ PVOID** Table,
_Inout_ PULONG Count,
_In_ PVOID Entry,
_Out_ PULONG EntryIndex,
_In_ PBL_TBL_SET_ROUTINE Callback
)
{
ULONG NewCount;
NTSTATUS Status = STATUS_SUCCESS;
ULONG Index = 0;
PVOID* NewTable;
/* Make sure all the parameters were specified */
if (!(Table) || !(*Table) || !(Count) || !(Callback))
{
return STATUS_INVALID_PARAMETER;
}
/* Read the current table */
NewTable = *Table;
NewCount = *Count;
/* Iterate over it */
while (Index < NewCount)
{
/* Look for a free index */
if (!NewTable[Index])
{
goto SetIndex;
}
/* No free index yet, keep going */
++Index;
}
/* No free index was found, try to purge some entries */
Index = 0;
while (Index < NewCount)
{
/* Call each purge callback, trying to make space */
Status = Callback(NewTable[Index]);
if (NT_SUCCESS(Status))
{
/* We should have this slot available now */
goto SetIndex;
}
/* Keep trying to purge more */
++Index;
}
/* Double the table */
NewTable = BlMmAllocateHeap(2 * sizeof(PVOID) * NewCount);
if (!NewTable)
{
return STATUS_NO_MEMORY;
}
/* Clear the new table, and copy the old entries */
RtlZeroMemory(&NewTable[NewCount], sizeof(PVOID) * NewCount);
RtlCopyMemory(NewTable, *Table, sizeof(PVOID) * NewCount);
/* Free the old table */
BlMmFreeHeap(*Table);
/* Return the new table and count */
*Count = 2 * NewCount;
*Table = NewTable;
SetIndex:
/* Set the index and return */
NewTable[Index] = Entry;
*EntryIndex = Index;
return Status;
}
NTSTATUS
BlTblMap (
_In_ PVOID *Table,
_In_ ULONG Count,
_In_ PBL_TBL_MAP_ROUTINE MapCallback
)
{
NTSTATUS Status, LocalStatus;
PVOID Entry;
ULONG Index;
/* Bail out if there's no table */
if (!Table)
{
return STATUS_INVALID_PARAMETER;
}
/* Assume success and loop each index */
Status = STATUS_SUCCESS;
for (Index = 0; Index < Count; Index++)
{
/* See if an entry exists at this index */
Entry = Table[Index];
if (Entry)
{
/* Call the map routine for this entry */
LocalStatus = MapCallback(Entry, Index);
if (!NT_SUCCESS(LocalStatus))
{
/* Propagate failure only */
Status = LocalStatus;
}
}
}
/* Return status to caller */
return Status;
}
ULONG HtTableSize;
PBL_HASH_TABLE* HtTableArray;
ULONG HtTableEntries;
ULONG
DefaultHashFunction (
_In_ PBL_HASH_ENTRY Entry,
_In_ ULONG TableSize
)
{
PUCHAR Value;
ULONG KeyHash, i;
/* Check if the value is a pointer, or embedded inline */
Value = (Entry->Flags & BL_HT_VALUE_IS_INLINE) ? Entry->Value : (PUCHAR)&Entry->Value;
/* Iterate over each byte, and sum it */
for (i = 0, KeyHash = 0; i < Entry->Size; i++)
{
KeyHash += Value[i++];
}
/* Modulo the number of buckets */
return KeyHash % TableSize;
}
BOOLEAN
HtpCompareKeys (
_In_ PBL_HASH_ENTRY Entry1,
_In_ PBL_HASH_ENTRY Entry2
)
{
ULONG Flags;
BOOLEAN ValueMatch;
/* Check if the flags or sizes are not matching */
Flags = Entry1->Flags;
if ((Entry1->Size != Entry2->Size) || (Flags != Entry2->Flags))
{
ValueMatch = FALSE;
}
else if (Flags & BL_HT_VALUE_IS_INLINE)
{
/* Check if this is an in-line value, compare it */
ValueMatch = Entry1->Value == Entry2->Value;
}
else
{
/* This is a pointer value, compare it */
ValueMatch = (RtlCompareMemory(Entry1->Value, Entry2->Value, Entry1->Size) ==
Entry1->Size);
}
/* Return if it matched */
return ValueMatch;
}
NTSTATUS
TblDoNotPurgeEntry (
_In_ PVOID Entry
)
{
/* Never purge this entry */
return STATUS_UNSUCCESSFUL;
}
NTSTATUS
BlHtCreate (
_In_ ULONG Size,
_In_ PBL_HASH_TABLE_HASH_FUNCTION HashFunction,
_In_ PBL_HASH_TABLE_COMPARE_FUNCTION CompareFunction,
_Out_ PULONG Id
)
{
NTSTATUS Status;
PBL_HASH_TABLE HashTable;
ULONG i;
/* Assume failure */
HashTable = NULL;
/* Can't create a table with no ID */
if (!Id)
{
return STATUS_INVALID_PARAMETER;
}
/* Check if we don't already have a hash table table */
if (!HtTableSize)
{
/* Allocate it and zero it out */
HtTableSize = 4;
HtTableArray = BlMmAllocateHeap(HtTableSize * sizeof(PVOID));
if (!HtTableArray)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
RtlZeroMemory(HtTableArray, HtTableSize * sizeof(PVOID));
HtTableEntries = 0;
}
/* Allocate the hash table */
HashTable = BlMmAllocateHeap(sizeof(*HashTable));
if (!HashTable)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Fill it out */
HashTable->HashFunction = HashFunction ? HashFunction : DefaultHashFunction;
HashTable->CompareFunction = CompareFunction ? CompareFunction : HtpCompareKeys;
HashTable->Size = Size ? Size : 13;
/* Allocate the hash links, one for each bucket */
HashTable->HashLinks = BlMmAllocateHeap(sizeof(LIST_ENTRY) * HashTable->Size);
if (!HashTable->HashLinks)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Initialize the hash links */
for (i = 0; i < HashTable->Size; i++)
{
InitializeListHead(&HashTable->HashLinks[i]);
}
/* Save us in the table of hash tables */
Status = BlTblSetEntry((PVOID**)&HtTableArray,
&Size,
HashTable,
Id,
TblDoNotPurgeEntry);
if (NT_SUCCESS(Status))
{
/* One more -- we're done */
++HtTableEntries;
return Status;
}
Quickie:
/* Check if we just allocated the table array now */
if (!(HtTableEntries) && (HtTableArray))
{
/* Free it */
BlMmFreeHeap(HtTableArray);
HtTableArray = NULL;
HtTableSize = 0;
}
/* Check if we allocated a hash table*/
if (HashTable)
{
/* With links? */
if (HashTable->HashLinks)
{
/* Free them */
BlMmFreeHeap(HashTable->HashLinks);
}
/* Free the table*/
BlMmFreeHeap(HashTable);
}
/* We're done */
return Status;
}
NTSTATUS
BlHtLookup (
_In_ ULONG TableId,
_In_ PBL_HASH_ENTRY Entry,
_Out_opt_ PBL_HASH_VALUE *Value
)
{
PBL_HASH_TABLE HashTable;
ULONG HashValue;
NTSTATUS Status;
PLIST_ENTRY HashLinkHead, HashLink;
PBL_HASH_NODE HashNode;
/* Check if the table ID is invalid, or we have no entry, or it's malformed */
if ((HtTableSize <= TableId) ||
!(Entry) ||
((Entry->Flags & BL_HT_VALUE_IS_INLINE) && (Entry->Size != sizeof(ULONG))))
{
/* Fail */
Status = STATUS_INVALID_PARAMETER;
}
else
{
/* Otherwise, get the hash table for this index */
HashTable = HtTableArray[TableId];
/* Get the hash bucket */
HashValue = HashTable->HashFunction(Entry, HashTable->Size);
/* Start iterating each entry in the bucket, assuming failure */
Status = STATUS_NOT_FOUND;
HashLinkHead = &HashTable->HashLinks[HashValue];
HashLink = HashLinkHead->Flink;
while (HashLink != HashLinkHead)
{
/* Get a node in this bucket, and compare the value */
HashNode = CONTAINING_RECORD(HashLink, BL_HASH_NODE, ListEntry);
if (HashTable->CompareFunction(&HashNode->Entry, Entry))
{
/* Does the caller want the value? */
if (Value)
{
/* Return it */
*Value = &HashNode->Value;
}
/* Return success and stop scanning */
Status = STATUS_SUCCESS;
break;
}
/* Try the next node */
HashLink = HashLink->Flink;
}
}
/* Return back to the caller */
return Status;
}
NTSTATUS
BlHtStore (
_In_ ULONG TableId,
_In_ PBL_HASH_ENTRY Entry,
_In_ PVOID Data,
_In_ ULONG DataSize
)
{
PBL_HASH_NODE HashNode;
NTSTATUS Status;
PLIST_ENTRY HashLinkHead;
PBL_HASH_TABLE HashTable;
/* Check for invalid table ID, missing arguments, or malformed entry */
if ((HtTableSize <= TableId) ||
!(Entry) ||
!(Data) ||
!(Entry->Size) ||
!(Entry->Value) ||
!(DataSize) ||
((Entry->Flags & BL_HT_VALUE_IS_INLINE) && (Entry->Size != sizeof(ULONG))))
{
/* Fail the call */
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Get the hash table for this ID */
HashTable = HtTableArray[TableId];
/* Allocate a hash node */
HashNode = BlMmAllocateHeap(sizeof(*HashNode));
if (!HashNode)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Capture all the data*/
HashNode->Entry.Size = Entry->Size;
HashNode->Entry.Flags = Entry->Flags;
HashNode->Entry.Value = Entry->Value;
HashNode->Value.DataSize = DataSize;
HashNode->Value.Data = Data;
/* Insert it into the bucket list and return success */
HashLinkHead = &HashTable->HashLinks[HashTable->HashFunction(Entry, HashTable->Size)];
InsertTailList(HashLinkHead, &HashNode->ListEntry);
Status = STATUS_SUCCESS;
Quickie:
return Status;
}
NTSTATUS
BlHtDelete (
_In_ ULONG TableId,
_In_ PBL_HASH_ENTRY Entry
)
{
PBL_HASH_TABLE HashTable;
ULONG HashValue;
NTSTATUS Status;
PLIST_ENTRY HashLinkHead, HashLink;
PBL_HASH_NODE HashNode;
/* Check if the table ID is invalid, or we have no entry, or it's malformed */
if ((HtTableSize <= TableId) ||
!(Entry) ||
!(Entry->Size) ||
!(Entry->Value) ||
((Entry->Flags & BL_HT_VALUE_IS_INLINE) && (Entry->Size != sizeof(ULONG))))
{
/* Fail */
Status = STATUS_INVALID_PARAMETER;
}
else
{
/* Otherwise, get the hash table for this index */
HashTable = HtTableArray[TableId];
/* Get the hash bucket */
HashValue = HashTable->HashFunction(Entry, HashTable->Size);
/* Start iterating each entry in the bucket, assuming failure */
Status = STATUS_NOT_FOUND;
HashLinkHead = &HashTable->HashLinks[HashValue];
HashLink = HashLinkHead->Flink;
while (HashLink != HashLinkHead)
{
/* Get a node in this bucket, and compare the value */
HashNode = CONTAINING_RECORD(HashLink, BL_HASH_NODE, ListEntry);
if (HashTable->CompareFunction(&HashNode->Entry, Entry))
{
/* Remove it from the list and free it */
RemoveEntryList(&HashNode->ListEntry);
BlMmFreeHeap(HashNode);
return STATUS_SUCCESS;
}
/* Try the next node */
HashLink = HashLink->Flink;
}
}
/* Return back to the caller */
return Status;
}
ULONG
BlUtlCheckSum (
_In_ ULONG PartialSum,
_In_ PUCHAR Buffer,
_In_ ULONG Length,
_In_ ULONG Flags
)
{
ULONG i;
if (Flags & BL_UTL_CHECKSUM_UCHAR_BUFFER)
{
EfiPrintf(L"Not supported\r\n");
return 0;
}
else if (Flags & BL_UTL_CHECKSUM_USHORT_BUFFER)
{
PartialSum = (unsigned __int16)PartialSum;
Length &= ~1;
for (i = 0; i < Length; i += 2)
{
PartialSum += *(unsigned __int16 *)&Buffer[i];
if (Flags & BL_UTL_CHECKSUM_COMPLEMENT)
{
PartialSum = (unsigned __int16)((PartialSum >> 16) + PartialSum);
}
}
if (i != Length)
{
PartialSum += (unsigned __int8)Buffer[Length];
if (Flags & BL_UTL_CHECKSUM_COMPLEMENT)
{
PartialSum = (unsigned __int16)((PartialSum >> 16) + PartialSum);
}
}
if (Flags & BL_UTL_CHECKSUM_NEGATE)
{
return ~PartialSum;
}
PartialSum = (unsigned __int16)PartialSum;
}
else
{
/* Invalid mode */
return 0;
}
if (Flags & BL_UTL_CHECKSUM_NEGATE)
{
return ~PartialSum;
}
return PartialSum;
}
#if defined(_M_IX86) || defined(_M_X64)
BOOLEAN
Archx86IsCpuidSupported (
VOID
)
{
ULONG CallerFlags, Flags;
/* Read the original flags, and add the CPUID bit */
CallerFlags = __readeflags() ^ 0x200000;
__writeeflags(CallerFlags);
/* Read our flags now */
Flags = __readeflags();
/* Check if the bit stuck */
return (((CallerFlags ^ Flags) >> 21) & 1) ^ 1;
}
#endif
BOOLEAN
BlArchIsCpuIdFunctionSupported (
_In_ ULONG Function
)
{
#if defined(_M_IX86) || defined(_M_X64)
BOOLEAN Supported;
INT CpuInfo[4];
/* Check if the CPU supports this instruction */
Supported = Archx86IsCpuidSupported();
if (!Supported)
{
return FALSE;
}
/* Check if it's the extended function */
if (Function >= 0x80000000)
{
/* Check if extended functions are supported */
__cpuid(CpuInfo, 0x80000000);
if ((CpuInfo[0] & 0xFFFFFF00) != 0x80000000)
{
/* Nope */
return FALSE;
}
}
else
{
/* It's a regular function, get the maximum one supported */
__cpuid(CpuInfo, 0);
}
/* Check if our function is within bounds */
if (Function <= CpuInfo[0])
{
return TRUE;
}
#else
EfiPrintf(L"BlArchIsCpuIdFunctionSupported not implemented for this platform.\r\n");
#endif
/* Nope */
return FALSE;
}
ULONGLONG
BlArchGetPerformanceCounter (
VOID
)
{
#if defined(_M_IX86) || defined(_M_X64)
INT CpuInfo[4];
/* Serialize with CPUID, if it exists */
if (Archx86IsCpuidSupported())
{
BlArchCpuId(0, 0, CpuInfo);
}
/* Read the TSC */
return __rdtsc();
#else
EfiPrintf(L"BlArchGetPerformanceCounter not implemented for this platform.\r\n");
return 0;
#endif
}
VOID
BlArchCpuId (
_In_ ULONG Function,
_In_ ULONG SubFunction,
_Out_ INT* Result
)
{
#if defined(_M_IX86) || defined(_M_X64)
/* Use the intrinsic */
__cpuidex(Result, Function, SubFunction);
#endif
}

View file

@ -0,0 +1,298 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/mm/blkalloc.c
* PURPOSE: Boot Library Memory Manager Block Allocator
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
PVOID* MmBlockAllocatorTable;
ULONG MmBlockAllocatorTableEntries;
BOOLEAN MmBlockAllocatorInitialized;
typedef struct _BL_BLOCK_DESCRIPTOR
{
LIST_ENTRY ListHead;
ULONG Unknown;
BL_MEMORY_TYPE Type;
ULONG Attributes;
ULONG Unknown2;
ULONG Count;
ULONG Count2;
ULONG Size;
ULONG BlockId;
ULONG ReferenceCount;
} BL_BLOCK_DESCRIPTOR, *PBL_BLOCK_DESCRIPTOR;
typedef struct _BL_BLOCK_ENTRY
{
LIST_ENTRY ListEntry;
ULONG Todo;
} BL_BLOCK_ENTRY, *PBL_BLOCK_ENTRY;
/* FUNCTIONS *****************************************************************/
BOOLEAN
MmBapCompareBlockAllocatorTableEntry (
_In_ PVOID Entry,
_In_ PVOID Argument1,
_In_ PVOID Argument2,
_In_ PVOID Argument3,
_In_ PVOID Argument4
)
{
PBL_BLOCK_DESCRIPTOR BlockInfo = (PBL_BLOCK_DESCRIPTOR)Entry;
ULONG BlockId = (ULONG)Argument1;
/* Check if the block ID matches */
return BlockInfo->BlockId == BlockId;
}
PBL_BLOCK_DESCRIPTOR
MmBapFindBlockInformation (
ULONG BlockId
)
{
ULONG EntryId;
/* Find the block that matches */
EntryId = BlockId;
return BlTblFindEntry(MmBlockAllocatorTable,
MmBlockAllocatorTableEntries,
&EntryId,
MmBapCompareBlockAllocatorTableEntry,
(PVOID)EntryId,
NULL,
NULL,
NULL);
}
NTSTATUS
MmBapFreeBlockAllocatorDescriptor (
_In_ PBL_BLOCK_DESCRIPTOR BlockInfo,
_In_ PBL_BLOCK_ENTRY BlockEntry
)
{
/* @TODO FIXME: Later */
EfiPrintf(L"Block free not yet implemented\r\n");
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
BlpMmDeleteBlockAllocator (
_In_ ULONG BlockId
)
{
NTSTATUS Status, LocalStatus;
PBL_BLOCK_DESCRIPTOR BlockInfo;
PLIST_ENTRY ListHead, NextEntry;
PBL_BLOCK_ENTRY BlockEntry;
/* Nothing to delete if we're not initialized */
if (!MmBlockAllocatorInitialized)
{
return STATUS_UNSUCCESSFUL;
}
/* Find the block descriptor */
BlockInfo = MmBapFindBlockInformation(BlockId);
if (BlockInfo)
{
/* Assume success for now */
Status = STATUS_SUCCESS;
/* Do we have at least one reference? */
if (BlockInfo->ReferenceCount)
{
/* Iterate over the allocated blocks */
ListHead = &BlockInfo->ListHead;
NextEntry = ListHead->Flink;
while (NextEntry != ListHead)
{
/* Free each one */
BlockEntry = CONTAINING_RECORD(NextEntry,
BL_BLOCK_ENTRY,
ListEntry);
LocalStatus = MmBapFreeBlockAllocatorDescriptor(BlockInfo,
BlockEntry);
if (!NT_SUCCESS(LocalStatus))
{
/* Remember status on failure only */
Status = LocalStatus;
}
}
/* Drop a reference */
BlockInfo->ReferenceCount--;
}
else
{
/* There aren't any references, so why are we being called? */
Status = STATUS_INVALID_PARAMETER;
}
}
else
{
/* No block exists with this ID */
Status = STATUS_UNSUCCESSFUL;
}
/* Return back */
return Status;
}
NTSTATUS
MmBapFreeBlockAllocatorTableEntry (
_In_ PVOID Entry,
_In_ ULONG Index
)
{
PBL_BLOCK_DESCRIPTOR BlockInfo = (PBL_BLOCK_DESCRIPTOR)Entry;
NTSTATUS Status, LocalStatus;
/* Assume success */
Status = STATUS_SUCCESS;
/* Check if there was at least one reference */
if (BlockInfo->ReferenceCount > 1)
{
/* Try to delete the allocator */
LocalStatus = BlpMmDeleteBlockAllocator(BlockInfo->BlockId);
if (!NT_SUCCESS(LocalStatus))
{
/* Remember status on failure only */
Status = LocalStatus;
}
}
/* Now destroy the allocator's descriptor */
LocalStatus = BlMmFreeHeap(BlockInfo);
if (!NT_SUCCESS(LocalStatus))
{
/* Remember status on failure only */
Status = LocalStatus;
}
/* Free the entry, and return failure, if any */
MmBlockAllocatorTable[Index] = NULL;
return Status;
}
NTSTATUS
MmBapPurgeBlockAllocatorTableEntry (
_In_ PVOID Entry
)
{
PBL_BLOCK_DESCRIPTOR BlockInfo = (PBL_BLOCK_DESCRIPTOR)Entry;
NTSTATUS Status;
/* Check if there's a reference on the block descriptor */
if (BlockInfo->ReferenceCount)
{
/* Don't allow purging */
Status = STATUS_UNSUCCESSFUL;
}
else
{
/* Free the entry */
Status = MmBapFreeBlockAllocatorTableEntry(BlockInfo,
BlockInfo->BlockId);
}
/* Return purge status */
return Status;
}
NTSTATUS
BlpMmCreateBlockAllocator (
VOID
)
{
PBL_BLOCK_DESCRIPTOR BlockInfo;
ULONG BlockId;
NTSTATUS Status;
/* If the block allocator isn't initialized, bail out */
BlockId = -1;
if (!MmBlockAllocatorInitialized)
{
goto Quickie;
}
/* Allocate a block descriptor and zero it out */
BlockInfo = BlMmAllocateHeap(sizeof(*BlockInfo));
if (!BlockInfo)
{
goto Quickie;
}
RtlZeroMemory(BlockInfo, sizeof(*BlockInfo));
/* Setup the block descriptor */
BlockInfo->Attributes = 0;
BlockInfo->Type = BlLoaderBlockMemory;
BlockInfo->Unknown = 1;
BlockInfo->Unknown2 = 1;
BlockInfo->Size = PAGE_SIZE;
BlockInfo->Count = 128;
BlockInfo->Count2 = 128;
InitializeListHead(&BlockInfo->ListHead);
/* Add it to the list of block descriptors */
Status = BlTblSetEntry(&MmBlockAllocatorTable,
&MmBlockAllocatorTableEntries,
BlockInfo,
&BlockId,
MmBapPurgeBlockAllocatorTableEntry);
if (NT_SUCCESS(Status))
{
/* Add the initial reference and store the block ID */
BlockInfo->ReferenceCount = 1;
BlockInfo->BlockId = BlockId;
}
Quickie:
/* On failure, free the block descriptor */
if (BlockId == -1)
{
BlMmFreeHeap(BlockInfo);
}
/* Return the block descriptor ID, or -1 on failure */
return BlockId;
}
NTSTATUS
MmBaInitialize (
VOID
)
{
NTSTATUS Status;
ULONG Size;
/* Allocate 8 table entries */
MmBlockAllocatorTableEntries = 8;
Size = sizeof(BL_BLOCK_DESCRIPTOR) * MmBlockAllocatorTableEntries;
MmBlockAllocatorTable = BlMmAllocateHeap(Size);
if (MmBlockAllocatorTable)
{
/* Zero them out -- we're all done */
Status = STATUS_SUCCESS;
RtlZeroMemory(MmBlockAllocatorTable, Size);
MmBlockAllocatorInitialized = 1;
}
else
{
/* Bail out since we're out of memory */
Status = STATUS_NO_MEMORY;
MmBlockAllocatorInitialized = 0;
}
/* Return initialization status */
return Status;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,716 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/mm/heapalloc.c
* PURPOSE: Boot Library Memory Manager Heap Allocator
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
#define BL_HEAP_POINTER_FLAG_BITS 3
typedef struct _BL_HEAP_POINTER
{
union
{
struct
{
ULONG_PTR BufferFree : 1;
ULONG_PTR BufferOnHeap : 1;
ULONG_PTR NotUsed : 1;
ULONG_PTR BufferPointer : ((8 * sizeof(ULONG_PTR)) - BL_HEAP_POINTER_FLAG_BITS);
};
PVOID P;
};
} BL_HEAP_POINTER, *PBL_HEAP_POINTER;
typedef struct _BL_FREE_HEAP_ENTRY
{
BL_HEAP_POINTER BufferNext;
BL_HEAP_POINTER BufferPrevious;
BL_HEAP_POINTER FreeNext;
BL_HEAP_POINTER FreePrevious;
} BL_FREE_HEAP_ENTRY, *PBL_FREE_HEAP_ENTRY;
typedef struct _BL_BUSY_HEAP_ENTRY
{
BL_HEAP_POINTER BufferNext;
BL_HEAP_POINTER BufferPrevious;
UCHAR Buffer[ANYSIZE_ARRAY];
} BL_BUSY_HEAP_ENTRY, *PBL_BUSY_HEAP_ENTRY;
typedef struct _BL_HEAP_BOUNDARIES
{
LIST_ENTRY ListEntry;
ULONG_PTR HeapEnd;
ULONG_PTR HeapLimit;
ULONG_PTR HeapBase;
PBL_BUSY_HEAP_ENTRY HeapStart;
} BL_HEAP_BOUNDARIES, *PBL_HEAP_BOUNDARIES;
ULONG HapInitializationStatus;
LIST_ENTRY MmHeapBoundaries;
ULONG HapMinimumHeapSize;
ULONG HapAllocationAttributes;
PBL_FREE_HEAP_ENTRY* MmFreeList;
/* INLINES *******************************************************************/
FORCEINLINE
PBL_FREE_HEAP_ENTRY
MmHapDecodeLink (
_In_ BL_HEAP_POINTER Link
)
{
/* Decode the buffer pointer by ignoring the flags */
return (PBL_FREE_HEAP_ENTRY)(Link.BufferPointer << BL_HEAP_POINTER_FLAG_BITS);
}
FORCEINLINE
ULONG
MmHapBufferSize (
_In_ PVOID FreeEntry
)
{
PBL_FREE_HEAP_ENTRY Entry = FreeEntry;
/* The space between the next buffer header and this one is the size */
return (ULONG_PTR)MmHapDecodeLink(Entry->BufferNext) - (ULONG_PTR)Entry;
}
FORCEINLINE
ULONG
MmHapUserBufferSize (
_In_ PVOID FreeEntry
)
{
PBL_FREE_HEAP_ENTRY Entry = FreeEntry;
/* Get the size of the buffer as the user sees it */
return MmHapBufferSize(Entry) - FIELD_OFFSET(BL_BUSY_HEAP_ENTRY, Buffer);
}
/* FUNCTIONS *****************************************************************/
NTSTATUS
MmHapHeapAllocatorExtend (
_In_ ULONG ExtendSize
)
{
ULONG HeapSize, AlignedSize, HeapLimit;
PBL_HEAP_BOUNDARIES Heap, NewHeap;
NTSTATUS Status;
PBL_BUSY_HEAP_ENTRY HeapBase = NULL;
/* Compute a new heap, and add 2 more pages for the free list */
HeapSize = ExtendSize + (2 * PAGE_SIZE);
if (HeapSize < ExtendSize)
{
return STATUS_INTEGER_OVERFLOW;
}
/* Make sure the new heap is at least the minimum configured size */
if (HapMinimumHeapSize > HeapSize)
{
HeapSize = HapMinimumHeapSize;
}
/* Align it on a page boundary */
AlignedSize = ALIGN_UP_BY(HeapSize, PAGE_SIZE);
if (!AlignedSize)
{
return STATUS_INTEGER_OVERFLOW;
}
/* Check if we already have a heap */
if (!IsListEmpty(&MmHeapBoundaries))
{
/* Find the first heap*/
Heap = CONTAINING_RECORD(MmHeapBoundaries.Flink,
BL_HEAP_BOUNDARIES,
ListEntry);
/* Check if we have a page free above the heap */
HeapLimit = Heap->HeapLimit + PAGE_SIZE;
if (HeapLimit <= Heap->HeapEnd)
{
EfiPrintf(L"Heap extension TODO\r\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
}
/* We do not -- allocate one */
Status = MmPapAllocatePagesInRange((PVOID*)&HeapBase,
BlLoaderHeap,
AlignedSize >> PAGE_SHIFT,
HapAllocationAttributes,
0,
NULL,
0);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"HEAP ALLOCATION FAILED\r\n");
EfiStall(1000000);
return Status;
}
/* Set the heap bottom, limit, and top */
NewHeap = (PBL_HEAP_BOUNDARIES)HeapBase->Buffer;
NewHeap->HeapBase = (ULONG_PTR)HeapBase;
NewHeap->HeapLimit = (ULONG_PTR)HeapBase + AlignedSize;
NewHeap->HeapStart = (PBL_BUSY_HEAP_ENTRY)(NewHeap + 1);
/* Set the buffer links */
HeapBase->BufferPrevious.P = NULL;
HeapBase->BufferNext.P = NewHeap->HeapStart;
/* Set the buffer at the top of the heap and mark it as being free */
NewHeap->HeapStart->BufferPrevious.P = HeapBase;
NewHeap->HeapStart->BufferNext.P = NewHeap->HeapStart;
NewHeap->HeapStart->BufferNext.BufferFree = 1;
NewHeap->HeapStart->BufferNext.BufferOnHeap = 1;
/* Is this the first heap ever? */
if (IsListEmpty(&MmHeapBoundaries))
{
/* We will host the free list at the top of the heap */
MmFreeList = (PBL_FREE_HEAP_ENTRY*)((ULONG_PTR)NewHeap->HeapLimit - 8 * sizeof(PBL_FREE_HEAP_ENTRY));
NewHeap->HeapLimit = (ULONG_PTR)MmFreeList;
RtlZeroMemory(MmFreeList, 8 * sizeof(PBL_FREE_HEAP_ENTRY));
}
/* Remove a page on top */
HeapLimit = NewHeap->HeapLimit;
NewHeap->HeapEnd = NewHeap->HeapLimit;
NewHeap->HeapLimit -= PAGE_SIZE;
/* Add us into the heap list */
InsertTailList(&MmHeapBoundaries, &NewHeap->ListEntry);
return STATUS_SUCCESS;
}
ULONG
MmHapGetBucketId (
_In_ ULONG Size
)
{
ULONG BucketIndex = 0;
/* Use the last bucket if this is a large allocation */
if (Size >= PAGE_SIZE)
{
return 7;
}
/* Otherwise, use a higher index for each new power of two */
while (Size >> BucketIndex)
{
BucketIndex++;
}
/* Allocations are at least 16 bytes (2^4 = 5th index) */
return BucketIndex - 5;
}
VOID
MmHapReportHeapCorruption (
_In_ PBL_FREE_HEAP_ENTRY BufferEntry
)
{
#if 0
BOOLEAN DebuggerEnabled;
BlStatusPrint(L"Heap corruption in the links surrounding %p!\r\n", BufferEntry);
DebuggerEnabled = BlBdDebuggerEnabled();
if (DebuggerEnabled)
{
BlStatusPrint(L"\n*** Fatal Error 0x%08x :\n (0x%p, 0x%p, 0x%p, 0x%p)\n\r\n", 2, BufferEntry, NULL, NULL, NULL);
__debugbreak();
}
#else
EfiPrintf(L"Heap corruption in the links surrounding %p!\r\n", BufferEntry);
#endif
}
PVOID
MmHapCheckFreeLinks (
_In_ PVOID BufferEntry
)
{
PBL_FREE_HEAP_ENTRY Prev, Next;
PBL_FREE_HEAP_ENTRY Entry = BufferEntry;
/* Get the previous and next free pointers */
Prev = MmHapDecodeLink(Entry->FreePrevious);
Next = MmHapDecodeLink(Entry->FreeNext);
/* Make sure that both the previous and next entries point to this one */
if (((Next) && (MmHapDecodeLink(Next->FreePrevious)) != Entry) ||
((Prev) && (MmHapDecodeLink(Prev->FreeNext)) != Entry))
{
/* They don't, so the free headers are corrupted */
MmHapReportHeapCorruption(Entry);
return NULL;
}
/* They do, return the free entry as valid */
return Entry;
}
PVOID
MmHapCheckBufferLinks (
_In_ PVOID BufferEntry
)
{
PBL_FREE_HEAP_ENTRY Prev, Next;
PBL_FREE_HEAP_ENTRY Entry = BufferEntry;
/* Get the previous and next buffer pointers */
Prev = MmHapDecodeLink(Entry->BufferPrevious);
Next = MmHapDecodeLink(Entry->BufferNext);
/* Make sure that both the previous and next entries point to this one */
if (((Next) && (MmHapDecodeLink(Next->BufferPrevious)) != Entry) ||
((Prev) && (MmHapDecodeLink(Prev->BufferNext)) != Entry))
{
/* They don't, so the heap headers are corrupted */
MmHapReportHeapCorruption(Entry);
return NULL;
}
/* They, do the entry is valid */
return Entry;
}
PBL_FREE_HEAP_ENTRY
MmHapRemoveBufferFromFreeList (
_In_ PBL_FREE_HEAP_ENTRY FreeEntry
)
{
PBL_FREE_HEAP_ENTRY Prev, Next;
/* Firest, make sure the free entry is valid */
FreeEntry = MmHapCheckFreeLinks(FreeEntry);
if (!FreeEntry)
{
return FreeEntry;
}
/* Get the previous and next entry */
Prev = MmHapDecodeLink(FreeEntry->FreePrevious);
Next = MmHapDecodeLink(FreeEntry->FreeNext);
/* Update the next entry to point to our previous entry */
if (Next)
{
Next->FreePrevious.P = Prev;
}
/* Are we at the head? */
if (Prev)
{
/* Nope, so update our previous entry to point to our next entry */
Prev->FreeNext.P = Next;
}
else
{
/* Yep, so update the appropriate bucket listhead */
MmFreeList[MmHapGetBucketId(MmHapBufferSize(FreeEntry))] = Prev;
}
/* Return the (now removed) entry */
return FreeEntry;
}
PBL_FREE_HEAP_ENTRY
MmHapCoalesceFreeBuffer (
_In_ PBL_FREE_HEAP_ENTRY FreeEntry
)
{
PBL_FREE_HEAP_ENTRY Prev, Next;
/* First make sure that this is a valid buffer entry */
if (!MmHapCheckBufferLinks(FreeEntry))
{
return NULL;
}
/* Get the next entry and check if it's free */
Next = MmHapDecodeLink(FreeEntry->BufferNext);
if (!(Next->BufferNext.BufferOnHeap) && (Next->BufferNext.BufferFree))
{
/* Remove the next buffer from the free list since we're coalescing */
Next = MmHapRemoveBufferFromFreeList(Next);
if (!Next)
{
return NULL;
}
/* The forward link of the *new* free buffer should now point to us */
MmHapDecodeLink(Next->BufferNext)->BufferPrevious.P = FreeEntry;
/* Our forward link should point to the *new* free buffer as well */
FreeEntry->BufferNext.P = MmHapDecodeLink(Next->BufferNext);
/* Mark our buffer as free */
FreeEntry->BufferNext.BufferFree = 1;
}
/* Get the previous entry and check if it's free */
Prev = MmHapDecodeLink(FreeEntry->BufferPrevious);
if (!(Prev) || !(Prev->BufferNext.BufferFree))
{
return FreeEntry;
}
/* It's free, so remove it */
Prev = MmHapRemoveBufferFromFreeList(Prev);
if (!Prev)
{
return NULL;
}
/* The previous link of our next buffer should now point to our *previous* */
MmHapDecodeLink(FreeEntry->BufferNext)->BufferPrevious.P = Prev;
/* Our previous link should point the next free buffer now */
Prev->BufferNext.P = MmHapDecodeLink(FreeEntry->BufferNext);
/* Set the new freed buffer as the previous buffer, and mark it free */
FreeEntry = Prev;
FreeEntry->BufferNext.BufferFree = 1;
return FreeEntry;
}
PBL_FREE_HEAP_ENTRY
MmHapAddToFreeList (
_In_ PBL_BUSY_HEAP_ENTRY Entry,
_In_ ULONG Flags
)
{
PBL_FREE_HEAP_ENTRY FreeEntry, Head;
ULONG BucketId;
BL_LIBRARY_PARAMETERS LocalParameters;
/* First, check if the entry is valid */
Entry = MmHapCheckBufferLinks(Entry);
if (!Entry)
{
return NULL;
}
/* Check if we should zero the entry */
LocalParameters = BlpLibraryParameters;
if ((LocalParameters.LibraryFlags & BL_LIBRARY_FLAG_ZERO_HEAP_ALLOCATIONS_ON_FREE) &&
!(Flags))
{
/* Yep, zero it out */
RtlZeroMemory(Entry->Buffer, MmHapUserBufferSize(Entry));
}
/* Now mark the entry as free */
Entry->BufferNext.BufferFree = 1;
/* Now that this buffer is free, try to coalesce it */
FreeEntry = MmHapCoalesceFreeBuffer((PBL_FREE_HEAP_ENTRY)Entry);
if (!FreeEntry)
{
return FreeEntry;
}
/* Compute the bucket ID for the free list */
BucketId = MmHapGetBucketId(MmHapBufferSize(Entry));
/* Get the current head for this bucket, if one exists */
Head = MmFreeList ? MmFreeList[BucketId] : NULL;
/* Update the head's backlink to point to this newly freed entry */
if (Head)
{
Head->FreePrevious.P = FreeEntry;
}
/* Nobody behind us, the old head in front of us */
FreeEntry->FreePrevious.P = NULL;
FreeEntry->FreeNext.P = Head;
/* Put us at the head of list now, and return the entry */
MmFreeList[BucketId] = FreeEntry;
return FreeEntry;
}
PBL_BUSY_HEAP_ENTRY
MmHapFindBufferInFreeList (
_In_ ULONG Size
)
{
PBL_FREE_HEAP_ENTRY FreeEntry = NULL;
PBL_BUSY_HEAP_ENTRY NextEntry;
ULONG BucketId;
/* Get the appropriate bucket for our size */
BucketId = MmHapGetBucketId(Size);
if (BucketId >= 8)
{
return NULL;
}
/* Keep going as long as we don't have a free entry */
while (!FreeEntry)
{
/* Fet the first free entry in this list */
FreeEntry = MmFreeList ? MmFreeList[BucketId] : NULL;
/* Loop as long as there's entries in the list */
while (FreeEntry)
{
/* Can this free entry satisfy our needs? */
if (MmHapBufferSize(FreeEntry) >= Size)
{
/* All good */
break;
}
/* It cannot, keep going to the next one */
FreeEntry = MmHapDecodeLink(FreeEntry->FreeNext);
}
/* Try the next list -- have we exhausted all the lists? */
if (++BucketId >= 8)
{
/* Have we not found an entry yet? Fail if so... */
if (!FreeEntry)
{
return NULL;
}
}
}
/* We should have an entry if we're here. Remove it from the free list */
NT_ASSERT(FreeEntry != NULL);
FreeEntry = MmHapRemoveBufferFromFreeList(FreeEntry);
if (!FreeEntry)
{
return NULL;
}
/* Make sure it's not corrupted */
FreeEntry = MmHapCheckBufferLinks(FreeEntry);
if (!FreeEntry)
{
return NULL;
}
/* Do we have space for at least another buffer? */
if ((MmHapBufferSize(FreeEntry) - Size) >= sizeof(BL_FREE_HEAP_ENTRY))
{
/* Go to where the new next buffer will start */
NextEntry = (PBL_BUSY_HEAP_ENTRY)((ULONG_PTR)FreeEntry + Size);
/* Make the new next buffer point to the next buffer */
NextEntry->BufferNext.P = MmHapDecodeLink(FreeEntry->BufferNext);
/* Make the old next buffer point back to the new one */
MmHapDecodeLink(FreeEntry->BufferNext)->BufferPrevious.P = NextEntry;
/* Point the new next buffer point back to us */
NextEntry->BufferPrevious.P = FreeEntry;
/* Point us to the new next buffer */
FreeEntry->BufferNext.P = NextEntry;
/* And insert the new next buffer into the free list */
MmHapAddToFreeList(NextEntry, 1);
}
/* Return the entry, which is now allocated */
return (PBL_BUSY_HEAP_ENTRY)FreeEntry;
}
NTSTATUS
MmHaInitialize (
_In_ ULONG HeapSize,
_In_ ULONG HeapAttributes
)
{
NTSTATUS Status;
/* No free list to begin with */
MmFreeList = NULL;
/* Configure the minimum heap size and allocation attributes */
HapMinimumHeapSize = ALIGN_UP_BY(HeapSize, PAGE_SIZE);
HapAllocationAttributes = HeapAttributes & 0x20000;
/* Initialize the heap boundary list */
InitializeListHead(&MmHeapBoundaries);
/* Initialize a heap big enough to handle a one pointer long allocation */
Status = MmHapHeapAllocatorExtend(sizeof(PVOID));
if (NT_SUCCESS(Status))
{
/* The heap is ready! */
HapInitializationStatus = 1;
Status = STATUS_SUCCESS;
}
/* Return initialization status */
return Status;
}
PVOID
BlMmAllocateHeap (
_In_ ULONG Size
)
{
ULONG BufferSize;
PBL_HEAP_BOUNDARIES Heap;
PBL_BUSY_HEAP_ENTRY BusyEntry, FreeEntry, NextEntry;
/* Ignore heap allocation if the heap allocator isn't ready yet */
if (HapInitializationStatus != 1)
{
return NULL;
}
/* Align the buffer size to the minimum size required */
BufferSize = ALIGN_UP(Size + FIELD_OFFSET(BL_BUSY_HEAP_ENTRY, Buffer),
FIELD_OFFSET(BL_BUSY_HEAP_ENTRY, Buffer));
/* Watch out for overflow */
if (BufferSize <= Size)
{
return NULL;
}
/* Make sure it's at least big enough to hold a free entry later on */
if (BufferSize < sizeof(BL_FREE_HEAP_ENTRY))
{
BufferSize = sizeof(BL_FREE_HEAP_ENTRY);
}
/* Loop while we try to allocate memory */
while (1)
{
/* Find a free buffer for this allocation */
BusyEntry = MmHapFindBufferInFreeList(BufferSize);
if (BusyEntry)
{
break;
}
/* We couldn't find a free buffer. Do we have any heaps? */
if (!IsListEmpty(&MmHeapBoundaries))
{
/* Get the current heap */
Heap = CONTAINING_RECORD(MmHeapBoundaries.Flink,
BL_HEAP_BOUNDARIES,
ListEntry);
/* Check if we have space in the heap page for this allocation? */
FreeEntry = Heap->HeapStart;
NextEntry = (PBL_BUSY_HEAP_ENTRY)((ULONG_PTR)FreeEntry + BufferSize);
if ((NextEntry >= FreeEntry) &&
((ULONG_PTR)NextEntry <=
Heap->HeapLimit - FIELD_OFFSET(BL_BUSY_HEAP_ENTRY, Buffer)))
{
/* Update the heap top pointer past this allocation */
Heap->HeapStart = NextEntry;
/* Make this allocation point to the slot */
FreeEntry->BufferNext.P = Heap->HeapStart;
/* And make the free heap entry point back to us */
Heap->HeapStart->BufferPrevious.P = FreeEntry;
/* Mark the heap entry as being free and on the heap */
Heap->HeapStart->BufferNext.BufferFree = 1;
Heap->HeapStart->BufferNext.BufferOnHeap = 1;
/* The previously freed entry on the heap page is now ours */
BusyEntry = FreeEntry;
break;
}
}
/* We have no heaps or space on any heap -- extend the heap and retry */
if (!NT_SUCCESS(MmHapHeapAllocatorExtend(BufferSize)))
{
EfiPrintf(L"Heap extension failed!\r\n");
return NULL;
}
EfiPrintf(L"Heap extended -- trying again\r\n");
}
/* Clear all the bits, marking this entry as allocated */
BusyEntry->BufferNext.P = MmHapDecodeLink(BusyEntry->BufferNext);
/* Return the entry's data buffer */
//EfiPrintf(L"Returning buffer at 0x%p\r\n", &BusyEntry->Buffer);
return &BusyEntry->Buffer;
}
NTSTATUS
BlMmFreeHeap (
_In_ PVOID Buffer
)
{
PBL_BUSY_HEAP_ENTRY BusyEntry;
PBL_HEAP_BOUNDARIES Heap;
PLIST_ENTRY NextEntry;
/* If the heap is not initialized, fail */
if (HapInitializationStatus != 1)
{
return STATUS_UNSUCCESSFUL;
}
/* Get the heap header */
//EfiPrintf(L"Freeing entry at: %p\r\n", Buffer);
if (Buffer)
{
/* Don't free heap until we discover the corruption */
return STATUS_SUCCESS;
}
BusyEntry = CONTAINING_RECORD(Buffer, BL_BUSY_HEAP_ENTRY, Buffer);
/* Loop all the heaps */
NextEntry = MmHeapBoundaries.Flink;
while (NextEntry != &MmHeapBoundaries)
{
/* Get the current heap in the list */
Heap = CONTAINING_RECORD(NextEntry, BL_HEAP_BOUNDARIES, ListEntry);
/* Is this entry part of this heap? */
if (((ULONG_PTR)Heap->HeapBase <= (ULONG_PTR)BusyEntry) &&
((ULONG_PTR)BusyEntry < (ULONG_PTR)Heap->HeapStart))
{
/* Ignore double-free */
if (BusyEntry->BufferNext.BufferFree)
{
return STATUS_INVALID_PARAMETER;
}
/* It is -- add it to the free list */
MmHapAddToFreeList(BusyEntry, 0);
return STATUS_SUCCESS;
}
/* It isn't, move to the next heap */
NextEntry = NextEntry->Flink;
}
/* The entry is not on any valid heap */
return STATUS_INVALID_PARAMETER;
}

File diff suppressed because it is too large Load diff

657
boot/environ/lib/mm/mm.c Normal file
View file

@ -0,0 +1,657 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/mm/mm.c
* PURPOSE: Boot Library Memory Manager Core
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
#include "bcd.h"
/* DATA VARIABLES ************************************************************/
/* This is a bug in Windows, but is required for MmTrInitialize to load */
BL_TRANSLATION_TYPE MmTranslationType = BlMax;
BL_TRANSLATION_TYPE MmOriginalTranslationType;
ULONG MmDescriptorCallTreeCount;
/* FUNCTIONS *****************************************************************/
NTSTATUS
TrpGenerateMappingTracker (
_In_ PVOID VirtualAddress,
_In_ ULONG Flags,
_In_ LARGE_INTEGER PhysicalAddress,
_In_ ULONGLONG Size
)
{
PBL_MEMORY_DESCRIPTOR Descriptor, NextDescriptor;
PLIST_ENTRY ListHead, NextEntry;
/* Increment descriptor call count */
MmDescriptorCallTreeCount++;
/* Initialize a descriptor for this allocation */
Descriptor = MmMdInitByteGranularDescriptor(Flags,
0,
PhysicalAddress.QuadPart,
(ULONG_PTR)VirtualAddress,
Size);
/* Loop the current tracker list */
ListHead = MmMdlMappingTrackers.First;
NextEntry = ListHead->Flink;
if (IsListEmpty(ListHead))
{
/* If it's empty, just add the descriptor at the end */
InsertTailList(ListHead, &Descriptor->ListEntry);
goto Quickie;
}
/* Otherwise, go to the last descriptor */
NextDescriptor = CONTAINING_RECORD(NextEntry,
BL_MEMORY_DESCRIPTOR,
ListEntry);
while (NextDescriptor->VirtualPage < Descriptor->VirtualPage)
{
/* Keep going... */
NextEntry = NextEntry->Flink;
NextDescriptor = CONTAINING_RECORD(NextEntry,
BL_MEMORY_DESCRIPTOR,
ListEntry);
/* If we hit the end of the list, just add it at the end */
if (NextEntry == ListHead)
{
goto Quickie;
}
/* Otherwise, add it right after this descriptor */
InsertTailList(&NextDescriptor->ListEntry, &Descriptor->ListEntry);
}
Quickie:
/* Release any global descriptors allocated */
MmMdFreeGlobalDescriptors();
--MmDescriptorCallTreeCount;
return STATUS_SUCCESS;
}
NTSTATUS
MmTrInitialize (
VOID
)
{
PBL_MEMORY_DESCRIPTOR Descriptor;
NTSTATUS Status;
PLIST_ENTRY NextEntry;
/* Nothing to track if we're using physical memory */
if (MmTranslationType == BlNone)
{
return STATUS_SUCCESS;
}
/* Initialize all the virtual lists */
MmMdInitializeListHead(&MmMdlMappingTrackers);
MmMdlMappingTrackers.Type = BlMdTracker;
MmMdInitializeListHead(&MmMdlFreeVirtual);
MmMdlFreeVirtual.Type = BlMdVirtual;
/* Initialize a 4GB free descriptor */
Descriptor = MmMdInitByteGranularDescriptor(0,
BlConventionalMemory,
0,
0,
((ULONGLONG)4 * 1024 * 1024 * 1024) >>
PAGE_SHIFT);
if (!Descriptor)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Add this 4GB region to the free virtual address space list */
Status = MmMdAddDescriptorToList(&MmMdlFreeVirtual,
Descriptor,
BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG);
if (!NT_SUCCESS(Status))
{
RtlZeroMemory(Descriptor, sizeof(*Descriptor));
goto Quickie;
}
/* Remove any reserved regions of virtual address space */
NextEntry = MmMdlReservedAllocated.First->Flink;
while (NextEntry != MmMdlReservedAllocated.First)
{
/* Grab the descriptor and see if it's mapped */
Descriptor = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
if (Descriptor->VirtualPage)
{
EfiPrintf(L"Need to handle reserved allocation: %llx %llx\r\n",
Descriptor->VirtualPage, Descriptor->PageCount);
EfiStall(100000);
Status = STATUS_NOT_IMPLEMENTED;
goto Quickie;
}
/* Next entry */
NextEntry = NextEntry->Flink;
}
/* Set success if we made it */
Status = STATUS_SUCCESS;
Quickie:
/* Return back to caller */
return Status;
}
NTSTATUS
BlMmRemoveBadMemory (
VOID
)
{
BOOLEAN AllowBad;
NTSTATUS Status;
PULONGLONG BadPages;
ULONGLONG BadPageCount;
/* First check if bad memory access is allowed */
AllowBad = FALSE;
Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
BcdLibraryBoolean_AllowBadMemoryAccess,
&AllowBad);
if ((NT_SUCCESS(Status)) && (AllowBad))
{
/* No point checking the list if it is */
return STATUS_SUCCESS;
}
/* Otherwise, check if there's a persisted bad page list */
Status = BlpGetBootOptionIntegerList(BlpApplicationEntry.BcdData,
BcdLibraryIntegerList_BadMemoryList,
&BadPages,
&BadPageCount,
TRUE);
if (NT_SUCCESS(Status))
{
EfiPrintf(L"Persistent bad page list not supported\r\n");
return STATUS_NOT_IMPLEMENTED;
}
/* All done here */
return STATUS_SUCCESS;
}
NTSTATUS
BlMmMapPhysicalAddressEx (
_In_ PVOID* VirtualAddress,
_In_ ULONG Flags,
_In_ ULONGLONG Size,
_In_ PHYSICAL_ADDRESS PhysicalAddress
)
{
NTSTATUS Status;
PVOID MappingAddress;
PHYSICAL_ADDRESS MappedAddress;
PVOID MappedBase;
ULONGLONG MapSize;
UCHAR CacheAttributes;
ULONGLONG BasePage, EndPage, MappedPage, FoundBasePage;
ULONGLONG PageOffset, FoundPageCount;
PBL_MEMORY_DESCRIPTOR Descriptor, NewDescriptor;
PBL_MEMORY_DESCRIPTOR_LIST List;
ULONG AddPages;
/* Increase call depth */
++MmDescriptorCallTreeCount;
/* Check if any parameters are missing */
if (!(VirtualAddress) || !(Size))
{
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Check for fixed allocation without an actual address */
if ((Flags & BlMemoryFixed) &&
(PhysicalAddress.QuadPart == -1) &&
!(*VirtualAddress))
{
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Check for invalid requirement flag, if one is present */
if (((Flags & BlMemoryValidAllocationAttributes) != BlMemoryFixed) &&
((Flags & BlMemoryValidAllocationAttributes) != BlMemoryKernelRange) &&
(Flags & BlMemoryValidAllocationAttributes))
{
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Check for invalid cache attribute flags */
if (((Flags & BlMemoryValidCacheAttributeMask) - 1) &
(Flags & BlMemoryValidCacheAttributeMask))
{
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Select an address to map this at */
Status = MmSelectMappingAddress(&MappingAddress,
*VirtualAddress,
Size,
Flags & BlMemoryValidAllocationAttributes,
Flags,
PhysicalAddress);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Map the selected address, using the appropriate caching attributes */
MappedAddress = PhysicalAddress;
MapSize = Size;
CacheAttributes = ((Flags & BlMemoryValidCacheAttributeMask) != 0x20) ?
(Flags & BlMemoryValidCacheAttributeMask) : 0;
Status = MmMapPhysicalAddress(&MappedAddress,
&MappingAddress,
&MapSize,
CacheAttributes);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Compute the final address where the mapping was made */
MappedBase = (PVOID)(ULONG_PTR)((ULONG_PTR)MappingAddress +
PhysicalAddress.QuadPart -
MappedAddress.QuadPart);
MappedAddress.QuadPart = (ULONG_PTR)MappedBase;
/* Check if we're in physical or virtual mode */
if (MmTranslationType == BlNone)
{
/* We are in physical mode -- just return this address directly */
Status = STATUS_SUCCESS;
*VirtualAddress = MappedBase;
goto Quickie;
}
/* Remove the mapping address from the list of free virtual memory */
Status = MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual,
BL_MM_REMOVE_VIRTUAL_REGION_FLAG,
(ULONG_PTR)MappingAddress >> PAGE_SHIFT,
MapSize >> PAGE_SHIFT,
NULL);
if (NT_SUCCESS(Status))
{
/* And then add an entry for the fact we mapped it */
Status = TrpGenerateMappingTracker(MappedBase,
CacheAttributes,
PhysicalAddress,
MapSize);
}
/* Abandon if we didn't update the memory map successfully */
if (!NT_SUCCESS(Status))
{
/* Unmap the virtual address so it can be used later */
MmUnmapVirtualAddress(MappingAddress, &MapSize);
goto Quickie;
}
/* Check if no real mapping into RAM was made */
if (PhysicalAddress.QuadPart == -1)
{
/* Then we're done here */
Status = STATUS_SUCCESS;
*VirtualAddress = MappedBase;
goto Quickie;
}
/* Loop over the entire allocation */
BasePage = MappedAddress.QuadPart >> PAGE_SHIFT;
EndPage = (MappedAddress.QuadPart + MapSize) >> PAGE_SHIFT;
MappedPage = (ULONG_PTR)MappingAddress >> PAGE_SHIFT;
do
{
/* Start with the unmapped allocated list */
List = &MmMdlUnmappedAllocated;
Descriptor = MmMdFindDescriptor(BL_MM_INCLUDE_UNMAPPED_ALLOCATED,
BL_MM_REMOVE_PHYSICAL_REGION_FLAG,
BasePage);
if (!Descriptor)
{
/* Try persistent next */
List = &MmMdlPersistentMemory;
Descriptor = MmMdFindDescriptor(BL_MM_INCLUDE_PERSISTENT_MEMORY,
BL_MM_REMOVE_PHYSICAL_REGION_FLAG,
BasePage);
}
if (!Descriptor)
{
/* Try unmapped, unallocated, next */
List = &MmMdlUnmappedUnallocated;
Descriptor = MmMdFindDescriptor(BL_MM_INCLUDE_UNMAPPED_UNALLOCATED,
BL_MM_REMOVE_PHYSICAL_REGION_FLAG,
BasePage);
}
if (!Descriptor)
{
/* Try reserved next */
List = &MmMdlReservedAllocated;
Descriptor = MmMdFindDescriptor(BL_MM_INCLUDE_RESERVED_ALLOCATED,
BL_MM_REMOVE_PHYSICAL_REGION_FLAG,
BasePage);
}
/* Check if we have a descriptor */
if (Descriptor)
{
/* Remove it from its list */
MmMdRemoveDescriptorFromList(List, Descriptor);
/* Check if it starts before our allocation */
FoundBasePage = Descriptor->BasePage;
if (FoundBasePage < BasePage)
{
/* Create a new descriptor to cover the gap before our allocation */
PageOffset = BasePage - FoundBasePage;
NewDescriptor = MmMdInitByteGranularDescriptor(Descriptor->Flags,
Descriptor->Type,
FoundBasePage,
0,
PageOffset);
/* Insert it */
MmMdAddDescriptorToList(List, NewDescriptor, 0);
/* Adjust ours to ignore that piece */
Descriptor->PageCount -= PageOffset;
Descriptor->BasePage = BasePage;
}
/* Check if it goes beyond our allocation */
FoundPageCount = Descriptor->PageCount;
if (EndPage < (FoundPageCount + Descriptor->BasePage))
{
/* Create a new descriptor to cover the range after our allocation */
PageOffset = EndPage - BasePage;
NewDescriptor = MmMdInitByteGranularDescriptor(Descriptor->Flags,
Descriptor->Type,
EndPage,
0,
FoundPageCount -
PageOffset);
/* Insert it */
MmMdAddDescriptorToList(List, NewDescriptor, 0);
/* Adjust ours to ignore that piece */
Descriptor->PageCount = PageOffset;
}
/* Update the descriptor to be mapepd at this virtual page */
Descriptor->VirtualPage = MappedPage;
/* Check if this was one of the regular lists */
if ((List != &MmMdlReservedAllocated) &&
(List != &MmMdlPersistentMemory))
{
/* Was it allocated, or unallocated? */
if (List != &MmMdlUnmappedAllocated)
{
/* In which case use the unallocated mapped list */
List = &MmMdlMappedUnallocated;
}
else
{
/* Insert it into the mapped list */
List = &MmMdlMappedAllocated;
}
}
/* Add the descriptor that was removed, into the right list */
MmMdAddDescriptorToList(List, Descriptor, 0);
/* Add the pages this descriptor had */
AddPages = Descriptor->PageCount;
}
else
{
/* Nope, so just add one page */
AddPages = 1;
}
/* Increment the number of pages the descriptor had */
MappedPage += AddPages;
BasePage += AddPages;
}
while (BasePage < EndPage);
/* We're done -- returned the address */
Status = STATUS_SUCCESS;
*VirtualAddress = MappedBase;
Quickie:
/* Cleanup descriptors and reduce depth */
MmMdFreeGlobalDescriptors();
--MmDescriptorCallTreeCount;
return Status;
}
NTSTATUS
MmUnmapVirtualAddress (
_Inout_ PVOID* VirtualAddress,
_Inout_ PULONGLONG Size
)
{
NTSTATUS Status;
/* Make sure parameters were passed in and are valid */
if ((VirtualAddress) && (Size) && (*Size <= 0xFFFFFFFF))
{
/* Nothing to do if translation isn't active */
if (MmTranslationType == BlNone)
{
Status = STATUS_SUCCESS;
}
else
{
/* We don't support virtual memory yet @TODO */
EfiPrintf(L"unmap not yet implemented in %S\r\n", __FUNCTION__);
EfiStall(1000000);
Status = STATUS_NOT_IMPLEMENTED;
}
}
else
{
/* Fail */
Status = STATUS_INVALID_PARAMETER;
}
/* All done */
return Status;
}
NTSTATUS
BlMmUnmapVirtualAddressEx (
_In_ PVOID VirtualAddress,
_In_ ULONGLONG Size
)
{
NTSTATUS Status;
/* Increment call depth */
++MmDescriptorCallTreeCount;
/* Make sure all parameters are there */
if ((VirtualAddress) && (Size))
{
/* Unmap the virtual address */
Status = MmUnmapVirtualAddress(&VirtualAddress, &Size);
/* Check if we actually had a virtual mapping active */
if ((NT_SUCCESS(Status)) && (MmTranslationType != BlNone))
{
/* We don't support virtual memory yet @TODO */
EfiPrintf(L"not yet implemented in %S\r\n", __FUNCTION__);
EfiStall(1000000);
Status = STATUS_NOT_IMPLEMENTED;
}
}
else
{
/* Fail */
Status = STATUS_INVALID_PARAMETER;
}
/* Cleanup descriptors and reduce depth */
MmMdFreeGlobalDescriptors();
--MmDescriptorCallTreeCount;
return Status;
}
BOOLEAN
BlMmTranslateVirtualAddress (
_In_ PVOID VirtualAddress,
_Out_ PPHYSICAL_ADDRESS PhysicalAddress
)
{
/* Make sure arguments are present */
if (!(VirtualAddress) || !(PhysicalAddress))
{
return FALSE;
}
/* Do the architecture-specific translation */
return MmArchTranslateVirtualAddress(VirtualAddress, PhysicalAddress, NULL);
}
NTSTATUS
BlpMmInitialize (
_In_ PBL_MEMORY_DATA MemoryData,
_In_ BL_TRANSLATION_TYPE TranslationType,
_In_ PBL_LIBRARY_PARAMETERS LibraryParameters
)
{
NTSTATUS Status;
/* Take a reference */
MmDescriptorCallTreeCount = 1;
/* Only support valid translation types */
if ((TranslationType > BlPae) || (LibraryParameters->TranslationType > BlPae))
{
/* Bail out */
EfiPrintf(L"Invalid translation types present\r\n");
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Initialize memory descriptors */
MmMdInitialize(0, LibraryParameters);
/* Remember the page type we came in with */
MmOriginalTranslationType = TranslationType;
/* Initialize the physical page allocator */
Status = MmPaInitialize(MemoryData,
LibraryParameters->MinimumAllocationCount);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Initialize the memory tracker */
Status = MmTrInitialize();
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"TR Mm init failed: %lx\r\n", Status);
//MmArchDestroy();
//MmPaDestroy(1);
goto Quickie;
}
/* Initialize paging, large pages, self-mapping, PAE, if needed */
Status = MmArchInitialize(1,
MemoryData,
TranslationType,
LibraryParameters->TranslationType);
if (NT_SUCCESS(Status))
{
/* Save the newly active transation type */
MmTranslationType = LibraryParameters->TranslationType;
/* Initialize the heap allocator now */
Status = MmHaInitialize(LibraryParameters->MinimumHeapSize,
LibraryParameters->HeapAllocationAttributes);
}
/* If Phase 1 init failed, bail out */
if (!NT_SUCCESS(Status))
{
/* Kill everything set setup so far */
EfiPrintf(L"Phase 1 Mm init failed: %lx\r\n", Status);
//MmPaDestroy(0);
//MmTrDestroy();
//MmArchDestroy();
//MmPaDestroy(1);
goto Quickie;
}
/* Do we have too many descriptors? */
if (LibraryParameters->DescriptorCount > 512)
{
/* Switch to using a dynamic buffer instead */
EfiPrintf(L"Warning: too many descriptors\r\n");
Status = STATUS_NOT_IMPLEMENTED;
goto Quickie;
//MmMdpSwitchToDynamicDescriptors(LibraryParameters->DescriptorCount);
}
/* Remove memory that the BCD says is bad */
BlMmRemoveBadMemory();
/* Now map all the memory regions as needed */
Status = MmArchInitialize(2,
MemoryData,
TranslationType,
LibraryParameters->TranslationType);
if (NT_SUCCESS(Status))
{
/* Initialize the block allocator */
Status = MmBaInitialize();
}
/* Check if anything in phase 2 failed */
if (!NT_SUCCESS(Status))
{
/* Go back to static descriptors and kill the heap */
EfiPrintf(L"Phase 2 Mm init failed: %lx\r\n", Status);
//MmMdpSwitchToStaticDescriptors();
//HapInitializationStatus = 0;
//++MmDescriptorCallTreeCount;
/* Destroy the Phase 1 initialization */
//MmPaDestroy(0);
//MmTrDestroy();
//MmArchDestroy();
//MmPaDestroy(1);
}
Quickie:
/* Free the memory descriptors and return the initialization state */
MmMdFreeGlobalDescriptors();
--MmDescriptorCallTreeCount;
return Status;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,52 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/mm/stub/mm.c
* PURPOSE: Boot Library Memory Manager Skeleton Code
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
BL_ADDRESS_RANGE MmArchKsegAddressRange;
ULONG_PTR MmArchTopOfApplicationAddressSpace;
ULONG MmArchLargePageSize;
/* FUNCTIONS *****************************************************************/
NTSTATUS
MmArchInitialize (
_In_ ULONG Phase,
_In_ PBL_MEMORY_DATA MemoryData,
_In_ BL_TRANSLATION_TYPE TranslationType,
_In_ BL_TRANSLATION_TYPE RequestedTranslationType
)
{
EfiPrintf(L" MmArchInitialize NOT IMPLEMENTED for this platform\r\n");
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
MmMapPhysicalAddress (
_Inout_ PPHYSICAL_ADDRESS PhysicalAddressPtr,
_Inout_ PVOID* VirtualAddressPtr,
_Inout_ PULONGLONG SizePtr,
_In_ ULONG CacheAttributes
)
{
EfiPrintf(L" MmMapPhysicalAddress NOT IMPLEMENTED for this platform\r\n");
return STATUS_NOT_IMPLEMENTED;
}
BOOLEAN
MmArchTranslateVirtualAddress (
_In_ PVOID VirtualAddress,
_Out_opt_ PPHYSICAL_ADDRESS PhysicalAddress,
_Out_opt_ PULONG CachingFlags
)
{
EfiPrintf(L" MmMapPhysicalAddress NOT IMPLEMENTED for this platform\r\n");
return FALSE;
}

0
boot/environ/lib/platform/.gitignore vendored Normal file
View file

View file

@ -0,0 +1,119 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/platform/time.c
* PURPOSE: Boot Library Time Management Routines
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
ULONGLONG BlpTimePerformanceFrequency;
/* FUNCTIONS *****************************************************************/
NTSTATUS
BlpTimeMeasureTscFrequency (
VOID
)
{
#if defined(_M_IX86) || defined(_M_X64)
ULONG Count;
INT CpuInfo[4];
ULONGLONG TimeStamp1, TimeStamp2, Delta;
/* Check if the ISVM bit it set, meaning we're in a hypervisor */
__cpuid(CpuInfo, 1);
Count = CpuInfo[2] & 0x80000000 ? 10 : 1;
/* Loop trying to get an accurate TSC */
do
{
/* Stall for 1us and get count 1 */
EfiStall(1);
TimeStamp1 = __rdtsc();
/* Stall for 1000us and get count 2*/
EfiStall(1000);
TimeStamp2 = __rdtsc();
/* Stall for 9000us and get the difference */
EfiStall(9000);
Delta = __rdtsc() - TimeStamp2;
/* Keep going as long as the TSC is fluctuating */
--Count;
} while (((TimeStamp2 - TimeStamp1) > Delta) && (Count));
/* Set the frequency based on the two measurements we took */
BlpTimePerformanceFrequency = 125 * (Delta - (TimeStamp2 - TimeStamp1)) & 0x1FFFFFFFFFFFFFF;
return STATUS_SUCCESS;
#else
EfiPrintf(L"BlpTimeMeasureTscFrequency not implemented for this platform.\r\n");
return STATUS_NOT_IMPLEMENTED;
#endif
}
NTSTATUS
BlpTimeCalibratePerformanceCounter (
VOID
)
{
#if defined(_M_IX86) || defined(_M_X64)
INT CpuInfo[4];
/* Check if the ISVM bit it set, meaning we're in a hypervisor */
__cpuid(CpuInfo, 1);
if (CpuInfo[2] & 0x80000000)
{
/* Get the Hypervisor Identification Leaf */
__cpuid(CpuInfo, 0x40000001);
/* Is this Hyper-V? */
if (CpuInfo[0] == '1#vH')
{
/* Get the Hypervisor Feature Identification Leaf */
__cpuid(CpuInfo, 0x40000003);
/* Check if HV_X64_MSR_REFERENCE_TSC is present */
if (CpuInfo[3] & 0x100)
{
/* Read the TSC frequency from the MSR */
BlpTimePerformanceFrequency = __readmsr(0x40000022);
return STATUS_SUCCESS;
}
}
}
/* On other systems, compute it */
return BlpTimeMeasureTscFrequency();
#else
EfiPrintf(L"BlpTimeCalibratePerformanceCounter not implemented for this platform.\r\n");
return STATUS_NOT_IMPLEMENTED;
#endif
}
ULONGLONG
BlTimeQueryPerformanceCounter (
_Out_opt_ PLARGE_INTEGER Frequency
)
{
#if defined(_M_IX86) || defined(_M_X64)
/* Check if caller wants frequency */
if (Frequency)
{
/* Return it */
Frequency->QuadPart = BlpTimePerformanceFrequency;
}
/* Return the TSC value */
return __rdtsc();
#else
EfiPrintf(L"BlTimeQueryPerformanceCounter not implemented for this platform.\r\n");
return 0;
#endif
};