mirror of
https://github.com/reactos/reactos.git
synced 2025-08-07 05:43:08 +00:00
Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers into modules, and delete rossubsys.
This commit is contained in:
parent
b94e2d8ca0
commit
c2c66aff7d
24198 changed files with 0 additions and 37285 deletions
0
boot/environ/lib/arch/.gitignore
vendored
Normal file
0
boot/environ/lib/arch/.gitignore
vendored
Normal file
305
boot/environ/lib/arch/i386/arch.c
Normal file
305
boot/environ/lib/arch/i386/arch.c
Normal 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;
|
||||
}
|
||||
|
82
boot/environ/lib/arch/i386/transfer.s
Normal file
82
boot/environ/lib/arch/i386/transfer.s
Normal 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
|
52
boot/environ/lib/arch/stub/arch.c
Normal file
52
boot/environ/lib/arch/stub/arch.c
Normal 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
0
boot/environ/lib/bd/.gitignore
vendored
Normal file
480
boot/environ/lib/bootlib.c
Normal file
480
boot/environ/lib/bootlib.c
Normal 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
0
boot/environ/lib/firmware/.gitignore
vendored
Normal file
2592
boot/environ/lib/firmware/efi/firmware.c
Normal file
2592
boot/environ/lib/firmware/efi/firmware.c
Normal file
File diff suppressed because it is too large
Load diff
35
boot/environ/lib/firmware/fwutil.c
Normal file
35
boot/environ/lib/firmware/fwutil.c
Normal 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
0
boot/environ/lib/io/.gitignore
vendored
Normal file
111
boot/environ/lib/io/blkcache.c
Normal file
111
boot/environ/lib/io/blkcache.c
Normal 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
2312
boot/environ/lib/io/device.c
Normal file
File diff suppressed because it is too large
Load diff
988
boot/environ/lib/io/display/display.c
Normal file
988
boot/environ/lib/io/display/display.c
Normal 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;
|
||||
}
|
280
boot/environ/lib/io/display/efi/gop.c
Normal file
280
boot/environ/lib/io/display/efi/gop.c
Normal 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;
|
||||
}
|
||||
|
168
boot/environ/lib/io/display/efi/guicons.c
Normal file
168
boot/environ/lib/io/display/efi/guicons.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
625
boot/environ/lib/io/display/efi/textcons.c
Normal file
625
boot/environ/lib/io/display/efi/textcons.c
Normal 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;
|
||||
}
|
||||
|
42
boot/environ/lib/io/display/efi/uga.c
Normal file
42
boot/environ/lib/io/display/efi/uga.c
Normal 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;
|
||||
}
|
58
boot/environ/lib/io/display/emscons.c
Normal file
58
boot/environ/lib/io/display/emscons.c
Normal 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;
|
||||
}
|
462
boot/environ/lib/io/display/guicons.c
Normal file
462
boot/environ/lib/io/display/guicons.c
Normal 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;
|
||||
}
|
270
boot/environ/lib/io/display/textcons.c
Normal file
270
boot/environ/lib/io/display/textcons.c
Normal 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
994
boot/environ/lib/io/etfs.c
Normal 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
110
boot/environ/lib/io/fat.c
Normal 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
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
70
boot/environ/lib/io/io.c
Normal 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
0
boot/environ/lib/mc/.gitignore
vendored
Normal file
1364
boot/environ/lib/misc/bcd.c
Normal file
1364
boot/environ/lib/misc/bcd.c
Normal file
File diff suppressed because it is too large
Load diff
870
boot/environ/lib/misc/bcdopt.c
Normal file
870
boot/environ/lib/misc/bcdopt.c
Normal 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;
|
||||
}
|
||||
|
947
boot/environ/lib/misc/bootreg.c
Normal file
947
boot/environ/lib/misc/bootreg.c
Normal 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;
|
||||
}
|
145
boot/environ/lib/misc/debug.c
Normal file
145
boot/environ/lib/misc/debug.c
Normal 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();
|
||||
}
|
||||
}
|
||||
|
196
boot/environ/lib/misc/font.c
Normal file
196
boot/environ/lib/misc/font.c
Normal 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;
|
||||
}
|
2074
boot/environ/lib/misc/image.c
Normal file
2074
boot/environ/lib/misc/image.c
Normal file
File diff suppressed because it is too large
Load diff
550
boot/environ/lib/misc/resource.c
Normal file
550
boot/environ/lib/misc/resource.c
Normal 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);
|
||||
}
|
98
boot/environ/lib/misc/rtlcompat.c
Normal file
98
boot/environ/lib/misc/rtlcompat.c
Normal 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);
|
||||
}
|
934
boot/environ/lib/misc/util.c
Normal file
934
boot/environ/lib/misc/util.c
Normal 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
|
||||
}
|
298
boot/environ/lib/mm/blkalloc.c
Normal file
298
boot/environ/lib/mm/blkalloc.c
Normal 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;
|
||||
}
|
1406
boot/environ/lib/mm/descriptor.c
Normal file
1406
boot/environ/lib/mm/descriptor.c
Normal file
File diff suppressed because it is too large
Load diff
716
boot/environ/lib/mm/heapalloc.c
Normal file
716
boot/environ/lib/mm/heapalloc.c
Normal 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;
|
||||
}
|
||||
|
1218
boot/environ/lib/mm/i386/mmx86.c
Normal file
1218
boot/environ/lib/mm/i386/mmx86.c
Normal file
File diff suppressed because it is too large
Load diff
657
boot/environ/lib/mm/mm.c
Normal file
657
boot/environ/lib/mm/mm.c
Normal 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;
|
||||
}
|
1702
boot/environ/lib/mm/pagealloc.c
Normal file
1702
boot/environ/lib/mm/pagealloc.c
Normal file
File diff suppressed because it is too large
Load diff
52
boot/environ/lib/mm/stub/mm.c
Normal file
52
boot/environ/lib/mm/stub/mm.c
Normal 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
0
boot/environ/lib/platform/.gitignore
vendored
Normal file
119
boot/environ/lib/platform/time.c
Normal file
119
boot/environ/lib/platform/time.c
Normal 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
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue