/** The function will connect root bridge @return EFI_SUCCESS Connect RootBridge successfully. **/ EFI_STATUS ConnectRootBridge ( VOID ) { EFI_STATUS Status; EFI_HANDLE RootHandle; // // Make all the PCI_IO protocols on PCI Seg 0 show up // BdsLibConnectDevicePath (gPlatformRootBridges[0]); Status = gBS->LocateDevicePath ( &gEfiDevicePathProtocolGuid, &gPlatformRootBridges[0], &RootHandle ); if (EFI_ERROR (Status)) { return Status; } Status = gBS->ConnectController (RootHandle, NULL, NULL, FALSE); if (EFI_ERROR (Status)) { return Status; } return EFI_SUCCESS; }
VOID PlatformBdsConnectSequence ( VOID ) /*++ Routine Description: Connect with predeined platform connect sequence, the OEM/IBV can customize with their own connect sequence. Arguments: None. Returns: None. --*/ { UINTN Index; DEBUG ((EFI_D_INFO, "PlatformBdsConnectSequence\n")); Index = 0; // // Here we can get the customized platform connect sequence // Notes: we can connect with new variable which record the // last time boots connect device path sequence // while (gPlatformConnectSequence[Index] != NULL) { // // Build the platform boot option // BdsLibConnectDevicePath (gPlatformConnectSequence[Index]); Index++; } // // Just use the simple policy to connect all devices // BdsLibConnectAll (); PciInitialization (); AcpiInitialization (); // // Clear the logo after all devices are connected. // gST->ConOut->ClearScreen (gST->ConOut); }
EFI_STATUS ConnectRootBridge ( VOID ) /*++ Routine Description: Connect RootBridge Arguments: None. Returns: EFI_SUCCESS - Connect RootBridge successfully. EFI_STATUS - Connect RootBridge fail. --*/ { EFI_STATUS Status; EFI_HANDLE RootHandle; // // Make all the PCI_IO protocols on PCI Seg 0 show up // BdsLibConnectDevicePath (gPlatformRootBridges[0]); Status = gBS->LocateDevicePath ( &gEfiDevicePathProtocolGuid, &gPlatformRootBridges[0], &RootHandle ); if (EFI_ERROR (Status)) { return Status; } Status = gBS->ConnectController (RootHandle, NULL, NULL, FALSE); if (EFI_ERROR (Status)) { return Status; } return EFI_SUCCESS; }
/** Try to boot the boot option triggered by hotkey. @retval EFI_SUCCESS There is HotkeyBootOption & it is processed @retval EFI_NOT_FOUND There is no HotkeyBootOption **/ EFI_STATUS HotkeyBoot ( VOID ) { EFI_STATUS Status; UINTN ExitDataSize; CHAR16 *ExitData; if (mHotkeyBootOption == NULL) { return EFI_NOT_FOUND; } BdsLibConnectDevicePath (mHotkeyBootOption->DevicePath); // // Clear the screen before launch this BootOption // gST->ConOut->Reset (gST->ConOut, FALSE); Status = BdsLibBootViaBootOption (mHotkeyBootOption, mHotkeyBootOption->DevicePath, &ExitDataSize, &ExitData); if (EFI_ERROR (Status)) { // // Call platform action to indicate the boot fail // mHotkeyBootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED)); PlatformBdsBootFail (mHotkeyBootOption, Status, ExitData, ExitDataSize); } else { // // Call platform action to indicate the boot success // mHotkeyBootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED)); PlatformBdsBootSuccess (mHotkeyBootOption); } FreePool (mHotkeyBootOption->Description); FreePool (mHotkeyBootOption->DevicePath); FreePool (mHotkeyBootOption->LoadOptions); FreePool (mHotkeyBootOption); mHotkeyBootOption = NULL; return EFI_SUCCESS; }
/** Connect with predefined platform connect sequence, the OEM/IBV can customize with their own connect sequence. **/ VOID PlatformBdsConnectSequence ( VOID ) { UINTN Index; DEBUG ((EFI_D_INFO, "PlatformBdsConnectSequence\n")); Index = 0; // // Here we can get the customized platform connect sequence // Notes: we can connect with new variable which record the // last time boots connect device path sequence // while (gPlatformConnectSequence[Index] != NULL) { // // Build the platform boot option // BdsLibConnectDevicePath (gPlatformConnectSequence[Index]); Index++; } }
/** The function will go through the driver option link list, load and start every driver the driver option device path point to. @param BdsDriverLists The header of the current driver option link list **/ VOID EFIAPI BdsLibLoadDrivers ( IN LIST_ENTRY *BdsDriverLists ) { EFI_STATUS Status; LIST_ENTRY *Link; BDS_COMMON_OPTION *Option; EFI_HANDLE ImageHandle; EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; UINTN ExitDataSize; CHAR16 *ExitData; BOOLEAN ReconnectAll; ReconnectAll = FALSE; // // Process the driver option // for (Link = BdsDriverLists->ForwardLink; Link != BdsDriverLists; Link = Link->ForwardLink) { Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE); // // If a load option is not marked as LOAD_OPTION_ACTIVE, // the boot manager will not automatically load the option. // if (!IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_ACTIVE)) { continue; } // // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT, // then all of the EFI drivers in the system will be disconnected and // reconnected after the last driver load option is processed. // if (IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_FORCE_RECONNECT)) { ReconnectAll = TRUE; } // // Make sure the driver path is connected. // BdsLibConnectDevicePath (Option->DevicePath); // // Load and start the image that Driver#### describes // Status = gBS->LoadImage ( FALSE, gImageHandle, Option->DevicePath, NULL, 0, &ImageHandle ); if (!EFI_ERROR (Status)) { gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo); // // Verify whether this image is a driver, if not, // exit it and continue to parse next load option // if (ImageInfo->ImageCodeType != EfiBootServicesCode && ImageInfo->ImageCodeType != EfiRuntimeServicesCode) { gBS->Exit (ImageHandle, EFI_INVALID_PARAMETER, 0, NULL); continue; } if (Option->LoadOptionsSize != 0) { ImageInfo->LoadOptionsSize = Option->LoadOptionsSize; ImageInfo->LoadOptions = Option->LoadOptions; } // // Before calling the image, enable the Watchdog Timer for // the 5 Minute period // gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL); Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData); DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Driver Return Status = %r\n", Status)); // // Clear the Watchdog Timer after the image returns // gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL); } } // // Process the LOAD_OPTION_FORCE_RECONNECT driver option // if (ReconnectAll) { BdsLibDisconnectAllEfi (); BdsLibConnectAll (); } }
VOID EFIAPI PlatformBdsPolicyBehavior ( IN OUT LIST_ENTRY *DriverOptionList, IN OUT LIST_ENTRY *BootOptionList, IN PROCESS_CAPSULES ProcessCapsules, IN BASEM_MEMORY_TEST BaseMemoryTest ) /*++ Routine Description: The function will excute with as the platform policy, current policy is driven by boot mode. IBV/OEM can customize this code for their specific policy action. Arguments: DriverOptionList - The header of the driver option link list BootOptionList - The header of the boot option link list ProcessCapsules - A pointer to ProcessCapsules() BaseMemoryTest - A pointer to BaseMemoryTest() Returns: None. --*/ { EFI_STATUS Status; UINT16 Timeout; EFI_EVENT UserInputDurationTime; LIST_ENTRY *Link; BDS_COMMON_OPTION *BootOption; UINTN Index; EFI_INPUT_KEY Key; EFI_TPL OldTpl; EFI_BOOT_MODE BootMode; VBoxLogFlowFuncEnter(); ConnectRootBridge (); if (PcdGetBool (PcdOvmfFlashVariablesEnable)) { DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars " "from disk since flash variables appear to be supported.\n")); } else { // // Try to restore variables from the hard disk early so // they can be used for the other BDS connect operations. // PlatformBdsRestoreNvVarsFromHardDisk (); } // // Init the time out value // Timeout = PcdGet16 (PcdPlatformBootTimeOut); // // Load the driver option as the driver option list // PlatformBdsGetDriverOption (DriverOptionList); // // Get current Boot Mode // Status = BdsLibGetBootMode (&BootMode); DEBUG ((EFI_D_ERROR, "Boot Mode:%x\n", BootMode)); // // Go the different platform policy with different boot mode // Notes: this part code can be change with the table policy // ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION); // // Connect platform console // Status = PlatformBdsConnectConsole (gPlatformConsole); if (EFI_ERROR (Status)) { // // Here OEM/IBV can customize with defined action // PlatformBdsNoConsoleAction (); } // // Create a 300ms duration event to ensure user has enough input time to enter Setup // Status = gBS->CreateEvent ( EVT_TIMER, 0, NULL, NULL, &UserInputDurationTime ); ASSERT (Status == EFI_SUCCESS); Status = gBS->SetTimer (UserInputDurationTime, TimerRelative, 3000000); ASSERT (Status == EFI_SUCCESS); // // Memory test and Logo show // PlatformBdsDiagnostics (IGNORE, TRUE, BaseMemoryTest); // // Perform some platform specific connect sequence // PlatformBdsConnectSequence (); // // Process QEMU's -kernel command line option // TryRunningQemuKernel (); // // Give one chance to enter the setup if we // have the time out // if (Timeout != 0) { //PlatformBdsEnterFrontPage (Timeout, FALSE); } DEBUG ((EFI_D_INFO, "BdsLibConnectAll\n")); BdsLibConnectAll (); #ifdef VBOX { UINTN cFileSystem = 0; EFI_HANDLE *phFileSystem = NULL; BDS_COMMON_OPTION *BootOption0080 = NULL; EFI_STATUS rc = EFI_SUCCESS; DEBUG ((EFI_D_INFO, "------------------ VBox Platform Specific Initialization Start -----------------------\n")); BootOption0080 = BdsLibVariableToOption(BootOptionList, L"Boot0080"); if (!BootOption0080) { rc = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &cFileSystem, &phFileSystem); VBoxLogFlowFuncMarkRC(rc); VBoxLogFlowFuncMarkVar(cFileSystem, "%d"); if ( rc == EFI_SUCCESS && cFileSystem > 0) { EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *pFSVolume; EFI_FILE_HANDLE hFSRoot; EFI_FILE_HANDLE hBootEfiFile; UINTN iFileSystem = 0; /* Ok, we've found several simple file system handles * 1. we should find if '\\System\\Library\\CoreServices\\boot.efi' present * 2. Alter 'BootOrder' to include this file in boot sequence. */ for (iFileSystem = 0; iFileSystem < cFileSystem; ++iFileSystem) { EFI_DEVICE_PATH_PROTOCOL *pDevicePath = NULL; /* mount and look up the boot.efi */ rc = gBS->HandleProtocol (phFileSystem[iFileSystem], &gEfiSimpleFileSystemProtocolGuid, (VOID *) &pFSVolume); VBoxLogFlowFuncMarkVar(iFileSystem, "%d"); VBoxLogFlowFuncMarkRC(rc); if (EFI_ERROR(rc)) continue; rc = pFSVolume->OpenVolume(pFSVolume, &hFSRoot); VBoxLogFlowFuncMarkRC(rc); if (EFI_ERROR(rc)) continue; rc = hFSRoot->Open(hFSRoot, &hBootEfiFile, L"\\System\\Library\\CoreServices\\boot.efi", EFI_FILE_MODE_READ, 0); VBoxLogFlowFuncMarkRC(rc); if (EFI_ERROR(rc)) continue; /* nice file is found and we have to register it */ pDevicePath = FileDevicePath(phFileSystem[iFileSystem], L"\\System\\Library\\CoreServices\\boot.efi"); VBoxLogFlowFuncMarkVar(pDevicePath,"%p"); if (!pDevicePath) continue; rc = BdsLibRegisterNewOption (BootOptionList, pDevicePath, L"Mac Boot", L"BootOrder"); VBoxLogFlowFuncMarkRC(rc); } } } else { VBoxLogFlowFuncMarkVar(BootOption0080->LoadOptionsSize, "%d"); if (BootOption0080->LoadOptionsSize) VBoxLogFlowFuncMarkVar(BootOption0080->LoadOptions, "%s"); #if 0 /* Boot0080 option is found */ UINT16 *BootOrder; UINTN BootOrderSize; UINTN Index = 0; CHAR16 *BootOptionName; ASSERT(BootOption0080->Signature == BDS_LOAD_OPTION_SIGNATURE); BootOrder = BdsLibGetVariableAndSize ( L"BootOrder", &gEfiGlobalVariableGuid, &BootOrderSize); ASSERT(BootOrder); BootOptionName = AllocateRuntimePool(256 * sizeof(UINT16)); UnicodeSPrint(BootOptionName, 256 * sizeof(UINT16), L"Boot%04x", BootOrder[Index]); BootOption0080->OptionName = BootOptionName; rc = gRT->SetVariable(BootOptionName, &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, sizeof(BDS_COMMON_OPTION), BootOption0080); LogFlowFuncMarkRC(rc); #if 0 rc = BdsLibRegisterNewOption (BootOptionList, BootOption0080->DevicePath, L"Mac Boot Temp", L"BootOrder"); #endif LogFlowFuncMarkRC(rc); #endif } DEBUG ((EFI_D_INFO, "------------------ VBox Platform Specific Initialization End -----------------------\n")); } #endif BdsLibEnumerateAllBootOption (BootOptionList); SetBootOrderFromQemu (BootOptionList); // // The BootOrder variable may have changed, reload the in-memory list with // it. // BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder"); // // To give the User a chance to enter Setup here, if user set TimeOut is 0. // BDS should still give user a chance to enter Setup // // Connect first boot option, and then check user input before exit // for (Link = BootOptionList->ForwardLink; Link != BootOptionList;Link = Link->ForwardLink) { BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE); if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) { // // skip the header of the link list, becuase it has no boot option // continue; } else { // // Make sure the boot option device path connected, but ignore the BBS device path // if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) { BdsLibConnectDevicePath (BootOption->DevicePath); } break; } } // // Check whether the user input after the duration time has expired // OldTpl = EfiGetCurrentTpl(); gBS->RestoreTPL (TPL_APPLICATION); gBS->WaitForEvent (1, &UserInputDurationTime, &Index); gBS->CloseEvent (UserInputDurationTime); Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); gBS->RaiseTPL (OldTpl); if (!EFI_ERROR (Status)) { // // Enter Setup if user input // Timeout = 0xffff; PlatformBdsEnterFrontPage (Timeout, FALSE); } VBoxLogFlowFuncLeave(); return ; }
/** Connect the console device base on the variable ConVarName, if device path of the ConVarName is multi-instance device path and anyone of the instances is connected success, then this function will return success. If the handle associate with one device path node can not be created successfully, then still give chance to do the dispatch, which load the missing drivers if possible.. @param ConVarName Console related variable name, ConIn, ConOut, ErrOut. @retval EFI_NOT_FOUND There is not any console devices connected success @retval EFI_SUCCESS Success connect any one instance of the console device path base on the variable ConVarName. **/ EFI_STATUS EFIAPI BdsLibConnectConsoleVariable ( IN CHAR16 *ConVarName ) { EFI_STATUS Status; EFI_DEVICE_PATH_PROTOCOL *StartDevicePath; UINTN VariableSize; EFI_DEVICE_PATH_PROTOCOL *Instance; EFI_DEVICE_PATH_PROTOCOL *Next; EFI_DEVICE_PATH_PROTOCOL *CopyOfDevicePath; UINTN Size; BOOLEAN DeviceExist; Status = EFI_SUCCESS; DeviceExist = FALSE; // // Check if the console variable exist // StartDevicePath = BdsLibGetVariableAndSize ( ConVarName, &gEfiGlobalVariableGuid, &VariableSize ); if (StartDevicePath == NULL) { return EFI_UNSUPPORTED; } CopyOfDevicePath = StartDevicePath; do { // // Check every instance of the console variable // Instance = GetNextDevicePathInstance (&CopyOfDevicePath, &Size); if (Instance == NULL) { FreePool (StartDevicePath); return EFI_UNSUPPORTED; } Next = Instance; while (!IsDevicePathEndType (Next)) { Next = NextDevicePathNode (Next); } SetDevicePathEndNode (Next); // // Connect the USB console // USB console device path is a short-form device path that // starts with the first element being a USB WWID // or a USB Class device path // if ((DevicePathType (Instance) == MESSAGING_DEVICE_PATH) && ((DevicePathSubType (Instance) == MSG_USB_CLASS_DP) || (DevicePathSubType (Instance) == MSG_USB_WWID_DP) )) { Status = BdsLibConnectUsbDevByShortFormDP (0xFF, Instance); if (!EFI_ERROR (Status)) { DeviceExist = TRUE; } } else { // // Connect the instance device path // Status = BdsLibConnectDevicePath (Instance); if (EFI_ERROR (Status)) { // // Delete the instance from the console varialbe // BdsLibUpdateConsoleVariable (ConVarName, NULL, Instance); } else { DeviceExist = TRUE; } } FreePool(Instance); } while (CopyOfDevicePath != NULL); FreePool (StartDevicePath); if (!DeviceExist) { return EFI_NOT_FOUND; } return EFI_SUCCESS; }
/** The function will execute with as the platform policy, current policy is driven by boot mode. IBV/OEM can customize this code for their specific policy action. @param DriverOptionList The header of the driver option link list @param BootOptionList The header of the boot option link list @param ProcessCapsules A pointer to ProcessCapsules() @param BaseMemoryTest A pointer to BaseMemoryTest() **/ VOID EFIAPI PlatformBdsPolicyBehavior ( IN LIST_ENTRY *DriverOptionList, IN LIST_ENTRY *BootOptionList, IN PROCESS_CAPSULES ProcessCapsules, IN BASEM_MEMORY_TEST BaseMemoryTest ) { EFI_STATUS Status; UINT16 Timeout; EFI_EVENT UserInputDurationTime; LIST_ENTRY *Link; BDS_COMMON_OPTION *BootOption; UINTN Index; EFI_INPUT_KEY Key; EFI_TPL OldTpl; EFI_BOOT_MODE BootMode; DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior\n")); ConnectRootBridge (); // // Init the time out value // Timeout = PcdGet16 (PcdPlatformBootTimeOut); // // Load the driver option as the driver option list // PlatformBdsGetDriverOption (DriverOptionList); // // Get current Boot Mode // Status = BdsLibGetBootMode (&BootMode); DEBUG ((EFI_D_ERROR, "Boot Mode:%x\n", BootMode)); // // Go the different platform policy with different boot mode // Notes: this part code can be change with the table policy // ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION); // // Connect platform console // Status = PlatformBdsConnectConsole (gPlatformConsole); if (EFI_ERROR (Status)) { // // Here OEM/IBV can customize with defined action // PlatformBdsNoConsoleAction (); } // // Create a 300ms duration event to ensure user has enough input time to enter Setup // Status = gBS->CreateEvent ( EVT_TIMER, 0, NULL, NULL, &UserInputDurationTime ); ASSERT (Status == EFI_SUCCESS); Status = gBS->SetTimer (UserInputDurationTime, TimerRelative, 3000000); ASSERT (Status == EFI_SUCCESS); // // Memory test and Logo show // PlatformBdsDiagnostics (IGNORE, TRUE, BaseMemoryTest); // // Perform some platform specific connect sequence // PlatformBdsConnectSequence (); // // In BOOT_WITH_FULL_CONFIGURATION boot mode, should always connect every device // and do enumerate all the default boot options. But in development system board, the boot mode // cannot be BOOT_ASSUMING_NO_CONFIGURATION_CHANGES because the machine box // is always open. So the following code only do the ConnectAll and EnumerateAll at first boot. // Status = BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder"); if (EFI_ERROR(Status)) { // // If cannot find "BootOrder" variable, it may be first boot. // Try to connect all devices and enumerate all boot options here. // BdsLibConnectAll (); BdsLibEnumerateAllBootOption (BootOptionList); } // // To give the User a chance to enter Setup here, if user set TimeOut is 0. // BDS should still give user a chance to enter Setup // // Connect first boot option, and then check user input before exit // for (Link = BootOptionList->ForwardLink; Link != BootOptionList;Link = Link->ForwardLink) { BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE); if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) { // // skip the header of the link list, becuase it has no boot option // continue; } else { // // Make sure the boot option device path connected, but ignore the BBS device path // if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) { BdsLibConnectDevicePath (BootOption->DevicePath); } break; } } // // Check whether the user input after the duration time has expired // OldTpl = EfiGetCurrentTpl(); gBS->RestoreTPL (TPL_APPLICATION); gBS->WaitForEvent (1, &UserInputDurationTime, &Index); gBS->CloseEvent (UserInputDurationTime); Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); gBS->RaiseTPL (OldTpl); if (!EFI_ERROR (Status)) { // // Enter Setup if user input // Timeout = 0xffff; PlatformBdsEnterFrontPage (Timeout, FALSE); } }
/** This function attempts to boot for the boot order specified by platform policy. **/ VOID BdsBootDeviceSelect ( VOID ) { EFI_STATUS Status; LIST_ENTRY *Link; BDS_COMMON_OPTION *BootOption; UINTN ExitDataSize; CHAR16 *ExitData; UINT16 Timeout; LIST_ENTRY BootLists; CHAR16 Buffer[20]; BOOLEAN BootNextExist; LIST_ENTRY *LinkBootNext; EFI_EVENT ConnectConInEvent; // // Got the latest boot option // BootNextExist = FALSE; LinkBootNext = NULL; ConnectConInEvent = NULL; InitializeListHead (&BootLists); // // First check the boot next option // ZeroMem (Buffer, sizeof (Buffer)); // // Create Event to signal ConIn connection request // if (PcdGetBool (PcdConInConnectOnDemand)) { Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_CALLBACK, BdsEmptyCallbackFunction, NULL, &gConnectConInEventGuid, &ConnectConInEvent ); if (EFI_ERROR(Status)) { ConnectConInEvent = NULL; } } if (mBootNext != NULL) { // // Indicate we have the boot next variable, so this time // boot will always have this boot option // BootNextExist = TRUE; // // Clear the this variable so it's only exist in this time boot // Status = gRT->SetVariable ( L"BootNext", &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, 0, NULL ); // // Deleting variable with current variable implementation shouldn't fail. // ASSERT_EFI_ERROR (Status); // // Add the boot next boot option // UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *mBootNext); BootOption = BdsLibVariableToOption (&BootLists, Buffer); // // If fail to get boot option from variable, just return and do nothing. // if (BootOption == NULL) { return; } BootOption->BootCurrent = *mBootNext; } // // Parse the boot order to get boot option // BdsLibBuildOptionFromVar (&BootLists, L"BootOrder"); // // When we didn't have chance to build boot option variables in the first // full configuration boot (e.g.: Reset in the first page or in Device Manager), // we have no boot options in the following mini configuration boot. // Give the last chance to enumerate the boot options. // if (IsListEmpty (&BootLists)) { BdsLibEnumerateAllBootOption (&BootLists); } Link = BootLists.ForwardLink; // // Parameter check, make sure the loop will be valid // if (Link == NULL) { return ; } // // Here we make the boot in a loop, every boot success will // return to the front page // for (;;) { // // Check the boot option list first // if (Link == &BootLists) { // // When LazyConIn enabled, signal connect ConIn event before enter UI // if (PcdGetBool (PcdConInConnectOnDemand) && ConnectConInEvent != NULL) { gBS->SignalEvent (ConnectConInEvent); } // // There are two ways to enter here: // 1. There is no active boot option, give user chance to // add new boot option // 2. All the active boot option processed, and there is no // one is success to boot, then we back here to allow user // add new active boot option // Timeout = 0xffff; PlatformBdsEnterFrontPage (Timeout, FALSE); InitializeListHead (&BootLists); BdsLibBuildOptionFromVar (&BootLists, L"BootOrder"); Link = BootLists.ForwardLink; continue; } // // Get the boot option from the link list // BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE); // // According to EFI Specification, if a load option is not marked // as LOAD_OPTION_ACTIVE, the boot manager will not automatically // load the option. // if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) { // // skip the header of the link list, because it has no boot option // Link = Link->ForwardLink; continue; } // // Make sure the boot option device path connected, // but ignore the BBS device path // if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) { // // Notes: the internal shell can not been connected with device path // so we do not check the status here // BdsLibConnectDevicePath (BootOption->DevicePath); } // // Restore to original mode before launching boot option. // BdsSetConsoleMode (FALSE); // // All the driver options should have been processed since // now boot will be performed. // Status = BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData); if (Status != EFI_SUCCESS) { // // Call platform action to indicate the boot fail // BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED)); PlatformBdsBootFail (BootOption, Status, ExitData, ExitDataSize); // // Check the next boot option // Link = Link->ForwardLink; } else { // // Call platform action to indicate the boot success // BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED)); PlatformBdsBootSuccess (BootOption); // // Boot success, then stop process the boot order, and // present the boot manager menu, front page // // // When LazyConIn enabled, signal connect ConIn Event before enter UI // if (PcdGetBool (PcdConInConnectOnDemand) && ConnectConInEvent != NULL) { gBS->SignalEvent (ConnectConInEvent); } Timeout = 0xffff; PlatformBdsEnterFrontPage (Timeout, FALSE); // // Rescan the boot option list, avoid potential risk of the boot // option change in front page // if (BootNextExist) { LinkBootNext = BootLists.ForwardLink; } InitializeListHead (&BootLists); if (LinkBootNext != NULL) { // // Reserve the boot next option // InsertTailList (&BootLists, LinkBootNext); } BdsLibBuildOptionFromVar (&BootLists, L"BootOrder"); Link = BootLists.ForwardLink; } } }
/** This is the common notification function for HotKeys, it will be registered with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle. @param KeyData A pointer to a buffer that is filled in with the keystroke information for the key that was pressed. @retval EFI_SUCCESS KeyData is successfully processed. @return EFI_NOT_FOUND Fail to find boot option variable. **/ EFI_STATUS EFIAPI HotkeyCallback ( IN EFI_KEY_DATA *KeyData ) { BOOLEAN HotkeyCatched; LIST_ENTRY BootLists; LIST_ENTRY *Link; BDS_HOTKEY_OPTION *Hotkey; UINT16 Buffer[10]; BDS_COMMON_OPTION *BootOption; UINTN ExitDataSize; CHAR16 *ExitData; EFI_STATUS Status; EFI_KEY_DATA *HotkeyData; if (mHotkeyCallbackPending) { // // When responsing to a Hotkey, ignore sequential hotkey stroke until // the current Boot#### load option returned // return EFI_SUCCESS; } Status = EFI_SUCCESS; Link = GetFirstNode (&mHotkeyList); while (!IsNull (&mHotkeyList, Link)) { HotkeyCatched = FALSE; Hotkey = BDS_HOTKEY_OPTION_FROM_LINK (Link); // // Is this Key Stroke we are waiting for? // ASSERT (Hotkey->WaitingKey < (sizeof (Hotkey->KeyData) / sizeof (Hotkey->KeyData[0]))); HotkeyData = &Hotkey->KeyData[Hotkey->WaitingKey]; if ((KeyData->Key.ScanCode == HotkeyData->Key.ScanCode) && (KeyData->Key.UnicodeChar == HotkeyData->Key.UnicodeChar) && (((HotkeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) ? (KeyData->KeyState.KeyShiftState == HotkeyData->KeyState.KeyShiftState) : TRUE)) { // // Receive an expecting key stroke // if (Hotkey->CodeCount > 1) { // // For hotkey of key combination, transit to next waiting state // Hotkey->WaitingKey++; if (Hotkey->WaitingKey == Hotkey->CodeCount) { // // Received the whole key stroke sequence // HotkeyCatched = TRUE; } } else { // // For hotkey of single key stroke // HotkeyCatched = TRUE; } } else { // // Receive an unexpected key stroke, reset to initial waiting state // Hotkey->WaitingKey = 0; } if (HotkeyCatched) { // // Reset to initial waiting state // Hotkey->WaitingKey = 0; // // Launch its BootOption // InitializeListHead (&BootLists); UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", Hotkey->BootOptionNumber); BootOption = BdsLibVariableToOption (&BootLists, Buffer); if (BootOption == NULL) { return EFI_NOT_FOUND; } BootOption->BootCurrent = Hotkey->BootOptionNumber; BdsLibConnectDevicePath (BootOption->DevicePath); // // Clear the screen before launch this BootOption // gST->ConOut->Reset (gST->ConOut, FALSE); mHotkeyCallbackPending = TRUE; Status = BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData); mHotkeyCallbackPending = FALSE; if (EFI_ERROR (Status)) { // // Call platform action to indicate the boot fail // BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED)); PlatformBdsBootFail (BootOption, Status, ExitData, ExitDataSize); } else { // // Call platform action to indicate the boot success // BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED)); PlatformBdsBootSuccess (BootOption); } } Link = GetNextNode (&mHotkeyList, Link); } return Status; }