[BOOTLIB]:

- WIP work to begin reading, parsing, mounting and loading the BCD hive into a data store. Untested, has missing pieces.
- Implement BlFileSet/GetInformation, BlFileReadEx, BlFileReadAtOffsetEx and helper structures/functions. Document multiple previously unknown/magic flags.
- Implement BlMmAllocatePhysicalPages. Stub BlMmFreePhysicalPages.
- Implement MmUnmapVirtualAddress, BlMmUnmapVirtualAddressEx when operating in real mode.
- Implement ImgpGetFileSize, ImgpReadFileAtOffset, ImgpOpenFile, ImgpCloseFile, BlImgAllocateImageBuffer, BlImgLoadImageWithProgress2.
- Implement BdDebuggerInitialized, BlBdDebuggerEnabled, BlStatusPrint, BlStatuserror. Stub BlBdPullRemoteFile.
- Implement BlGetBootOptionDevice.
- Implement BiReferenceHive, BiDereferenceHive, BiCloseKey, BiOpenKey. Stub BiFlushKey, BiLoadHive.
- Implement BiAddStoreFromFile, BcdOpenStoreFromFile.
- Stub BlUtlUpdateProcess and BlResourceFindMessage.
- Other misc. cleanups.
[BOOTMGR]:
- Implement BmpFatalErrorMessageFilter, BmErrorPurge, BmpErrorLog, BmFatalErrorEx.
- Implement BmpFwGetFullPath.
- Implement BmOpenDataStore.
- Stub BmOpenBootIni

svn path=/trunk/; revision=69447
This commit is contained in:
Alex Ionescu 2015-10-04 21:07:12 +00:00
parent e17f8bc3e7
commit e7dee1f989
13 changed files with 2465 additions and 147 deletions

View file

@ -10,8 +10,10 @@ add_definitions(-D_NTHAL_ -D_BLDR_ -D_NTSYSTEM_)
list(APPEND BOOTLIB_SOURCE
app/bootmgr/bootmgr.h
lib/bootlib.c
lib/misc/debug.c
lib/misc/bcd.c
lib/misc/util.c
lib/misc/image.c
lib/firmware/efi/firmware.c
lib/mm/mm.c
lib/mm/pagealloc.c

View file

@ -23,6 +23,14 @@ ULONGLONG PostTime;
GUID BmApplicationIdentifier;
PWCHAR BootDirectory;
BL_BOOT_ERROR BmpErrorBuffer;
PBL_BOOT_ERROR BmpInternalBootError;
BL_PACKED_BOOT_ERROR BmpPackedBootError;
BOOLEAN BmBootIniUsed;
WCHAR BmpFileNameBuffer[128];
PWCHAR ParentFileName = L"";
/* FUNCTIONS *****************************************************************/
NTSTATUS
@ -120,8 +128,8 @@ BmpFwGetApplicationDirectoryPath (
/* All done! */
return Status;
}
NTSTATUS
BmFwInitializeBootDirectoryPath (
VOID
@ -187,6 +195,7 @@ BmFwInitializeBootDirectoryPath (
goto Quickie;
}
/* Save the boot directory */
BootDirectory = L"\\EFI\\Microsoft\\Boot";
Quickie:
@ -216,6 +225,441 @@ Quickie:
return Status;
}
NTSTATUS
BmOpenBootIni (
VOID
)
{
/* Don't yet handled boot.ini */
return STATUS_NOT_FOUND;
}
ULONG
BmpFatalErrorMessageFilter (
_In_ NTSTATUS ErrorStatus,
_Out_ PULONG ErrorResourceId
)
{
ULONG Result;
/* Assume no message for now, check for known status message */
Result = 0;
switch (ErrorStatus)
{
/* Convert each status to a resource ID */
case STATUS_UNEXPECTED_IO_ERROR:
*ErrorResourceId = 9017;
Result = 1;
break;
case STATUS_IMAGE_CHECKSUM_MISMATCH:
*ErrorResourceId = 9018;
break;
case STATUS_INVALID_IMAGE_WIN_64:
*ErrorResourceId = 9016;
break;
case 0xC0000428:
*ErrorResourceId = 9019;
Result = 2;
break;
case 0xC0210000:
*ErrorResourceId = 9013;
break;
}
/* Return the type of message */
return Result;
}
VOID
BmErrorPurge (
VOID
)
{
/* Check if a boot error is present */
if (BmpPackedBootError.BootError)
{
/* Purge it */
BlMmFreeHeap(BmpPackedBootError.BootError);
BmpPackedBootError.BootError = NULL;
}
/* Zero out the packed buffer */
BmpPackedBootError.Size = 0;
BmpInternalBootError = NULL;
RtlZeroMemory(&BmpErrorBuffer, sizeof(BmpErrorBuffer));
}
VOID
BmpErrorLog (
_In_ ULONG ErrorCode,
_In_ NTSTATUS ErrorStatus,
_In_ ULONG ErrorMsgId,
_In_ PWCHAR FileName,
_In_ ULONG HelpMsgId
)
{
PWCHAR ErrorMsgString;
/* Check if we already had an error */
if (BmpInternalBootError)
{
/* Purge it */
BmErrorPurge();
}
/* Find the string for this error ID */
ErrorMsgString = BlResourceFindMessage(ErrorMsgId);
if (ErrorMsgString)
{
/* Fill out the error buffer */
BmpErrorBuffer.Unknown1 = 0;
BmpErrorBuffer.Unknown2 = 0;
BmpErrorBuffer.ErrorString = ErrorMsgString;
BmpErrorBuffer.FileName = FileName;
BmpErrorBuffer.ErrorCode = ErrorCode;
BmpErrorBuffer.ErrorStatus = ErrorStatus;
BmpErrorBuffer.HelpMsgId = HelpMsgId;
BmpInternalBootError = &BmpErrorBuffer;
}
}
VOID
BmFatalErrorEx (
_In_ ULONG ErrorCode,
_In_ ULONG_PTR Parameter1,
_In_ ULONG_PTR Parameter2,
_In_ ULONG_PTR Parameter3,
_In_ ULONG_PTR Parameter4
)
{
PWCHAR FileName, Buffer;
NTSTATUS ErrorStatus;
WCHAR FormatString[256];
ULONG ErrorResourceId, ErrorHelpId;
BOOLEAN Restart, NoError;
/* Assume no buffer for now */
Buffer = NULL;
/* Check what error code is being raised */
switch (ErrorCode)
{
/* Error reading the BCD */
case BL_FATAL_ERROR_BCD_READ:
/* Check if we have a name for the BCD file */
if (Parameter1)
{
/* Check if the name fits into our buffer */
FileName = (PWCHAR)Parameter1;
if (wcslen(FileName) < sizeof(BmpFileNameBuffer))
{
/* Copy it in there */
Buffer = BmpFileNameBuffer;
wcsncpy(BmpFileNameBuffer,
FileName,
RTL_NUMBER_OF(BmpFileNameBuffer));
}
}
/* If we don't have a buffer, use an empty one */
if (!Buffer)
{
Buffer = ParentFileName;
}
/* The NTSTATUS code is in parameter 2*/
ErrorStatus = (NTSTATUS)Parameter2;
/* Build the error string */
swprintf(FormatString,
L"\nAn error occurred (%08x) while attempting"
L"to read the boot configuration data file %s\n",
ErrorStatus,
Buffer);
/* Select the resource ID message */
ErrorResourceId = 9002;
break;
default:
/* The rest is not yet handled */
EfiPrintf(L"Unexpected fatal error: %lx\n", ErrorCode);
while (1);
break;
}
/* Check if the BCD option for restart is set */
BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
BcdLibraryBoolean_RestartOnFailure,
&Restart);
if (Restart)
{
/* Yes, so no error should be shown since we'll auto-restart */
NoError = TRUE;
}
else
{
/* Check if the option for not showing errors is set in the BCD */
BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
BcdBootMgrBoolean_NoErrorDisplay,
&NoError);
}
/* Do we want an error? */
if (!NoError)
{
/* Yep, print it and then raise an error */
BlStatusPrint(FormatString);
BlStatusError(1, ErrorCode, Parameter1, Parameter2, Parameter3);
}
/* Get the help message ID */
ErrorHelpId = BmpFatalErrorMessageFilter(ErrorStatus, &ErrorResourceId);
BmpErrorLog(ErrorCode, ErrorStatus, ErrorResourceId, Buffer, ErrorHelpId);
}
NTSTATUS
BmpFwGetFullPath (
_In_ PWCHAR FileName,
_Out_ PWCHAR* FullPath
)
{
NTSTATUS Status;
ULONG BootDirLength, BootDirLengthWithNul;
ULONG PathLength, FullPathLength;
/* Compute the length of the directory, and add a NUL */
BootDirLength = wcslen(BootDirectory);
BootDirLengthWithNul = BootDirLength + 1;
if (BootDirLengthWithNul < BootDirLength)
{
/* This would overflow */
BootDirLengthWithNul = -1;
Status = STATUS_INTEGER_OVERFLOW;
}
else
{
/* We have space */
Status = STATUS_SUCCESS;
}
/* Fail on overflow */
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Add the length of the file, make sure it fits */
PathLength = wcslen(FileName);
FullPathLength = PathLength + BootDirLength;
if (FullPathLength < PathLength)
{
/* Nope */
FullPathLength = -1;
Status = STATUS_INTEGER_OVERFLOW;
}
else
{
/* All good */
Status = STATUS_SUCCESS;
}
/* Fail on overflow */
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Allocate the full path */
FullPathLength = FullPathLength * sizeof(WCHAR);
*FullPath = BlMmAllocateHeap(FullPathLength);
if (*FullPath)
{
/* Copy the directory followed by the file name */
wcsncpy(*FullPath, BootDirectory, FullPathLength / sizeof(WCHAR));
wcsncat(*FullPath, FileName, FullPathLength / sizeof(WCHAR));
}
else
{
/* Bail out since we have no memory */
Status = STATUS_NO_MEMORY;
}
Quickie:
/* Return to caller */
return Status;
}
NTSTATUS
BmOpenDataStore (
_Out_ PHANDLE Handle
)
{
NTSTATUS Status;
PBL_DEVICE_DESCRIPTOR BcdDevice;
PWCHAR BcdPath, FullPath, PathBuffer;
BOOLEAN HavePath;
ULONG PathLength, PathLengthWithNul, FullSize;
PVOID FinalBuffer;
UNICODE_STRING BcdString;
PathBuffer = NULL;
BcdDevice = NULL;
BcdPath = NULL;
HavePath = FALSE;
/* Check if a boot.ini file exists */
Status = BmOpenBootIni();
if (NT_SUCCESS(Status))
{
BmBootIniUsed = TRUE;
}
/* Check on which device the BCD is */
Status = BlGetBootOptionDevice(BlpApplicationEntry.BcdData,
BcdBootMgrDevice_BcdDevice,
&BcdDevice,
NULL);
if (!NT_SUCCESS(Status))
{
/* It's not on a custom device, so it must be where we are */
Status = BlGetBootOptionDevice(BlpApplicationEntry.BcdData,
BcdLibraryDevice_ApplicationDevice,
&BcdDevice,
NULL);
if (!NT_SUCCESS(Status))
{
/* This BCD option is required */
goto Quickie;
}
}
/* Next, check what file contains the BCD */
Status = BlGetBootOptionString(BlpApplicationEntry.BcdData,
BcdBootMgrString_BcdFilePath,
&BcdPath);
if (NT_SUCCESS(Status))
{
/* We don't handle custom BCDs yet */
EfiPrintf(L"Not handled\n");
Status = STATUS_NOT_IMPLEMENTED;
goto Quickie;
}
/* Now check if the BCD is on a remote share */
if (BcdDevice->DeviceType == UdpDevice)
{
/* Nope. Nope. Nope */
EfiPrintf(L"Not handled\n");
Status = STATUS_NOT_IMPLEMENTED;
goto Quickie;
}
/* Otherwise, compute the hardcoded path of the BCD */
Status = BmpFwGetFullPath(L"\\BCD", &FullPath);
if (!NT_SUCCESS(Status))
{
/* User the raw path */
PathBuffer = BcdPath;
}
else
{
/* Use the path we got */
PathBuffer = FullPath;
HavePath = TRUE;
}
/* Check if we failed to get the BCD path */
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Add a NUL to the path, make sure it'll fit */
Status = STATUS_SUCCESS;
PathLength = wcslen(PathBuffer);
PathLengthWithNul = PathLength + 1;
if (PathLengthWithNul < PathLength)
{
PathLengthWithNul = -1;
Status = STATUS_INTEGER_OVERFLOW;
}
/* Bail out if it doesn't fit */
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Now add the size of the path to the device path, check if it fits */
PathLengthWithNul = PathLengthWithNul * sizeof(WCHAR);
FullSize = PathLengthWithNul + BcdDevice->Size;
if (FullSize < BcdDevice->Size)
{
FullSize = -1;
Status = STATUS_INTEGER_OVERFLOW;
}
else
{
Status = STATUS_SUCCESS;
}
/* Bail out if it doesn't fit */
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Allocate a final structure to hold both entities */
FinalBuffer = BlMmAllocateHeap(FullSize);
if (!FinalBuffer)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Copy the device path and file path into the final buffer */
RtlCopyMemory(FinalBuffer, BcdDevice, BcdDevice->Size);
RtlCopyMemory((PVOID)((ULONG_PTR)FinalBuffer + BcdDevice->Size),
PathBuffer,
PathLengthWithNul);
/* Now tell the BCD engine to open the store */
BcdString.Length = FullSize;
BcdString.MaximumLength = FullSize;
BcdString.Buffer = FinalBuffer;
Status = BcdOpenStoreFromFile(&BcdString, Handle);
/* Free our final buffer */
BlMmFreeHeap(FinalBuffer);
Quickie:
/* Did we allocate a device? */
if (BcdDevice)
{
/* Free it */
BlMmFreeHeap(BcdDevice);
}
/* Is this the failure path? */
if (!NT_SUCCESS(Status))
{
/* Raise a fatal error */
BmFatalErrorEx(1, (ULONG_PTR)PathBuffer, Status, 0, 0);
}
/* Did we get an allocated path? */
if ((PathBuffer) && (HavePath))
{
/* Free it */
BlMmFreeHeap(PathBuffer);
}
/* Return back to the caller */
return Status;
}
/*++
* @name BmMain
@ -240,7 +684,7 @@ BmMain (
PBL_RETURN_ARGUMENTS ReturnArguments;
BOOLEAN RebootOnError;
PGUID AppIdentifier;
// HANDLE BcdHandle;
HANDLE BcdHandle;
EfiPrintf(L"ReactOS UEFI Boot Manager Initializing...\n");
@ -280,15 +724,18 @@ BmMain (
/* None was given, so set our default one */
AppIdentifier = (PGUID)&GUID_WINDOWS_BOOTMGR;
}
/* Save our identifier */
BmApplicationIdentifier = *AppIdentifier;
/* Initialize the file system to open a handle to our root boot directory */
BmFwInitializeBootDirectoryPath();
//Status = BmOpenDataStore(&BcdHandle);
/* Load and initialize the boot configuration database (BCD) */
Status = BmOpenDataStore(&BcdHandle);
EfiPrintf(L"BCD Open: %lx\r\n", Status);
/* do more stuff!! */
EfiPrintf(L"We are A-OK!\r\n");
EfiStall(10000000);

View file

@ -29,6 +29,28 @@
/* BCD Headers */
#include <bcd.h>
/* STRUCTURES ****************************************************************/
typedef struct _BL_BOOT_ERROR
{
ULONG ErrorCode;
NTSTATUS ErrorStatus;
ULONG Unknown1;
PWCHAR ErrorString;
PWCHAR FileName;
ULONG HelpMsgId;
ULONG Unknown2;
} BL_BOOT_ERROR, *PBL_BOOT_ERROR;
typedef struct _BL_PACKED_BOOT_ERROR
{
PBL_BOOT_ERROR BootError;
ULONG Unknown;
ULONG Size;
} BL_PACKED_BOOT_ERROR, *PBL_PACKED_BOOT_ERROR;
#define BL_FATAL_ERROR_BCD_READ 0x02
/* FUNCTIONS *****************************************************************/
NTSTATUS

View file

@ -9,7 +9,6 @@
/* INCLUDES ******************************************************************/
#include "bootmgr.h"
#include <bcd.h>
/* DATA STRUCTURES ***********************************************************/
@ -206,8 +205,7 @@ EfiInitpConvertEfiFilePath (
)
{
ULONG BytesAppended, DataSize, StringLength;
PBCDE_STRING StringEntry;
PWCHAR PathString;
PWCHAR StringEntry, PathString;
FILEPATH_DEVICE_PATH *FilePath;
NTSTATUS Status;
@ -227,8 +225,8 @@ EfiInitpConvertEfiFilePath (
Option->DataOffset = sizeof(*Option);
/* Extract the string option */
StringEntry = (PBCDE_STRING)(Option + 1);
PathString = StringEntry->String;
StringEntry = (PWCHAR)(Option + 1);
PathString = StringEntry;
/* Start parsing the device path */
FilePath = (FILEPATH_DEVICE_PATH*)DevicePath;
@ -282,7 +280,7 @@ EfiInitpConvertEfiFilePath (
DataSize += sizeof(UNICODE_NULL);
/* Check if all of this has amounted to a single NULL-char */
if (PathString == StringEntry->String)
if (PathString == StringEntry)
{
/* Then this option is empty */
Option->Empty = TRUE;
@ -520,7 +518,7 @@ EfiInitpConvertEfiDevicePath (
_In_ ULONG MaximumLength
)
{
PBCDE_DEVICE DeviceEntry;
PBCD_DEVICE_OPTION BcdDevice;
NTSTATUS Status;
/* Make sure we have enough space for the option */
@ -534,15 +532,17 @@ EfiInitpConvertEfiDevicePath (
RtlZeroMemory(Option, sizeof(*Option));
/* Make sure we have enough space for the device entry */
if ((MaximumLength - sizeof(*Option)) < (ULONG)FIELD_OFFSET(BCDE_DEVICE, Device))
if ((MaximumLength - sizeof(*Option)) <
(ULONG)FIELD_OFFSET(BCD_DEVICE_OPTION, DeviceDescriptor))
{
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Fill it out */
DeviceEntry = (PBCDE_DEVICE)(Option + 1);
Status = EfiInitTranslateDevicePath(DevicePath, &DeviceEntry->Device);
BcdDevice = (PBCD_DEVICE_OPTION)(Option + 1);
Status = EfiInitTranslateDevicePath(DevicePath,
&BcdDevice->DeviceDescriptor);
if (!NT_SUCCESS(Status))
{
goto Quickie;
@ -551,8 +551,8 @@ EfiInitpConvertEfiDevicePath (
/* Fill out the rest of the option structure */
Option->DataOffset = sizeof(*Option);
Option->Type = DeviceType;
Option->DataSize = FIELD_OFFSET(BCDE_DEVICE, Device) +
DeviceEntry->Device.Size;
Option->DataSize = FIELD_OFFSET(BCD_DEVICE_OPTION, DeviceDescriptor) +
BcdDevice->DeviceDescriptor.Size;
Status = STATUS_SUCCESS;
Quickie:
@ -618,7 +618,7 @@ EfiInitpCreateApplicationEntry (
NTSTATUS Status;
UNICODE_STRING GuidString;
GUID ObjectGuid;
PBCDE_DEVICE BcdDevice;
PBCD_DEVICE_OPTION BcdDevice;
BOOLEAN HaveBinaryOptions, HaveGuid;
PBL_FILE_PATH_DESCRIPTOR OsPath;
EFI_DEVICE_PATH *OsDevicePath;
@ -719,7 +719,7 @@ EfiInitpCreateApplicationEntry (
/* Extract the device descriptor and return it */
BcdDevice = (PVOID)((ULONG_PTR)&Entry->BcdData + Entry->BcdData.DataOffset);
*AppEntryDevice = &BcdDevice->Device;
*AppEntryDevice = &BcdDevice->DeviceDescriptor;
/* Calculate how big this option was and consume that from the buffer */
TotalOptionSize = BlGetBootOptionSize(&Entry->BcdData);

View file

@ -137,17 +137,39 @@ typedef enum BcdOSLoaderElementTypes
BcdOSLoaderInteger_XSaveDisable = 0x2500012b
} BcdOSLoaderElementTypes;
typedef enum BcdBootMgrElementTypes
{
BcdBootMgrObjectList_DisplayOrder = 0x24000001,
BcdBootMgrObjectList_BootSequence = 0x24000002,
BcdBootMgrObject_DefaultObject = 0x23000003,
BcdBootMgrInteger_Timeout = 0x25000004,
BcdBootMgrBoolean_AttemptResume = 0x26000005,
BcdBootMgrObject_ResumeObject = 0x23000006,
BcdBootMgrObjectList_ToolsDisplayOrder = 0x24000010,
BcdBootMgrBoolean_DisplayBootMenu = 0x26000020,
BcdBootMgrBoolean_NoErrorDisplay = 0x26000021,
BcdBootMgrDevice_BcdDevice = 0x21000022,
BcdBootMgrString_BcdFilePath = 0x22000023,
BcdBootMgrBoolean_ProcessCustomActionsFirst = 0x26000028,
BcdBootMgrIntegerList_CustomActionsList = 0x27000030,
BcdBootMgrBoolean_PersistBootSequence = 0x26000031
} BcdBootMgrElementTypes;
/* DATA STRUCTURES ***********************************************************/
typedef struct _BCDE_DEVICE
typedef struct _BCD_DEVICE_OPTION
{
GUID AdditionalOptions;
BL_DEVICE_DESCRIPTOR Device;
} BCDE_DEVICE, *PBCDE_DEVICE;
GUID AssociatedEntry;
BL_DEVICE_DESCRIPTOR DeviceDescriptor;
} BCD_DEVICE_OPTION, *PBCD_DEVICE_OPTION;
typedef struct _BCDE_STRING
{
WCHAR String[ANYSIZE_ARRAY];
} BCDE_STRING, *PBCDE_STRING;
/* FUNCTIONS ******************************************************************/
NTSTATUS
BcdOpenStoreFromFile (
_In_ PUNICODE_STRING FileName,
_In_ PHANDLE StoreHandle
);
#endif

View file

@ -1,4 +1,4 @@
/*
/*b
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/include/bl.h
@ -30,6 +30,10 @@
#include <UgaDraw.h>
#include <BlockIo.h>
/* Registry Headers */
#define __FREELDR_H
#include <cmlib.h>
/* DEFINES *******************************************************************/
#define BL_APPLICATION_FLAG_CONVERTED_FROM_EFI 0x01
@ -85,6 +89,30 @@
#define BL_MEMORY_CLASS_SHIFT 28
#define BL_FILE_READ_ACCESS 0x01
#define BL_FILE_WRITE_ACCESS 0x02
#define BL_DIRECTORY_ACCESS 0x04
#define BL_UNKNOWN_ACCESS 0x10
#define BL_DEVICE_ENTRY_OPENED 0x01
#define BL_DEVICE_ENTRY_READ_ACCESS 0x02
#define BL_DEVICE_ENTRY_WRITE_ACCESS 0x04
#define BL_FILE_ENTRY_OPENED 0x01
#define BL_FILE_ENTRY_READ_ACCESS 0x02
#define BL_FILE_ENTRY_WRITE_ACCESS 0x04
#define BL_FILE_ENTRY_UNKNOWN_ACCESS 0x10
#define BL_IMG_VALID_FILE 0x01
#define BL_IMG_MEMORY_FILE 0x02
#define BL_IMG_REMOTE_FILE 0x04
#define BL_LOAD_IMG_VIRTUAL_BUFFER 0x01
#define BL_LOAD_IMG_EXISTING_BUFFER 0x04
#define BL_LOAD_IMG_UNKNOWN_BUFFER_FLAG 0x08
#define BL_LOAD_IMG_COMPUTE_SIGNATURE 0x10
#define BL_LOAD_IMG_COMPUTE_HASH 0x40000
/* ENUMERATIONS **************************************************************/
typedef enum _BL_COLOR
@ -169,6 +197,7 @@ typedef enum _BL_PARTITION_TYPE
//
typedef enum _BL_PATH_TYPE
{
InternalPath = 3,
EfiPath = 4
} BL_PATH_TYPE;
@ -266,6 +295,7 @@ typedef enum _BL_MEMORY_ATTR
/* CALLBACKS *****************************************************************/
struct _BL_FILE_ENTRY;
struct _BL_FILE_INFORMATION;
typedef
NTSTATUS
(*PBL_FILE_OPEN) (
@ -284,7 +314,10 @@ NTSTATUS
typedef
NTSTATUS
(*PBL_FILE_READ) (
VOID
_In_ struct _BL_FILE_ENTRY* FileEntry,
_In_ PVOID Buffer,
_In_ ULONG Size,
_Out_ PULONG BytesRead
);
typedef
@ -302,13 +335,15 @@ NTSTATUS
typedef
NTSTATUS
(*PBL_FILE_GET_INFO) (
VOID
_In_ struct _BL_FILE_ENTRY* FileEntry,
_Out_ struct _BL_FILE_INFORMATION* FileInfo
);
typedef
NTSTATUS
(*PBL_FILE_SET_INFO) (
VOID
_In_ struct _BL_FILE_ENTRY* FileEntry,
_In_ struct _BL_FILE_INFORMATION* FileInfo
);
typedef
@ -745,6 +780,12 @@ typedef struct _BL_ADDRESS_RANGE
ULONGLONG Maximum;
} BL_ADDRESS_RANGE, *PBL_ADDRESS_RANGE;
typedef struct _BL_FILE_INFORMATION
{
ULONGLONG FileSize;
ULONGLONG CurrentOffset;
} BL_FILE_INFORMATION, *PBL_FILE_INFORMATION;
typedef struct _BL_FILE_CALLBACKS
{
PBL_FILE_OPEN Open;
@ -767,7 +808,6 @@ typedef struct _BL_FILE_ENTRY
ULONGLONG Unknown1;
ULONGLONG Unknown2;
BL_FILE_CALLBACKS Callbacks;
//PBL_FILE_DESTROY_CALLBACK DestroyCallback;
PVOID FsSpecificData;
} BL_FILE_ENTRY, *PBL_FILE_ENTRY;
@ -966,6 +1006,18 @@ typedef struct _BL_DEVICE_ENTRY
PBL_DEVICE_DESCRIPTOR DeviceDescriptor;
} BL_DEVICE_ENTRY, *PBL_DEVICE_ENTRY;
typedef struct _BL_IMG_FILE
{
UCHAR Flags;
union
{
PVOID BaseAddress;
ULONG FileId;
};
ULONG FileSize;
PWCHAR FileName;
} BL_IMG_FILE, *PBL_IMG_FILE;
/* INLINE ROUTINES ***********************************************************/
FORCEINLINE
@ -1238,8 +1290,44 @@ EtfsMount (
_Out_ PBL_FILE_ENTRY* FileEntry
);
/* DEBUG ROUTINES ************************************************************/
BOOLEAN
BlBdDebuggerEnabled (
VOID
);
NTSTATUS
BlBdPullRemoteFile (
_In_ PWCHAR FilePath,
_Out_ PVOID BaseAddress,
_Out_ PULONGLONG FileSize
);
VOID
BlStatusPrint (
_In_ PCWCH Format,
...
);
VOID
BlStatusError (
_In_ ULONG ErrorCode,
_In_ ULONG Parameter1,
_In_ ULONG_PTR Parameter2,
_In_ ULONG_PTR Parameter3,
_In_ ULONG_PTR Parameter4
);
/* UTILITY ROUTINES **********************************************************/
VOID
BlUtlUpdateProgress (
_In_ ULONG Percentage,
_Out_opt_ PBOOLEAN Completed
);
EFI_STATUS
EfiGetEfiStatusCode(
_In_ NTSTATUS Status
@ -1265,6 +1353,11 @@ BlGetApplicationIdentifier (
VOID
);
PWCHAR
BlResourceFindMessage (
_In_ ULONG MsgId
);
/* TABLE ROUTINES ************************************************************/
NTSTATUS
@ -1353,6 +1446,14 @@ BlGetBootOptionBoolean (
_Out_ PBOOLEAN Value
);
NTSTATUS
BlGetBootOptionDevice (
_In_ PBL_BCD_OPTION List,
_In_ ULONG Type,
_Out_ PBL_DEVICE_DESCRIPTOR* Value,
_In_opt_ PBL_BCD_OPTION* ExtraOptions
);
/* CONTEXT ROUTINES **********************************************************/
VOID
@ -1423,6 +1524,20 @@ MmMdFreeDescriptor (
/* PAGE ALLOCATOR ROUTINES ***************************************************/
NTSTATUS
BlMmAllocatePhysicalPages(
_Inout_ PPHYSICAL_ADDRESS Address,
_In_ BL_MEMORY_TYPE MemoryType,
_In_ ULONGLONG PageCount,
_In_ ULONG Attributes,
_In_ ULONG Alignment
);
NTSTATUS
BlMmFreePhysicalPages (
_In_ PHYSICAL_ADDRESS Address
);
NTSTATUS
MmPapAllocatePagesInRange (
_Inout_ PVOID* PhysicalAddress,
@ -1450,6 +1565,12 @@ BlMmMapPhysicalAddressEx (
_In_ PHYSICAL_ADDRESS PhysicalAddress
);
NTSTATUS
BlMmUnmapVirtualAddressEx (
_In_ PVOID VirtualAddress,
_In_ ULONGLONG Size
);
/* BLOCK ALLOCATOR ROUTINES **************************************************/
NTSTATUS
@ -1525,11 +1646,27 @@ BlFileClose (
_In_ ULONG FileId
);
NTSTATUS
BlFileReadAtOffsetEx (
_In_ ULONG FileId,
_In_ ULONG Size,
_In_ ULONGLONG ByteOffset,
_In_ PVOID Buffer,
_Out_ PULONG BytesReturned,
_In_ ULONG Flags
);
NTSTATUS
BlFileGetInformation (
_In_ ULONG FileId,
_In_ PBL_FILE_INFORMATION FileInfo
);
NTSTATUS
BlFileOpen (
_In_ ULONG DeviceId,
_In_ PWCHAR FileName,
_In_ ULONG OpenFlags,
_In_ ULONG Flags,
_Out_ PULONG FileId
);
@ -1691,4 +1828,5 @@ extern BL_DISPLAY_MODE ConsoleGraphicalResolutionList[];
extern BL_DISPLAY_MODE ConsoleTextResolutionList[];
extern ULONG ConsoleGraphicalResolutionListSize;
extern PVOID DspRemoteInputConsole;
extern WCHAR BlScratchBuffer[8192];
#endif

View file

@ -31,7 +31,6 @@ BL_FILE_SYSTEM_REGISTRATION_TABLE EtfsRegisterFunctionTable =
NULL
};
extern ULONG DmTableEntries;
extern PVOID* DmDeviceTable;
@ -120,7 +119,9 @@ FileTableCompareWithSubsetAttributes (
Found = FALSE;
if ((FileEntry->DeviceId == DeviceId) && !(_wcsicmp(FileEntry->FilePath, FilePath)) && (FileEntry->Unknown == Unknown))
if ((FileEntry->DeviceId == DeviceId) &&
!(_wcsicmp(FileEntry->FilePath, FilePath)) &&
(FileEntry->Unknown == Unknown))
{
if ((!(Flags & 1) || (FileEntry->Flags & 2)) && (!(Flags & 2) || (FileEntry->Flags & 4)))
{
@ -151,7 +152,9 @@ FileTableCompareWithSameAttributes (
Found = FALSE;
if ((FileEntry->DeviceId == DeviceId) && !(_wcsicmp(FileEntry->FilePath, FilePath)) && (FileEntry->Unknown == Unknown))
if ((FileEntry->DeviceId == DeviceId) &&
!(_wcsicmp(FileEntry->FilePath, FilePath)) &&
(FileEntry->Unknown == Unknown))
{
if ((!(Flags & 1) || (FileEntry->Flags & 2)) && ((Flags & 1) || !(FileEntry->Flags & 2)) && (!(Flags & 2) || (FileEntry->Flags & 4)) && ((Flags & 2) || !(FileEntry->Flags & 4)))
{
@ -192,24 +195,25 @@ FileTableDestroyEntry (
return Status;
}
#define BL_FILE_PURGE_LIMIT 512
NTSTATUS
FileTablePurgeEntry (
_In_ PVOID Entry
)
{
PBL_FILE_ENTRY FileEntry = (PBL_FILE_ENTRY)Entry;
NTSTATUS Status;
if (((FileEntry->Flags & 1) || (FileEntry->Flags & 0x10000)) && (FileEntries < 0x200))
/* Don't purge opened files, or if there's less than 512 files cached */
if (((FileEntry->Flags & BL_FILE_ENTRY_OPENED) ||
(FileEntry->Flags & 0x10000)) &&
(FileEntries < BL_FILE_PURGE_LIMIT))
{
Status = STATUS_UNSUCCESSFUL;
}
else
{
Status = FileTableDestroyEntry(FileEntry, FileEntry->FileId);
return STATUS_UNSUCCESSFUL;
}
return Status;
/* Purge the entry othwrwise */
return FileTableDestroyEntry(FileEntry, FileEntry->FileId);
}
NTSTATUS
@ -219,28 +223,34 @@ BlFileClose (
{
PBL_FILE_ENTRY FileEntry;
/* Validate the file ID */
if (FileEntries <= FileId)
{
return STATUS_INVALID_PARAMETER;
}
/* Make sure a file entry actually exists */
FileEntry = FileTable[FileId];
if (!FileEntry)
{
return STATUS_INVALID_PARAMETER;
}
if (!(FileEntry->Flags & 1))
/* And that it's actually open */
if (!(FileEntry->Flags & BL_FILE_ENTRY_OPENED))
{
return STATUS_INVALID_PARAMETER;
}
/* Drop a reference, check if this was the last one */
--FileEntry->ReferenceCount;
if (!FileEntry->ReferenceCount)
{
FileEntry->Flags &= ~1;
/* File is no longer open */
FileEntry->Flags &= ~BL_FILE_ENTRY_OPENED;
}
/* All good */
return STATUS_SUCCESS;
}
@ -251,46 +261,58 @@ FileIoOpen (
_In_ ULONG Flags,
_In_ ULONG Unknown,
_In_ PBL_TBL_LOOKUP_ROUTINE CompareRoutine,
_Out_ PBL_FILE_ENTRY *ReturnFileEntry
_Out_opt_ PBL_FILE_ENTRY *NewFileEntry
)
{
PWCHAR FileNameCopy, ParentFileName;
NTSTATUS Status;
PBL_DEVICE_ENTRY DeviceEntry;
PBL_FILE_SYSTEM_ENTRY FileSystem;
ULONG FileId;
PBL_FILE_ENTRY ParentDirectoryEntry, FileEntry;
ULONG FileId, CheckFlags;
PBL_FILE_ENTRY DirectoryEntry, FileEntry;
PLIST_ENTRY NextEntry, ListHead;
ParentDirectoryEntry = NULL;
/* Preinitialize variables for failure */
DirectoryEntry = NULL;
FileNameCopy = NULL;
Flags |= 1;
ParentFileName = NULL;
Status = STATUS_SUCCESS;
/* Bail out if the device ID is invalid */
if (DmTableEntries <= DeviceId)
{
return STATUS_ACCESS_DENIED;
}
/* Bail out if there's no device entry */
DeviceEntry = DmDeviceTable[DeviceId];
if (!DeviceEntry)
{
return STATUS_ACCESS_DENIED;
}
if ((Flags & 1) && (!(DeviceEntry->Flags & 1) || !(DeviceEntry->Flags & 2)))
/* Read access is always required for touching the device */
CheckFlags = Flags | BL_FILE_READ_ACCESS;
/* Check if the device is granting us read access */
if ((CheckFlags & BL_FILE_READ_ACCESS) &&
(!(DeviceEntry->Flags & BL_DEVICE_ENTRY_OPENED) ||
!(DeviceEntry->Flags & BL_DEVICE_ENTRY_READ_ACCESS)))
{
EfiPrintf(L"Access denied\r\n");
return STATUS_ACCESS_DENIED;
}
if ((Flags & 2) && (!(DeviceEntry->Flags & 1) || !(DeviceEntry->Flags & 4)))
/* Check if the device is granting us write access */
if ((CheckFlags & BL_FILE_WRITE_ACCESS) &&
(!(DeviceEntry->Flags & BL_DEVICE_ENTRY_OPENED) ||
!(DeviceEntry->Flags & BL_DEVICE_ENTRY_WRITE_ACCESS)))
{
EfiPrintf(L"Access denied2\r\n");
return STATUS_ACCESS_DENIED;
}
/* Check if we already have this file open */
FileEntry = (PBL_FILE_ENTRY )BlTblFindEntry(FileTable,
FileEntries,
&FileId,
@ -305,80 +327,89 @@ FileIoOpen (
goto FileOpened;
}
/* Check if we are opening the root drive or an actual file/directory */
if ((*FileName != OBJ_NAME_PATH_SEPARATOR) || (FileName[1]))
{
/* Get the name of the directory */
ParentFileName = FileIoCopyParentDirectoryPath(FileName);
if (!ParentFileName)
{
Status = STATUS_NO_MEMORY;
goto FileOpenEnd;
goto Quickie;
}
/* Open it */
Status = FileIoOpen(DeviceId,
ParentFileName,
5,
BL_FILE_READ_ACCESS | BL_DIRECTORY_ACCESS,
Unknown,
FileTableCompareWithSubsetAttributes,
&ParentDirectoryEntry);
if (Status < 0)
&DirectoryEntry);
if (NT_SUCCESS(Status))
{
goto FileOpenEnd;
goto Quickie;
}
/* Now get the the file name itself */
FileNameCopy = FileIoCopyFileName(FileName);
if (!FileNameCopy)
{
Status = STATUS_NO_MEMORY;
goto FileOpenEnd;
goto Quickie;
}
Status = ParentDirectoryEntry->Callbacks.Open(ParentDirectoryEntry,
FileNameCopy,
Flags,
&FileEntry);
/* Open it */
Status = DirectoryEntry->Callbacks.Open(DirectoryEntry,
FileNameCopy,
Flags,
&FileEntry);
}
else
{
EfiPrintf(L"Opening root drive\r\n");
/* We're opening the root, scan through all the file systems */
Status = STATUS_UNSUCCESSFUL;
ListHead = &RegisteredFileSystems;
NextEntry = ListHead->Flink;
while (NextEntry != ListHead)
{
/* Try to mount this one */
FileSystem = CONTAINING_RECORD(NextEntry, BL_FILE_SYSTEM_ENTRY, ListEntry);
EfiPrintf(L"Calling filesystem %p mount routine: %p\r\n", FileSystem, FileSystem->MountCallback);
Status = FileSystem->MountCallback(DeviceId, Unknown, &FileEntry);
if (NT_SUCCESS(Status))
{
/* Mount successful */
break;
}
/* Try the next file system */
NextEntry = NextEntry->Flink;
}
/* Nothing to free on this path */
FileNameCopy = NULL;
}
/* Handle failure */
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"Could not open file!: %lx\r\n", Status);
goto FileOpenEnd;
goto Quickie;
}
/* Save the unknown */
FileEntry->Unknown = Unknown;
if (Flags & 1)
/* Convert open flags into entry flags */
if (Flags & BL_FILE_READ_ACCESS)
{
FileEntry->Flags |= 2u;
FileEntry->Flags |= BL_FILE_ENTRY_READ_ACCESS;
}
if (Flags & 2)
if (Flags & BL_FILE_WRITE_ACCESS)
{
FileEntry->Flags |= 4u;
FileEntry->Flags |= BL_FILE_ENTRY_WRITE_ACCESS;
}
/* Save the file into the file table */
Status = BlTblSetEntry(&FileTable,
&FileEntries,
(PVOID)FileEntry,
@ -386,48 +417,62 @@ FileIoOpen (
FileTablePurgeEntry);
if (!NT_SUCCESS(Status))
{
/* Close it if that failed */
FileEntry->Callbacks.Close(FileEntry);
goto FileOpenEnd;
goto Quickie;
}
/* Add a reference on the device, and save our file ID */
++DeviceEntry->ReferenceCount;
Status = STATUS_SUCCESS;
EfiPrintf(L"File %s opened with ID: %lx\r\n", FileEntry->FilePath, FileId);
FileEntry->FileId = FileId;
EfiPrintf(L"File %s opened with ID: %lx\r\n", FileEntry->FilePath, FileId);
FileOpened:
/* Add a reference to the file entry, and see if this is the first one */
if (++FileEntry->ReferenceCount == 1)
{
/* Reset unknowns */
FileEntry->Unknown1 = 0;
FileEntry->Unknown2 = 0;
}
FileEntry->Flags |= 1;
if (Flags & 0x10)
/* Set the file as opened */
FileEntry->Flags |= BL_FILE_ENTRY_OPENED;
/* Not sure what this flag does */
if (Flags & BL_UNKNOWN_ACCESS)
{
FileEntry->Flags |= 0x10;
FileEntry->Flags |= BL_FILE_ENTRY_UNKNOWN_ACCESS;
}
if (ReturnFileEntry)
/* If the caller wanted the entry back, return it */
if (NewFileEntry)
{
*ReturnFileEntry = FileEntry;
*NewFileEntry = FileEntry;
}
FileOpenEnd:
if (ParentDirectoryEntry)
Quickie:
/* Close the parent */
if (DirectoryEntry)
{
BlFileClose(ParentDirectoryEntry->FileId);
BlFileClose(DirectoryEntry->FileId);
}
/* Free the parent name copy */
if (ParentFileName)
{
BlMmFreeHeap(ParentFileName);
}
/* Free the file name copy */
if (FileNameCopy)
{
BlMmFreeHeap(FileNameCopy);
}
/* Return back to caller */
return Status;
}
@ -443,15 +488,17 @@ BlFileOpen (
PBL_FILE_ENTRY FileEntry;
BL_DEVICE_INFORMATION DeviceInformation;
/* Make sure we have a valid file name, access flags and parameters */
if (!(FileName) ||
(*FileName != OBJ_NAME_PATH_SEPARATOR) ||
!(FileId) ||
!(Flags & 3))
!(Flags & (BL_FILE_READ_ACCESS | BL_FILE_WRITE_ACCESS)))
{
EfiPrintf(L"Invalid file options\r\n");
return STATUS_INVALID_PARAMETER;
}
/* Get information on the underlying device */
Status = BlDeviceGetInformation(DeviceId, &DeviceInformation);
if (!NT_SUCCESS(Status))
{
@ -459,6 +506,7 @@ BlFileOpen (
return Status;
}
/* Make sure it's a device that can host files */
if ((DeviceInformation.DeviceType != DiskDevice) &&
(DeviceInformation.DeviceType != LegacyPartitionDevice) &&
(DeviceInformation.DeviceType != UdpDevice))
@ -467,6 +515,7 @@ BlFileOpen (
return STATUS_INVALID_PARAMETER;
}
/* Open a file on this device, creating one if needed */
Status = FileIoOpen(DeviceId,
FileName,
Flags,
@ -475,10 +524,339 @@ BlFileOpen (
&FileEntry);
if (NT_SUCCESS(Status))
{
/* Return the file ID back to the caller */
EfiPrintf(L"File opened: %lx\r\n", FileEntry->FileId);
*FileId = FileEntry->FileId;
}
/* All good */
return Status;
}
NTSTATUS
BlFileSetInformation (
_In_ ULONG FileId,
_Out_ PBL_FILE_INFORMATION FileInfo
)
{
PBL_FILE_ENTRY FileEntry;
/* Make sure caller passed this in */
if (!FileInfo)
{
return STATUS_INVALID_PARAMETER;
}
/* Validate file ID */
if (FileEntries > FileId)
{
return STATUS_INVALID_PARAMETER;
}
/* Make sure an opened file exits with this ID */
FileEntry = FileTable[FileId];
if (!(FileEntry) || !(FileEntry->Flags & BL_FILE_ENTRY_OPENED))
{
return STATUS_INVALID_PARAMETER;
}
/* Do the I/O operation */
return FileEntry->Callbacks.SetInfo(FileEntry, FileInfo);
}
NTSTATUS
BlFileGetInformation (
_In_ ULONG FileId,
_In_ PBL_FILE_INFORMATION FileInfo
)
{
PBL_FILE_ENTRY FileEntry;
/* Make sure caller passed this in */
if (!FileInfo)
{
return STATUS_INVALID_PARAMETER;
}
/* Validate file ID */
if (FileEntries > FileId)
{
return STATUS_INVALID_PARAMETER;
}
/* Make sure an opened file exits with this ID */
FileEntry = FileTable[FileId];
if (!(FileEntry) || !(FileEntry->Flags & BL_FILE_ENTRY_OPENED))
{
return STATUS_INVALID_PARAMETER;
}
/* Do the I/O operation */
return FileEntry->Callbacks.GetInfo(FileEntry, FileInfo);
}
NTSTATUS
FileInformationCheck (
_In_ PBL_FILE_INFORMATION FileInformation,
_In_ BOOLEAN Write,
_In_opt_ PULONG InputSize,
_In_opt_ PULONG BytesReturned,
_Out_opt_ PULONG RequiredSize
)
{
NTSTATUS Status;
ULONG Size;
/* Initialize variables */
Status = STATUS_SUCCESS;
Size = 0;
/* Make sure we didn't overshoot */
if (FileInformation->CurrentOffset > FileInformation->FileSize)
{
/* Bail out */
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Compute the appropriate 32-bit size of this read, based on file size */
Size = ULONG_MAX;
if ((FileInformation->FileSize - FileInformation->CurrentOffset) <= ULONG_MAX)
{
Size = (ULONG)(FileInformation->FileSize) - (ULONG)(FileInformation->CurrentOffset);
}
/* Check if the caller has an input buffer */
if (InputSize)
{
/* Is the size bigger than what the caller can handle? */
if (Size >= *InputSize)
{
/* Yes, so cap it at the size of the caller's buffer */
Size = *InputSize;
}
else if (!(BytesReturned) || (Write))
{
/* Caller's input buffer is too smaller is fatal for writes */
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
}
Quickie:
/* Does the caller want to know how big to make their buffer? */
if (RequiredSize)
{
/* Let them know*/
*RequiredSize = Size;
}
/* Return final status */
return Status;
}
NTSTATUS
BlFileReadEx (
_In_ ULONG FileId,
_Out_ PVOID Buffer,
_In_ ULONG Size,
_Out_ PULONG BytesReturned,
_In_ ULONG Flags
)
{
PBL_FILE_ENTRY FileEntry;
NTSTATUS Status;
ULONG OldUnknown, RequiredSize;
BOOLEAN ChangedUnknown;
BL_DEVICE_INFORMATION DeviceInfo;
BL_FILE_INFORMATION fileInfo;
/* Initialize variables */
RtlZeroMemory(&DeviceInfo, sizeof(DeviceInfo));
OldUnknown = 0;
ChangedUnknown = FALSE;
/* Bail out if there's no buffer */
if (!Buffer)
{
return STATUS_INVALID_PARAMETER;
}
/* Bail out of the file ID is invalid */
if (FileEntries > FileId)
{
return STATUS_INVALID_PARAMETER;
}
/* Bail out if there's no file opened for read access */
FileEntry = FileTable[FileId];
if (!(FileEntry) ||
!(FileEntry->Flags & (BL_FILE_ENTRY_OPENED | BL_FILE_ENTRY_READ_ACCESS)))
{
return STATUS_INVALID_PARAMETER;
}
/* Bail out if we can't read the file's information */
Status = BlFileGetInformation(FileId, &fileInfo);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Ensure the read attempt is valid, and fix up the size if needed */
RequiredSize = Size;
Status = FileInformationCheck(&fileInfo,
FALSE,
&RequiredSize,
BytesReturned,
&RequiredSize);
if (!NT_SUCCESS(Status))
{
/* Invalid or illegal read attempt */
return Status;
}
/* Is there anything left to read after all? */
if (RequiredSize)
{
/* Check if flags 2 or 4 are set */
if ((Flags & 2) || (Flags & 4))
{
/* Check if this is a disk or partition device */
BlDeviceGetInformation(FileEntry->DeviceId, &DeviceInfo);
if ((DeviceInfo.DeviceType == DiskDevice) ||
(DeviceInfo.DeviceType == LegacyPartitionDevice))
{
/* Check if request flags are incompatible with device flags */
if ((!(DeviceInfo.BlockDeviceInfo.Unknown & 1) && (Flags & 2)) ||
(!(DeviceInfo.BlockDeviceInfo.Unknown & 2) && (Flags & 4)))
{
/* We're going to change the device flags */
ChangedUnknown = TRUE;
/* Set unknown flag 1 for request flag 2 */
if (Flags & 2)
{
DeviceInfo.BlockDeviceInfo.Unknown |= 1;
}
/* Set unknown flag 2 for request flag 4 */
if (Flags & 4)
{
DeviceInfo.BlockDeviceInfo.Unknown |= 2;
}
/* Save the new device flags */
BlDeviceSetInformation(FileEntry->DeviceId, &DeviceInfo);
}
}
}
/* Issue the read to the underlying file system */
Status = FileEntry->Callbacks.Read(FileEntry,
Buffer,
RequiredSize,
BytesReturned);
if (!NT_SUCCESS(Status))
{
/* Don't update the bytes read on failure */
RequiredSize = 0;
}
}
else
{
/* There's nothing to do, return success and 0 bytes */
Status = STATUS_SUCCESS;
if (BytesReturned)
{
*BytesReturned = 0;
}
}
/* Increment the number of bytes read */
FileEntry->Unknown1 += RequiredSize;
/* Check if the unknown flag on the device was changed during this routine */
if (ChangedUnknown)
{
/* Reset it back to its original value */
DeviceInfo.BlockDeviceInfo.Unknown = OldUnknown;
BlDeviceSetInformation(FileEntry->DeviceId, &DeviceInfo);
}
/* Return the final status */
return Status;
}
NTSTATUS
BlFileReadAtOffsetEx (
_In_ ULONG FileId,
_In_ ULONG Size,
_In_ ULONGLONG ByteOffset,
_In_ PVOID Buffer,
_Out_ PULONG BytesReturned,
_In_ ULONG Flags
)
{
NTSTATUS Status;
BL_FILE_INFORMATION FileInfo;
ULONG RequiredSize;
ULONGLONG FileOffset;
/* Get information on the specified file */
Status = BlFileGetInformation(FileId, &FileInfo);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Save the current offset, and overwrite it with the one we want */
FileOffset = FileInfo.CurrentOffset;
FileInfo.CurrentOffset = ByteOffset;
/* Check the validity of the read and the actual size to read */
RequiredSize = Size;
Status = FileInformationCheck(&FileInfo,
FALSE,
&RequiredSize,
BytesReturned,
&RequiredSize);
if (!NT_SUCCESS(Status))
{
/* Bail out if the read is invalid */
return Status;
}
/* Check if the offset we're requesting is not the current offset */
if (FileInfo.CurrentOffset != FileOffset)
{
/* Set the new offset to use */
Status = BlFileSetInformation(FileId, &FileInfo);
if (!NT_SUCCESS(Status))
{
/* Can't do much if that failed */
return Status;
}
}
/* Do the read at the required offset now */
Status = BlFileReadEx(FileId,
Buffer,
RequiredSize,
BytesReturned,
Flags);
if (!NT_SUCCESS(Status))
{
/* The read failed -- had we modified the offset? */
if (FileInfo.CurrentOffset != FileOffset)
{
/* Restore the offset back to its original value */
FileInfo.CurrentOffset = FileOffset;
BlFileSetInformation(FileId, &FileInfo);
}
}
/* Return the status of the read */
return Status;
}

View file

@ -61,6 +61,86 @@ MiscGetBootOption (
return Option;
}
/*++
* @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 != 0);
/* 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 != 0)
{
/* 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 != 0)
{
/* Go get those too */
Size += BlGetBootOptionListSize((PVOID)((ULONG_PTR)BcdOption + Offset));
}
/* Return the final size */
return Size;
}
NTSTATUS
BlGetBootOptionString (
_In_ PBL_BCD_OPTION List,
@ -161,6 +241,151 @@ BlGetBootOptionString (
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;
/* Make sure this is a BCD_DEVICE */
if ((Type & 0xF000000) != 0x1000000)
{
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 */
Status = STATUS_SUCCESS;
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,
@ -231,80 +456,342 @@ BlGetBootOptionBoolean (
return Status;
}
/*++
* @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
#define BI_FLUSH_HIVE 0x01
typedef struct _BI_KEY_HIVE
{
PVOID ImageBase;
PBL_FILE_PATH_DESCRIPTOR FilePath;
CMHIVE Hive;
LONG ReferenceCount;
ULONG Flags;
} 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;
PVOID
NTAPI
CmpAllocate (
_In_ SIZE_T Size,
_In_ BOOLEAN Paged,
_In_ ULONG Tag
)
{
ULONG Size = 0, NextOffset = 0;
PBL_BCD_OPTION NextOption;
UNREFERENCED_PARAMETER(Paged);
UNREFERENCED_PARAMETER(Tag);
/* 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 != 0);
/* Return final computed size */
return Size;
/* Call the heap allocator */
return BlMmAllocateHeap(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
VOID
NTAPI
CmpFree (
_In_ PVOID Ptr,
_In_ ULONG Quota
)
{
ULONG Size, Offset;
UNREFERENCED_PARAMETER(Quota);
/* Check if there's any data */
if (BcdOption->DataOffset != 0)
/* Call the heap allocator */
BlMmFreeHeap(Ptr);
}
FORCEINLINE
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))
{
/* Add the size of the data */
Size = BcdOption->DataOffset + BcdOption->DataSize;
/* 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->ImageBase, 1);
EfiPrintf(L"Leaking hive memory\r\n");
/* 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)Hive->GetCellRoutine(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
BiLoadHive (
_In_ PBL_FILE_PATH_DESCRIPTOR FilePath,
_Out_ PHANDLE HiveHandle
)
{
/* This is TODO */
EfiPrintf(L"Loading a hive is not yet implemented\r\n");
*HiveHandle = NULL;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
BiAddStoreFromFile (
_In_ PBL_FILE_PATH_DESCRIPTOR FilePath,
_Out_ PHANDLE StoreHandle
)
{
NTSTATUS Status;
HANDLE HiveHandle, KeyHandle;
/* Load the specified hive */
Status = BiLoadHive(FilePath, &HiveHandle);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Open the description key to make sure this is really a BCD */
Status = BiOpenKey(HiveHandle, L"Description", &KeyHandle);
if (NT_SUCCESS(Status))
{
/* It is -- close the key as we don't need it */
BiCloseKey(KeyHandle);
*StoreHandle = HiveHandle;
}
else
{
/* No data, just the structure itself */
Size = sizeof(*BcdOption);
/* Failure, drop a reference on the hive and close the key */
BiDereferenceHive(HiveHandle);
BiCloseKey(HiveHandle);
}
/* Any associated options? */
Offset = BcdOption->ListOffset;
if (Offset != 0)
{
/* Go get those too */
Size += BlGetBootOptionListSize((PVOID)((ULONG_PTR)BcdOption + Offset));
}
/* Return the final size */
return Size;
/* Return the status */
return Status;
}
NTSTATUS
BcdOpenStoreFromFile (
_In_ PUNICODE_STRING FileName,
_In_ PHANDLE StoreHandle
)
{
ULONG Length;
PBL_FILE_PATH_DESCRIPTOR FilePath;
NTSTATUS Status;
HANDLE LocalHandle;
/* Assume failure */
LocalHandle = NULL;
/* Allocate a path descriptor */
Length = FileName->Length + sizeof(*FilePath);
FilePath = BlMmAllocateHeap(Length);
if (!FilePath)
{
return STATUS_NO_MEMORY;
}
/* Initialize it */
FilePath->Version = 1;
FilePath->PathType = InternalPath;
FilePath->Length = Length;
/* Copy the name and NULL-terminate it */
RtlCopyMemory(FilePath->Path, FileName->Buffer, Length);
FilePath->Path[Length / sizeof(WCHAR)] = UNICODE_NULL;
/* Open the BCD */
Status = BiAddStoreFromFile(FilePath, &LocalHandle);
if (NT_SUCCESS(Status))
{
/* Return the handle on success */
*StoreHandle = LocalHandle;
}
/* Free the descriptor and return the status */
BlMmFreeHeap(FilePath);
return Status;
}

View file

@ -0,0 +1,137 @@
/*
* 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())
{
/* Print the string out into a buffer */
if (vswprintf(BlScratchBuffer, Format, va) > 0)
{
/* Make it a UNICODE_STRING */
RtlInitUnicodeString(&UnicodeString, BlScratchBuffer);
/* Then convert it into an ANSI_STRING */
AnsiString.Length = 0;
AnsiString.MaximumLength = sizeof(AnsiBuffer);
AnsiString.Buffer = AnsiBuffer;
Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
if (NT_SUCCESS(Status))
{
/* Print it out to the debugger if that worked */
DbgPrint(AnsiString.Buffer);
}
}
}
va_end(va);
}
VOID
BlStatusError (
_In_ ULONG ErrorCode,
_In_ ULONG Parameter1,
_In_ ULONG_PTR Parameter2,
_In_ ULONG_PTR Parameter3,
_In_ ULONG_PTR Parameter4
)
{
/* Check if the boot debugger is enabled */
if (BlBdDebuggerEnabled())
{
/* Print out the fatal error */
BlStatusPrint(L"\n"
L"*** Fatal Error 0x%08x :\n"
L" (0x%p, 0x%p, 0x%p, 0x%p)\n"
L"\n",
ErrorCode,
Parameter1,
Parameter2,
Parameter3,
Parameter4);
/* Issue a breakpoint */
__debugbreak();
}
}

View file

@ -0,0 +1,551 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/misc/image.c
* PURPOSE: Boot Library Image Routines
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* FUNCTIONS *****************************************************************/
NTSTATUS
ImgpGetFileSize (
_In_ PBL_IMG_FILE File,
_Out_ PULONG FileSize
)
{
NTSTATUS Status;
ULONG Size;
BL_FILE_INFORMATION FileInformation;
/* Check if the file was memory mapped */
if (File->Flags & BL_IMG_MEMORY_FILE)
{
/* Just read the size of the mapping */
Size = File->FileSize;
}
else
{
/* Do file I/O to get the file size */
Status = BlFileGetInformation(File->FileId,
&FileInformation);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* We only support files less than 4GB in the Image Mapped */
Size = FileInformation.FileSize;
if (FileInformation.FileSize > ULONG_MAX)
{
return STATUS_NOT_SUPPORTED;
}
}
/* Return the size and success */
*FileSize = Size;
return STATUS_SUCCESS;
}
NTSTATUS
ImgpReadAtFileOffset (
_In_ PBL_IMG_FILE File,
_In_ ULONG Size,
_In_ ULONGLONG ByteOffset,
_In_ PVOID Buffer,
_Out_ PULONG BytesReturned
)
{
NTSTATUS Status;
/* Check what if this is a mapped file or not */
if (File->Flags & BL_IMG_MEMORY_FILE)
{
/* Check if the boundaries are within the file size */
if ((ByteOffset + Size) <= File->FileSize)
{
/* Yep, copy into the caller-supplied buffer */
RtlCopyMemory(Buffer,
(PVOID)((ULONG_PTR)File->BaseAddress + (ULONG_PTR)ByteOffset),
Size);
/* If caller wanted to know, return the size copied */
if (BytesReturned)
{
*BytesReturned = Size;
}
/* All good */
Status = STATUS_SUCCESS;
}
else
{
/* Doesn't fit */
Status = STATUS_INVALID_PARAMETER;
}
}
else
{
/* Issue the file I/O instead */
Status = BlFileReadAtOffsetEx(File->FileId,
Size,
ByteOffset,
Buffer,
BytesReturned,
0);
}
/* Return the final status */
return Status;
}
NTSTATUS
ImgpOpenFile (
_In_ ULONG DeviceId,
_In_ PWCHAR FileName,
_In_ ULONG Flags,
_Out_ PBL_IMG_FILE NewFile
)
{
NTSTATUS Status;
ULONG FileSize;
ULONGLONG RemoteFileSize;
PVOID RemoteFileAddress;
ULONG FileId;
/* First, try to see if BD has this file remotely */
Status = BlBdPullRemoteFile(FileName,
&RemoteFileAddress,
&RemoteFileSize);
if (NT_SUCCESS(Status))
{
/* Yep, get the file size and make sure it's < 4GB */
FileSize = RemoteFileSize;
if (RemoteFileSize <= ULONG_MAX)
{
/* Remember this is a memory mapped remote file */
NewFile->Flags |= (BL_IMG_MEMORY_FILE | BL_IMG_REMOTE_FILE);
NewFile->FileSize = FileSize;
NewFile->BaseAddress = RemoteFileAddress;
goto Quickie;
}
}
/* Use File I/O instead */
Status = BlFileOpen(DeviceId,
FileName,
BL_FILE_READ_ACCESS,
&FileId);
if (!NT_SUCCESS(Status))
{
/* Bail out on failure */
return Status;
}
/* Make sure nobody thinks this is a memory file */
NewFile->Flags &= ~BL_IMG_MEMORY_FILE;
NewFile->FileId = FileId;
Quickie:
/* Set common data for both memory and I/O based file */
NewFile->Flags |= BL_IMG_VALID_FILE;
NewFile->FileName = FileName;
return Status;
}
NTSTATUS
ImgpCloseFile (
_In_ PBL_IMG_FILE File
)
{
NTSTATUS Status;
/* Make sure this is a valid file, otherwise no-op */
Status = STATUS_SUCCESS;
if (File->Flags & BL_IMG_VALID_FILE)
{
/* Is this a memory mapped file? */
if (!(File->Flags & BL_IMG_MEMORY_FILE))
{
/* Nope, close the file handle */
return BlFileClose(File->FileId);
}
/* Is this a remote file? */
if (File->Flags & BL_IMG_REMOTE_FILE)
{
/* Then only free the memory in that scenario */
EfiPrintf(L"TODO\r\n");
//return MmPapFreePages(File->BaseAddress, TRUE);
}
}
/* Return the final status */
return Status;
}
NTSTATUS
BlImgAllocateImageBuffer (
_Inout_ PVOID* ImageBuffer,
_In_ ULONG MemoryType,
_In_ ULONGLONG ImageSize,
_In_ ULONG Flags
)
{
ULONG Attributes;
ULONGLONG Pages, Size;
PVOID MappedBase, CurrentBuffer;
NTSTATUS Status;
PHYSICAL_ADDRESS PhysicalAddress;
/* Read and reset the current buffer address */
CurrentBuffer = *ImageBuffer;
*ImageBuffer = NULL;
/* Align the image size to page */
Size = ROUND_TO_PAGES(ImageSize);
/* Not sure what this attribute does yet */
Attributes = 0;
if (Flags & BL_LOAD_IMG_UNKNOWN_BUFFER_FLAG)
{
Attributes = 0x10000;
}
/* Check if the caller wants a virtual buffer */
if (Flags & BL_LOAD_IMG_VIRTUAL_BUFFER)
{
/* Set the physical address to the current buffer */
PhysicalAddress.QuadPart = (ULONG_PTR)CurrentBuffer;
Pages = Size >> PAGE_SHIFT;
/* Allocate the physical pages */
Status = BlMmAllocatePhysicalPages(&PhysicalAddress,
Pages,
MemoryType,
Attributes,
0);
if (!NT_SUCCESS(Status))
{
/* If that failed, remove allocation attributes */
PhysicalAddress.QuadPart = 0;
Attributes &= ~BlMemoryValidAllocationAttributeMask,
Status = BlMmAllocatePhysicalPages(&PhysicalAddress,
Pages,
MemoryType,
Attributes,
0);
}
/* Check if either attempts succeeded */
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Now map the physical buffer at the address requested */
MappedBase = (PVOID)PhysicalAddress.LowPart;
Status = BlMmMapPhysicalAddressEx(&MappedBase,
BlMemoryFixed,
Size,
PhysicalAddress);
if (!NT_SUCCESS(Status))
{
/* Free on failure if needed */
BlMmFreePhysicalPages(PhysicalAddress);
return Status;
}
}
else
{
/* Otherwise, allocate raw physical pages */
MappedBase = CurrentBuffer;
Pages = Size >> PAGE_SHIFT;
Status = MmPapAllocatePagesInRange(&MappedBase,
MemoryType,
Pages,
Attributes,
0,
NULL,
0);
if (!NT_SUCCESS(Status))
{
/* If that failed, try without allocation attributes */
MappedBase = NULL;
Attributes &= ~BlMemoryValidAllocationAttributeMask,
Status = MmPapAllocatePagesInRange(&MappedBase,
MemoryType,
Pages,
Attributes,
0,
NULL,
0);
}
/* Check if either attempts succeeded */
if (!NT_SUCCESS(Status))
{
return Status;
}
}
/* Success path, returned allocated address */
*ImageBuffer = MappedBase;
return STATUS_SUCCESS;
}
NTSTATUS
BlImgLoadImageWithProgress2 (
_In_ ULONG DeviceId,
_In_ BL_MEMORY_TYPE MemoryType,
_In_ PWCHAR FileName,
_Inout_ PVOID* MappedBase,
_Inout_ PULONG MappedSize,
_In_ ULONG ImageFlags,
_In_ BOOLEAN ShowProgress,
_Out_opt_ PUCHAR* HashBuffer,
_Out_opt_ PULONG HashSize
)
{
NTSTATUS Status;
PVOID BaseAddress, Buffer;
ULONG RemainingLength, CurrentSize, ImageSize, ReadSize;
BOOLEAN ComputeSignature, ComputeHash, Completed;
BL_IMG_FILE FileHandle;
ULONGLONG ByteOffset;
PHYSICAL_ADDRESS PhysicalAddress;
/* Initialize variables */
BaseAddress = 0;
ImageSize = 0;
Completed = FALSE;
RtlZeroMemory(&FileHandle, sizeof(FileHandle));
/* Check for missing parameters */
if (!MappedBase)
{
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
if (!FileName)
{
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
if (!MappedSize)
{
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Check if the image buffer is being provided */
if (ImageFlags & BL_LOAD_IMG_EXISTING_BUFFER)
{
/* An existing base must already exist */
if (!(*MappedBase))
{
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
}
/* Check of a hash is being requested */
if (ImageFlags & BL_LOAD_IMG_COMPUTE_HASH)
{
/* Make sure we can return the hash */
if (!HashBuffer)
{
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
if (!HashSize)
{
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
}
/* Check for invalid combination of parameters */
if ((ImageFlags & BL_LOAD_IMG_COMPUTE_HASH) && (ImageFlags & 0x270))
{
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Initialize hash if requested by caller */
if (HashBuffer)
{
*HashBuffer = 0;
}
/* Do the same for the hash size */
if (HashSize)
{
*HashSize = 0;
}
/* Open the image file */
Status = ImgpOpenFile(DeviceId, FileName, DeviceId, &FileHandle);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Get the size of the image */
Status = ImgpGetFileSize(&FileHandle, &ImageSize);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Read the current base address */
BaseAddress = *MappedBase;
if (ImageFlags & BL_LOAD_IMG_EXISTING_BUFFER)
{
/* Check if the current buffer is too small */
if (*MappedSize < ImageSize)
{
/* Return the required size of the buffer */
*MappedSize = ImageSize;
Status = STATUS_BUFFER_TOO_SMALL;
}
}
else
{
/* A buffer was not provided, allocate one ourselves */
Status = BlImgAllocateImageBuffer(&BaseAddress,
MemoryType,
ImageSize,
ImageFlags);
}
/* Bail out if allocation failed */
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Set the initial byte offset and length to read */
RemainingLength = ImageSize;
ByteOffset = 0;
Buffer = BaseAddress;
/* Update the initial progress */
Completed = FALSE;
if (ShowProgress)
{
BlUtlUpdateProgress(0, &Completed);
ShowProgress &= (Completed != 0) - 1;
}
/* Set the chunk size for each read */
ReadSize = 0x100000;
if (ReadSize > ImageSize)
{
ReadSize = ImageSize;
}
/* Check if we should compute hash and/or signatures */
ComputeSignature = ImageFlags & BL_LOAD_IMG_COMPUTE_SIGNATURE;
if ((ComputeSignature) || (ImageFlags & BL_LOAD_IMG_COMPUTE_HASH))
{
ComputeHash = TRUE;
// todo: crypto is hard
}
/* Begin the read loop */
while (RemainingLength)
{
/* Check if we've got more than a chunk left to read */
if (RemainingLength > ReadSize)
{
/* Read a chunk*/
CurrentSize = ReadSize;
}
else
{
/* Read only what's left */
CurrentSize = RemainingLength;
}
/* Read the chunk */
Status = ImgpReadAtFileOffset(&FileHandle,
CurrentSize,
ByteOffset,
Buffer,
0);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Check if we need to compute the hash of this chunk */
if (ComputeHash)
{
// todo: crypto is hard
}
/* Update our position and read information */
Buffer = (PVOID)((ULONG_PTR)Buffer + CurrentSize);
RemainingLength -= CurrentSize;
ByteOffset += CurrentSize;
/* Check if we should update the progress bar */
if (ShowProgress)
{
/* Compute new percentage completed, check if we're done */
BlUtlUpdateProgress(100 - 100 * RemainingLength / ImageSize,
&Completed);
ShowProgress &= (Completed != 0) - 1;
}
}
/* Is the read fully complete? We need to finalize the hash if requested */
if (ComputeHash != RemainingLength)
{
// todo: CRYPTO IS HARD
}
/* Success path, return back the buffer and the size of the image */
*MappedBase = BaseAddress;
*MappedSize = ImageSize;
Quickie:
/* Close the file handle */
ImgpCloseFile(&FileHandle);
/* Check if we failed and had allocated a buffer */
if (!(NT_SUCCESS(Status)) &&
(BaseAddress) &&
!(ImageFlags & BL_LOAD_IMG_EXISTING_BUFFER))
{
/* Check what kind of buffer we had allocated */
if (ImageFlags & BL_LOAD_IMG_VIRTUAL_BUFFER)
{
/* Unmap and free the virtual buffer */
PhysicalAddress.QuadPart = (ULONG_PTR)BaseAddress;
BlMmUnmapVirtualAddressEx(BaseAddress, ImageSize);
BlMmFreePhysicalPages(PhysicalAddress);
}
else
{
/* Free the physical buffer */
//MmPapFreePages(VirtualAddress, 1);
EfiPrintf(L"Leaking memory\r\n");
}
}
/* If we hadn't gotten to 100% yet, do it now */
if (ShowProgress)
{
BlUtlUpdateProgress(100, &Completed);
}
/* Return the final status */
return Status;
}

View file

@ -28,8 +28,47 @@ ULONG UtlNextUpdatePercentage;
BOOLEAN UtlProgressNeedsInfoUpdate;
PVOID UtlProgressInfo;
PVOID ResRootDirectory;
/* FUNCTIONS *****************************************************************/
VOID
BlUtlUpdateProgress (
_In_ ULONG Percentage,
_Out_opt_ PBOOLEAN Completed
)
{
if (UtlProgressRoutine)
{
EfiPrintf(L"Unimplemented\r\n");
}
else if (*Completed)
{
*Completed = TRUE;
}
}
PWCHAR
BlResourceFindMessage (
_In_ ULONG MsgId
)
{
PWCHAR Message;
/* Assume failure */
Message = NULL;
/* Check if we've loaded resources */
if (ResRootDirectory)
{
/* Not yet handled */
EfiPrintf(L"Not implemented\r\n");
}
/* Return the message for this ID */
return Message;
}
/*++
* @name EfiGetEfiStatusCode
*

View file

@ -204,6 +204,72 @@ Quickie:
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;
}
/* TODO */
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 tehre */
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))
{
/* TODO */
Status = STATUS_NOT_IMPLEMENTED;
}
}
else
{
/* Fail */
Status = STATUS_INVALID_PARAMETER;
}
/* Cleanup descriptors and reduce depth */
MmMdFreeGlobalDescriptors();
--MmDescriptorCallTreeCount;
return Status;
}
NTSTATUS
BlpMmInitialize (
_In_ PBL_MEMORY_DATA MemoryData,

View file

@ -568,4 +568,33 @@ MmPaInitialize (
return Status;
}
NTSTATUS
BlMmAllocatePhysicalPages(
_In_ PPHYSICAL_ADDRESS Address,
_In_ BL_MEMORY_TYPE MemoryType,
_In_ ULONGLONG PageCount,
_In_ ULONG Attributes,
_In_ ULONG Alignment
)
{
/* Call the physical allocator */
return MmPapAllocatePhysicalPagesInRange(Address,
MemoryType,
PageCount,
Attributes,
Alignment,
&MmMdlUnmappedAllocated,
NULL,
0);
}
NTSTATUS
BlMmFreePhysicalPages (
_In_ PHYSICAL_ADDRESS Address
)
{
/* Call the physical allocator */
EfiPrintf(L"Leaking memory!\r\n");
return STATUS_SUCCESS;
//return MmPapFreePhysicalPages(4, 0, Address);
}