\r
return Valid;\r
}\r
+\r
+/**\r
+ Check whether a USB device match the specified USB Class device path. This\r
+ function follows "Load Option Processing" behavior in UEFI specification.\r
+\r
+ @param UsbIo USB I/O protocol associated with the USB device.\r
+ @param UsbClass The USB Class device path to match.\r
+\r
+ @retval TRUE The USB device match the USB Class device path.\r
+ @retval FALSE The USB device does not match the USB Class device path.\r
+\r
+**/\r
+BOOLEAN\r
+BdsMatchUsbClass (\r
+ IN EFI_USB_IO_PROTOCOL *UsbIo,\r
+ IN USB_CLASS_DEVICE_PATH *UsbClass\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_USB_DEVICE_DESCRIPTOR DevDesc;\r
+ EFI_USB_INTERFACE_DESCRIPTOR IfDesc;\r
+ UINT8 DeviceClass;\r
+ UINT8 DeviceSubClass;\r
+ UINT8 DeviceProtocol;\r
+\r
+ if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) ||\r
+ (DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP)){\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Check Vendor Id and Product Id.\r
+ //\r
+ Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+\r
+ if ((UsbClass->VendorId != 0xffff) &&\r
+ (UsbClass->VendorId != DevDesc.IdVendor)) {\r
+ return FALSE;\r
+ }\r
+\r
+ if ((UsbClass->ProductId != 0xffff) &&\r
+ (UsbClass->ProductId != DevDesc.IdProduct)) {\r
+ return FALSE;\r
+ }\r
+\r
+ DeviceClass = DevDesc.DeviceClass;\r
+ DeviceSubClass = DevDesc.DeviceSubClass;\r
+ DeviceProtocol = DevDesc.DeviceProtocol;\r
+ if (DeviceClass == 0) {\r
+ //\r
+ // If Class in Device Descriptor is set to 0, use the Class, SubClass and\r
+ // Protocol in Interface Descriptor instead.\r
+ //\r
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+\r
+ DeviceClass = IfDesc.InterfaceClass;\r
+ DeviceSubClass = IfDesc.InterfaceSubClass;\r
+ DeviceProtocol = IfDesc.InterfaceProtocol;\r
+ }\r
+\r
+ //\r
+ // Check Class, SubClass and Protocol.\r
+ //\r
+ if ((UsbClass->DeviceClass != 0xff) &&\r
+ (UsbClass->DeviceClass != DeviceClass)) {\r
+ return FALSE;\r
+ }\r
+\r
+ if ((UsbClass->DeviceSubClass != 0xff) &&\r
+ (UsbClass->DeviceSubClass != DeviceSubClass)) {\r
+ return FALSE;\r
+ }\r
+\r
+ if ((UsbClass->DeviceProtocol != 0xff) &&\r
+ (UsbClass->DeviceProtocol != DeviceProtocol)) {\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Check whether a USB device match the specified USB WWID device path. This\r
+ function follows "Load Option Processing" behavior in UEFI specification.\r
+\r
+ @param UsbIo USB I/O protocol associated with the USB device.\r
+ @param UsbWwid The USB WWID device path to match.\r
+\r
+ @retval TRUE The USB device match the USB WWID device path.\r
+ @retval FALSE The USB device does not match the USB WWID device path.\r
+\r
+**/\r
+BOOLEAN\r
+BdsMatchUsbWwid (\r
+ IN EFI_USB_IO_PROTOCOL *UsbIo,\r
+ IN USB_WWID_DEVICE_PATH *UsbWwid\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_USB_DEVICE_DESCRIPTOR DevDesc;\r
+ EFI_USB_INTERFACE_DESCRIPTOR IfDesc;\r
+ UINT16 *LangIdTable;\r
+ UINT16 TableSize;\r
+ UINT16 Index;\r
+ CHAR16 *CompareStr;\r
+ UINTN CompareLen;\r
+ CHAR16 *SerialNumberStr;\r
+ UINTN Length;\r
+\r
+ if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) ||\r
+ (DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP )){\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Check Vendor Id and Product Id.\r
+ //\r
+ Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+ if ((DevDesc.IdVendor != UsbWwid->VendorId) ||\r
+ (DevDesc.IdProduct != UsbWwid->ProductId)) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Check Interface Number.\r
+ //\r
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+ if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Check Serial Number.\r
+ //\r
+ if (DevDesc.StrSerialNumber == 0) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Get all supported languages.\r
+ //\r
+ TableSize = 0;\r
+ LangIdTable = NULL;\r
+ Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize);\r
+ if (EFI_ERROR (Status) || (TableSize == 0) || (LangIdTable == NULL)) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.\r
+ //\r
+ CompareStr = (CHAR16 *) (UINTN) (UsbWwid + 1);\r
+ CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16);\r
+ if (CompareStr[CompareLen - 1] == L'\0') {\r
+ CompareLen--;\r
+ }\r
+\r
+ //\r
+ // Compare serial number in each supported language.\r
+ //\r
+ for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) {\r
+ SerialNumberStr = NULL;\r
+ Status = UsbIo->UsbGetStringDescriptor (\r
+ UsbIo,\r
+ LangIdTable[Index],\r
+ DevDesc.StrSerialNumber,\r
+ &SerialNumberStr\r
+ );\r
+ if (EFI_ERROR (Status) || (SerialNumberStr == NULL)) {\r
+ continue;\r
+ }\r
+\r
+ Length = StrLen (SerialNumberStr);\r
+ if ((Length >= CompareLen) &&\r
+ (CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) {\r
+ FreePool (SerialNumberStr);\r
+ return TRUE;\r
+ }\r
+\r
+ FreePool (SerialNumberStr);\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Find a USB device which match the specified short-form device path start with \r
+ USB Class or USB WWID device path. If ParentDevicePath is NULL, this function\r
+ will search in all USB devices of the platform. If ParentDevicePath is not NULL,\r
+ this function will only search in its child devices.\r
+\r
+ @param ParentDevicePath The device path of the parent.\r
+ @param ShortFormDevicePath The USB Class or USB WWID device path to match.\r
+\r
+ @return The handle of matched USB device, or NULL if not found.\r
+\r
+**/\r
+EFI_HANDLE *\r
+BdsFindUsbDevice (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *ShortFormDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN UsbIoHandleCount;\r
+ EFI_HANDLE *UsbIoHandleBuffer;\r
+ EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath;\r
+ EFI_USB_IO_PROTOCOL *UsbIo;\r
+ UINTN Index;\r
+ UINTN ParentSize;\r
+ UINTN Size;\r
+ EFI_HANDLE ReturnHandle;\r
+\r
+ //\r
+ // Get all UsbIo Handles.\r
+ //\r
+ UsbIoHandleCount = 0;\r
+ UsbIoHandleBuffer = NULL;\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiUsbIoProtocolGuid,\r
+ NULL,\r
+ &UsbIoHandleCount,\r
+ &UsbIoHandleBuffer\r
+ );\r
+ if (EFI_ERROR (Status) || (UsbIoHandleCount == 0) || (UsbIoHandleBuffer == NULL)) {\r
+ return NULL;\r
+ }\r
+\r
+ ReturnHandle = NULL;\r
+ ParentSize = (ParentDevicePath == NULL) ? 0 : GetDevicePathSize (ParentDevicePath);\r
+ for (Index = 0; Index < UsbIoHandleCount; Index++) {\r
+ //\r
+ // Get the Usb IO interface.\r
+ //\r
+ Status = gBS->HandleProtocol(\r
+ UsbIoHandleBuffer[Index],\r
+ &gEfiUsbIoProtocolGuid,\r
+ (VOID **) &UsbIo\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ if (ParentDevicePath != NULL) {\r
+ //\r
+ // Compare starting part of UsbIoHandle's device path with ParentDevicePath.\r
+ //\r
+ UsbIoDevicePath = DevicePathFromHandle (UsbIoHandleBuffer[Index]);\r
+ ASSERT (UsbIoDevicePath != NULL);\r
+\r
+ Size = GetDevicePathSize (UsbIoDevicePath);\r
+ if ((Size < ParentSize) ||\r
+ (CompareMem (UsbIoDevicePath, ParentDevicePath, ParentSize - END_DEVICE_PATH_LENGTH) != 0)) {\r
+ continue;\r
+ }\r
+ }\r
+\r
+ if (BdsMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ShortFormDevicePath) ||\r
+ BdsMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ShortFormDevicePath)) {\r
+ ReturnHandle = UsbIoHandleBuffer[Index];\r
+ break;\r
+ }\r
+ }\r
+\r
+ FreePool (UsbIoHandleBuffer);\r
+ return ReturnHandle;\r
+}\r
+\r
+/**\r
+ Expand USB Class or USB WWID device path node to be full device path of a USB\r
+ device in platform.\r
+\r
+ This function support following 4 cases:\r
+ 1) Boot Option device path starts with a USB Class or USB WWID device path,\r
+ and there is no Media FilePath device path in the end.\r
+ In this case, it will follow Removable Media Boot Behavior.\r
+ 2) Boot Option device path starts with a USB Class or USB WWID device path,\r
+ and ended with Media FilePath device path.\r
+ 3) Boot Option device path starts with a full device path to a USB Host Controller,\r
+ contains a USB Class or USB WWID device path node, while not ended with Media\r
+ FilePath device path. In this case, it will follow Removable Media Boot Behavior.\r
+ 4) Boot Option device path starts with a full device path to a USB Host Controller,\r
+ contains a USB Class or USB WWID device path node, and ended with Media\r
+ FilePath device path.\r
+\r
+ @param DevicePath The Boot Option device path.\r
+\r
+ @return The full device path after expanding, or NULL if there is no USB Class\r
+ or USB WWID device path found, or USB Class or USB WWID device path\r
+ was found but failed to expand it.\r
+\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+BdsExpandUsbShortFormDevicePath (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ )\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;\r
+ EFI_HANDLE *UsbIoHandle;\r
+ EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *NextDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *ShortFormDevicePath;\r
+\r
+ //\r
+ // Search for USB Class or USB WWID device path node.\r
+ //\r
+ ShortFormDevicePath = NULL;\r
+ TempDevicePath = DevicePath;\r
+ while (!IsDevicePathEnd (TempDevicePath)) {\r
+ if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&\r
+ ((DevicePathSubType (TempDevicePath) == MSG_USB_CLASS_DP) ||\r
+ (DevicePathSubType (TempDevicePath) == MSG_USB_WWID_DP))) {\r
+ ShortFormDevicePath = TempDevicePath;\r
+ break;\r
+ }\r
+\r
+ TempDevicePath = NextDevicePathNode (TempDevicePath);\r
+ }\r
+\r
+ if (ShortFormDevicePath == NULL) {\r
+ //\r
+ // No USB Class or USB WWID device path node found, do nothing.\r
+ //\r
+ return NULL;\r
+ }\r
+\r
+ if (ShortFormDevicePath == DevicePath) {\r
+ //\r
+ // Boot Option device path starts with USB Class or USB WWID device path.\r
+ //\r
+ UsbIoHandle = BdsFindUsbDevice (NULL, ShortFormDevicePath);\r
+ if (UsbIoHandle == NULL) {\r
+ //\r
+ // Failed to find a match in existing devices, connect the short form USB\r
+ // device path and try again.\r
+ //\r
+ BdsLibConnectUsbDevByShortFormDP (0xff, ShortFormDevicePath);\r
+ UsbIoHandle = BdsFindUsbDevice (NULL, ShortFormDevicePath);\r
+ }\r
+ } else {\r
+ //\r
+ // Boot Option device path contains USB Class or USB WWID device path node.\r
+ //\r
+\r
+ //\r
+ // Prepare the parent device path for search.\r
+ //\r
+ TempDevicePath = DuplicateDevicePath (DevicePath);\r
+ ASSERT (TempDevicePath != NULL);\r
+ SetDevicePathEndNode (((UINT8 *) TempDevicePath) + ((UINTN) ShortFormDevicePath - (UINTN) DevicePath));\r
+\r
+ //\r
+ // The USB Host Controller device path is in already in Boot Option device path\r
+ // and USB Bus driver already support RemainingDevicePath starts with USB\r
+ // Class or USB WWID device path, so just search in existing USB devices and\r
+ // doesn't perform ConnectController here.\r
+ //\r
+ UsbIoHandle = BdsFindUsbDevice (TempDevicePath, ShortFormDevicePath);\r
+ FreePool (TempDevicePath);\r
+ }\r
+\r
+ if (UsbIoHandle == NULL) {\r
+ //\r
+ // Failed to expand USB Class or USB WWID device path.\r
+ //\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Get device path of the matched USB device.\r
+ //\r
+ UsbIoDevicePath = DevicePathFromHandle (UsbIoHandle);\r
+ ASSERT (UsbIoDevicePath != NULL);\r
+\r
+ FullDevicePath = NULL;\r
+ //\r
+ // Advance to next device path node to skip the USB Class or USB WWID device path.\r
+ //\r
+ NextDevicePath = NextDevicePathNode (ShortFormDevicePath);\r
+ if (!IsDevicePathEnd (NextDevicePath)) {\r
+ //\r
+ // There is remaining device path after USB Class or USB WWID device path\r
+ // node, append it to the USB device path.\r
+ //\r
+ FullDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePath);\r
+\r
+ //\r
+ // Connect the full device path, so that Simple File System protocol\r
+ // could be installed for this USB device.\r
+ //\r
+ BdsLibConnectDevicePath (FullDevicePath);\r
+ } else {\r
+ //\r
+ // USB Class or WWID device path is in the end.\r
+ //\r
+ FullDevicePath = UsbIoDevicePath;\r
+ }\r
+\r
+ return FullDevicePath;\r
+}\r
+\r
/**\r
Process the boot option follow the UEFI specification and\r
special treat the legacy boot option with BBS_DEVICE_PATH.\r
DevicePath = WorkingDevicePath;\r
}\r
}\r
+\r
+ //\r
+ // Expand USB Class or USB WWID drive path node to full device path.\r
+ //\r
+ WorkingDevicePath = BdsExpandUsbShortFormDevicePath (DevicePath);\r
+ if (WorkingDevicePath != NULL) {\r
+ DevicePath = WorkingDevicePath;\r
+ }\r
+\r
//\r
// Signal the EVT_SIGNAL_READY_TO_BOOT event\r
//\r
if (mEnumBootDevice) {\r
LastLang = GetVariable (L"LastEnumLang", &mBdsLibLastLangGuid);\r
PlatLang = GetEfiGlobalVariable (L"PlatformLang");\r
- if (LastLang == PlatLang) {\r
+ ASSERT (PlatLang != NULL);\r
+ if ((LastLang != NULL) && (AsciiStrCmp (LastLang, PlatLang) == 0)) {\r
Status = BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");\r
+ FreePool (LastLang);\r
+ FreePool (PlatLang);\r
return Status;\r
} else {\r
Status = gRT->SetVariable (\r
L"LastEnumLang",\r
&mBdsLibLastLangGuid,\r
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
- sizeof (PlatLang),\r
+ AsciiStrSize (PlatLang),\r
PlatLang\r
);\r
ASSERT_EFI_ERROR (Status);\r
+\r
+ if (LastLang != NULL) {\r
+ FreePool (LastLang);\r
+ }\r
+ FreePool (PlatLang);\r
}\r
}\r
\r
// and assume it is ready to boot now\r
//\r
while (!IsDevicePathEnd (TempDevicePath)) {\r
- LastDeviceNode = TempDevicePath;\r
- TempDevicePath = NextDevicePathNode (TempDevicePath);\r
+ //\r
+ // If there is USB Class or USB WWID device path node, treat it as valid EFI\r
+ // Boot Option. BdsExpandUsbShortFormDevicePath () will be used to expand it\r
+ // to full device path.\r
+ //\r
+ if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&\r
+ ((DevicePathSubType (TempDevicePath) == MSG_USB_CLASS_DP) ||\r
+ (DevicePathSubType (TempDevicePath) == MSG_USB_WWID_DP))) {\r
+ return TRUE;\r
+ }\r
+\r
+ LastDeviceNode = TempDevicePath;\r
+ TempDevicePath = NextDevicePathNode (TempDevicePath);\r
}\r
if ((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) &&\r
(DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) {\r