mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-23 11:35:19 +01:00
cd23181296
Signed-off-by: SergeySlice <sergey.slice@gmail.com>
903 lines
28 KiB
C
903 lines
28 KiB
C
/** @file
|
|
Library functions which relates with booting.
|
|
|
|
Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR>
|
|
(C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include <Uefi.h>
|
|
|
|
#include <IndustryStandard/Pci.h>
|
|
|
|
#include <Guid/Gpt.h>
|
|
|
|
#include <Protocol/BlockIo.h>
|
|
#include <Protocol/LoadFile.h>
|
|
#include <Protocol/PciIo.h>
|
|
#include <Protocol/SimpleFileSystem.h>
|
|
#include <Protocol/UsbIo.h>
|
|
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/DevicePathLib.h>
|
|
#include <Library/OcDevicePathLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/OcFileLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
|
|
// CHANGE: Track InternalConnectAll() execution status.
|
|
STATIC BOOLEAN mConnectAllExecuted = FALSE;
|
|
|
|
// CHANGE: Added from UefiBootManagerLib
|
|
/**
|
|
Connect all the drivers to all the controllers.
|
|
|
|
This function makes sure all the current system drivers manage the correspoinding
|
|
controllers if have. And at the same time, makes sure all the system controllers
|
|
have driver to manage it if have.
|
|
**/
|
|
VOID
|
|
InternalConnectAll (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN HandleCount;
|
|
EFI_HANDLE *HandleBuffer;
|
|
UINTN Index;
|
|
|
|
// CHANGE: Report execution status.
|
|
mConnectAllExecuted = TRUE;
|
|
|
|
//
|
|
// Connect All EFI 1.10 drivers following EFI 1.10 algorithm
|
|
// CHANGE: Only connect device handles. Do not call gDS->Dispatch().
|
|
//
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiDevicePathProtocolGuid,
|
|
NULL,
|
|
&HandleCount,
|
|
&HandleBuffer
|
|
);
|
|
if (!EFI_ERROR(Status)) {
|
|
for (Index = 0; Index < HandleCount; Index++) {
|
|
gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
|
|
}
|
|
|
|
FreePool (HandleBuffer);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Check whether a USB device match the specified USB Class device path. This
|
|
function follows "Load Option Processing" behavior in UEFI specification.
|
|
|
|
@param UsbIo USB I/O protocol associated with the USB device.
|
|
@param UsbClass The USB Class device path to match.
|
|
|
|
@retval TRUE The USB device match the USB Class device path.
|
|
@retval FALSE The USB device does not match the USB Class device path.
|
|
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
BmMatchUsbClass (
|
|
IN EFI_USB_IO_PROTOCOL *UsbIo,
|
|
IN USB_CLASS_DEVICE_PATH *UsbClass
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_USB_DEVICE_DESCRIPTOR DevDesc;
|
|
EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
|
|
UINT8 DeviceClass;
|
|
UINT8 DeviceSubClass;
|
|
UINT8 DeviceProtocol;
|
|
|
|
if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) ||
|
|
(DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP)){
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Check Vendor Id and Product Id.
|
|
//
|
|
Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
|
|
if (EFI_ERROR(Status)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if ((UsbClass->VendorId != 0xffff) &&
|
|
(UsbClass->VendorId != DevDesc.IdVendor)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if ((UsbClass->ProductId != 0xffff) &&
|
|
(UsbClass->ProductId != DevDesc.IdProduct)) {
|
|
return FALSE;
|
|
}
|
|
|
|
DeviceClass = DevDesc.DeviceClass;
|
|
DeviceSubClass = DevDesc.DeviceSubClass;
|
|
DeviceProtocol = DevDesc.DeviceProtocol;
|
|
if (DeviceClass == 0) {
|
|
//
|
|
// If Class in Device Descriptor is set to 0, use the Class, SubClass and
|
|
// Protocol in Interface Descriptor instead.
|
|
//
|
|
Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
|
|
if (EFI_ERROR(Status)) {
|
|
return FALSE;
|
|
}
|
|
|
|
DeviceClass = IfDesc.InterfaceClass;
|
|
DeviceSubClass = IfDesc.InterfaceSubClass;
|
|
DeviceProtocol = IfDesc.InterfaceProtocol;
|
|
}
|
|
|
|
//
|
|
// Check Class, SubClass and Protocol.
|
|
//
|
|
if ((UsbClass->DeviceClass != 0xff) &&
|
|
(UsbClass->DeviceClass != DeviceClass)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if ((UsbClass->DeviceSubClass != 0xff) &&
|
|
(UsbClass->DeviceSubClass != DeviceSubClass)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if ((UsbClass->DeviceProtocol != 0xff) &&
|
|
(UsbClass->DeviceProtocol != DeviceProtocol)) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
Check whether a USB device match the specified USB WWID device path. This
|
|
function follows "Load Option Processing" behavior in UEFI specification.
|
|
|
|
@param UsbIo USB I/O protocol associated with the USB device.
|
|
@param UsbWwid The USB WWID device path to match.
|
|
|
|
@retval TRUE The USB device match the USB WWID device path.
|
|
@retval FALSE The USB device does not match the USB WWID device path.
|
|
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
BmMatchUsbWwid (
|
|
IN EFI_USB_IO_PROTOCOL *UsbIo,
|
|
IN USB_WWID_DEVICE_PATH *UsbWwid
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_USB_DEVICE_DESCRIPTOR DevDesc;
|
|
EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
|
|
UINT16 *LangIdTable;
|
|
UINT16 TableSize;
|
|
UINT16 Index;
|
|
CHAR16 *CompareStr;
|
|
UINTN CompareLen;
|
|
CHAR16 *SerialNumberStr;
|
|
UINTN Length;
|
|
|
|
if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) ||
|
|
(DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Check Vendor Id and Product Id.
|
|
//
|
|
Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
|
|
if (EFI_ERROR(Status)) {
|
|
return FALSE;
|
|
}
|
|
if ((DevDesc.IdVendor != UsbWwid->VendorId) ||
|
|
(DevDesc.IdProduct != UsbWwid->ProductId)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Check Interface Number.
|
|
//
|
|
Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
|
|
if (EFI_ERROR(Status)) {
|
|
return FALSE;
|
|
}
|
|
if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Check Serial Number.
|
|
//
|
|
if (DevDesc.StrSerialNumber == 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Get all supported languages.
|
|
//
|
|
TableSize = 0;
|
|
LangIdTable = NULL;
|
|
Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize);
|
|
if (EFI_ERROR(Status) || (TableSize == 0) || (LangIdTable == NULL)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
|
|
//
|
|
CompareStr = (CHAR16 *) (UINTN) (UsbWwid + 1);
|
|
CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16);
|
|
if (CompareStr[CompareLen - 1] == L'\0') {
|
|
CompareLen--;
|
|
}
|
|
|
|
//
|
|
// Compare serial number in each supported language.
|
|
//
|
|
for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) {
|
|
SerialNumberStr = NULL;
|
|
Status = UsbIo->UsbGetStringDescriptor (
|
|
UsbIo,
|
|
LangIdTable[Index],
|
|
DevDesc.StrSerialNumber,
|
|
&SerialNumberStr
|
|
);
|
|
if (EFI_ERROR(Status) || (SerialNumberStr == NULL)) {
|
|
continue;
|
|
}
|
|
|
|
Length = StrLen (SerialNumberStr);
|
|
if ((Length >= CompareLen) &&
|
|
(CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) {
|
|
FreePool (SerialNumberStr);
|
|
return TRUE;
|
|
}
|
|
|
|
FreePool (SerialNumberStr);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Find a USB device which match the specified short-form device path start with
|
|
USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
|
|
will search in all USB devices of the platform. If ParentDevicePath is not NULL,
|
|
this function will only search in its child devices.
|
|
|
|
@param DevicePath The device path that contains USB Class or USB WWID device path.
|
|
@param ParentDevicePathSize The length of the device path before the USB Class or
|
|
USB WWID device path.
|
|
@param UsbIoHandleCount A pointer to the count of the returned USB IO handles.
|
|
|
|
@retval NULL The matched USB IO handles cannot be found.
|
|
@retval other The matched USB IO handles.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_HANDLE *
|
|
BmFindUsbDevice (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
|
|
IN UINTN ParentDevicePathSize,
|
|
OUT UINTN *UsbIoHandleCount
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE *UsbIoHandles;
|
|
EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath;
|
|
EFI_USB_IO_PROTOCOL *UsbIo;
|
|
UINTN Index;
|
|
BOOLEAN Matched;
|
|
|
|
ASSERT (UsbIoHandleCount != NULL);
|
|
|
|
//
|
|
// Get all UsbIo Handles.
|
|
//
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiUsbIoProtocolGuid,
|
|
NULL,
|
|
UsbIoHandleCount,
|
|
&UsbIoHandles
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
*UsbIoHandleCount = 0;
|
|
UsbIoHandles = NULL;
|
|
}
|
|
|
|
for (Index = 0; Index < *UsbIoHandleCount; ) {
|
|
//
|
|
// Get the Usb IO interface.
|
|
//
|
|
Status = gBS->HandleProtocol(
|
|
UsbIoHandles[Index],
|
|
&gEfiUsbIoProtocolGuid,
|
|
(VOID **) &UsbIo
|
|
);
|
|
UsbIoDevicePath = DevicePathFromHandle (UsbIoHandles[Index]);
|
|
Matched = FALSE;
|
|
if (!EFI_ERROR(Status) && (UsbIoDevicePath != NULL)) {
|
|
|
|
//
|
|
// Compare starting part of UsbIoHandle's device path with ParentDevicePath.
|
|
//
|
|
if (CompareMem (UsbIoDevicePath, DevicePath, ParentDevicePathSize) == 0) {
|
|
if (BmMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize)) ||
|
|
BmMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize))) {
|
|
Matched = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!Matched) {
|
|
(*UsbIoHandleCount) --;
|
|
CopyMem (&UsbIoHandles[Index], &UsbIoHandles[Index + 1], (*UsbIoHandleCount - Index) * sizeof (EFI_HANDLE));
|
|
} else {
|
|
Index++;
|
|
}
|
|
}
|
|
|
|
return UsbIoHandles;
|
|
}
|
|
|
|
/**
|
|
Expand USB Class or USB WWID device path node to be full device path of a USB
|
|
device in platform.
|
|
|
|
This function support following 4 cases:
|
|
1) Boot Option device path starts with a USB Class or USB WWID device path,
|
|
and there is no Media FilePath device path in the end.
|
|
In this case, it will follow Removable Media Boot Behavior.
|
|
2) Boot Option device path starts with a USB Class or USB WWID device path,
|
|
and ended with Media FilePath device path.
|
|
3) Boot Option device path starts with a full device path to a USB Host Controller,
|
|
contains a USB Class or USB WWID device path node, while not ended with Media
|
|
FilePath device path. In this case, it will follow Removable Media Boot Behavior.
|
|
4) Boot Option device path starts with a full device path to a USB Host Controller,
|
|
contains a USB Class or USB WWID device path node, and ended with Media
|
|
FilePath device path.
|
|
|
|
@param FilePath The device path pointing to a load option.
|
|
It could be a short-form device path.
|
|
@param FullPath The full path returned by the routine in last call.
|
|
Set to NULL in first call.
|
|
@param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
|
|
|
|
@return The next possible full path pointing to the load option.
|
|
Caller is responsible to free the memory.
|
|
**/
|
|
STATIC
|
|
EFI_DEVICE_PATH_PROTOCOL *
|
|
BmExpandUsbDevicePath (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *FullPath,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *ShortformNode
|
|
)
|
|
{
|
|
UINTN ParentDevicePathSize;
|
|
EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
|
|
EFI_HANDLE *Handles;
|
|
UINTN HandleCount;
|
|
UINTN Index;
|
|
BOOLEAN GetNext;
|
|
|
|
NextFullPath = NULL;
|
|
GetNext = (BOOLEAN)(FullPath == NULL);
|
|
ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) FilePath;
|
|
RemainingDevicePath = NextDevicePathNode (ShortformNode);
|
|
Handles = BmFindUsbDevice (FilePath, ParentDevicePathSize, &HandleCount);
|
|
|
|
for (Index = 0; Index < HandleCount; Index++) {
|
|
FilePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);
|
|
if (FilePath == NULL) {
|
|
//
|
|
// Out of memory.
|
|
//
|
|
continue;
|
|
}
|
|
NextFullPath = OcGetNextLoadOptionDevicePath (FilePath, NULL);
|
|
FreePool (FilePath);
|
|
if (NextFullPath == NULL) {
|
|
//
|
|
// No BlockIo or SimpleFileSystem under FilePath.
|
|
//
|
|
continue;
|
|
}
|
|
if (GetNext) {
|
|
break;
|
|
} else {
|
|
GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
|
|
FreePool (NextFullPath);
|
|
NextFullPath = NULL;
|
|
}
|
|
}
|
|
|
|
if (Handles != NULL) {
|
|
FreePool (Handles);
|
|
}
|
|
|
|
return NextFullPath;
|
|
}
|
|
|
|
/**
|
|
Expand the media device path which points to a BlockIo or SimpleFileSystem instance.
|
|
|
|
@param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
|
|
@param FullPath The full path returned by the routine in last call.
|
|
Set to NULL in first call.
|
|
|
|
@return The next possible full path pointing to the load option.
|
|
Caller is responsible to free the memory.
|
|
**/
|
|
STATIC
|
|
EFI_DEVICE_PATH_PROTOCOL *
|
|
BmExpandMediaDevicePath (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *FullPath,
|
|
IN EFI_HANDLE Handle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
|
VOID *Buffer;
|
|
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
|
|
UINTN Size;
|
|
UINTN TempSize;
|
|
EFI_HANDLE *SimpleFileSystemHandles;
|
|
UINTN NumberSimpleFileSystemHandles;
|
|
UINTN Index;
|
|
BOOLEAN GetNext;
|
|
|
|
GetNext = (BOOLEAN)(FullPath == NULL);
|
|
//
|
|
// Check whether the device is connected
|
|
// CHANGE: This branch has been removed as it has been covered by a caller change
|
|
//
|
|
|
|
// CHANGE: Get Handle via parameter as the function is called by the caller too
|
|
|
|
//
|
|
// For device boot option only pointing to the removable device handle,
|
|
// should make sure all its children handles (its child partion or media handles)
|
|
// are created and connected.
|
|
//
|
|
gBS->ConnectController (Handle, NULL, NULL, TRUE);
|
|
|
|
//
|
|
// Issue a dummy read to the device to check for media change.
|
|
// When the removable media is changed, any Block IO read/write will
|
|
// cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
|
|
// returned. After the Block IO protocol is reinstalled, subsequent
|
|
// Block IO read/write will success.
|
|
//
|
|
Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
|
|
// CHANGE: Do not ASSERT.
|
|
if (EFI_ERROR(Status)) {
|
|
return NULL;
|
|
}
|
|
Buffer = AllocatePool (BlockIo->Media->BlockSize);
|
|
if (Buffer != NULL) {
|
|
BlockIo->ReadBlocks (
|
|
BlockIo,
|
|
BlockIo->Media->MediaId,
|
|
0,
|
|
BlockIo->Media->BlockSize,
|
|
Buffer
|
|
);
|
|
FreePool (Buffer);
|
|
}
|
|
|
|
//
|
|
// Detect the the default boot file from removable Media
|
|
//
|
|
NextFullPath = NULL;
|
|
Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;
|
|
gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiSimpleFileSystemProtocolGuid,
|
|
NULL,
|
|
&NumberSimpleFileSystemHandles,
|
|
&SimpleFileSystemHandles
|
|
);
|
|
for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
|
|
//
|
|
// Get the device path size of SimpleFileSystem handle
|
|
//
|
|
TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
|
|
TempSize = GetDevicePathSize (TempDevicePath) - END_DEVICE_PATH_LENGTH;
|
|
//
|
|
// Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
|
|
//
|
|
if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) {
|
|
// CHANGE: Do not append EFI boot file.
|
|
NextFullPath = DuplicateDevicePath (TempDevicePath);
|
|
if (GetNext) {
|
|
break;
|
|
} else {
|
|
GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
|
|
FreePool (NextFullPath);
|
|
NextFullPath = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SimpleFileSystemHandles != NULL) {
|
|
FreePool (SimpleFileSystemHandles);
|
|
}
|
|
|
|
return NextFullPath;
|
|
}
|
|
|
|
/**
|
|
Check whether there is a instance in BlockIoDevicePath, which contain multi device path
|
|
instances, has the same partition node with HardDriveDevicePath device path
|
|
|
|
@param Handle The partition's device handle
|
|
@param BlockIoDevicePath Multi device path instances which need to check
|
|
@param HardDriveDevicePath A device path which starts with a hard drive media
|
|
device path.
|
|
@param LocateEsp Use ESP- instead of PartitionNumber-matching.
|
|
|
|
@retval TRUE There is a matched device path instance.
|
|
@retval FALSE There is no matched device path instance.
|
|
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
BmMatchPartitionDevicePathNode (
|
|
IN EFI_HANDLE Handle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
|
|
IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath,
|
|
IN BOOLEAN LocateEsp
|
|
)
|
|
{
|
|
HARDDRIVE_DEVICE_PATH *Node;
|
|
CONST EFI_PARTITION_ENTRY *PartEntry;
|
|
|
|
if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
|
|
return FALSE;
|
|
}
|
|
|
|
// CHANGE: Abort early if partition cannot be an ESP while it was requested.
|
|
if (LocateEsp
|
|
&& (HardDriveDevicePath->MBRType != MBR_TYPE_EFI_PARTITION_TABLE_HEADER
|
|
|| HardDriveDevicePath->SignatureType != SIGNATURE_TYPE_GUID)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Match all the partition device path nodes including the nested partition nodes
|
|
//
|
|
while (!IsDevicePathEnd (BlockIoDevicePath)) {
|
|
if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) &&
|
|
(DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP)
|
|
) {
|
|
//
|
|
// See if the harddrive device path in blockio matches the orig Hard Drive Node
|
|
//
|
|
Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;
|
|
|
|
//
|
|
// Match Signature and PartitionNumber.
|
|
// Unused bytes in Signature are initiaized with zeros.
|
|
//
|
|
if ((Node->MBRType == HardDriveDevicePath->MBRType) &&
|
|
(Node->SignatureType == HardDriveDevicePath->SignatureType) &&
|
|
(CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0)) {
|
|
// CHANGE: Allow ESP location when PartitionNumber mismatches.
|
|
if (!LocateEsp) {
|
|
if (Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) {
|
|
return TRUE;
|
|
}
|
|
} else {
|
|
PartEntry = OcGetGptPartitionEntry (Handle);
|
|
if (PartEntry != NULL
|
|
&& CompareGuid (&PartEntry->PartitionTypeGUID, &gEfiPartTypeSystemPartGuid)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Expand a device path that starts with a hard drive media device path node to be a
|
|
full device path that includes the full hardware path to the device. We need
|
|
to do this so it can be booted. As an optimization the front match (the part point
|
|
to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
|
|
so a connect all is not required on every boot. All successful history device path
|
|
which point to partition node (the front part) will be saved.
|
|
|
|
@param FilePath The device path pointing to a load option.
|
|
It could be a short-form device path.
|
|
|
|
@return The full device path pointing to the load option.
|
|
**/
|
|
STATIC
|
|
EFI_DEVICE_PATH_PROTOCOL *
|
|
BmExpandPartitionDevicePath (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *FilePath
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN BlockIoHandleCount;
|
|
EFI_HANDLE *BlockIoBuffer;
|
|
EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
|
|
UINTN Index;
|
|
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *FullPath;
|
|
BOOLEAN LocateEsp;
|
|
|
|
// CHANGE: Remove HDDP variable code.
|
|
|
|
FullPath = NULL;
|
|
//
|
|
// If we get here we fail to find or 'HDDP' not exist, and now we need
|
|
// to search all devices in the system for a matched partition
|
|
//
|
|
// CHANGE: Only connect all on failure.
|
|
//
|
|
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
|
|
if (EFI_ERROR(Status)) {
|
|
BlockIoHandleCount = 0;
|
|
BlockIoBuffer = NULL;
|
|
}
|
|
//
|
|
// Loop through all the device handles that support the BLOCK_IO Protocol
|
|
// CHANGE: Locate ESP when failing to find an exact match
|
|
//
|
|
LocateEsp = FALSE;
|
|
do {
|
|
for (Index = 0; Index < BlockIoHandleCount; Index++) {
|
|
BlockIoDevicePath = DevicePathFromHandle (BlockIoBuffer[Index]);
|
|
if (BlockIoDevicePath == NULL) {
|
|
continue;
|
|
}
|
|
|
|
if (BmMatchPartitionDevicePathNode (BlockIoBuffer[Index], BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *) FilePath, LocateEsp)) {
|
|
//
|
|
// Find the matched partition device path
|
|
//
|
|
TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath));
|
|
FullPath = OcGetNextLoadOptionDevicePath (TempDevicePath, NULL);
|
|
FreePool (TempDevicePath);
|
|
|
|
if (FullPath != NULL) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FullPath != NULL) {
|
|
break;
|
|
}
|
|
|
|
if (!mConnectAllExecuted) {
|
|
InternalConnectAll ();
|
|
FullPath = BmExpandPartitionDevicePath (FilePath);
|
|
break;
|
|
}
|
|
|
|
if (LocateEsp) {
|
|
break;
|
|
}
|
|
LocateEsp = TRUE;
|
|
} while (TRUE);
|
|
|
|
if (BlockIoBuffer != NULL) {
|
|
FreePool (BlockIoBuffer);
|
|
}
|
|
|
|
return FullPath;
|
|
}
|
|
|
|
/**
|
|
Connect the specific Usb device which match the short form device path,
|
|
and whose bus is determined by Host Controller (Uhci or Ehci).
|
|
|
|
@param DevicePath A short-form device path that starts with the first
|
|
element being a USB WWID or a USB Class device
|
|
path
|
|
|
|
@return EFI_INVALID_PARAMETER DevicePath is NULL pointer.
|
|
DevicePath is not a USB device path.
|
|
|
|
@return EFI_SUCCESS Success to connect USB device
|
|
@return EFI_NOT_FOUND Fail to find handle for USB controller to connect.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
BmConnectUsbShortFormDevicePath (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE *Handles;
|
|
UINTN HandleCount;
|
|
UINTN Index;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
UINT8 Class[3];
|
|
BOOLEAN AtLeastOneConnected;
|
|
|
|
//
|
|
// Check the passed in parameters
|
|
//
|
|
if (DevicePath == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH) ||
|
|
((DevicePathSubType (DevicePath) != MSG_USB_CLASS_DP) && (DevicePathSubType (DevicePath) != MSG_USB_WWID_DP))
|
|
) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Find the usb host controller firstly, then connect with the remaining device path
|
|
//
|
|
AtLeastOneConnected = FALSE;
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiPciIoProtocolGuid,
|
|
NULL,
|
|
&HandleCount,
|
|
&Handles
|
|
);
|
|
if (!EFI_ERROR(Status)) {
|
|
for (Index = 0; Index < HandleCount; Index++) {
|
|
Status = gBS->HandleProtocol (
|
|
Handles[Index],
|
|
&gEfiPciIoProtocolGuid,
|
|
(VOID **) &PciIo
|
|
);
|
|
if (!EFI_ERROR(Status)) {
|
|
//
|
|
// Check whether the Pci device is the wanted usb host controller
|
|
//
|
|
Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 3, &Class);
|
|
if (!EFI_ERROR(Status) &&
|
|
((PCI_CLASS_SERIAL == Class[2]) && (PCI_CLASS_SERIAL_USB == Class[1]))
|
|
) {
|
|
Status = gBS->ConnectController (
|
|
Handles[Index],
|
|
NULL,
|
|
DevicePath,
|
|
FALSE
|
|
);
|
|
if (!EFI_ERROR(Status)) {
|
|
AtLeastOneConnected = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Handles != NULL) {
|
|
FreePool (Handles);
|
|
}
|
|
}
|
|
|
|
return AtLeastOneConnected ? EFI_SUCCESS : EFI_NOT_FOUND;
|
|
}
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *
|
|
OcGetNextLoadOptionDevicePath (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *FullPath
|
|
)
|
|
{
|
|
EFI_HANDLE Handle;
|
|
EFI_DEVICE_PATH_PROTOCOL *Node;
|
|
EFI_STATUS Status;
|
|
|
|
ASSERT (FilePath != NULL);
|
|
|
|
//
|
|
// CHANGE: If SimpleFileSystem is located, the device path is already expanded.
|
|
//
|
|
Node = FilePath;
|
|
Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);
|
|
if (!EFI_ERROR(Status)) {
|
|
if (FullPath != NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
return DuplicateDevicePath (FilePath);
|
|
}
|
|
|
|
Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &Node, &Handle);
|
|
if (!EFI_ERROR(Status) && IsDevicePathEnd (Node)) {
|
|
return BmExpandMediaDevicePath (FilePath, FullPath, Handle);
|
|
}
|
|
|
|
// CHANGE: File Path node support removed.
|
|
|
|
//
|
|
// Expand the short-form device path to full device path
|
|
//
|
|
if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
|
|
(DevicePathSubType (FilePath) == MEDIA_HARDDRIVE_DP)) {
|
|
//
|
|
// Expand the Harddrive device path
|
|
//
|
|
if (FullPath == NULL) {
|
|
return BmExpandPartitionDevicePath (FilePath);
|
|
} else {
|
|
return NULL;
|
|
}
|
|
} else if ((DevicePathType (FilePath) == MESSAGING_DEVICE_PATH) &&
|
|
(DevicePathSubType (FilePath) == MSG_URI_DP)) {
|
|
//
|
|
// CHANGE: Removed expansion of the URI device path
|
|
//
|
|
return NULL;
|
|
} else {
|
|
Node = FilePath;
|
|
Status = gBS->LocateDevicePath (&gEfiUsbIoProtocolGuid, &Node, &Handle);
|
|
if (EFI_ERROR(Status)) {
|
|
//
|
|
// Only expand the USB WWID/Class device path
|
|
// when FilePath doesn't point to a physical UsbIo controller.
|
|
// Otherwise, infinite recursion will happen.
|
|
//
|
|
for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {
|
|
if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&
|
|
((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP))) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Expand the USB WWID/Class device path
|
|
//
|
|
if (!IsDevicePathEnd (Node)) {
|
|
if (FilePath == Node) {
|
|
//
|
|
// Boot Option device path starts with USB Class or USB WWID device path.
|
|
// For Boot Option device path which doesn't begin with the USB Class or
|
|
// USB WWID device path, it's not needed to connect again here.
|
|
//
|
|
BmConnectUsbShortFormDevicePath (FilePath);
|
|
}
|
|
return BmExpandUsbDevicePath (FilePath, FullPath, Node);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// For the below cases, FilePath only expands to one Full path.
|
|
// So just handle the case when FullPath == NULL.
|
|
//
|
|
if (FullPath != NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
// CHANGE: SimleFileSystem case has been covered at the beginning of the function
|
|
|
|
// CHANGE: Removed FV support.
|
|
|
|
//
|
|
// CHANGE: Remove LoadFile support (e.g. PXE network boot).
|
|
//
|
|
return NULL;
|
|
}
|