/** 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 ) { // // Locate the PCI root bridges and make the PCI bus driver connect each, // non-recursively. This will produce a number of child handles with PciIo on // them. // FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect); // // Signal the ACPI platform driver that it can download QEMU ACPI tables. // EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid); // // Find all display class PCI devices (using the handles from the previous // step), and connect them non-recursively. This should produce a number of // child handles with GOPs on them. // FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect); // // Now add the device path of all handles with GOP on them to ConOut and // ErrOut. // FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput); // // Add the hardcoded short-form USB keyboard device path to ConIn. // BdsLibUpdateConsoleVariable (L"ConIn", (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL); // // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut. // CopyGuid (&mSerialConsole.TermType.Guid, PcdGetPtr (PcdTerminalTypeGuidBuffer)); BdsLibUpdateConsoleVariable (L"ConIn", (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL); BdsLibUpdateConsoleVariable (L"ConOut", (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL); BdsLibUpdateConsoleVariable (L"ErrOut", (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL); // // Connect the consoles based on the above variables. // BdsLibConnectAllDefaultConsoles (); // // Show the splash screen. // EnableQuietBoot (PcdGetPtr (PcdLogoFile)); // // Connect the rest of the devices. // BdsLibConnectAll (); // // Process QEMU's -kernel command line option. Note that the kernel booted // this way should receive ACPI tables, which is why we connect all devices // first (see above) -- PCI enumeration blocks ACPI table installation, if // there is a PCI host. // TryRunningQemuKernel (); BdsLibEnumerateAllBootOption (BootOptionList); SetBootOrderFromQemu (BootOptionList); // // The BootOrder variable may have changed, reload the in-memory list with // it. // BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder"); PlatformBdsEnterFrontPage (GetFrontPageTimeoutFromQemu(), TRUE); }
/** 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 = NULL; //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; } } }
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; DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior\n")); ConnectRootBridge (); // // 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 (); // // 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 (); BdsLibEnumerateAllBootOption (BootOptionList); // // Please uncomment above ConnectAll and EnumerateAll code and remove following first boot // checking code in real production tip. // // 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); } return ; }