mirror of https://github.com/acidanthera/audk.git
Add support for BootOption with USB Class or USB WWID device path node.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11198 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
parent
84909ad446
commit
7389fdd0b8
|
@ -158,6 +158,421 @@ IsBootOptionValidNVVarialbe (
|
|||
|
||||
return Valid;
|
||||
}
|
||||
|
||||
/**
|
||||
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.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
BdsMatchUsbClass (
|
||||
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.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
BdsMatchUsbWwid (
|
||||
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 ParentDevicePath The device path of the parent.
|
||||
@param ShortFormDevicePath The USB Class or USB WWID device path to match.
|
||||
|
||||
@return The handle of matched USB device, or NULL if not found.
|
||||
|
||||
**/
|
||||
EFI_HANDLE *
|
||||
BdsFindUsbDevice (
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *ShortFormDevicePath
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN UsbIoHandleCount;
|
||||
EFI_HANDLE *UsbIoHandleBuffer;
|
||||
EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath;
|
||||
EFI_USB_IO_PROTOCOL *UsbIo;
|
||||
UINTN Index;
|
||||
UINTN ParentSize;
|
||||
UINTN Size;
|
||||
EFI_HANDLE ReturnHandle;
|
||||
|
||||
//
|
||||
// Get all UsbIo Handles.
|
||||
//
|
||||
UsbIoHandleCount = 0;
|
||||
UsbIoHandleBuffer = NULL;
|
||||
Status = gBS->LocateHandleBuffer (
|
||||
ByProtocol,
|
||||
&gEfiUsbIoProtocolGuid,
|
||||
NULL,
|
||||
&UsbIoHandleCount,
|
||||
&UsbIoHandleBuffer
|
||||
);
|
||||
if (EFI_ERROR (Status) || (UsbIoHandleCount == 0) || (UsbIoHandleBuffer == NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ReturnHandle = NULL;
|
||||
ParentSize = (ParentDevicePath == NULL) ? 0 : GetDevicePathSize (ParentDevicePath);
|
||||
for (Index = 0; Index < UsbIoHandleCount; Index++) {
|
||||
//
|
||||
// Get the Usb IO interface.
|
||||
//
|
||||
Status = gBS->HandleProtocol(
|
||||
UsbIoHandleBuffer[Index],
|
||||
&gEfiUsbIoProtocolGuid,
|
||||
(VOID **) &UsbIo
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ParentDevicePath != NULL) {
|
||||
//
|
||||
// Compare starting part of UsbIoHandle's device path with ParentDevicePath.
|
||||
//
|
||||
UsbIoDevicePath = DevicePathFromHandle (UsbIoHandleBuffer[Index]);
|
||||
ASSERT (UsbIoDevicePath != NULL);
|
||||
|
||||
Size = GetDevicePathSize (UsbIoDevicePath);
|
||||
if ((Size < ParentSize) ||
|
||||
(CompareMem (UsbIoDevicePath, ParentDevicePath, ParentSize - END_DEVICE_PATH_LENGTH) != 0)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (BdsMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ShortFormDevicePath) ||
|
||||
BdsMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ShortFormDevicePath)) {
|
||||
ReturnHandle = UsbIoHandleBuffer[Index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FreePool (UsbIoHandleBuffer);
|
||||
return ReturnHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
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 DevicePath The Boot Option device path.
|
||||
|
||||
@return The full device path after expanding, or NULL if there is no USB Class
|
||||
or USB WWID device path found, or USB Class or USB WWID device path
|
||||
was found but failed to expand it.
|
||||
|
||||
**/
|
||||
EFI_DEVICE_PATH_PROTOCOL *
|
||||
BdsExpandUsbShortFormDevicePath (
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
||||
)
|
||||
{
|
||||
EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
|
||||
EFI_HANDLE *UsbIoHandle;
|
||||
EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath;
|
||||
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
|
||||
EFI_DEVICE_PATH_PROTOCOL *NextDevicePath;
|
||||
EFI_DEVICE_PATH_PROTOCOL *ShortFormDevicePath;
|
||||
|
||||
//
|
||||
// Search for USB Class or USB WWID device path node.
|
||||
//
|
||||
ShortFormDevicePath = NULL;
|
||||
TempDevicePath = DevicePath;
|
||||
while (!IsDevicePathEnd (TempDevicePath)) {
|
||||
if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&
|
||||
((DevicePathSubType (TempDevicePath) == MSG_USB_CLASS_DP) ||
|
||||
(DevicePathSubType (TempDevicePath) == MSG_USB_WWID_DP))) {
|
||||
ShortFormDevicePath = TempDevicePath;
|
||||
break;
|
||||
}
|
||||
|
||||
TempDevicePath = NextDevicePathNode (TempDevicePath);
|
||||
}
|
||||
|
||||
if (ShortFormDevicePath == NULL) {
|
||||
//
|
||||
// No USB Class or USB WWID device path node found, do nothing.
|
||||
//
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ShortFormDevicePath == DevicePath) {
|
||||
//
|
||||
// Boot Option device path starts with USB Class or USB WWID device path.
|
||||
//
|
||||
UsbIoHandle = BdsFindUsbDevice (NULL, ShortFormDevicePath);
|
||||
if (UsbIoHandle == NULL) {
|
||||
//
|
||||
// Failed to find a match in existing devices, connect the short form USB
|
||||
// device path and try again.
|
||||
//
|
||||
BdsLibConnectUsbDevByShortFormDP (0xff, ShortFormDevicePath);
|
||||
UsbIoHandle = BdsFindUsbDevice (NULL, ShortFormDevicePath);
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// Boot Option device path contains USB Class or USB WWID device path node.
|
||||
//
|
||||
|
||||
//
|
||||
// Prepare the parent device path for search.
|
||||
//
|
||||
TempDevicePath = DuplicateDevicePath (DevicePath);
|
||||
ASSERT (TempDevicePath != NULL);
|
||||
SetDevicePathEndNode (((UINT8 *) TempDevicePath) + ((UINTN) ShortFormDevicePath - (UINTN) DevicePath));
|
||||
|
||||
//
|
||||
// The USB Host Controller device path is in already in Boot Option device path
|
||||
// and USB Bus driver already support RemainingDevicePath starts with USB
|
||||
// Class or USB WWID device path, so just search in existing USB devices and
|
||||
// doesn't perform ConnectController here.
|
||||
//
|
||||
UsbIoHandle = BdsFindUsbDevice (TempDevicePath, ShortFormDevicePath);
|
||||
FreePool (TempDevicePath);
|
||||
}
|
||||
|
||||
if (UsbIoHandle == NULL) {
|
||||
//
|
||||
// Failed to expand USB Class or USB WWID device path.
|
||||
//
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Get device path of the matched USB device.
|
||||
//
|
||||
UsbIoDevicePath = DevicePathFromHandle (UsbIoHandle);
|
||||
ASSERT (UsbIoDevicePath != NULL);
|
||||
|
||||
FullDevicePath = NULL;
|
||||
//
|
||||
// Advance to next device path node to skip the USB Class or USB WWID device path.
|
||||
//
|
||||
NextDevicePath = NextDevicePathNode (ShortFormDevicePath);
|
||||
if (!IsDevicePathEnd (NextDevicePath)) {
|
||||
//
|
||||
// There is remaining device path after USB Class or USB WWID device path
|
||||
// node, append it to the USB device path.
|
||||
//
|
||||
FullDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePath);
|
||||
|
||||
//
|
||||
// Connect the full device path, so that Simple File System protocol
|
||||
// could be installed for this USB device.
|
||||
//
|
||||
BdsLibConnectDevicePath (FullDevicePath);
|
||||
} else {
|
||||
//
|
||||
// USB Class or WWID device path is in the end.
|
||||
//
|
||||
FullDevicePath = UsbIoDevicePath;
|
||||
}
|
||||
|
||||
return FullDevicePath;
|
||||
}
|
||||
|
||||
/**
|
||||
Process the boot option follow the UEFI specification and
|
||||
special treat the legacy boot option with BBS_DEVICE_PATH.
|
||||
|
@ -222,6 +637,15 @@ BdsLibBootViaBootOption (
|
|||
DevicePath = WorkingDevicePath;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Expand USB Class or USB WWID drive path node to full device path.
|
||||
//
|
||||
WorkingDevicePath = BdsExpandUsbShortFormDevicePath (DevicePath);
|
||||
if (WorkingDevicePath != NULL) {
|
||||
DevicePath = WorkingDevicePath;
|
||||
}
|
||||
|
||||
//
|
||||
// Signal the EVT_SIGNAL_READY_TO_BOOT event
|
||||
//
|
||||
|
@ -1882,8 +2306,19 @@ BdsLibIsValidEFIBootOptDevicePathExt (
|
|||
// and assume it is ready to boot now
|
||||
//
|
||||
while (!IsDevicePathEnd (TempDevicePath)) {
|
||||
LastDeviceNode = TempDevicePath;
|
||||
TempDevicePath = NextDevicePathNode (TempDevicePath);
|
||||
//
|
||||
// If there is USB Class or USB WWID device path node, treat it as valid EFI
|
||||
// Boot Option. BdsExpandUsbShortFormDevicePath () will be used to expand it
|
||||
// to full device path.
|
||||
//
|
||||
if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&
|
||||
((DevicePathSubType (TempDevicePath) == MSG_USB_CLASS_DP) ||
|
||||
(DevicePathSubType (TempDevicePath) == MSG_USB_WWID_DP))) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
LastDeviceNode = TempDevicePath;
|
||||
TempDevicePath = NextDevicePathNode (TempDevicePath);
|
||||
}
|
||||
if ((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) &&
|
||||
(DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) {
|
||||
|
|
|
@ -111,6 +111,7 @@
|
|||
gEfiOEMBadgingProtocolGuid # PROTOCOL CONSUMES
|
||||
gEfiHiiFontProtocolGuid # PROTOCOL CONSUMES
|
||||
gEfiUserManagerProtocolGuid # PROTOCOL CONSUMES
|
||||
gEfiUsbIoProtocolGuid # PROTOCOL SOMETIMES_CONSUMES
|
||||
|
||||
[FeaturePcd]
|
||||
gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport
|
||||
|
|
|
@ -40,6 +40,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||
#include <Protocol/UgaDraw.h>
|
||||
#include <Protocol/HiiFont.h>
|
||||
#include <Protocol/HiiImage.h>
|
||||
#include <Protocol/UsbIo.h>
|
||||
|
||||
#include <Guid/MemoryTypeInformation.h>
|
||||
#include <Guid/FileInfo.h>
|
||||
|
|
Loading…
Reference in New Issue