diff --git a/BOOT/ENVIRON/LIB/EFI/efiinit.c b/BOOT/ENVIRON/LIB/EFI/efiinit.c index f224bfd..e871e10 100644 --- a/BOOT/ENVIRON/LIB/EFI/efiinit.c +++ b/BOOT/ENVIRON/LIB/EFI/efiinit.c @@ -23,15 +23,247 @@ UCHAR EfiInitScratch[2048]; const EFI_GUID EfiLoadedImageProtocol = LOADED_IMAGE_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 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 EFI_DEVICE_PATH *EfiDevicePath, + IN EFI_DEVICE_PATH *EfiFilePath, IN PWCHAR LoadOptions, IN ULONG LoadOptionsSize, + IN ULONG Flags, OUT PULONG BufferUsed, OUT PBOOT_DEVICE *BootDevice ) @@ -50,14 +282,16 @@ Arguments: 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. LoadOptionsSize - Length of the string pointed to by LoadOptions. + Flags - Unused. + BufferUsed - Returns the amount of buffer space used by the routine. BootDevice - Returns a pointer to the device the application was loaded from. @@ -69,9 +303,18 @@ Return Value: --*/ { + NTSTATUS Status; + ULONG BufferRemaining; PWCHAR BcdOptionString; BOOLEAN BcdIdentifierSet; UNICODE_STRING UnicodeString; + PBOOT_APPLICATION_ENTRY_OPTION Option; + PBCDE_DEVICE BootDeviceElement; + + (VOID)SystemTable; + (VOID)EfiDevicePath; + (VOID)EfiFilePath; + (VOID)Flags; *BufferUsed = 0; *BootDevice = NULL; @@ -80,7 +323,8 @@ Return Value: // // Require enough space for the application entry. // - if (BufferSize < sizeof(BOOT_APPLICATION_ENTRY)) { + BufferRemaining = BufferSize; + if (BufferRemaining < sizeof(BOOT_APPLICATION_ENTRY)) { return; } @@ -110,15 +354,27 @@ Return Value: } 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. // - (VOID)SystemTable; - (VOID)DevicePath; - (VOID)FilePath; } PBOOT_INPUT_PARAMETERS @@ -236,6 +492,7 @@ Return Value: LoadedImage->FilePath, LoadedImage->LoadOptions, LoadedImage->LoadOptionsSize, + 0, &ApplicationEntrySize, &BootDevice );