mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
747 lines
21 KiB
C
Executable File
747 lines
21 KiB
C
Executable File
/** @file
|
|
Copyright (C) 2016 - 2018, The HermitCrabs Lab. All rights reserved.
|
|
|
|
All rights reserved.
|
|
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
**/
|
|
|
|
#include <Uefi.h>
|
|
|
|
#include <Protocol/DevicePathToText.h>
|
|
#include <Protocol/SimpleFileSystem.h>
|
|
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DevicePathLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/OcGuardLib.h>
|
|
#include <Library/OcStringLib.h>
|
|
#include <Library/OcDevicePathLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *
|
|
AppendFileNameDevicePath (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
|
|
IN CHAR16 *FileName
|
|
)
|
|
{
|
|
EFI_DEVICE_PATH_PROTOCOL *AppendedDevicePath;
|
|
|
|
FILEPATH_DEVICE_PATH *FilePathNode;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePathEndNode;
|
|
UINTN FileNameSize;
|
|
UINTN FileDevicePathNodeSize;
|
|
|
|
AppendedDevicePath = NULL;
|
|
|
|
if (DevicePath != NULL && FileName != NULL) {
|
|
FileNameSize = StrSize (FileName);
|
|
FileDevicePathNodeSize = (FileNameSize + SIZE_OF_FILEPATH_DEVICE_PATH + END_DEVICE_PATH_LENGTH);
|
|
FilePathNode = AllocateZeroPool (FileDevicePathNodeSize);
|
|
|
|
if (FilePathNode != NULL) {
|
|
FilePathNode->Header.Type = MEDIA_DEVICE_PATH;
|
|
FilePathNode->Header.SubType = MEDIA_FILEPATH_DP;
|
|
|
|
SetDevicePathNodeLength (&FilePathNode->Header, FileNameSize + SIZE_OF_FILEPATH_DEVICE_PATH);
|
|
|
|
CopyMem (FilePathNode->PathName, FileName, FileNameSize);
|
|
|
|
DevicePathEndNode = NextDevicePathNode (&FilePathNode->Header);
|
|
|
|
SetDevicePathEndNode (DevicePathEndNode);
|
|
|
|
AppendedDevicePath = AppendDevicePath (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)FilePathNode);
|
|
|
|
FreePool (FilePathNode);
|
|
}
|
|
}
|
|
|
|
return AppendedDevicePath;
|
|
}
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *
|
|
FindDevicePathNodeWithType (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
|
|
IN UINT8 Type,
|
|
IN UINT8 SubType OPTIONAL
|
|
)
|
|
{
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
|
|
|
|
DevicePathNode = NULL;
|
|
|
|
while (!IsDevicePathEnd (DevicePath)) {
|
|
if ((DevicePathType (DevicePath) == Type)
|
|
&& ((SubType == 0) || (DevicePathSubType (DevicePath) == SubType))) {
|
|
DevicePathNode = DevicePath;
|
|
|
|
break;
|
|
}
|
|
|
|
DevicePath = NextDevicePathNode (DevicePath);
|
|
}
|
|
|
|
return DevicePathNode;
|
|
}
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *
|
|
AbsoluteDevicePath (
|
|
IN EFI_HANDLE Handle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RelativePath OPTIONAL
|
|
)
|
|
{
|
|
EFI_DEVICE_PATH_PROTOCOL *HandlePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *NewPath;
|
|
|
|
HandlePath = DevicePathFromHandle (Handle);
|
|
if (HandlePath == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
if (RelativePath == NULL) {
|
|
return DuplicateDevicePath (HandlePath);
|
|
}
|
|
|
|
NewPath = AppendDevicePath (HandlePath, RelativePath);
|
|
|
|
if (NewPath == NULL) {
|
|
return DuplicateDevicePath (HandlePath);
|
|
}
|
|
|
|
return NewPath;
|
|
}
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *
|
|
TrailedBooterDevicePath (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
|
)
|
|
{
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePathWalker;
|
|
EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
|
|
FILEPATH_DEVICE_PATH *FilePath;
|
|
FILEPATH_DEVICE_PATH *NewFilePath;
|
|
UINTN Length;
|
|
UINTN Size;
|
|
|
|
DevicePathWalker = DevicePath;
|
|
|
|
while (!IsDevicePathEnd (DevicePathWalker)) {
|
|
if ((DevicePathType (DevicePathWalker) == MEDIA_DEVICE_PATH)
|
|
&& (DevicePathSubType (DevicePathWalker) == MEDIA_FILEPATH_DP)
|
|
&& IsDevicePathEnd (NextDevicePathNode (DevicePathWalker))) {
|
|
FilePath = (FILEPATH_DEVICE_PATH *) DevicePathWalker;
|
|
Length = OcFileDevicePathNameLen (FilePath);
|
|
if (Length > 0) {
|
|
if (FilePath->PathName[Length - 1] == L'\\') {
|
|
//
|
|
// Already appended, good. It should never be true with Apple entries though.
|
|
//
|
|
return NULL;
|
|
} else if (Length > 4 && (FilePath->PathName[Length - 4] != '.'
|
|
|| (FilePath->PathName[Length - 3] != 'e' && FilePath->PathName[Length - 3] != 'E')
|
|
|| (FilePath->PathName[Length - 2] != 'f' && FilePath->PathName[Length - 2] != 'F')
|
|
|| (FilePath->PathName[Length - 1] != 'i' && FilePath->PathName[Length - 1] != 'I'))) {
|
|
//
|
|
// Found! We should have gotten something like:
|
|
// PciRoot(0x0)/Pci(...)/Pci(...)/Sata(...)/HD(...)/\com.apple.recovery.boot
|
|
//
|
|
|
|
Size = GetDevicePathSize (DevicePath);
|
|
NewDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocatePool (Size + sizeof (CHAR16));
|
|
if (NewDevicePath == NULL) {
|
|
//
|
|
// Allocation failure, just ignore.
|
|
//
|
|
return NULL;
|
|
}
|
|
//
|
|
// Strip the string termination and DP end node, which will get re-set
|
|
//
|
|
CopyMem (NewDevicePath, DevicePath, Size - sizeof (CHAR16) - END_DEVICE_PATH_LENGTH);
|
|
NewFilePath = (FILEPATH_DEVICE_PATH *) ((UINT8 *)DevicePathWalker - (UINT8 *)DevicePath + (UINT8 *)NewDevicePath);
|
|
Size = DevicePathNodeLength (DevicePathWalker) + sizeof (CHAR16);
|
|
SetDevicePathNodeLength (NewFilePath, Size);
|
|
NewFilePath->PathName[Length] = L'\\';
|
|
NewFilePath->PathName[Length+1] = L'\0';
|
|
SetDevicePathEndNode ((UINT8 *) NewFilePath + Size);
|
|
return NewDevicePath;
|
|
}
|
|
}
|
|
}
|
|
|
|
DevicePathWalker = NextDevicePathNode (DevicePathWalker);
|
|
}
|
|
|
|
//
|
|
// Has .efi suffix or unsupported format.
|
|
//
|
|
return NULL;
|
|
}
|
|
|
|
INTN
|
|
OcFixAppleBootDevicePath (
|
|
IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
|
|
)
|
|
{
|
|
INTN Result;
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *OriginalDevPath;
|
|
|
|
EFI_DEV_PATH_PTR InvalidNode;
|
|
UINT8 NodeType;
|
|
UINT8 NodeSubType;
|
|
UINTN NodeSize;
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *RemainingDevPath;
|
|
EFI_HANDLE Device;
|
|
|
|
ASSERT (DevicePath != NULL);
|
|
ASSERT (*DevicePath != NULL);
|
|
ASSERT (IsDevicePathValid (*DevicePath, 0));
|
|
//
|
|
// CAUTION: When adding new fixes, ensure short-form device paths are not
|
|
// modified and success is returned.
|
|
//
|
|
OriginalDevPath = *DevicePath;
|
|
//
|
|
// Failure will be returned explicitly within the loop. If this loop is run
|
|
// only once, it means the Device Path had already been valid. Hence, Result
|
|
// will be 0 on termination. Shall any switch-case continue, which it needs
|
|
// to in order to patch subsequent nodes, Result will be incremented.
|
|
//
|
|
Result = -1;
|
|
while (TRUE) {
|
|
if (Result != MAX_INTN) {
|
|
++Result;
|
|
}
|
|
|
|
RemainingDevPath = OriginalDevPath;
|
|
gBS->LocateDevicePath (
|
|
&gEfiDevicePathProtocolGuid,
|
|
&RemainingDevPath,
|
|
&Device
|
|
);
|
|
|
|
*DevicePath = RemainingDevPath;
|
|
|
|
InvalidNode.DevPath = RemainingDevPath;
|
|
NodeType = DevicePathType (InvalidNode.DevPath);
|
|
NodeSubType = DevicePathSubType (InvalidNode.DevPath);
|
|
|
|
if (NodeType == MESSAGING_DEVICE_PATH) {
|
|
switch (NodeSubType) {
|
|
case MSG_SATA_DP:
|
|
{
|
|
if (InvalidNode.Sata->PortMultiplierPortNumber != 0xFFFF) {
|
|
//
|
|
// Must be set to 0xFFFF if the device is directly connected to the
|
|
// HBA. This rule has been established by UEFI 2.5 via an Erratum
|
|
// and has not been followed by Apple thus far.
|
|
// Reference: AppleACPIPlatform.kext,
|
|
// appendSATADevicePathNodeForIOMedia
|
|
//
|
|
InvalidNode.Sata->PortMultiplierPortNumber = 0xFFFF;
|
|
continue;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
case MSG_SASEX_DP:
|
|
{
|
|
OC_INLINE_STATIC_ASSERT (
|
|
(sizeof (SASEX_DEVICE_PATH) != sizeof (NVME_NAMESPACE_DEVICE_PATH)),
|
|
"SasEx and NVMe DPs must differ in size for fixing to be accurate."
|
|
);
|
|
//
|
|
// Apple uses SubType 0x16 (SasEx) for NVMe, while the UEFI
|
|
// Specification defines it as SubType 0x17. The structures are
|
|
// identical.
|
|
// Reference: AppleACPIPlatform.kext,
|
|
// appendNVMeDevicePathNodeForIOMedia
|
|
//
|
|
NodeSize = DevicePathNodeLength (InvalidNode.DevPath);
|
|
if (NodeSize == sizeof (NVME_NAMESPACE_DEVICE_PATH)) {
|
|
InvalidNode.SasEx->Header.SubType = MSG_NVME_NAMESPACE_DP;
|
|
continue;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
} else if (NodeType == ACPI_DEVICE_PATH) {
|
|
//
|
|
// Apple uses PciRoot (EISA 0x0A03) nodes while some firmwares might use
|
|
// PcieRoot (EISA 0x0A08).
|
|
//
|
|
switch (NodeSubType) {
|
|
case ACPI_DP:
|
|
{
|
|
if (EISA_ID_TO_NUM (InvalidNode.Acpi->HID) == 0x0A03) {
|
|
InvalidNode.Acpi->HID = BitFieldWrite32 (
|
|
InvalidNode.Acpi->HID,
|
|
16,
|
|
31,
|
|
0x0A08
|
|
);
|
|
continue;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
case ACPI_EXTENDED_DP:
|
|
{
|
|
if (EISA_ID_TO_NUM (InvalidNode.ExtendedAcpi->HID) == 0x0A03) {
|
|
InvalidNode.ExtendedAcpi->HID = BitFieldWrite32 (
|
|
InvalidNode.ExtendedAcpi->HID,
|
|
16,
|
|
31,
|
|
0x0A08
|
|
);
|
|
continue;
|
|
}
|
|
|
|
if (((EISA_ID_TO_NUM (InvalidNode.ExtendedAcpi->CID) == 0x0A03)
|
|
&& (EISA_ID_TO_NUM (InvalidNode.ExtendedAcpi->HID) != 0x0A08))) {
|
|
InvalidNode.ExtendedAcpi->CID = BitFieldWrite32 (
|
|
InvalidNode.ExtendedAcpi->CID,
|
|
16,
|
|
31,
|
|
0x0A08
|
|
);
|
|
continue;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
}
|
|
|
|
STATIC
|
|
BOOLEAN
|
|
InternalFileDevicePathsEqualClipBottom (
|
|
IN CONST FILEPATH_DEVICE_PATH *FilePath,
|
|
IN OUT UINTN *FilePathLength,
|
|
IN OUT UINTN *ClipIndex
|
|
)
|
|
{
|
|
UINTN Index;
|
|
|
|
ASSERT (FilePathLength != NULL);
|
|
ASSERT (*FilePathLength != 0);
|
|
ASSERT (FilePath != NULL);
|
|
ASSERT (ClipIndex != NULL);
|
|
|
|
Index = *ClipIndex;
|
|
if (FilePath->PathName[Index] == L'\\') {
|
|
*ClipIndex = Index + 1;
|
|
--(*FilePathLength);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
STATIC
|
|
UINTN
|
|
InternalFileDevicePathsEqualClipNode (
|
|
IN FILEPATH_DEVICE_PATH **FilePath,
|
|
OUT UINTN *ClipIndex
|
|
)
|
|
{
|
|
EFI_DEV_PATH_PTR DevPath;
|
|
UINTN Index;
|
|
|
|
UINTN Length;
|
|
EFI_DEVICE_PATH_PROTOCOL *NextNode;
|
|
|
|
ASSERT (FilePath != NULL);
|
|
ASSERT (ClipIndex != NULL);
|
|
//
|
|
// It is unlikely to be encountered, but empty nodes are not forbidden.
|
|
//
|
|
for (
|
|
Length = 0, NextNode = &(*FilePath)->Header;
|
|
Length == 0;
|
|
NextNode = NextDevicePathNode (DevPath.DevPath)
|
|
) {
|
|
DevPath.DevPath = NextNode;
|
|
|
|
if ((DevicePathType (DevPath.DevPath) != MEDIA_DEVICE_PATH)
|
|
|| (DevicePathSubType (DevPath.DevPath) != MEDIA_FILEPATH_DP)) {
|
|
return 0;
|
|
}
|
|
|
|
Length = OcFileDevicePathNameLen (DevPath.FilePath);
|
|
if (Length > 0) {
|
|
Index = 0;
|
|
InternalFileDevicePathsEqualClipBottom (DevPath.FilePath, &Length, &Index);
|
|
if ((Length > 0)
|
|
&& DevPath.FilePath->PathName[Index + Length - 1] == L'\\') {
|
|
--Length;
|
|
}
|
|
|
|
*ClipIndex = Index;
|
|
}
|
|
}
|
|
|
|
*FilePath = DevPath.FilePath;
|
|
return Length;
|
|
}
|
|
|
|
STATIC
|
|
UINTN
|
|
InternalFileDevicePathsEqualClipNextNode (
|
|
IN FILEPATH_DEVICE_PATH **FilePath,
|
|
OUT UINTN *ClipIndex
|
|
)
|
|
{
|
|
ASSERT (FilePath != NULL);
|
|
ASSERT (ClipIndex != NULL);
|
|
|
|
*FilePath = (FILEPATH_DEVICE_PATH *)NextDevicePathNode (*FilePath);
|
|
return InternalFileDevicePathsEqualClipNode (FilePath, ClipIndex);
|
|
}
|
|
|
|
BOOLEAN
|
|
InternalFileDevicePathsEqualWorker (
|
|
IN FILEPATH_DEVICE_PATH **FilePath1,
|
|
IN FILEPATH_DEVICE_PATH **FilePath2
|
|
)
|
|
{
|
|
UINTN Clip1Index;
|
|
UINTN Clip2Index;
|
|
UINTN Len1;
|
|
UINTN Len2;
|
|
UINTN CurrentLen;
|
|
UINTN Index;
|
|
CHAR16 Char1;
|
|
CHAR16 Char2;
|
|
BOOLEAN Result;
|
|
|
|
ASSERT (FilePath1 != NULL);
|
|
ASSERT (*FilePath1 != NULL);
|
|
ASSERT (FilePath2 != NULL);
|
|
ASSERT (*FilePath2 != NULL);
|
|
|
|
ASSERT (IsDevicePathValid (&(*FilePath1)->Header, 0));
|
|
ASSERT (IsDevicePathValid (&(*FilePath2)->Header, 0));
|
|
|
|
Len1 = InternalFileDevicePathsEqualClipNode (FilePath1, &Clip1Index);
|
|
Len2 = InternalFileDevicePathsEqualClipNode (FilePath2, &Clip2Index);
|
|
|
|
do {
|
|
if ((Len1 == 0) && (Len2 == 0)) {
|
|
return TRUE;
|
|
}
|
|
|
|
CurrentLen = MIN (Len1, Len2);
|
|
if (CurrentLen == 0) {
|
|
return FALSE;
|
|
}
|
|
//
|
|
// FIXME: Discuss case sensitivity. For UEFI FAT, case insensitivity is
|
|
// guaranteed.
|
|
//
|
|
for (Index = 0; Index < CurrentLen; ++Index) {
|
|
Char1 = CharToUpper ((*FilePath1)->PathName[Clip1Index + Index]);
|
|
Char2 = CharToUpper ((*FilePath2)->PathName[Clip2Index + Index]);
|
|
if (Char1 != Char2) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (Len1 == Len2) {
|
|
Len1 = InternalFileDevicePathsEqualClipNextNode (FilePath1, &Clip1Index);
|
|
Len2 = InternalFileDevicePathsEqualClipNextNode (FilePath2, &Clip2Index);
|
|
} else if (Len1 < Len2) {
|
|
Len1 = InternalFileDevicePathsEqualClipNextNode (FilePath1, &Clip1Index);
|
|
if (Len1 == 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
Len2 -= CurrentLen;
|
|
Clip2Index += CurrentLen;
|
|
//
|
|
// Switching to the next node for the other Device Path implies a path
|
|
// separator. Verify we hit such in the currently walked path too.
|
|
//
|
|
Result = InternalFileDevicePathsEqualClipBottom (*FilePath2, &Len2, &Clip2Index);
|
|
if (!Result) {
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
Len2 = InternalFileDevicePathsEqualClipNextNode (FilePath2, &Clip2Index);
|
|
if (Len2 == 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
Len1 -= CurrentLen;
|
|
Clip1Index += CurrentLen;
|
|
//
|
|
// Switching to the next node for the other Device Path implies a path
|
|
// separator. Verify we hit such in the currently walked path too.
|
|
//
|
|
Result = InternalFileDevicePathsEqualClipBottom (*FilePath1, &Len1, &Clip1Index);
|
|
if (!Result) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
} while (TRUE);
|
|
}
|
|
|
|
/**
|
|
Check whether File Device Paths are equal.
|
|
|
|
@param[in] FilePath1 The first device path protocol to compare.
|
|
@param[in] FilePath2 The second device path protocol to compare.
|
|
|
|
@retval TRUE The device paths matched
|
|
@retval FALSE The device paths were different
|
|
**/
|
|
BOOLEAN
|
|
FileDevicePathsEqual (
|
|
IN FILEPATH_DEVICE_PATH *FilePath1,
|
|
IN FILEPATH_DEVICE_PATH *FilePath2
|
|
)
|
|
{
|
|
ASSERT (FilePath1 != NULL);
|
|
ASSERT (FilePath2 != NULL);
|
|
|
|
return InternalFileDevicePathsEqualWorker (&FilePath1, &FilePath2);
|
|
}
|
|
|
|
STATIC
|
|
BOOLEAN
|
|
InternalDevicePathCmpWorker (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *ParentPath,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *ChildPath,
|
|
IN BOOLEAN CheckChild
|
|
)
|
|
{
|
|
BOOLEAN Result;
|
|
INTN CmpResult;
|
|
|
|
EFI_DEV_PATH_PTR ChildPathPtr;
|
|
EFI_DEV_PATH_PTR ParentPathPtr;
|
|
|
|
UINT8 NodeType;
|
|
UINT8 NodeSubType;
|
|
UINTN NodeSize;
|
|
|
|
ASSERT (ParentPath != NULL);
|
|
ASSERT (IsDevicePathValid (ParentPath, 0));
|
|
ASSERT (ChildPath != NULL);
|
|
ASSERT (IsDevicePathValid (ChildPath, 0));
|
|
|
|
ParentPathPtr.DevPath = ParentPath;
|
|
ChildPathPtr.DevPath = ChildPath;
|
|
|
|
while (TRUE) {
|
|
NodeType = DevicePathType (ChildPathPtr.DevPath);
|
|
NodeSubType = DevicePathSubType (ChildPathPtr.DevPath);
|
|
|
|
if (NodeType == END_DEVICE_PATH_TYPE) {
|
|
//
|
|
// We only support single-instance Device Paths.
|
|
//
|
|
ASSERT (NodeSubType == END_ENTIRE_DEVICE_PATH_SUBTYPE);
|
|
return (CheckChild
|
|
|| (DevicePathType (ParentPathPtr.DevPath) == END_DEVICE_PATH_TYPE));
|
|
}
|
|
|
|
if ((DevicePathType (ParentPathPtr.DevPath) != NodeType)
|
|
|| (DevicePathSubType (ParentPathPtr.DevPath) != NodeSubType)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if ((NodeType == MEDIA_DEVICE_PATH)
|
|
&& (NodeSubType == MEDIA_FILEPATH_DP)) {
|
|
//
|
|
// File Paths need special consideration for prepended and appended
|
|
// terminators, as well as multiple nodes.
|
|
//
|
|
Result = InternalFileDevicePathsEqualWorker (
|
|
&ParentPathPtr.FilePath,
|
|
&ChildPathPtr.FilePath
|
|
);
|
|
if (!Result) {
|
|
return FALSE;
|
|
}
|
|
//
|
|
// InternalFileDevicePathsEqualWorker advances the nodes.
|
|
//
|
|
} else {
|
|
NodeSize = DevicePathNodeLength (ChildPathPtr.DevPath);
|
|
if (DevicePathNodeLength (ParentPathPtr.DevPath) != NodeSize) {
|
|
return FALSE;
|
|
}
|
|
|
|
OC_INLINE_STATIC_ASSERT (
|
|
(sizeof (*ChildPathPtr.DevPath) == 4),
|
|
"The Device Path comparison logic depends on the entire header being checked"
|
|
);
|
|
|
|
CmpResult = CompareMem (
|
|
(ChildPathPtr.DevPath + 1),
|
|
(ParentPathPtr.DevPath + 1),
|
|
(NodeSize - sizeof (*ChildPathPtr.DevPath))
|
|
);
|
|
if (CmpResult != 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
ParentPathPtr.DevPath = NextDevicePathNode (ParentPathPtr.DevPath);
|
|
ChildPathPtr.DevPath = NextDevicePathNode (ChildPathPtr.DevPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
EFIAPI
|
|
IsDevicePathEqual (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath1,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath2
|
|
)
|
|
{
|
|
return InternalDevicePathCmpWorker (DevicePath1, DevicePath2, FALSE);
|
|
}
|
|
|
|
BOOLEAN
|
|
EFIAPI
|
|
IsDevicePathChild (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *ParentPath,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *ChildPath
|
|
)
|
|
{
|
|
return InternalDevicePathCmpWorker (ParentPath, ChildPath, TRUE);
|
|
}
|
|
|
|
UINTN
|
|
OcFileDevicePathNameSize (
|
|
IN CONST FILEPATH_DEVICE_PATH *FilePath
|
|
)
|
|
{
|
|
ASSERT (FilePath != NULL);
|
|
ASSERT (IsDevicePathValid (&FilePath->Header, 0));
|
|
return (OcFileDevicePathNameLen (FilePath) + 1) * sizeof (*FilePath->PathName);
|
|
}
|
|
|
|
UINTN
|
|
OcFileDevicePathNameLen (
|
|
IN CONST FILEPATH_DEVICE_PATH *FilePath
|
|
)
|
|
{
|
|
UINTN Size;
|
|
UINTN Len;
|
|
|
|
ASSERT (FilePath != NULL);
|
|
ASSERT (IsDevicePathValid (&FilePath->Header, 0));
|
|
|
|
Size = DevicePathNodeLength (FilePath) - SIZE_OF_FILEPATH_DEVICE_PATH;
|
|
//
|
|
// Account for more than one termination character.
|
|
//
|
|
Len = (Size / sizeof (*FilePath->PathName)) - 1;
|
|
while (Len > 0 && FilePath->PathName[Len - 1] == L'\0') {
|
|
--Len;
|
|
}
|
|
|
|
return Len;
|
|
}
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *
|
|
OcAppendDevicePathInstanceDedupe (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL,
|
|
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePathInstance
|
|
)
|
|
{
|
|
INTN CmpResult;
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *DevPathWalker;
|
|
EFI_DEVICE_PATH_PROTOCOL *CurrentInstance;
|
|
|
|
UINTN AppendInstanceSize;
|
|
UINTN CurrentInstanceSize;
|
|
|
|
ASSERT (DevicePathInstance != NULL);
|
|
|
|
if (DevicePath != NULL) {
|
|
AppendInstanceSize = GetDevicePathSize (DevicePathInstance);
|
|
DevPathWalker = DevicePath;
|
|
|
|
while (TRUE) {
|
|
CurrentInstance = GetNextDevicePathInstance (
|
|
&DevPathWalker,
|
|
&CurrentInstanceSize
|
|
);
|
|
if (CurrentInstance == NULL) {
|
|
break;
|
|
}
|
|
|
|
if (CurrentInstanceSize != AppendInstanceSize) {
|
|
FreePool (CurrentInstance);
|
|
continue;
|
|
}
|
|
|
|
CmpResult = CompareMem (
|
|
CurrentInstance,
|
|
DevicePathInstance,
|
|
CurrentInstanceSize
|
|
);
|
|
|
|
FreePool (CurrentInstance);
|
|
|
|
if (CmpResult == 0) {
|
|
return DuplicateDevicePath (DevicePath);
|
|
}
|
|
}
|
|
}
|
|
|
|
return AppendDevicePathInstance (DevicePath, DevicePathInstance);
|
|
}
|
|
|
|
UINTN
|
|
OcGetNumDevicePathInstances (
|
|
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
|
)
|
|
{
|
|
UINTN NumInstances;
|
|
|
|
NumInstances = 1;
|
|
|
|
while (!IsDevicePathEnd (DevicePath)) {
|
|
if (IsDevicePathEndInstance (DevicePath)) {
|
|
++NumInstances;
|
|
}
|
|
|
|
DevicePath = NextDevicePathNode (DevicePath);
|
|
}
|
|
|
|
return NumInstances;
|
|
}
|