EDK2 doxygen online documents - Firmware Encoding Index 1
EDK2 doxygen online documents - Firmware Encoding Index

IntelFrameworkModulePkg/Library/GenericBdsLib/BdsBoot.c

Go to the documentation of this file.
00001 
00015 #include "InternalBdsLib.h"
00016 #include "String.h"
00017 
00018 BOOLEAN mEnumBootDevice = FALSE;
00019 EFI_HII_HANDLE gBdsLibStringPackHandle = NULL;
00020 
00033 EFI_STATUS
00034 EFIAPI
00035 GenericBdsLibConstructor (
00036   IN EFI_HANDLE        ImageHandle,
00037   IN EFI_SYSTEM_TABLE  *SystemTable
00038   )
00039 {
00040 
00041   gBdsLibStringPackHandle = HiiAddPackages (
00042                               &gBdsLibStringPackageGuid,
00043                               &ImageHandle,
00044                               GenericBdsLibStrings,
00045                               NULL
00046                               );
00047 
00048   ASSERT (gBdsLibStringPackHandle != NULL);
00049 
00050   return EFI_SUCCESS;
00051 }
00052 
00053 
00054 
00065 EFI_STATUS
00066 BdsLibDoLegacyBoot (
00067   IN  BDS_COMMON_OPTION           *Option
00068   )
00069 {
00070   EFI_STATUS                Status;
00071   EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
00072 
00073   Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
00074   if (EFI_ERROR (Status)) {
00075     //
00076     // If no LegacyBios protocol we do not support legacy boot
00077     //
00078     return EFI_UNSUPPORTED;
00079   }
00080   //
00081   // Notes: if we separate the int 19, then we don't need to refresh BBS
00082   //
00083   BdsRefreshBbsTableForBoot (Option);
00084 
00085   //
00086   // Write boot to OS performance data for legacy boot.
00087   //
00088   PERF_CODE (
00089     WriteBootToOsPerformanceData ();
00090   );
00091 
00092   DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Legacy Boot: %S\n", Option->Description));
00093   return LegacyBios->LegacyBoot (
00094                       LegacyBios,
00095                       (BBS_BBS_DEVICE_PATH *) Option->DevicePath,
00096                       Option->LoadOptionsSize,
00097                       Option->LoadOptions
00098                       );
00099 }
00100 
00110 BOOLEAN
00111 IsBootOptionValidNVVarialbe (
00112   IN  BDS_COMMON_OPTION             *OptionToCheck
00113   )
00114 {
00115   LIST_ENTRY        TempList;
00116   BDS_COMMON_OPTION *BootOption;
00117   BOOLEAN           Valid;
00118   CHAR16            OptionName[20];
00119 
00120   Valid = FALSE;
00121 
00122   InitializeListHead (&TempList);
00123   UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionToCheck->BootCurrent);
00124 
00125   BootOption = BdsLibVariableToOption (&TempList, OptionName);
00126   if (BootOption == NULL) {
00127     return FALSE;
00128   }
00129 
00130   //
00131   // If the Boot Option Number and Device Path matches, OptionToCheck matches a
00132   // valid EFI NV Boot####.
00133   //
00134   if ((OptionToCheck->BootCurrent == BootOption->BootCurrent) &&
00135       (CompareMem (OptionToCheck->DevicePath, BootOption->DevicePath, GetDevicePathSize (OptionToCheck->DevicePath)) == 0))
00136       {
00137     Valid = TRUE;
00138   }
00139 
00140   FreePool (BootOption);
00141 
00142   return Valid;
00143 }
00144 
00156 BOOLEAN
00157 BdsMatchUsbClass (
00158   IN EFI_USB_IO_PROTOCOL        *UsbIo,
00159   IN USB_CLASS_DEVICE_PATH      *UsbClass
00160   )
00161 {
00162   EFI_STATUS                    Status;
00163   EFI_USB_DEVICE_DESCRIPTOR     DevDesc;
00164   EFI_USB_INTERFACE_DESCRIPTOR  IfDesc;
00165   UINT8                         DeviceClass;
00166   UINT8                         DeviceSubClass;
00167   UINT8                         DeviceProtocol;
00168 
00169   if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) ||
00170       (DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP)){
00171     return FALSE;
00172   }
00173 
00174   //
00175   // Check Vendor Id and Product Id.
00176   //
00177   Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
00178   if (EFI_ERROR (Status)) {
00179     return FALSE;
00180   }
00181 
00182   if ((UsbClass->VendorId != 0xffff) &&
00183       (UsbClass->VendorId != DevDesc.IdVendor)) {
00184     return FALSE;
00185   }
00186 
00187   if ((UsbClass->ProductId != 0xffff) &&
00188       (UsbClass->ProductId != DevDesc.IdProduct)) {
00189     return FALSE;
00190   }
00191 
00192   DeviceClass    = DevDesc.DeviceClass;
00193   DeviceSubClass = DevDesc.DeviceSubClass;
00194   DeviceProtocol = DevDesc.DeviceProtocol;
00195   if (DeviceClass == 0) {
00196     //
00197     // If Class in Device Descriptor is set to 0, use the Class, SubClass and
00198     // Protocol in Interface Descriptor instead.
00199     //
00200     Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
00201     if (EFI_ERROR (Status)) {
00202       return FALSE;
00203     }
00204 
00205     DeviceClass    = IfDesc.InterfaceClass;
00206     DeviceSubClass = IfDesc.InterfaceSubClass;
00207     DeviceProtocol = IfDesc.InterfaceProtocol;
00208   }
00209 
00210   //
00211   // Check Class, SubClass and Protocol.
00212   //
00213   if ((UsbClass->DeviceClass != 0xff) &&
00214       (UsbClass->DeviceClass != DeviceClass)) {
00215     return FALSE;
00216   }
00217 
00218   if ((UsbClass->DeviceSubClass != 0xff) &&
00219       (UsbClass->DeviceSubClass != DeviceSubClass)) {
00220     return FALSE;
00221   }
00222 
00223   if ((UsbClass->DeviceProtocol != 0xff) &&
00224       (UsbClass->DeviceProtocol != DeviceProtocol)) {
00225     return FALSE;
00226   }
00227 
00228   return TRUE;
00229 }
00230 
00242 BOOLEAN
00243 BdsMatchUsbWwid (
00244   IN EFI_USB_IO_PROTOCOL        *UsbIo,
00245   IN USB_WWID_DEVICE_PATH       *UsbWwid
00246   )
00247 {
00248   EFI_STATUS                   Status;
00249   EFI_USB_DEVICE_DESCRIPTOR    DevDesc;
00250   EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
00251   UINT16                       *LangIdTable;
00252   UINT16                       TableSize;
00253   UINT16                       Index;
00254   CHAR16                       *CompareStr;
00255   UINTN                        CompareLen;
00256   CHAR16                       *SerialNumberStr;
00257   UINTN                        Length;
00258 
00259   if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) ||
00260       (DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP )){
00261     return FALSE;
00262   }
00263 
00264   //
00265   // Check Vendor Id and Product Id.
00266   //
00267   Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
00268   if (EFI_ERROR (Status)) {
00269     return FALSE;
00270   }
00271   if ((DevDesc.IdVendor != UsbWwid->VendorId) ||
00272       (DevDesc.IdProduct != UsbWwid->ProductId)) {
00273     return FALSE;
00274   }
00275 
00276   //
00277   // Check Interface Number.
00278   //
00279   Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
00280   if (EFI_ERROR (Status)) {
00281     return FALSE;
00282   }
00283   if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) {
00284     return FALSE;
00285   }
00286 
00287   //
00288   // Check Serial Number.
00289   //
00290   if (DevDesc.StrSerialNumber == 0) {
00291     return FALSE;
00292   }
00293 
00294   //
00295   // Get all supported languages.
00296   //
00297   TableSize = 0;
00298   LangIdTable = NULL;
00299   Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize);
00300   if (EFI_ERROR (Status) || (TableSize == 0) || (LangIdTable == NULL)) {
00301     return FALSE;
00302   }
00303 
00304   //
00305   // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
00306   //
00307   CompareStr = (CHAR16 *) (UINTN) (UsbWwid + 1);
00308   CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16);
00309   if (CompareStr[CompareLen - 1] == L'\0') {
00310     CompareLen--;
00311   }
00312 
00313   //
00314   // Compare serial number in each supported language.
00315   //
00316   for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) {
00317     SerialNumberStr = NULL;
00318     Status = UsbIo->UsbGetStringDescriptor (
00319                       UsbIo,
00320                       LangIdTable[Index],
00321                       DevDesc.StrSerialNumber,
00322                       &SerialNumberStr
00323                       );
00324     if (EFI_ERROR (Status) || (SerialNumberStr == NULL)) {
00325       continue;
00326     }
00327 
00328     Length = StrLen (SerialNumberStr);
00329     if ((Length >= CompareLen) &&
00330         (CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) {
00331       FreePool (SerialNumberStr);
00332       return TRUE;
00333     }
00334 
00335     FreePool (SerialNumberStr);
00336   }
00337 
00338   return FALSE;
00339 }
00340 
00355 EFI_HANDLE *
00356 BdsFindUsbDevice (
00357   IN EFI_DEVICE_PATH_PROTOCOL   *ParentDevicePath,
00358   IN EFI_DEVICE_PATH_PROTOCOL   *ShortFormDevicePath
00359   )
00360 {
00361   EFI_STATUS                Status;
00362   UINTN                     UsbIoHandleCount;
00363   EFI_HANDLE                *UsbIoHandleBuffer;
00364   EFI_DEVICE_PATH_PROTOCOL  *UsbIoDevicePath;
00365   EFI_USB_IO_PROTOCOL       *UsbIo;
00366   UINTN                     Index;
00367   UINTN                     ParentSize;
00368   UINTN                     Size;
00369   EFI_HANDLE                ImageHandle;
00370   EFI_HANDLE                Handle;
00371   EFI_DEVICE_PATH_PROTOCOL  *FullDevicePath;
00372   EFI_DEVICE_PATH_PROTOCOL  *NextDevicePath;
00373 
00374   FullDevicePath = NULL;
00375   ImageHandle    = NULL;
00376 
00377   //
00378   // Get all UsbIo Handles.
00379   //
00380   UsbIoHandleCount = 0;
00381   UsbIoHandleBuffer = NULL;
00382   Status = gBS->LocateHandleBuffer (
00383                   ByProtocol,
00384                   &gEfiUsbIoProtocolGuid,
00385                   NULL,
00386                   &UsbIoHandleCount,
00387                   &UsbIoHandleBuffer
00388                   );
00389   if (EFI_ERROR (Status) || (UsbIoHandleCount == 0) || (UsbIoHandleBuffer == NULL)) {
00390     return NULL;
00391   }
00392 
00393   ParentSize = (ParentDevicePath == NULL) ? 0 : GetDevicePathSize (ParentDevicePath);
00394   for (Index = 0; Index < UsbIoHandleCount; Index++) {
00395     //
00396     // Get the Usb IO interface.
00397     //
00398     Status = gBS->HandleProtocol(
00399                     UsbIoHandleBuffer[Index],
00400                     &gEfiUsbIoProtocolGuid,
00401                     (VOID **) &UsbIo
00402                     );
00403     if (EFI_ERROR (Status)) {
00404       continue;
00405     }
00406 
00407     UsbIoDevicePath = DevicePathFromHandle (UsbIoHandleBuffer[Index]);
00408     if (UsbIoDevicePath == NULL) {
00409       continue;
00410     }
00411 
00412     if (ParentDevicePath != NULL) {
00413       //
00414       // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
00415       //
00416       Size = GetDevicePathSize (UsbIoDevicePath);
00417       if ((Size < ParentSize) ||
00418           (CompareMem (UsbIoDevicePath, ParentDevicePath, ParentSize - END_DEVICE_PATH_LENGTH) != 0)) {
00419         continue;
00420       }
00421     }
00422 
00423     if (BdsMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ShortFormDevicePath) ||
00424         BdsMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ShortFormDevicePath)) {
00425       //
00426       // Try to find if there is the boot file in this DevicePath
00427       //
00428       NextDevicePath = NextDevicePathNode (ShortFormDevicePath);
00429       if (!IsDevicePathEnd (NextDevicePath)) {
00430         FullDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePath);
00431         //
00432         // Connect the full device path, so that Simple File System protocol
00433         // could be installed for this USB device.
00434         //
00435         BdsLibConnectDevicePath (FullDevicePath);
00436         REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
00437         Status = gBS->LoadImage (
00438                        TRUE,
00439                        gImageHandle,
00440                        FullDevicePath,
00441                        NULL,
00442                        0,
00443                        &ImageHandle
00444                        );
00445         FreePool (FullDevicePath);
00446       } else {
00447         FullDevicePath = UsbIoDevicePath;
00448         Status = EFI_NOT_FOUND;
00449       }
00450 
00451       //
00452       // If we didn't find an image directly, we need to try as if it is a removable device boot option
00453       // and load the image according to the default boot behavior for removable device.
00454       //
00455       if (EFI_ERROR (Status)) {
00456         //
00457         // check if there is a bootable removable media could be found in this device path ,
00458         // and get the bootable media handle
00459         //
00460         Handle = BdsLibGetBootableHandle(UsbIoDevicePath);
00461         if (Handle == NULL) {
00462           continue;
00463         }
00464         //
00465         // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
00466         //  machinename is ia32, ia64, x64, ...
00467         //
00468         FullDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
00469         if (FullDevicePath != NULL) {
00470           REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
00471           Status = gBS->LoadImage (
00472                           TRUE,
00473                           gImageHandle,
00474                           FullDevicePath,
00475                           NULL,
00476                           0,
00477                           &ImageHandle
00478                           );
00479           if (EFI_ERROR (Status)) {
00480             //
00481             // The DevicePath failed, and it's not a valid
00482             // removable media device.
00483             //
00484             continue;
00485           }
00486         } else {
00487           continue;
00488         }
00489       }
00490       break;
00491     }
00492   }
00493 
00494   FreePool (UsbIoHandleBuffer);
00495   return ImageHandle;
00496 }
00497 
00522 EFI_HANDLE *
00523 BdsExpandUsbShortFormDevicePath (
00524   IN EFI_DEVICE_PATH_PROTOCOL       *DevicePath
00525   )
00526 {
00527   EFI_HANDLE                *ImageHandle;
00528   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
00529   EFI_DEVICE_PATH_PROTOCOL  *ShortFormDevicePath;
00530 
00531   //
00532   // Search for USB Class or USB WWID device path node.
00533   //
00534   ShortFormDevicePath = NULL;
00535   ImageHandle         = NULL;
00536   TempDevicePath      = DevicePath;
00537   while (!IsDevicePathEnd (TempDevicePath)) {
00538     if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&
00539         ((DevicePathSubType (TempDevicePath) == MSG_USB_CLASS_DP) ||
00540          (DevicePathSubType (TempDevicePath) == MSG_USB_WWID_DP))) {
00541       ShortFormDevicePath = TempDevicePath;
00542       break;
00543     }
00544     TempDevicePath = NextDevicePathNode (TempDevicePath);
00545   }
00546 
00547   if (ShortFormDevicePath == NULL) {
00548     //
00549     // No USB Class or USB WWID device path node found, do nothing.
00550     //
00551     return NULL;
00552   }
00553 
00554   if (ShortFormDevicePath == DevicePath) {
00555     //
00556     // Boot Option device path starts with USB Class or USB WWID device path.
00557     //
00558     ImageHandle = BdsFindUsbDevice (NULL, ShortFormDevicePath);
00559     if (ImageHandle == NULL) {
00560       //
00561       // Failed to find a match in existing devices, connect the short form USB
00562       // device path and try again.
00563       //
00564       BdsLibConnectUsbDevByShortFormDP (0xff, ShortFormDevicePath);
00565       ImageHandle = BdsFindUsbDevice (NULL, ShortFormDevicePath);
00566     }
00567   } else {
00568     //
00569     // Boot Option device path contains USB Class or USB WWID device path node.
00570     //
00571 
00572     //
00573     // Prepare the parent device path for search.
00574     //
00575     TempDevicePath = DuplicateDevicePath (DevicePath);
00576     ASSERT (TempDevicePath != NULL);
00577     SetDevicePathEndNode (((UINT8 *) TempDevicePath) + ((UINTN) ShortFormDevicePath - (UINTN) DevicePath));
00578 
00579     //
00580     // The USB Host Controller device path is already in Boot Option device path
00581     // and USB Bus driver already support RemainingDevicePath starts with USB
00582     // Class or USB WWID device path, so just search in existing USB devices and
00583     // doesn't perform ConnectController here.
00584     //
00585     ImageHandle = BdsFindUsbDevice (TempDevicePath, ShortFormDevicePath);
00586     FreePool (TempDevicePath);
00587   }
00588 
00589   return ImageHandle;
00590 }
00591 
00607 EFI_STATUS
00608 EFIAPI
00609 BdsLibBootViaBootOption (
00610   IN  BDS_COMMON_OPTION             *Option,
00611   IN  EFI_DEVICE_PATH_PROTOCOL      *DevicePath,
00612   OUT UINTN                         *ExitDataSize,
00613   OUT CHAR16                        **ExitData OPTIONAL
00614   )
00615 {
00616   EFI_STATUS                Status;
00617   EFI_HANDLE                Handle;
00618   EFI_HANDLE                ImageHandle;
00619   EFI_DEVICE_PATH_PROTOCOL  *FilePath;
00620   EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
00621   EFI_DEVICE_PATH_PROTOCOL  *WorkingDevicePath;
00622   EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save;
00623   LIST_ENTRY                TempBootLists;
00624 
00625   //
00626   // Record the performance data for End of BDS
00627   //
00628   PERF_END(NULL, "BDS", NULL, 0);
00629 
00630   *ExitDataSize = 0;
00631   *ExitData     = NULL;
00632 
00633   //
00634   // Notes: this code can be remove after the s3 script table
00635   // hook on the event EVT_SIGNAL_READY_TO_BOOT or
00636   // EVT_SIGNAL_LEGACY_BOOT
00637   //
00638   Status = gBS->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid, NULL, (VOID **) &AcpiS3Save);
00639   if (!EFI_ERROR (Status)) {
00640     AcpiS3Save->S3Save (AcpiS3Save, NULL);
00641   }
00642   //
00643   // If it's Device Path that starts with a hard drive path, append it with the front part to compose a
00644   // full device path
00645   //
00646   WorkingDevicePath = NULL;
00647   if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
00648       (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)) {
00649     WorkingDevicePath = BdsExpandPartitionPartialDevicePathToFull (
00650                           (HARDDRIVE_DEVICE_PATH *)DevicePath
00651                           );
00652     if (WorkingDevicePath != NULL) {
00653       DevicePath = WorkingDevicePath;
00654     }
00655   }
00656 
00657   //
00658   // Set Boot Current
00659   //
00660   if (IsBootOptionValidNVVarialbe (Option)) {
00661     //
00662     // For a temporary boot (i.e. a boot by selected a EFI Shell using "Boot From File"), Boot Current is actually not valid.
00663     // In this case, "BootCurrent" is not created.
00664     // Only create the BootCurrent variable when it points to a valid Boot#### variable.
00665     //
00666     gRT->SetVariable (
00667           L"BootCurrent",
00668           &gEfiGlobalVariableGuid,
00669           EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
00670           sizeof (UINT16),
00671           &Option->BootCurrent
00672           );
00673   }
00674 
00675   //
00676   // Signal the EVT_SIGNAL_READY_TO_BOOT event
00677   //
00678   EfiSignalEventReadyToBoot();
00679 
00680   //
00681   // Expand USB Class or USB WWID device path node to be full device path of a USB
00682   // device in platform then load the boot file on this full device path and get the
00683   // image handle.
00684   //
00685   ImageHandle = BdsExpandUsbShortFormDevicePath (DevicePath);
00686 
00687   //
00688   // Adjust the different type memory page number just before booting
00689   // and save the updated info into the variable for next boot to use
00690   //
00691   BdsSetMemoryTypeInformationVariable ();
00692 
00693   //
00694   // By expanding the USB Class or WWID device path, the ImageHandle has returnned.
00695   // Here get the ImageHandle for the non USB class or WWID device path.
00696   //
00697   if (ImageHandle == NULL) {
00698     ASSERT (Option->DevicePath != NULL);
00699     if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&
00700         (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)
00701        ) {
00702       //
00703       // Check to see if we should legacy BOOT. If yes then do the legacy boot
00704       //
00705       return BdsLibDoLegacyBoot (Option);
00706     }
00707 
00708     //
00709     // If the boot option point to Internal FV shell, make sure it is valid
00710     //
00711     Status = BdsLibUpdateFvFileDevicePath (&DevicePath, PcdGetPtr(PcdShellFile));
00712     if (!EFI_ERROR(Status)) {
00713       if (Option->DevicePath != NULL) {
00714         FreePool(Option->DevicePath);
00715       }
00716       Option->DevicePath  = AllocateZeroPool (GetDevicePathSize (DevicePath));
00717       ASSERT(Option->DevicePath != NULL);
00718       CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));
00719       //
00720       // Update the shell boot option
00721       //
00722       InitializeListHead (&TempBootLists);
00723       BdsLibRegisterNewOption (&TempBootLists, DevicePath, L"EFI Internal Shell", L"BootOrder");
00724 
00725       //
00726       // free the temporary device path created by BdsLibUpdateFvFileDevicePath()
00727       //
00728       FreePool (DevicePath);
00729       DevicePath = Option->DevicePath;
00730     }
00731 
00732     DEBUG_CODE_BEGIN();
00733 
00734     if (Option->Description == NULL) {
00735       DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting from unknown device path\n"));
00736     } else {
00737       DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting %S\n", Option->Description));
00738     }
00739         
00740     DEBUG_CODE_END();
00741   
00742     //
00743     // Report status code for OS Loader LoadImage.
00744     //
00745     REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
00746     Status = gBS->LoadImage (
00747                     TRUE,
00748                     gImageHandle,
00749                     DevicePath,
00750                     NULL,
00751                     0,
00752                     &ImageHandle
00753                     );
00754 
00755     //
00756     // If we didn't find an image directly, we need to try as if it is a removable device boot option
00757     // and load the image according to the default boot behavior for removable device.
00758     //
00759     if (EFI_ERROR (Status)) {
00760       //
00761       // check if there is a bootable removable media could be found in this device path ,
00762       // and get the bootable media handle
00763       //
00764       Handle = BdsLibGetBootableHandle(DevicePath);
00765       if (Handle == NULL) {
00766         goto Done;
00767       }
00768       //
00769       // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
00770       //  machinename is ia32, ia64, x64, ...
00771       //
00772       FilePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
00773       if (FilePath != NULL) {
00774         REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
00775         Status = gBS->LoadImage (
00776                         TRUE,
00777                         gImageHandle,
00778                         FilePath,
00779                         NULL,
00780                         0,
00781                         &ImageHandle
00782                         );
00783        if (EFI_ERROR (Status)) {
00784           //
00785           // The DevicePath failed, and it's not a valid
00786           // removable media device.
00787           //
00788           goto Done;
00789         }
00790       }
00791     }
00792 
00793     if (EFI_ERROR (Status)) {
00794       //
00795       // It there is any error from the Boot attempt exit now.
00796       //
00797       goto Done;
00798     }
00799   }
00800   //
00801   // Provide the image with it's load options
00802   //
00803   if (ImageHandle == NULL) {
00804     goto Done;
00805   }
00806   Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
00807   ASSERT_EFI_ERROR (Status);
00808 
00809   if (Option->LoadOptionsSize != 0) {
00810     ImageInfo->LoadOptionsSize  = Option->LoadOptionsSize;
00811     ImageInfo->LoadOptions      = Option->LoadOptions;
00812   }
00813   //
00814   // Before calling the image, enable the Watchdog Timer for
00815   // the 5 Minute period
00816   //
00817   gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
00818 
00819   //
00820   // Write boot to OS performance data for UEFI boot
00821   //
00822   PERF_CODE (
00823     WriteBootToOsPerformanceData ();
00824   );
00825 
00826   //
00827   // Report status code for OS Loader StartImage.
00828   //
00829   REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));
00830 
00831   Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);
00832   DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));
00833 
00834   //
00835   // Clear the Watchdog Timer after the image returns
00836   //
00837   gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
00838 
00839 Done:
00840   //
00841   // Clear Boot Current
00842   //
00843   gRT->SetVariable (
00844         L"BootCurrent",
00845         &gEfiGlobalVariableGuid,
00846         EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
00847         0,
00848         &Option->BootCurrent
00849         );
00850 
00851   return Status;
00852 }
00853 
00854 
00869 EFI_DEVICE_PATH_PROTOCOL *
00870 EFIAPI
00871 BdsExpandPartitionPartialDevicePathToFull (
00872   IN  HARDDRIVE_DEVICE_PATH      *HardDriveDevicePath
00873   )
00874 {
00875   EFI_STATUS                Status;
00876   UINTN                     BlockIoHandleCount;
00877   EFI_HANDLE                *BlockIoBuffer;
00878   EFI_DEVICE_PATH_PROTOCOL  *FullDevicePath;
00879   EFI_DEVICE_PATH_PROTOCOL  *BlockIoDevicePath;
00880   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
00881   UINTN                     Index;
00882   UINTN                     InstanceNum;
00883   EFI_DEVICE_PATH_PROTOCOL  *CachedDevicePath;
00884   EFI_DEVICE_PATH_PROTOCOL  *TempNewDevicePath;
00885   UINTN                     CachedDevicePathSize;
00886   BOOLEAN                   DeviceExist;
00887   BOOLEAN                   NeedAdjust;
00888   EFI_DEVICE_PATH_PROTOCOL  *Instance;
00889   UINTN                     Size;
00890 
00891   FullDevicePath = NULL;
00892   //
00893   // Check if there is prestore HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable.
00894   // If exist, search the front path which point to partition node in the variable instants.
00895   // If fail to find or HD_BOOT_DEVICE_PATH_VARIABLE_NAME not exist, reconnect all and search in all system
00896   //
00897   CachedDevicePath = BdsLibGetVariableAndSize (
00898                       HD_BOOT_DEVICE_PATH_VARIABLE_NAME,
00899                       &gHdBootDevicePathVariablGuid,
00900                       &CachedDevicePathSize
00901                       );
00902 
00903   if (CachedDevicePath != NULL) {
00904     TempNewDevicePath = CachedDevicePath;
00905     DeviceExist = FALSE;
00906     NeedAdjust = FALSE;
00907     do {
00908       //
00909       // Check every instance of the variable
00910       // First, check whether the instance contain the partition node, which is needed for distinguishing  multi
00911       // partial partition boot option. Second, check whether the instance could be connected.
00912       //
00913       Instance  = GetNextDevicePathInstance (&TempNewDevicePath, &Size);
00914       if (MatchPartitionDevicePathNode (Instance, HardDriveDevicePath)) {
00915         //
00916         // Connect the device path instance, the device path point to hard drive media device path node
00917         // e.g. ACPI() /PCI()/ATA()/Partition()
00918         //
00919         Status = BdsLibConnectDevicePath (Instance);
00920         if (!EFI_ERROR (Status)) {
00921           DeviceExist = TRUE;
00922           break;
00923         }
00924       }
00925       //
00926       // Come here means the first instance is not matched
00927       //
00928       NeedAdjust = TRUE;
00929       FreePool(Instance);
00930     } while (TempNewDevicePath != NULL);
00931 
00932     if (DeviceExist) {
00933       //
00934       // Find the matched device path.
00935       // Append the file path information from the boot option and return the fully expanded device path.
00936       //
00937       DevicePath     = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
00938       FullDevicePath = AppendDevicePath (Instance, DevicePath);
00939 
00940       //
00941       // Adjust the HD_BOOT_DEVICE_PATH_VARIABLE_NAME instances sequence if the matched one is not first one.
00942       //
00943       if (NeedAdjust) {
00944         //
00945         // First delete the matched instance.
00946         //
00947         TempNewDevicePath = CachedDevicePath;
00948         CachedDevicePath  = BdsLibDelPartMatchInstance (CachedDevicePath, Instance );
00949         FreePool (TempNewDevicePath);
00950 
00951         //
00952         // Second, append the remaining path after the matched instance
00953         //
00954         TempNewDevicePath = CachedDevicePath;
00955         CachedDevicePath = AppendDevicePathInstance (Instance, CachedDevicePath );
00956         FreePool (TempNewDevicePath);
00957         //
00958         // Save the matching Device Path so we don't need to do a connect all next time
00959         //
00960         Status = gRT->SetVariable (
00961                         HD_BOOT_DEVICE_PATH_VARIABLE_NAME,
00962                         &gHdBootDevicePathVariablGuid,
00963                         EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
00964                         GetDevicePathSize (CachedDevicePath),
00965                         CachedDevicePath
00966                         );
00967       }
00968 
00969       FreePool (Instance);
00970       FreePool (CachedDevicePath);
00971       return FullDevicePath;
00972     }
00973   }
00974 
00975   //
00976   // If we get here we fail to find or HD_BOOT_DEVICE_PATH_VARIABLE_NAME not exist, and now we need
00977   // to search all devices in the system for a matched partition
00978   //
00979   BdsLibConnectAllDriversToAllControllers ();
00980   Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
00981   if (EFI_ERROR (Status) || BlockIoHandleCount == 0 || BlockIoBuffer == NULL) {
00982     //
00983     // If there was an error or there are no device handles that support
00984     // the BLOCK_IO Protocol, then return.
00985     //
00986     return NULL;
00987   }
00988   //
00989   // Loop through all the device handles that support the BLOCK_IO Protocol
00990   //
00991   for (Index = 0; Index < BlockIoHandleCount; Index++) {
00992 
00993     Status = gBS->HandleProtocol (BlockIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath);
00994     if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) {
00995       continue;
00996     }
00997 
00998     if (MatchPartitionDevicePathNode (BlockIoDevicePath, HardDriveDevicePath)) {
00999       //
01000       // Find the matched partition device path
01001       //
01002       DevicePath    = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
01003       FullDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath);
01004 
01005       //
01006       // Save the matched partition device path in HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable
01007       //
01008       if (CachedDevicePath != NULL) {
01009         //
01010         // Save the matched partition device path as first instance of HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable
01011         //
01012         if (BdsLibMatchDevicePaths (CachedDevicePath, BlockIoDevicePath)) {
01013           TempNewDevicePath = CachedDevicePath;
01014           CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, BlockIoDevicePath);
01015           FreePool(TempNewDevicePath);
01016 
01017           TempNewDevicePath = CachedDevicePath;
01018           CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);
01019           if (TempNewDevicePath != NULL) {
01020             FreePool(TempNewDevicePath);
01021           }
01022         } else {
01023           TempNewDevicePath = CachedDevicePath;
01024           CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);
01025           FreePool(TempNewDevicePath);
01026         }
01027         //
01028         // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
01029         // If the user try to boot many OS in different HDs or partitions, in theory, 
01030         // the HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable maybe become larger and larger.
01031         //
01032         InstanceNum = 0;
01033         ASSERT (CachedDevicePath != NULL);
01034         TempNewDevicePath = CachedDevicePath;
01035         while (!IsDevicePathEnd (TempNewDevicePath)) {
01036           TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
01037           //
01038           // Parse one instance
01039           //
01040           while (!IsDevicePathEndType (TempNewDevicePath)) {
01041             TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
01042           }
01043           InstanceNum++;
01044           //
01045           // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
01046           //
01047           if (InstanceNum >= 12) {
01048             SetDevicePathEndNode (TempNewDevicePath);
01049             break;
01050           }
01051         }
01052       } else {
01053         CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath);
01054       }
01055 
01056       //
01057       // Save the matching Device Path so we don't need to do a connect all next time
01058       //
01059       Status = gRT->SetVariable (
01060                       HD_BOOT_DEVICE_PATH_VARIABLE_NAME,
01061                       &gHdBootDevicePathVariablGuid,
01062                       EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
01063                       GetDevicePathSize (CachedDevicePath),
01064                       CachedDevicePath
01065                       );
01066 
01067       break;
01068     }
01069   }
01070 
01071   if (CachedDevicePath != NULL) {
01072     FreePool (CachedDevicePath);
01073   }
01074   if (BlockIoBuffer != NULL) {
01075     FreePool (BlockIoBuffer);
01076   }
01077   return FullDevicePath;
01078 }
01079 
01092 BOOLEAN
01093 EFIAPI
01094 MatchPartitionDevicePathNode (
01095   IN  EFI_DEVICE_PATH_PROTOCOL   *BlockIoDevicePath,
01096   IN  HARDDRIVE_DEVICE_PATH      *HardDriveDevicePath
01097   )
01098 {
01099   HARDDRIVE_DEVICE_PATH     *TmpHdPath;
01100   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
01101   BOOLEAN                   Match;
01102   EFI_DEVICE_PATH_PROTOCOL  *BlockIoHdDevicePathNode;
01103 
01104   if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
01105     return FALSE;
01106   }
01107 
01108   //
01109   // Make PreviousDevicePath == the device path node before the end node
01110   //
01111   DevicePath              = BlockIoDevicePath;
01112   BlockIoHdDevicePathNode = NULL;
01113 
01114   //
01115   // find the partition device path node
01116   //
01117   while (!IsDevicePathEnd (DevicePath)) {
01118     if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
01119         (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)
01120         ) {
01121       BlockIoHdDevicePathNode = DevicePath;
01122       break;
01123     }
01124 
01125     DevicePath = NextDevicePathNode (DevicePath);
01126   }
01127 
01128   if (BlockIoHdDevicePathNode == NULL) {
01129     return FALSE;
01130   }
01131   //
01132   // See if the harddrive device path in blockio matches the orig Hard Drive Node
01133   //
01134   TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePathNode;
01135   Match = FALSE;
01136 
01137   //
01138   // Check for the match
01139   //
01140   if ((TmpHdPath->MBRType == HardDriveDevicePath->MBRType) &&
01141       (TmpHdPath->SignatureType == HardDriveDevicePath->SignatureType)) {
01142     switch (TmpHdPath->SignatureType) {
01143     case SIGNATURE_TYPE_GUID:
01144       Match = CompareGuid ((EFI_GUID *)TmpHdPath->Signature, (EFI_GUID *)HardDriveDevicePath->Signature);
01145       break;
01146     case SIGNATURE_TYPE_MBR:
01147       Match = (BOOLEAN)(*((UINT32 *)(&(TmpHdPath->Signature[0]))) == ReadUnaligned32((UINT32 *)(&(HardDriveDevicePath->Signature[0]))));
01148       break;
01149     default:
01150       Match = FALSE;
01151       break;
01152     }
01153   }
01154 
01155   return Match;
01156 }
01157 
01170 EFI_STATUS
01171 BdsLibDeleteOptionFromHandle (
01172   IN  EFI_HANDLE                 Handle
01173   )
01174 {
01175   UINT16                    *BootOrder;
01176   UINT8                     *BootOptionVar;
01177   UINTN                     BootOrderSize;
01178   UINTN                     BootOptionSize;
01179   EFI_STATUS                Status;
01180   UINTN                     Index;
01181   UINT16                    BootOption[BOOT_OPTION_MAX_CHAR];
01182   UINTN                     DevicePathSize;
01183   UINTN                     OptionDevicePathSize;
01184   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
01185   EFI_DEVICE_PATH_PROTOCOL  *OptionDevicePath;
01186   UINT8                     *TempPtr;
01187 
01188   Status        = EFI_SUCCESS;
01189   BootOrder     = NULL;
01190   BootOrderSize = 0;
01191 
01192   //
01193   // Check "BootOrder" variable, if no, means there is no any boot order.
01194   //
01195   BootOrder = BdsLibGetVariableAndSize (
01196                 L"BootOrder",
01197                 &gEfiGlobalVariableGuid,
01198                 &BootOrderSize
01199                 );
01200   if (BootOrder == NULL) {
01201     return EFI_NOT_FOUND;
01202   }
01203 
01204   //
01205   // Convert device handle to device path protocol instance
01206   //
01207   DevicePath = DevicePathFromHandle (Handle);
01208   if (DevicePath == NULL) {
01209     return EFI_NOT_FOUND;
01210   }
01211   DevicePathSize = GetDevicePathSize (DevicePath);
01212 
01213   //
01214   // Loop all boot order variable and find the matching device path
01215   //
01216   Index = 0;
01217   while (Index < BootOrderSize / sizeof (UINT16)) {
01218     UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
01219     BootOptionVar = BdsLibGetVariableAndSize (
01220                       BootOption,
01221                       &gEfiGlobalVariableGuid,
01222                       &BootOptionSize
01223                       );
01224 
01225     if (BootOptionVar == NULL) {
01226       FreePool (BootOrder);
01227       return EFI_OUT_OF_RESOURCES;
01228     }
01229 
01230     TempPtr = BootOptionVar;
01231     TempPtr += sizeof (UINT32) + sizeof (UINT16);
01232     TempPtr += StrSize ((CHAR16 *) TempPtr);
01233     OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
01234     OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);
01235 
01236     //
01237     // Check whether the device path match
01238     //
01239     if ((OptionDevicePathSize == DevicePathSize) &&
01240         (CompareMem (DevicePath, OptionDevicePath, DevicePathSize) == 0)) {
01241       BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);
01242       FreePool (BootOptionVar);
01243       break;
01244     }
01245 
01246     FreePool (BootOptionVar);
01247     Index++;
01248   }
01249 
01250   //
01251   // Adjust number of boot option for "BootOrder" variable.
01252   //
01253   Status = gRT->SetVariable (
01254                   L"BootOrder",
01255                   &gEfiGlobalVariableGuid,
01256                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
01257                   BootOrderSize,
01258                   BootOrder
01259                   );
01260 
01261   FreePool (BootOrder);
01262 
01263   return Status;
01264 }
01265 
01266 
01276 EFI_STATUS
01277 BdsDeleteAllInvalidEfiBootOption (
01278   VOID
01279   )
01280 {
01281   UINT16                    *BootOrder;
01282   UINT8                     *BootOptionVar;
01283   UINTN                     BootOrderSize;
01284   UINTN                     BootOptionSize;
01285   EFI_STATUS                Status;
01286   UINTN                     Index;
01287   UINTN                     Index2;
01288   UINT16                    BootOption[BOOT_OPTION_MAX_CHAR];
01289   EFI_DEVICE_PATH_PROTOCOL  *OptionDevicePath;
01290   UINT8                     *TempPtr;
01291   CHAR16                    *Description;
01292 
01293   Status        = EFI_SUCCESS;
01294   BootOrder     = NULL;
01295   BootOrderSize = 0;
01296 
01297   //
01298   // Check "BootOrder" variable firstly, this variable hold the number of boot options
01299   //
01300   BootOrder = BdsLibGetVariableAndSize (
01301                 L"BootOrder",
01302                 &gEfiGlobalVariableGuid,
01303                 &BootOrderSize
01304                 );
01305   if (NULL == BootOrder) {
01306     return EFI_NOT_FOUND;
01307   }
01308 
01309   Index = 0;
01310   while (Index < BootOrderSize / sizeof (UINT16)) {
01311     UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
01312     BootOptionVar = BdsLibGetVariableAndSize (
01313                       BootOption,
01314                       &gEfiGlobalVariableGuid,
01315                       &BootOptionSize
01316                       );
01317     if (NULL == BootOptionVar) {
01318       FreePool (BootOrder);
01319       return EFI_OUT_OF_RESOURCES;
01320     }
01321 
01322     TempPtr = BootOptionVar;
01323     TempPtr += sizeof (UINT32) + sizeof (UINT16);
01324     Description = (CHAR16 *) TempPtr;
01325     TempPtr += StrSize ((CHAR16 *) TempPtr);
01326     OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
01327 
01328     //
01329     // Skip legacy boot option (BBS boot device)
01330     //
01331     if ((DevicePathType (OptionDevicePath) == BBS_DEVICE_PATH) &&
01332         (DevicePathSubType (OptionDevicePath) == BBS_BBS_DP)) {
01333       FreePool (BootOptionVar);
01334       Index++;
01335       continue;
01336     }
01337 
01338     if (!BdsLibIsValidEFIBootOptDevicePathExt (OptionDevicePath, FALSE, Description)) {
01339       //
01340       // Delete this invalid boot option "Boot####"
01341       //
01342       Status = gRT->SetVariable (
01343                       BootOption,
01344                       &gEfiGlobalVariableGuid,
01345                       EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
01346                       0,
01347                       NULL
01348                       );
01349       //
01350       // Mark this boot option in boot order as deleted
01351       //
01352       BootOrder[Index] = 0xffff;
01353     }
01354 
01355     FreePool (BootOptionVar);
01356     Index++;
01357   }
01358 
01359   //
01360   // Adjust boot order array
01361   //
01362   Index2 = 0;
01363   for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
01364     if (BootOrder[Index] != 0xffff) {
01365       BootOrder[Index2] = BootOrder[Index];
01366       Index2 ++;
01367     }
01368   }
01369   Status = gRT->SetVariable (
01370                   L"BootOrder",
01371                   &gEfiGlobalVariableGuid,
01372                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
01373                   Index2 * sizeof (UINT16),
01374                   BootOrder
01375                   );
01376 
01377   FreePool (BootOrder);
01378 
01379   return Status;
01380 }
01381 
01382 
01427 EFI_STATUS
01428 EFIAPI
01429 BdsLibEnumerateAllBootOption (
01430   IN OUT LIST_ENTRY          *BdsBootOptionList
01431   )
01432 {
01433   EFI_STATUS                    Status;
01434   UINT16                        FloppyNumber;
01435   UINT16                        HarddriveNumber;
01436   UINT16                        CdromNumber;
01437   UINT16                        UsbNumber;
01438   UINT16                        MiscNumber;
01439   UINT16                        ScsiNumber;
01440   UINT16                        NonBlockNumber;
01441   UINTN                         NumberBlockIoHandles;
01442   EFI_HANDLE                    *BlockIoHandles;
01443   EFI_BLOCK_IO_PROTOCOL         *BlkIo;
01444   BOOLEAN                       Removable[2];
01445   UINTN                         RemovableIndex;
01446   UINTN                         Index;
01447   UINTN                         NumOfLoadFileHandles;
01448   EFI_HANDLE                    *LoadFileHandles;
01449   UINTN                         FvHandleCount;
01450   EFI_HANDLE                    *FvHandleBuffer;
01451   EFI_FV_FILETYPE               Type;
01452   UINTN                         Size;
01453   EFI_FV_FILE_ATTRIBUTES        Attributes;
01454   UINT32                        AuthenticationStatus;
01455   EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
01456   EFI_DEVICE_PATH_PROTOCOL      *DevicePath;
01457   UINTN                         DevicePathType;
01458   CHAR16                        Buffer[40];
01459   EFI_HANDLE                    *FileSystemHandles;
01460   UINTN                         NumberFileSystemHandles;
01461   BOOLEAN                       NeedDelete;
01462   EFI_IMAGE_DOS_HEADER          DosHeader;
01463   CHAR8                         *PlatLang;
01464   CHAR8                         *LastLang;
01465   EFI_IMAGE_OPTIONAL_HEADER_UNION       HdrData;
01466   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
01467 
01468   FloppyNumber    = 0;
01469   HarddriveNumber = 0;
01470   CdromNumber     = 0;
01471   UsbNumber       = 0;
01472   MiscNumber      = 0;
01473   ScsiNumber      = 0;
01474   PlatLang        = NULL;
01475   LastLang        = NULL;
01476   ZeroMem (Buffer, sizeof (Buffer));
01477 
01478   //
01479   // If the boot device enumerate happened, just get the boot
01480   // device from the boot order variable
01481   //
01482   if (mEnumBootDevice) {
01483     LastLang = GetVariable (LAST_ENUM_LANGUAGE_VARIABLE_NAME, &gLastEnumLangGuid);
01484     PlatLang = GetEfiGlobalVariable (L"PlatformLang");
01485     ASSERT (PlatLang != NULL);
01486     if ((LastLang != NULL) && (AsciiStrCmp (LastLang, PlatLang) == 0)) {
01487       Status = BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
01488       FreePool (LastLang);
01489       FreePool (PlatLang);
01490       return Status;
01491     } else {
01492       Status = gRT->SetVariable (
01493         LAST_ENUM_LANGUAGE_VARIABLE_NAME,
01494         &gLastEnumLangGuid,
01495         EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
01496         AsciiStrSize (PlatLang),
01497         PlatLang
01498         );
01499       ASSERT_EFI_ERROR (Status);
01500 
01501       if (LastLang != NULL) {
01502         FreePool (LastLang);
01503       }
01504       FreePool (PlatLang);
01505     }
01506   }
01507 
01508   //
01509   // Notes: this dirty code is to get the legacy boot option from the
01510   // BBS table and create to variable as the EFI boot option, it should
01511   // be removed after the CSM can provide legacy boot option directly
01512   //
01513   REFRESH_LEGACY_BOOT_OPTIONS;
01514 
01515   //
01516   // Delete invalid boot option
01517   //
01518   BdsDeleteAllInvalidEfiBootOption ();
01519 
01520   //
01521   // Parse removable media followed by fixed media.
01522   // The Removable[] array is used by the for-loop below to create removable media boot options 
01523   // at first, and then to create fixed media boot options.
01524   //
01525   Removable[0]  = FALSE;
01526   Removable[1]  = TRUE;
01527 
01528   gBS->LocateHandleBuffer (
01529         ByProtocol,
01530         &gEfiBlockIoProtocolGuid,
01531         NULL,
01532         &NumberBlockIoHandles,
01533         &BlockIoHandles
01534         );
01535 
01536   for (RemovableIndex = 0; RemovableIndex < 2; RemovableIndex++) {
01537     for (Index = 0; Index < NumberBlockIoHandles; Index++) {
01538       Status = gBS->HandleProtocol (
01539                       BlockIoHandles[Index],
01540                       &gEfiBlockIoProtocolGuid,
01541                       (VOID **) &BlkIo
01542                       );
01543       //
01544       // skip the fixed block io then the removable block io
01545       //
01546       if (EFI_ERROR (Status) || (BlkIo->Media->RemovableMedia == Removable[RemovableIndex])) {
01547         continue;
01548       }
01549       DevicePath  = DevicePathFromHandle (BlockIoHandles[Index]);
01550       DevicePathType = BdsGetBootTypeFromDevicePath (DevicePath);
01551 
01552       switch (DevicePathType) {
01553       case BDS_EFI_ACPI_FLOPPY_BOOT:
01554         if (FloppyNumber != 0) {
01555           UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY)), FloppyNumber);
01556         } else {
01557           UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY)));
01558         }
01559         BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
01560         FloppyNumber++;
01561         break;
01562 
01563       //
01564       // Assume a removable SATA device should be the DVD/CD device, a fixed SATA device should be the Hard Drive device.
01565       //
01566       case BDS_EFI_MESSAGE_ATAPI_BOOT:
01567       case BDS_EFI_MESSAGE_SATA_BOOT:
01568         if (BlkIo->Media->RemovableMedia) {
01569           if (CdromNumber != 0) {
01570             UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_CD_DVD)), CdromNumber);
01571           } else {
01572             UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_CD_DVD)));
01573           }
01574           CdromNumber++;
01575         } else {
01576           if (HarddriveNumber != 0) {
01577             UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_HARDDRIVE)), HarddriveNumber);
01578           } else {
01579             UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_HARDDRIVE)));
01580           }
01581           HarddriveNumber++;
01582         }
01583         DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Buffer: %S\n", Buffer));
01584         BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
01585         break;
01586 
01587       case BDS_EFI_MESSAGE_USB_DEVICE_BOOT:
01588         if (UsbNumber != 0) {
01589           UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_USB)), UsbNumber);
01590         } else {
01591           UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_USB)));
01592         }
01593         BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
01594         UsbNumber++;
01595         break;
01596 
01597       case BDS_EFI_MESSAGE_SCSI_BOOT:
01598         if (ScsiNumber != 0) {
01599           UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI)), ScsiNumber);
01600         } else {
01601           UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI)));
01602         }
01603         BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
01604         ScsiNumber++;
01605         break;
01606 
01607       case BDS_EFI_MESSAGE_MISC_BOOT:
01608         if (MiscNumber != 0) {
01609           UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC)), MiscNumber);
01610         } else {
01611           UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC)));
01612         }
01613         BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
01614         MiscNumber++;
01615         break;
01616 
01617       default:
01618         break;
01619       }
01620     }
01621   }
01622 
01623   if (NumberBlockIoHandles != 0) {
01624     FreePool (BlockIoHandles);
01625   }
01626 
01627   //
01628   // If there is simple file protocol which does not consume block Io protocol, create a boot option for it here.
01629   //
01630   NonBlockNumber = 0;
01631   gBS->LocateHandleBuffer (
01632         ByProtocol,
01633         &gEfiSimpleFileSystemProtocolGuid,
01634         NULL,
01635         &NumberFileSystemHandles,
01636         &FileSystemHandles
01637         );
01638   for (Index = 0; Index < NumberFileSystemHandles; Index++) {
01639     Status = gBS->HandleProtocol (
01640                     FileSystemHandles[Index],
01641                     &gEfiBlockIoProtocolGuid,
01642                     (VOID **) &BlkIo
01643                     );
01644      if (!EFI_ERROR (Status)) {
01645       //
01646       //  Skip if the file system handle supports a BlkIo protocol,
01647       //
01648       continue;
01649     }
01650 
01651     //
01652     // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI
01653     //  machinename is ia32, ia64, x64, ...
01654     //
01655     Hdr.Union  = &HdrData;
01656     NeedDelete = TRUE;
01657     Status     = BdsLibGetImageHeader (
01658                    FileSystemHandles[Index],
01659                    EFI_REMOVABLE_MEDIA_FILE_NAME,
01660                    &DosHeader,
01661                    Hdr
01662                    );
01663     if (!EFI_ERROR (Status) &&
01664         EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&
01665         Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
01666       NeedDelete = FALSE;
01667     }
01668 
01669     if (NeedDelete) {
01670       //
01671       // No such file or the file is not a EFI application, delete this boot option
01672       //
01673       BdsLibDeleteOptionFromHandle (FileSystemHandles[Index]);
01674     } else {
01675       if (NonBlockNumber != 0) {
01676         UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NON_BLOCK)), NonBlockNumber);
01677       } else {
01678         UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NON_BLOCK)));
01679       }
01680       BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList, Buffer);
01681       NonBlockNumber++;
01682     }
01683   }
01684 
01685   if (NumberFileSystemHandles != 0) {
01686     FreePool (FileSystemHandles);
01687   }
01688 
01689   //
01690   // Parse Network Boot Device
01691   //
01692   NumOfLoadFileHandles = 0;
01693   //
01694   // Search Load File protocol for PXE boot option.
01695   //
01696   gBS->LocateHandleBuffer (
01697         ByProtocol,
01698         &gEfiLoadFileProtocolGuid,
01699         NULL,
01700         &NumOfLoadFileHandles,
01701         &LoadFileHandles
01702         );
01703 
01704   for (Index = 0; Index < NumOfLoadFileHandles; Index++) {
01705     if (Index != 0) {
01706       UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NETWORK)), Index);
01707     } else {
01708       UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NETWORK)));
01709     }
01710     BdsLibBuildOptionFromHandle (LoadFileHandles[Index], BdsBootOptionList, Buffer);
01711   }
01712 
01713   if (NumOfLoadFileHandles != 0) {
01714     FreePool (LoadFileHandles);
01715   }
01716 
01717   //
01718   // Check if we have on flash shell
01719   //
01720   gBS->LocateHandleBuffer (
01721         ByProtocol,
01722         &gEfiFirmwareVolume2ProtocolGuid,
01723         NULL,
01724         &FvHandleCount,
01725         &FvHandleBuffer
01726         );
01727   for (Index = 0; Index < FvHandleCount; Index++) {
01728     gBS->HandleProtocol (
01729           FvHandleBuffer[Index],
01730           &gEfiFirmwareVolume2ProtocolGuid,
01731           (VOID **) &Fv
01732           );
01733 
01734     Status = Fv->ReadFile (
01735                   Fv,
01736                   PcdGetPtr(PcdShellFile),
01737                   NULL,
01738                   &Size,
01739                   &Type,
01740                   &Attributes,
01741                   &AuthenticationStatus
01742                   );
01743     if (EFI_ERROR (Status)) {
01744       //
01745       // Skip if no shell file in the FV
01746       //
01747       continue;
01748     }
01749     //
01750     // Build the shell boot option
01751     //
01752     BdsLibBuildOptionFromShell (FvHandleBuffer[Index], BdsBootOptionList);
01753   }
01754 
01755   if (FvHandleCount != 0) {
01756     FreePool (FvHandleBuffer);
01757   }
01758   //
01759   // Make sure every boot only have one time
01760   // boot device enumerate
01761   //
01762   Status = BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
01763   mEnumBootDevice = TRUE;
01764 
01765   return Status;
01766 }
01767 
01778 VOID
01779 EFIAPI
01780 BdsLibBuildOptionFromHandle (
01781   IN  EFI_HANDLE                 Handle,
01782   IN  LIST_ENTRY                 *BdsBootOptionList,
01783   IN  CHAR16                     *String
01784   )
01785 {
01786   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
01787 
01788   DevicePath = DevicePathFromHandle (Handle);
01789 
01790   //
01791   // Create and register new boot option
01792   //
01793   BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, String, L"BootOrder");
01794 }
01795 
01796 
01806 VOID
01807 EFIAPI
01808 BdsLibBuildOptionFromShell (
01809   IN EFI_HANDLE                  Handle,
01810   IN OUT LIST_ENTRY              *BdsBootOptionList
01811   )
01812 {
01813   EFI_DEVICE_PATH_PROTOCOL          *DevicePath;
01814   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode;
01815 
01816   DevicePath = DevicePathFromHandle (Handle);
01817 
01818   //
01819   // Build the shell device path
01820   //
01821   EfiInitializeFwVolDevicepathNode (&ShellNode, PcdGetPtr(PcdShellFile));
01822 
01823   DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode);
01824 
01825   //
01826   // Create and register the shell boot option
01827   //
01828   BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, L"EFI Internal Shell", L"BootOrder");
01829 
01830 }
01831 
01836 VOID
01837 EFIAPI
01838 BdsLibBootNext (
01839   VOID
01840   )
01841 {
01842   UINT16            *BootNext;
01843   UINTN             BootNextSize;
01844   CHAR16            Buffer[20];
01845   BDS_COMMON_OPTION *BootOption;
01846   LIST_ENTRY        TempList;
01847   UINTN             ExitDataSize;
01848   CHAR16            *ExitData;
01849 
01850   //
01851   // Init the boot option name buffer and temp link list
01852   //
01853   InitializeListHead (&TempList);
01854   ZeroMem (Buffer, sizeof (Buffer));
01855 
01856   BootNext = BdsLibGetVariableAndSize (
01857               L"BootNext",
01858               &gEfiGlobalVariableGuid,
01859               &BootNextSize
01860               );
01861 
01862   //
01863   // Clear the boot next variable first
01864   //
01865   if (BootNext != NULL) {
01866     gRT->SetVariable (
01867           L"BootNext",
01868           &gEfiGlobalVariableGuid,
01869           EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
01870           0,
01871           BootNext
01872           );
01873 
01874     //
01875     // Start to build the boot option and try to boot
01876     //
01877     UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext);
01878     BootOption = BdsLibVariableToOption (&TempList, Buffer);
01879     ASSERT (BootOption != NULL);
01880     BdsLibConnectDevicePath (BootOption->DevicePath);
01881     BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
01882   }
01883 
01884 }
01885 
01897 EFI_HANDLE
01898 EFIAPI
01899 BdsLibGetBootableHandle (
01900   IN  EFI_DEVICE_PATH_PROTOCOL      *DevicePath
01901   )
01902 {
01903   EFI_STATUS                      Status;
01904   EFI_TPL                         OldTpl;
01905   EFI_DEVICE_PATH_PROTOCOL        *UpdatedDevicePath;
01906   EFI_DEVICE_PATH_PROTOCOL        *DupDevicePath;
01907   EFI_HANDLE                      Handle;
01908   EFI_BLOCK_IO_PROTOCOL           *BlockIo;
01909   VOID                            *Buffer;
01910   EFI_DEVICE_PATH_PROTOCOL        *TempDevicePath;
01911   UINTN                           Size;
01912   UINTN                           TempSize;
01913   EFI_HANDLE                      ReturnHandle;
01914   EFI_HANDLE                      *SimpleFileSystemHandles;
01915 
01916   UINTN                           NumberSimpleFileSystemHandles;
01917   UINTN                           Index;
01918   EFI_IMAGE_DOS_HEADER            DosHeader;
01919   EFI_IMAGE_OPTIONAL_HEADER_UNION       HdrData;
01920   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
01921 
01922   UpdatedDevicePath = DevicePath;
01923 
01924   //
01925   // Enter to critical section to protect the acquired BlockIo instance 
01926   // from getting released due to the USB mass storage hotplug event
01927   //
01928   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
01929 
01930   //
01931   // Check whether the device is connected
01932   //
01933   Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &UpdatedDevicePath, &Handle);
01934   if (EFI_ERROR (Status)) {
01935     //
01936     // Skip the case that the boot option point to a simple file protocol which does not consume block Io protocol,
01937     //
01938     Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &UpdatedDevicePath, &Handle);
01939     if (EFI_ERROR (Status)) {
01940       //
01941       // Fail to find the proper BlockIo and simple file protocol, maybe because device not present,  we need to connect it firstly
01942       //
01943       UpdatedDevicePath = DevicePath;
01944       Status            = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);
01945       gBS->ConnectController (Handle, NULL, NULL, TRUE);
01946     }
01947   } else {
01948     //
01949     // For removable device boot option, its contained device path only point to the removable device handle, 
01950     // should make sure all its children handles (its child partion or media handles) are created and connected. 
01951     //
01952     gBS->ConnectController (Handle, NULL, NULL, TRUE); 
01953     //
01954     // Get BlockIo protocol and check removable attribute
01955     //
01956     Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
01957     ASSERT_EFI_ERROR (Status);
01958 
01959     //
01960     // Issue a dummy read to the device to check for media change.
01961     // When the removable media is changed, any Block IO read/write will
01962     // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
01963     // returned. After the Block IO protocol is reinstalled, subsequent
01964     // Block IO read/write will success.
01965     //
01966     Buffer = AllocatePool (BlockIo->Media->BlockSize);
01967     if (Buffer != NULL) {
01968       BlockIo->ReadBlocks (
01969                BlockIo,
01970                BlockIo->Media->MediaId,
01971                0,
01972                BlockIo->Media->BlockSize,
01973                Buffer
01974                );
01975       FreePool(Buffer);
01976     }
01977   }
01978 
01979   //
01980   // Detect the the default boot file from removable Media
01981   //
01982 
01983   //
01984   // If fail to get bootable handle specified by a USB boot option, the BDS should try to find other bootable device in the same USB bus
01985   // Try to locate the USB node device path first, if fail then use its previous PCI node to search
01986   //
01987   DupDevicePath = DuplicateDevicePath (DevicePath);
01988   ASSERT (DupDevicePath != NULL);
01989 
01990   UpdatedDevicePath = DupDevicePath;
01991   Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);
01992   //
01993   // if the resulting device path point to a usb node, and the usb node is a dummy node, should only let device path only point to the previous Pci node
01994   // Acpi()/Pci()/Usb() --> Acpi()/Pci()
01995   //
01996   if ((DevicePathType (UpdatedDevicePath) == MESSAGING_DEVICE_PATH) &&
01997       (DevicePathSubType (UpdatedDevicePath) == MSG_USB_DP)) {
01998     //
01999     // Remove the usb node, let the device path only point to PCI node
02000     //
02001     SetDevicePathEndNode (UpdatedDevicePath);
02002     UpdatedDevicePath = DupDevicePath;
02003   } else {
02004     UpdatedDevicePath = DevicePath;
02005   }
02006 
02007   //
02008   // Get the device path size of boot option
02009   //
02010   Size = GetDevicePathSize(UpdatedDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node
02011   ReturnHandle = NULL;
02012   gBS->LocateHandleBuffer (
02013       ByProtocol,
02014       &gEfiSimpleFileSystemProtocolGuid,
02015       NULL,
02016       &NumberSimpleFileSystemHandles,
02017       &SimpleFileSystemHandles
02018       );
02019   for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
02020     //
02021     // Get the device path size of SimpleFileSystem handle
02022     //
02023     TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
02024     TempSize = GetDevicePathSize (TempDevicePath)- sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node
02025     //
02026     // Check whether the device path of boot option is part of the  SimpleFileSystem handle's device path
02027     //
02028     if (Size <= TempSize && CompareMem (TempDevicePath, UpdatedDevicePath, Size)==0) {
02029       //
02030       // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
02031       //  machinename is ia32, ia64, x64, ...
02032       //
02033       Hdr.Union = &HdrData;
02034       Status = BdsLibGetImageHeader (
02035                  SimpleFileSystemHandles[Index],
02036                  EFI_REMOVABLE_MEDIA_FILE_NAME,
02037                  &DosHeader,
02038                  Hdr
02039                  );
02040       if (!EFI_ERROR (Status) &&
02041         EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&
02042         Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
02043         ReturnHandle = SimpleFileSystemHandles[Index];
02044         break;
02045       }
02046     }
02047   }
02048 
02049   FreePool(DupDevicePath);
02050 
02051   if (SimpleFileSystemHandles != NULL) {
02052     FreePool(SimpleFileSystemHandles);
02053   }
02054 
02055   gBS->RestoreTPL (OldTpl);
02056 
02057   return ReturnHandle;
02058 }
02059 
02070 BOOLEAN
02071 BdsLibNetworkBootWithMediaPresent (
02072   IN  EFI_DEVICE_PATH_PROTOCOL      *DevicePath
02073   )
02074 {
02075   EFI_STATUS                      Status;
02076   EFI_DEVICE_PATH_PROTOCOL        *UpdatedDevicePath;
02077   EFI_HANDLE                      Handle;
02078   EFI_SIMPLE_NETWORK_PROTOCOL     *Snp;
02079   BOOLEAN                         MediaPresent;
02080   UINT32                          InterruptStatus;
02081 
02082   MediaPresent = FALSE;
02083 
02084   UpdatedDevicePath = DevicePath;
02085   //
02086   // Locate Load File Protocol for PXE boot option first
02087   //
02088   Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &UpdatedDevicePath, &Handle);
02089   if (EFI_ERROR (Status)) {
02090     //
02091     // Device not present so see if we need to connect it
02092     //
02093     Status = BdsLibConnectDevicePath (DevicePath);
02094     if (!EFI_ERROR (Status)) {
02095       //
02096       // This one should work after we did the connect
02097       //
02098       Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &UpdatedDevicePath, &Handle);
02099     }
02100   }
02101 
02102   if (!EFI_ERROR (Status)) {
02103     Status = gBS->HandleProtocol (Handle, &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp);
02104     if (EFI_ERROR (Status)) {
02105       //
02106       // Failed to open SNP from this handle, try to get SNP from parent handle
02107       //
02108       UpdatedDevicePath = DevicePathFromHandle (Handle);
02109       if (UpdatedDevicePath != NULL) {
02110         Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &UpdatedDevicePath, &Handle);
02111         if (!EFI_ERROR (Status)) {
02112           //
02113           // SNP handle found, get SNP from it
02114           //
02115           Status = gBS->HandleProtocol (Handle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &Snp);
02116         }
02117       }
02118     }
02119 
02120     if (!EFI_ERROR (Status)) {
02121       if (Snp->Mode->MediaPresentSupported) {
02122         if (Snp->Mode->State == EfiSimpleNetworkInitialized) {
02123           //
02124           // Invoke Snp->GetStatus() to refresh the media status
02125           //
02126           Snp->GetStatus (Snp, &InterruptStatus, NULL);
02127 
02128           //
02129           // In case some one else is using the SNP check to see if it's connected
02130           //
02131           MediaPresent = Snp->Mode->MediaPresent;
02132         } else {
02133           //
02134           // No one is using SNP so we need to Start and Initialize so
02135           // MediaPresent will be valid.
02136           //
02137           Status = Snp->Start (Snp);
02138           if (!EFI_ERROR (Status)) {
02139             Status = Snp->Initialize (Snp, 0, 0);
02140             if (!EFI_ERROR (Status)) {
02141               MediaPresent = Snp->Mode->MediaPresent;
02142               Snp->Shutdown (Snp);
02143             }
02144             Snp->Stop (Snp);
02145           }
02146         }
02147       } else {
02148         MediaPresent = TRUE;
02149       }
02150     }
02151   }
02152 
02153   return MediaPresent;
02154 }
02155 
02179 UINT32
02180 EFIAPI
02181 BdsGetBootTypeFromDevicePath (
02182   IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
02183   )
02184 {
02185   ACPI_HID_DEVICE_PATH          *Acpi;
02186   EFI_DEVICE_PATH_PROTOCOL      *TempDevicePath;
02187   EFI_DEVICE_PATH_PROTOCOL      *LastDeviceNode;
02188   UINT32                        BootType;
02189 
02190   if (NULL == DevicePath) {
02191     return BDS_EFI_UNSUPPORT;
02192   }
02193 
02194   TempDevicePath = DevicePath;
02195 
02196   while (!IsDevicePathEndType (TempDevicePath)) {
02197     switch (DevicePathType (TempDevicePath)) {
02198       case BBS_DEVICE_PATH:
02199          return BDS_LEGACY_BBS_BOOT;
02200       case MEDIA_DEVICE_PATH:
02201         if (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP) {
02202           return BDS_EFI_MEDIA_HD_BOOT;
02203         } else if (DevicePathSubType (TempDevicePath) == MEDIA_CDROM_DP) {
02204           return BDS_EFI_MEDIA_CDROM_BOOT;
02205         }
02206         break;
02207       case ACPI_DEVICE_PATH:
02208         Acpi = (ACPI_HID_DEVICE_PATH *) TempDevicePath;
02209         if (EISA_ID_TO_NUM (Acpi->HID) == 0x0604) {
02210           return BDS_EFI_ACPI_FLOPPY_BOOT;
02211         }
02212         break;
02213       case MESSAGING_DEVICE_PATH:
02214         //
02215         // Get the last device path node
02216         //
02217         LastDeviceNode = NextDevicePathNode (TempDevicePath);
02218         if (DevicePathSubType(LastDeviceNode) == MSG_DEVICE_LOGICAL_UNIT_DP) {
02219           //
02220           // if the next node type is Device Logical Unit, which specify the Logical Unit Number (LUN),
02221           // skip it
02222           //
02223           LastDeviceNode = NextDevicePathNode (LastDeviceNode);
02224         }
02225         //
02226         // if the device path not only point to driver device, it is not a messaging device path,
02227         //
02228         if (!IsDevicePathEndType (LastDeviceNode)) {
02229           break;
02230         }
02231 
02232         switch (DevicePathSubType (TempDevicePath)) {
02233         case MSG_ATAPI_DP:
02234           BootType = BDS_EFI_MESSAGE_ATAPI_BOOT;
02235           break;
02236 
02237         case MSG_USB_DP:
02238           BootType = BDS_EFI_MESSAGE_USB_DEVICE_BOOT;
02239           break;
02240 
02241         case MSG_SCSI_DP:
02242           BootType = BDS_EFI_MESSAGE_SCSI_BOOT;
02243           break;
02244 
02245         case MSG_SATA_DP:
02246           BootType = BDS_EFI_MESSAGE_SATA_BOOT;
02247           break;
02248 
02249         case MSG_MAC_ADDR_DP:
02250         case MSG_VLAN_DP:
02251         case MSG_IPv4_DP:
02252         case MSG_IPv6_DP:
02253           BootType = BDS_EFI_MESSAGE_MAC_BOOT;
02254           break;
02255 
02256         default:
02257           BootType = BDS_EFI_MESSAGE_MISC_BOOT;
02258           break;
02259         }
02260         return BootType;
02261 
02262       default:
02263         break;
02264     }
02265     TempDevicePath = NextDevicePathNode (TempDevicePath);
02266   }
02267 
02268   return BDS_EFI_UNSUPPORT;
02269 }
02270 
02282 BOOLEAN
02283 EFIAPI
02284 BdsLibIsValidEFIBootOptDevicePath (
02285   IN EFI_DEVICE_PATH_PROTOCOL     *DevPath,
02286   IN BOOLEAN                      CheckMedia
02287   )
02288 {
02289   return BdsLibIsValidEFIBootOptDevicePathExt (DevPath, CheckMedia, NULL);
02290 }
02291 
02307 BOOLEAN
02308 EFIAPI
02309 BdsLibIsValidEFIBootOptDevicePathExt (
02310   IN EFI_DEVICE_PATH_PROTOCOL     *DevPath,
02311   IN BOOLEAN                      CheckMedia,
02312   IN CHAR16                       *Description
02313   )
02314 {
02315   EFI_STATUS                Status;
02316   EFI_HANDLE                Handle;
02317   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
02318   EFI_DEVICE_PATH_PROTOCOL  *LastDeviceNode;
02319   EFI_BLOCK_IO_PROTOCOL     *BlockIo;
02320 
02321   TempDevicePath = DevPath;
02322   LastDeviceNode = DevPath;
02323 
02324   //
02325   // Check if it's a valid boot option for network boot device.
02326   // Check if there is EfiLoadFileProtocol installed. 
02327   // If yes, that means there is a boot option for network.
02328   //
02329   Status = gBS->LocateDevicePath (
02330                   &gEfiLoadFileProtocolGuid,
02331                   &TempDevicePath,
02332                   &Handle
02333                   );
02334   if (EFI_ERROR (Status)) {
02335     //
02336     // Device not present so see if we need to connect it
02337     //
02338     TempDevicePath = DevPath;
02339     BdsLibConnectDevicePath (TempDevicePath);
02340     Status = gBS->LocateDevicePath (
02341                     &gEfiLoadFileProtocolGuid,
02342                     &TempDevicePath,
02343                     &Handle
02344                     );
02345   }
02346 
02347   if (!EFI_ERROR (Status)) {
02348     if (!IsDevicePathEnd (TempDevicePath)) {
02349       //
02350       // LoadFile protocol is not installed on handle with exactly the same DevPath
02351       //
02352       return FALSE;
02353     }
02354 
02355     if (CheckMedia) {
02356       //
02357       // Test if it is ready to boot now
02358       //
02359       if (BdsLibNetworkBootWithMediaPresent(DevPath)) {
02360         return TRUE;
02361       }
02362     } else {
02363       return TRUE;
02364     }    
02365   }
02366 
02367   //
02368   // If the boot option point to a file, it is a valid EFI boot option,
02369   // and assume it is ready to boot now
02370   //
02371   while (!IsDevicePathEnd (TempDevicePath)) {
02372     //
02373     // If there is USB Class or USB WWID device path node, treat it as valid EFI
02374     // Boot Option. BdsExpandUsbShortFormDevicePath () will be used to expand it
02375     // to full device path.
02376     //
02377     if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&
02378         ((DevicePathSubType (TempDevicePath) == MSG_USB_CLASS_DP) ||
02379          (DevicePathSubType (TempDevicePath) == MSG_USB_WWID_DP))) {
02380       return TRUE;
02381     }
02382 
02383     LastDeviceNode = TempDevicePath;
02384     TempDevicePath = NextDevicePathNode (TempDevicePath);
02385   }
02386   if ((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) &&
02387     (DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) {
02388     return TRUE;
02389   }
02390 
02391   //
02392   // Check if it's a valid boot option for internal FV application
02393   //
02394   if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) != NULL) {
02395     //
02396     // If the boot option point to internal FV application, make sure it is valid
02397     //
02398     TempDevicePath = DevPath;
02399     Status = BdsLibUpdateFvFileDevicePath (
02400                &TempDevicePath,
02401                EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode)
02402                );
02403     if (Status == EFI_ALREADY_STARTED) {
02404       return TRUE;
02405     } else {
02406       if (Status == EFI_SUCCESS) {
02407         FreePool (TempDevicePath);
02408       }
02409       return FALSE;
02410     }
02411   }
02412 
02413   //
02414   // If the boot option point to a blockIO device:
02415   //    if it is a removable blockIo device, it is valid.
02416   //    if it is a fixed blockIo device, check its description confliction.
02417   //
02418   TempDevicePath = DevPath;
02419   Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
02420   if (EFI_ERROR (Status)) {
02421     //
02422     // Device not present so see if we need to connect it
02423     //
02424     Status = BdsLibConnectDevicePath (DevPath);
02425     if (!EFI_ERROR (Status)) {
02426       //
02427       // Try again to get the Block Io protocol after we did the connect
02428       //
02429       TempDevicePath = DevPath;
02430       Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
02431     }
02432   }
02433 
02434   if (!EFI_ERROR (Status)) {
02435     Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
02436     if (!EFI_ERROR (Status)) {
02437       if (CheckMedia) {
02438         //
02439         // Test if it is ready to boot now
02440         //
02441         if (BdsLibGetBootableHandle (DevPath) != NULL) {
02442           return TRUE;
02443         }
02444       } else {
02445         return TRUE;
02446       }
02447     }
02448   } else {
02449     //
02450     // if the boot option point to a simple file protocol which does not consume block Io protocol, it is also a valid EFI boot option,
02451     //
02452     Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);
02453     if (!EFI_ERROR (Status)) {
02454       if (CheckMedia) {
02455         //
02456         // Test if it is ready to boot now
02457         //
02458         if (BdsLibGetBootableHandle (DevPath) != NULL) {
02459           return TRUE;
02460         }
02461       } else {
02462         return TRUE;
02463       }
02464     }
02465   }
02466 
02467   return FALSE;
02468 }
02469 
02470 
02491 EFI_STATUS
02492 EFIAPI
02493 BdsLibUpdateFvFileDevicePath (
02494   IN  OUT EFI_DEVICE_PATH_PROTOCOL      ** DevicePath,
02495   IN  EFI_GUID                          *FileGuid
02496   )
02497 {
02498   EFI_DEVICE_PATH_PROTOCOL      *TempDevicePath;
02499   EFI_DEVICE_PATH_PROTOCOL      *LastDeviceNode;
02500   EFI_STATUS                    Status;
02501   EFI_GUID                      *GuidPoint;
02502   UINTN                         Index;
02503   UINTN                         FvHandleCount;
02504   EFI_HANDLE                    *FvHandleBuffer;
02505   EFI_FV_FILETYPE               Type;
02506   UINTN                         Size;
02507   EFI_FV_FILE_ATTRIBUTES        Attributes;
02508   UINT32                        AuthenticationStatus;
02509   BOOLEAN                       FindFvFile;
02510   EFI_LOADED_IMAGE_PROTOCOL     *LoadedImage;
02511   EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
02512   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode;
02513   EFI_HANDLE                    FoundFvHandle;
02514   EFI_DEVICE_PATH_PROTOCOL      *NewDevicePath;
02515 
02516   if ((DevicePath == NULL) || (*DevicePath == NULL)) {
02517     return EFI_INVALID_PARAMETER;
02518   }
02519   if (FileGuid == NULL) {
02520     return EFI_INVALID_PARAMETER;
02521   }
02522 
02523   //
02524   // Check whether the device path point to the default the input Fv file
02525   //
02526   TempDevicePath = *DevicePath;
02527   LastDeviceNode = TempDevicePath;
02528   while (!IsDevicePathEnd (TempDevicePath)) {
02529      LastDeviceNode = TempDevicePath;
02530      TempDevicePath = NextDevicePathNode (TempDevicePath);
02531   }
02532   GuidPoint = EfiGetNameGuidFromFwVolDevicePathNode (
02533                 (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode
02534                 );
02535   if (GuidPoint == NULL) {
02536     //
02537     // if this option does not points to a Fv file, just return EFI_UNSUPPORTED
02538     //
02539     return EFI_UNSUPPORTED;
02540   }
02541   if (!CompareGuid (GuidPoint, FileGuid)) {
02542     //
02543     // If the Fv file is not the input file guid, just return EFI_UNSUPPORTED
02544     //
02545     return EFI_UNSUPPORTED;
02546   }
02547 
02548   //
02549   // Check whether the input Fv file device path is valid
02550   //
02551   TempDevicePath = *DevicePath;
02552   FoundFvHandle = NULL;
02553   Status = gBS->LocateDevicePath (
02554                   &gEfiFirmwareVolume2ProtocolGuid,
02555                   &TempDevicePath,
02556                   &FoundFvHandle
02557                   );
02558   if (!EFI_ERROR (Status)) {
02559     Status = gBS->HandleProtocol (
02560                     FoundFvHandle,
02561                     &gEfiFirmwareVolume2ProtocolGuid,
02562                     (VOID **) &Fv
02563                     );
02564     if (!EFI_ERROR (Status)) {
02565       //
02566       // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there
02567       //
02568       Status = Fv->ReadFile (
02569                     Fv,
02570                     FileGuid,
02571                     NULL,
02572                     &Size,
02573                     &Type,
02574                     &Attributes,
02575                     &AuthenticationStatus
02576                     );
02577       if (!EFI_ERROR (Status)) {
02578         return EFI_ALREADY_STARTED;
02579       }
02580     }
02581   }
02582 
02583   //
02584   // Look for the input wanted FV file in current FV
02585   // First, try to look for in Bds own FV. Bds and input wanted FV file usually are in the same FV
02586   //
02587   FindFvFile = FALSE;
02588   FoundFvHandle = NULL;
02589   Status = gBS->HandleProtocol (
02590              gImageHandle,
02591              &gEfiLoadedImageProtocolGuid,
02592              (VOID **) &LoadedImage
02593              );
02594   if (!EFI_ERROR (Status)) {
02595     Status = gBS->HandleProtocol (
02596                     LoadedImage->DeviceHandle,
02597                     &gEfiFirmwareVolume2ProtocolGuid,
02598                     (VOID **) &Fv
02599                     );
02600     if (!EFI_ERROR (Status)) {
02601       Status = Fv->ReadFile (
02602                     Fv,
02603                     FileGuid,
02604                     NULL,
02605                     &Size,
02606                     &Type,
02607                     &Attributes,
02608                     &AuthenticationStatus
02609                     );
02610       if (!EFI_ERROR (Status)) {
02611         FindFvFile = TRUE;
02612         FoundFvHandle = LoadedImage->DeviceHandle;
02613       }
02614     }
02615   }
02616   //
02617   // Second, if fail to find, try to enumerate all FV
02618   //
02619   if (!FindFvFile) {
02620     FvHandleBuffer = NULL;
02621     gBS->LocateHandleBuffer (
02622           ByProtocol,
02623           &gEfiFirmwareVolume2ProtocolGuid,
02624           NULL,
02625           &FvHandleCount,
02626           &FvHandleBuffer
02627           );
02628     for (Index = 0; Index < FvHandleCount; Index++) {
02629       gBS->HandleProtocol (
02630             FvHandleBuffer[Index],
02631             &gEfiFirmwareVolume2ProtocolGuid,
02632             (VOID **) &Fv
02633             );
02634 
02635       Status = Fv->ReadFile (
02636                     Fv,
02637                     FileGuid,
02638                     NULL,
02639                     &Size,
02640                     &Type,
02641                     &Attributes,
02642                     &AuthenticationStatus
02643                     );
02644       if (EFI_ERROR (Status)) {
02645         //
02646         // Skip if input Fv file not in the FV
02647         //
02648         continue;
02649       }
02650       FindFvFile = TRUE;
02651       FoundFvHandle = FvHandleBuffer[Index];
02652       break;
02653     }
02654 
02655     if (FvHandleBuffer != NULL) {
02656       FreePool (FvHandleBuffer);
02657     }
02658   }
02659 
02660   if (FindFvFile) {
02661     //
02662     // Build the shell device path
02663     //
02664     NewDevicePath = DevicePathFromHandle (FoundFvHandle);
02665     EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid);
02666     NewDevicePath = AppendDevicePathNode (NewDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode);
02667     *DevicePath = NewDevicePath;
02668     return EFI_SUCCESS;
02669   }
02670   return EFI_NOT_FOUND;
02671 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Defines