[BOOT:LIB] Major work on efiinit.c

Improved EfiInitpCreateApplicationEntry()
Implemented EfiInitpGetDeviceNode(), EfiInitTranslateDevicePath(),
and EfiInitpConvertDevicePath()
This commit is contained in:
Quinn Stephens 2024-08-24 09:30:52 -04:00
parent 9b66f166d6
commit fd670ace0d

View File

@ -23,15 +23,247 @@ UCHAR EfiInitScratch[2048];
const EFI_GUID EfiLoadedImageProtocol = LOADED_IMAGE_PROTOCOL; const EFI_GUID EfiLoadedImageProtocol = LOADED_IMAGE_PROTOCOL;
const EFI_GUID EfiDevicePathProtocol = DEVICE_PATH_PROTOCOL; const EFI_GUID EfiDevicePathProtocol = DEVICE_PATH_PROTOCOL;
EFI_DEVICE_PATH *
EfiInitpGetDeviceNode (
IN EFI_DEVICE_PATH *DevicePath
)
/*++
Routine Description:
Searches an EFI device path for the last device path node
before a file path node.
Arguments:
DevicePath - EFI device path to search.
Return Value:
Pointer to the last device path node.
--*/
{
EFI_DEVICE_PATH *Node;
//
// Check if the current node is the end of the path.
//
if (IsDevicePathEndType(DevicePath)) {
return DevicePath;
}
//
// Find the last non-filepath node.
//
Node = NextDevicePathNode(DevicePath);
while (!IsDevicePathEndType(Node)) {
if (DevicePathType(Node) == MEDIA_DEVICE_PATH && DevicePathSubType(Node) == MEDIA_FILEPATH_DP) {
break;
}
DevicePath = Node;
Node = NextDevicePathNode(Node);
}
return DevicePath;
}
NTSTATUS
EfiInitTranslateDevicePath (
IN EFI_DEVICE_PATH *EfiDevicePath,
IN OUT PBOOT_DEVICE BootDevice,
IN ULONG BufferSize
)
/*++
Routine Description:
Translates an EFI device path into boot device format.
Arguments:
EfiDevicePath - The EFI device path to be translated.
BootDevice - Pointer to the destination device structure.
BufferSize - The amount of available space in the buffer.
Return Value:
STATUS_SUCCESS if successful,
STATUS_INVALID_PARAMETER if the buffer is too small.
STATUS_UNSUCCESSFUL if the path could not be translated.
--*/
{
EFI_DEVICE_PATH *DeviceNode;
MEMMAP_DEVICE_PATH *MemmapNode;
HARDDRIVE_DEVICE_PATH *HarddriveNode;
PBOOT_BLOCK_IDENTIFIER BlockDevice;
//
// Check for available buffer space.
//
if (BufferSize < sizeof(BOOT_DEVICE)) {
return STATUS_INVALID_PARAMETER;
}
BootDevice->Size = sizeof(BOOT_DEVICE);
//
// Memory mapped device paths are treated as ramdisks.
//
if (DevicePathType(EfiDevicePath) == HARDWARE_DEVICE_PATH && DevicePathSubType(EfiDevicePath) == HW_MEMMAP_DP) {
MemmapNode = (MEMMAP_DEVICE_PATH *)EfiDevicePath;
BlockDevice = &BootDevice->Block;
BootDevice->Type = BOOT_DEVICE_TYPE_BLOCK;
BlockDevice->Type = BOOT_BLOCK_DEVICE_TYPE_RAMDISK;
BlockDevice->Ramdisk.ImageBase.QuadPart = MemmapNode->StartingAddress;
BlockDevice->Ramdisk.ImageSize = MemmapNode->EndingAddress - MemmapNode->StartingAddress;
BlockDevice->Ramdisk.ImageOffset = 0;
return STATUS_SUCCESS;
}
//
// Get the device node, the device the application was loaded from.
// TODO: Only media devices and ramdisks are currently supported.
//
DeviceNode = EfiInitpGetDeviceNode(EfiDevicePath);
if (DevicePathType(DeviceNode) != MEDIA_DEVICE_PATH) {
return STATUS_UNSUCCESSFUL;
}
//
// Check device node subtype.
//
switch (DevicePathSubType(DeviceNode)) {
case MEDIA_HARDDRIVE_DP:
HarddriveNode = (HARDDRIVE_DEVICE_PATH *)DeviceNode;
//
// Use correct block device and partition format.
//
if (HarddriveNode->SignatureType != SIGNATURE_TYPE_MBR) {
BlockDevice = &BootDevice->PartitionEx.Parent;
BootDevice->Type = BOOT_DEVICE_TYPE_PARTITION_EX;
} else {
BlockDevice = &BootDevice->Partition.Parent;
BootDevice->Type = BOOT_DEVICE_TYPE_PARTITION;
}
BlockDevice->Type = BOOT_BLOCK_DEVICE_TYPE_HARDDRIVE;
//
// Initialize partition based on the drive's partitioning system.
//
switch (HarddriveNode->SignatureType) {
case SIGNATURE_TYPE_MBR:
BlockDevice->Harddrive.PartitionType = BOOT_HARDDRIVE_PARTITION_TYPE_MBR;
BlockDevice->Harddrive.Mbr.Signature = *((ULONG *)HarddriveNode->Signature);
BootDevice->Partition.Mbr.PartitionNumber = HarddriveNode->PartitionNumber;
break;
case SIGNATURE_TYPE_GUID:
BootDevice->Attributes |= BOOT_DEVICE_ATTRIBUTE_NO_PARENT_SIGNATURE;
BlockDevice->Harddrive.PartitionType = BOOT_HARDDRIVE_PARTITION_TYPE_GPT;
RtlCopyMemory(&BootDevice->PartitionEx.Gpt.PartitionIdentifier, &HarddriveNode->Signature, sizeof(HarddriveNode->Signature));
break;
default:
BlockDevice->Harddrive.PartitionType = BOOT_HARDDRIVE_PARTITION_TYPE_RAW;
BlockDevice->Harddrive.Raw.DriveNumber = 0;
}
break;
case MEDIA_CDROM_DP:
BootDevice->Type = BOOT_DEVICE_TYPE_BLOCK;
BootDevice->Block.Type = BOOT_BLOCK_DEVICE_TYPE_CDROM;
BootDevice->Block.Cdrom.DriveNumber = 0;
break;
default:
return STATUS_UNSUCCESSFUL;
}
return STATUS_SUCCESS;
}
NTSTATUS
EfiInitpConvertEfiDevicePath (
IN EFI_DEVICE_PATH *EfiDevicePath,
IN BCDE_DATA_TYPE OptionType,
IN OUT PBOOT_APPLICATION_ENTRY_OPTION Option,
IN ULONG BufferSize
)
/*++
Routine Description:
Converts an EFI device path into BCD format.
Arguments:
EfiDevicePath - The EFI device path to be converted.
OptionType - The data type to be assigned to option.
Option - Pointer to the destination option structure.
BufferSize - The amount of available space in the buffer.
Return Value:
STATUS_SUCCESS if successful.
other NTSTATUS value if failure occurs.
--*/
{
NTSTATUS Status;
PBCDE_DEVICE DeviceElement;
//
// Check for available buffer space.
//
if (BufferSize < sizeof(BOOT_APPLICATION_ENTRY_OPTION) + FIELD_OFFSET(BCDE_DEVICE, Device)) {
return STATUS_INVALID_PARAMETER;
}
//
// Translate device path.
//
RtlZeroMemory(Option, sizeof(BOOT_APPLICATION_ENTRY_OPTION));
DeviceElement = (PBCDE_DEVICE)((PUCHAR)Option + sizeof(BOOT_APPLICATION_ENTRY_OPTION));
Status = EfiInitTranslateDevicePath(
EfiDevicePath,
&DeviceElement->Device,
BufferSize - (sizeof(BOOT_APPLICATION_ENTRY_OPTION) + FIELD_OFFSET(BCDE_DEVICE, Device))
);
if (!NT_SUCCESS(Status)) {
return Status;
}
//
// Set up option structure.
//
Option->Type = OptionType;
Option->DataOffset = sizeof(BOOT_APPLICATION_ENTRY_OPTION);
Option->DataSize = FIELD_OFFSET(BCDE_DEVICE, Device) + DeviceElement->Device.Size;
return STATUS_SUCCESS;
}
VOID VOID
EfiInitpCreateApplicationEntry ( EfiInitpCreateApplicationEntry (
IN EFI_SYSTEM_TABLE *SystemTable, IN EFI_SYSTEM_TABLE *SystemTable,
IN OUT PBOOT_APPLICATION_ENTRY Entry, IN OUT PBOOT_APPLICATION_ENTRY Entry,
IN ULONG BufferSize, IN ULONG BufferSize,
IN EFI_DEVICE_PATH *DevicePath, IN EFI_DEVICE_PATH *EfiDevicePath,
IN EFI_DEVICE_PATH *FilePath, IN EFI_DEVICE_PATH *EfiFilePath,
IN PWCHAR LoadOptions, IN PWCHAR LoadOptions,
IN ULONG LoadOptionsSize, IN ULONG LoadOptionsSize,
IN ULONG Flags,
OUT PULONG BufferUsed, OUT PULONG BufferUsed,
OUT PBOOT_DEVICE *BootDevice OUT PBOOT_DEVICE *BootDevice
) )
@ -50,14 +282,16 @@ Arguments:
BufferSize - The amount of available space in the buffer. BufferSize - The amount of available space in the buffer.
DevicePath - The device path for the application. EfiDevicePath - The device path for the application.
FilePath - The file path for the application. EfiFilePath - The file path for the application.
LoadOptions - Firmware load options string. LoadOptions - Firmware load options string.
LoadOptionsSize - Length of the string pointed to by LoadOptions. LoadOptionsSize - Length of the string pointed to by LoadOptions.
Flags - Unused.
BufferUsed - Returns the amount of buffer space used by the routine. BufferUsed - Returns the amount of buffer space used by the routine.
BootDevice - Returns a pointer to the device the application was loaded from. BootDevice - Returns a pointer to the device the application was loaded from.
@ -69,9 +303,18 @@ Return Value:
--*/ --*/
{ {
NTSTATUS Status;
ULONG BufferRemaining;
PWCHAR BcdOptionString; PWCHAR BcdOptionString;
BOOLEAN BcdIdentifierSet; BOOLEAN BcdIdentifierSet;
UNICODE_STRING UnicodeString; UNICODE_STRING UnicodeString;
PBOOT_APPLICATION_ENTRY_OPTION Option;
PBCDE_DEVICE BootDeviceElement;
(VOID)SystemTable;
(VOID)EfiDevicePath;
(VOID)EfiFilePath;
(VOID)Flags;
*BufferUsed = 0; *BufferUsed = 0;
*BootDevice = NULL; *BootDevice = NULL;
@ -80,7 +323,8 @@ Return Value:
// //
// Require enough space for the application entry. // Require enough space for the application entry.
// //
if (BufferSize < sizeof(BOOT_APPLICATION_ENTRY)) { BufferRemaining = BufferSize;
if (BufferRemaining < sizeof(BOOT_APPLICATION_ENTRY)) {
return; return;
} }
@ -110,15 +354,27 @@ Return Value:
} }
if (!BcdIdentifierSet) { if (!BcdIdentifierSet) {
Entry->Attributes |= BOOT_APPLICATION_ENTRY_BCD_IDENTIFIER_NOT_SET; Entry->Attributes |= BOOT_APPLICATION_ENTRY_NO_BCD_IDENTIFIER;
} }
//
// Convert the EFI device path into a boot device option.
//
Option = &Entry->Options;
BufferRemaining -= FIELD_OFFSET(BOOT_APPLICATION_ENTRY, Options);
Status = EfiInitpConvertEfiDevicePath(EfiDevicePath, BCDE_DATA_TYPE_APPLICATION_DEVICE, Option, BufferRemaining);
if (!NT_SUCCESS(Status)) {
Option->IsInvalid = TRUE;
*BufferUsed = sizeof(BOOT_APPLICATION_ENTRY_OPTION);
return;
}
BootDeviceElement = (PBCDE_DEVICE)((PUCHAR)Option + Option->DataOffset);
*BootDevice = &BootDeviceElement->Device;
// //
// TODO: This routine is not fully implemented. // TODO: This routine is not fully implemented.
// //
(VOID)SystemTable;
(VOID)DevicePath;
(VOID)FilePath;
} }
PBOOT_INPUT_PARAMETERS PBOOT_INPUT_PARAMETERS
@ -236,6 +492,7 @@ Return Value:
LoadedImage->FilePath, LoadedImage->FilePath,
LoadedImage->LoadOptions, LoadedImage->LoadOptions,
LoadedImage->LoadOptionsSize, LoadedImage->LoadOptionsSize,
0,
&ApplicationEntrySize, &ApplicationEntrySize,
&BootDevice &BootDevice
); );