alcyone/BOOT/ENVIRON/LIB/EFI/efiinit.c

285 lines
7.7 KiB
C

/*++
Copyright (c) 2024, Quinn Stephens.
Provided under the BSD 3-Clause license.
Module Name:
efiinit.c
Abstract:
Provides EFI initialization utilities.
--*/
#include <ntrtl.h>
#include <string.h>
#include <wchar.h>
#include "bootmgr.h"
#include "efi.h"
UCHAR EfiInitScratch[2048];
const EFI_GUID EfiLoadedImageProtocol = LOADED_IMAGE_PROTOCOL;
const EFI_GUID EfiDevicePathProtocol = DEVICE_PATH_PROTOCOL;
VOID
EfiInitpCreateApplicationEntry (
IN EFI_SYSTEM_TABLE *SystemTable,
IN OUT PBOOT_APPLICATION_ENTRY Entry,
IN ULONG BufferSize,
IN EFI_DEVICE_PATH *DevicePath,
IN EFI_DEVICE_PATH *FilePath,
IN PWCHAR LoadOptions,
IN ULONG LoadOptionsSize,
OUT PULONG BufferUsed,
OUT PBOOT_DEVICE *BootDevice
)
/*++
Routine Description:
Creates an application entry structure for the boot application.
Arguments:
SystemTable - Pointer to the EFI system table.
Entry - A buffer to put the entry in.
BufferSize - The amount of available space in the buffer.
DevicePath - The device path for the application.
FilePath - The file path for the application.
LoadOptions - Firmware load options string.
LoadOptionsSize - Length of the string pointed to by LoadOptions.
BufferUsed - Returns the amount of buffer space used by the routine.
BootDevice - Returns a pointer to the device the application was loaded from.
Return Value:
None.
--*/
{
PWCHAR BcdOptionString;
BOOLEAN BcdIdentifierSet;
UNICODE_STRING UnicodeString;
*BufferUsed = 0;
*BootDevice = NULL;
BcdIdentifierSet = FALSE;
//
// Require enough space for the application entry.
//
if (BufferSize < sizeof(BOOT_APPLICATION_ENTRY)) {
return;
}
//
// Terminate load options string.
//
LoadOptionsSize /= sizeof(WCHAR);
if (LoadOptionsSize != 0 && wcsnlen(LoadOptions, LoadOptionsSize) == LoadOptionsSize) {
LoadOptions[LoadOptionsSize - 1] = L'\0';
}
//
// Set up application entry structure.
//
RtlZeroMemory(Entry, sizeof(BOOT_APPLICATION_ENTRY));
Entry->Signature = BOOT_APPLICATION_ENTRY_SIGNATURE;
*BufferUsed = sizeof(BOOT_APPLICATION_ENTRY);
//
// Parse BCD GUID if present.
//
if (LoadOptions != NULL && (BcdOptionString = wcsstr(LoadOptions, L"BCDOBJECT=")) != NULL) {
RtlInitUnicodeString(&UnicodeString, (PWCHAR)((PUCHAR)BcdOptionString + sizeof(L"BCDOBJECT=") - sizeof(UNICODE_NULL)));
if (NT_SUCCESS(RtlGUIDFromString(&UnicodeString, &Entry->BcdIdentifier))) {
BcdIdentifierSet = TRUE;
}
}
if (!BcdIdentifierSet) {
Entry->Attributes |= BOOT_APPLICATION_ENTRY_BCD_IDENTIFIER_NOT_SET;
}
//
// TODO: This routine is not fully implemented.
//
(VOID)SystemTable;
(VOID)DevicePath;
(VOID)FilePath;
}
PBOOT_INPUT_PARAMETERS
EfiInitCreateInputParameters (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
Creates the input parameter structure for the boot application.
Arguments:
ImageHandle - Handle for the boot manager image.
SystemTable - Pointer to the EFI system table.
Return Value:
Pointer to parameter structure on success or NULL on failure.
--*/
{
ULONG ScratchUsed = 0;
ULONG ApplicationEntrySize = 0;
EFI_STATUS Status;
EFI_PHYSICAL_ADDRESS BadPageAddress;
EFI_LOADED_IMAGE *LoadedImage;
EFI_DEVICE_PATH *DevicePath;
PBOOT_INPUT_PARAMETERS InputParameters;
PBOOT_MEMORY_INFO MemoryInfo;
PBOOT_MEMORY_DESCRIPTOR MemoryDescriptor;
PBOOT_DEVICE BootDevice;
PBOOT_FIRMWARE_DATA FirmwareData;
PBOOT_RETURN_DATA ReturnData;
//
// Page 0x102 may be broken on some machines.
// It is mapped here so that it does not get used.
//
BadPageAddress = 0x102 << PAGE_SHIFT;
SystemTable->BootServices->AllocatePages(AllocateAddress, EfiLoaderData, 1, &BadPageAddress);
//
// Get boot manager image information.
//
Status = SystemTable->BootServices->HandleProtocol(
ImageHandle,
(EFI_GUID*)&EfiLoadedImageProtocol,
(VOID**)&LoadedImage
);
if (Status != EFI_SUCCESS) {
return NULL;
}
//
// Get boot manager image device path.
//
Status = SystemTable->BootServices->HandleProtocol(
LoadedImage->DeviceHandle,
(EFI_GUID*)&EfiDevicePathProtocol,
(VOID**)&DevicePath
);
if (Status != EFI_SUCCESS) {
return NULL;
}
//
// Create input parameters structure.
//
InputParameters = (PBOOT_INPUT_PARAMETERS)(&EfiInitScratch[ScratchUsed]);
ScratchUsed += sizeof(BOOT_INPUT_PARAMETERS);
InputParameters->Signature = BOOT_INPUT_PARAMETERS_SIGNATURE;
InputParameters->Version = BOOT_INPUT_PARAMETERS_VERSION;
InputParameters->MachineType = BOOT_MACHINE_TYPE;
InputParameters->TranslationType = BOOT_TRANSLATION_TYPE;
InputParameters->ImageBase = LoadedImage->ImageBase;
InputParameters->ImageSize = LoadedImage->ImageSize;
//
// Create memory info structure.
//
InputParameters->MemoryInfoOffset = ScratchUsed;
MemoryInfo = (PBOOT_MEMORY_INFO)(&EfiInitScratch[ScratchUsed]);
ScratchUsed += sizeof(BOOT_MEMORY_INFO);
MemoryInfo->Version = BOOT_MEMORY_INFO_VERSION;
MemoryInfo->MdlOffset = sizeof(BOOT_MEMORY_INFO);
MemoryInfo->DescriptorCount = 1;
MemoryInfo->DescriptorSize = sizeof(BOOT_MEMORY_DESCRIPTOR);
MemoryInfo->BasePageOffset = FIELD_OFFSET(BOOT_MEMORY_DESCRIPTOR, BasePage);
//
// Create a memory descriptor for the boot manager image.
//
MemoryDescriptor = (PBOOT_MEMORY_DESCRIPTOR)(&EfiInitScratch[ScratchUsed]);
ScratchUsed += sizeof(BOOT_MEMORY_DESCRIPTOR);
MemoryDescriptor->BasePage = (UINTN)InputParameters->ImageBase >> PAGE_SHIFT;
MemoryDescriptor->Pages = ALIGN_UP(InputParameters->ImageSize, PAGE_SIZE) >> PAGE_SHIFT;
MemoryDescriptor->Attributes = MEMORY_ATTRIBUTE_CACHE_WB;
MemoryDescriptor->Type = MEMORY_TYPE_BOOT_APPLICATION;
//
// Create an application entry for the boot application.
//
InputParameters->ApplicationEntryOffset = ScratchUsed;
EfiInitpCreateApplicationEntry(
SystemTable,
(PBOOT_APPLICATION_ENTRY)(&EfiInitScratch[ScratchUsed]),
sizeof(EfiInitScratch) - ScratchUsed,
DevicePath,
LoadedImage->FilePath,
LoadedImage->LoadOptions,
LoadedImage->LoadOptionsSize,
&ApplicationEntrySize,
&BootDevice
);
ScratchUsed += ApplicationEntrySize;
//
// Copy application device to scratch area.
//
InputParameters->BootDeviceOffset = ScratchUsed;
if (BootDevice != NULL) {
RtlCopyMemory(&EfiInitScratch[ScratchUsed], BootDevice, BootDevice->Size);
ScratchUsed += BootDevice->Size;
} else {
RtlZeroMemory(&EfiInitScratch[ScratchUsed], sizeof(BOOT_DEVICE));
ScratchUsed += sizeof(BOOT_DEVICE);
}
//
// Create firmware data structure.
//
InputParameters->FirmwareDataOffset = ScratchUsed;
FirmwareData = (PBOOT_FIRMWARE_DATA)(&EfiInitScratch[ScratchUsed]);
ScratchUsed += sizeof(BOOT_FIRMWARE_DATA);
FirmwareData->Version = BOOT_FIRMWARE_DATA_VERSION;
FirmwareData->Reserved = 0;
FirmwareData->ImageHandle = ImageHandle;
FirmwareData->SystemTable = SystemTable;
//
// Create return data structure.
//
InputParameters->ReturnDataOffset = ScratchUsed;
ReturnData = (PBOOT_RETURN_DATA)(&EfiInitScratch[ScratchUsed]);
ScratchUsed += sizeof(BOOT_RETURN_DATA);
ReturnData->Version = BOOT_RETURN_DATA_VERSION;
//
// Set and validate total size.
//
InputParameters->Size = ScratchUsed;
if (InputParameters->Size > sizeof(EfiInitScratch)) {
return NULL;
}
return InputParameters;
}