2 Implementation for PlatformBootManagerLib library class interfaces.
4 Copyright (C) 2015-2016, Red Hat, Inc.
5 Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
6 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
7 Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
9 This program and the accompanying materials are licensed and made available
10 under the terms and conditions of the BSD License which accompanies this
11 distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
15 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 #include <IndustryStandard/Pci22.h>
20 #include <Library/BootLogoLib.h>
21 #include <Library/CapsuleLib.h>
22 #include <Library/DevicePathLib.h>
23 #include <Library/HobLib.h>
24 #include <Library/PcdLib.h>
25 #include <Library/UefiBootManagerLib.h>
26 #include <Library/UefiLib.h>
27 #include <Protocol/DevicePath.h>
28 #include <Protocol/EsrtManagement.h>
29 #include <Protocol/GraphicsOutput.h>
30 #include <Protocol/LoadedImage.h>
31 #include <Protocol/PciIo.h>
32 #include <Protocol/PciRootBridgeIo.h>
33 #include <Guid/EventGroup.h>
34 #include <Guid/TtyTerm.h>
36 #include "PlatformBm.h"
38 #define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }
42 VENDOR_DEVICE_PATH SerialDxe
;
43 UART_DEVICE_PATH Uart
;
44 VENDOR_DEFINED_DEVICE_PATH TermType
;
45 EFI_DEVICE_PATH_PROTOCOL End
;
46 } PLATFORM_SERIAL_CONSOLE
;
49 #define SERIAL_DXE_FILE_GUID { \
50 0xD3987D4B, 0x971A, 0x435F, \
51 { 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } \
54 STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole
= {
56 // VENDOR_DEVICE_PATH SerialDxe
59 { HARDWARE_DEVICE_PATH
, HW_VENDOR_DP
, DP_NODE_LEN (VENDOR_DEVICE_PATH
) },
64 // UART_DEVICE_PATH Uart
67 { MESSAGING_DEVICE_PATH
, MSG_UART_DP
, DP_NODE_LEN (UART_DEVICE_PATH
) },
69 FixedPcdGet64 (PcdUartDefaultBaudRate
), // BaudRate
70 FixedPcdGet8 (PcdUartDefaultDataBits
), // DataBits
71 FixedPcdGet8 (PcdUartDefaultParity
), // Parity
72 FixedPcdGet8 (PcdUartDefaultStopBits
) // StopBits
76 // VENDOR_DEFINED_DEVICE_PATH TermType
80 MESSAGING_DEVICE_PATH
, MSG_VENDOR_DP
,
81 DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH
)
84 // Guid to be filled in dynamically
89 // EFI_DEVICE_PATH_PROTOCOL End
92 END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
93 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL
)
100 USB_CLASS_DEVICE_PATH Keyboard
;
101 EFI_DEVICE_PATH_PROTOCOL End
;
102 } PLATFORM_USB_KEYBOARD
;
105 STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard
= {
107 // USB_CLASS_DEVICE_PATH Keyboard
111 MESSAGING_DEVICE_PATH
, MSG_USB_CLASS_DP
,
112 DP_NODE_LEN (USB_CLASS_DEVICE_PATH
)
114 0xFFFF, // VendorId: any
115 0xFFFF, // ProductId: any
116 3, // DeviceClass: HID
117 1, // DeviceSubClass: boot
118 1 // DeviceProtocol: keyboard
122 // EFI_DEVICE_PATH_PROTOCOL End
125 END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
126 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL
)
132 Check if the handle satisfies a particular condition.
134 @param[in] Handle The handle to check.
135 @param[in] ReportText A caller-allocated string passed in for reporting
136 purposes. It must never be NULL.
138 @retval TRUE The condition is satisfied.
139 @retval FALSE Otherwise. This includes the case when the condition could not
140 be fully evaluated due to an error.
144 (EFIAPI
*FILTER_FUNCTION
) (
145 IN EFI_HANDLE Handle
,
146 IN CONST CHAR16
*ReportText
153 @param[in] Handle The handle to process.
154 @param[in] ReportText A caller-allocated string passed in for reporting
155 purposes. It must never be NULL.
159 (EFIAPI
*CALLBACK_FUNCTION
) (
160 IN EFI_HANDLE Handle
,
161 IN CONST CHAR16
*ReportText
165 Locate all handles that carry the specified protocol, filter them with a
166 callback function, and pass each handle that passes the filter to another
169 @param[in] ProtocolGuid The protocol to look for.
171 @param[in] Filter The filter function to pass each handle to. If this
172 parameter is NULL, then all handles are processed.
174 @param[in] Process The callback function to pass each handle to that
180 IN EFI_GUID
*ProtocolGuid
,
181 IN FILTER_FUNCTION Filter OPTIONAL
,
182 IN CALLBACK_FUNCTION Process
190 Status
= gBS
->LocateHandleBuffer (ByProtocol
, ProtocolGuid
,
191 NULL
/* SearchKey */, &NoHandles
, &Handles
);
192 if (EFI_ERROR (Status
)) {
194 // This is not an error, just an informative condition.
196 DEBUG ((EFI_D_VERBOSE
, "%a: %g: %r\n", __FUNCTION__
, ProtocolGuid
,
201 ASSERT (NoHandles
> 0);
202 for (Idx
= 0; Idx
< NoHandles
; ++Idx
) {
203 CHAR16
*DevicePathText
;
204 STATIC CHAR16 Fallback
[] = L
"<device path unavailable>";
207 // The ConvertDevicePathToText() function handles NULL input transparently.
209 DevicePathText
= ConvertDevicePathToText (
210 DevicePathFromHandle (Handles
[Idx
]),
211 FALSE
, // DisplayOnly
212 FALSE
// AllowShortcuts
214 if (DevicePathText
== NULL
) {
215 DevicePathText
= Fallback
;
218 if (Filter
== NULL
|| Filter (Handles
[Idx
], DevicePathText
)) {
219 Process (Handles
[Idx
], DevicePathText
);
222 if (DevicePathText
!= Fallback
) {
223 FreePool (DevicePathText
);
226 gBS
->FreePool (Handles
);
231 This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.
237 IN EFI_HANDLE Handle
,
238 IN CONST CHAR16
*ReportText
242 EFI_PCI_IO_PROTOCOL
*PciIo
;
245 Status
= gBS
->HandleProtocol (Handle
, &gEfiPciIoProtocolGuid
,
247 if (EFI_ERROR (Status
)) {
249 // This is not an error worth reporting.
254 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, 0 /* Offset */,
255 sizeof Pci
/ sizeof (UINT32
), &Pci
);
256 if (EFI_ERROR (Status
)) {
257 DEBUG ((EFI_D_ERROR
, "%a: %s: %r\n", __FUNCTION__
, ReportText
, Status
));
261 return IS_PCI_DISPLAY (&Pci
);
266 This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking
267 the matching driver to produce all first-level child handles.
273 IN EFI_HANDLE Handle
,
274 IN CONST CHAR16
*ReportText
279 Status
= gBS
->ConnectController (
280 Handle
, // ControllerHandle
281 NULL
, // DriverImageHandle
282 NULL
, // RemainingDevicePath -- produce all children
285 DEBUG ((EFI_ERROR (Status
) ? EFI_D_ERROR
: EFI_D_VERBOSE
, "%a: %s: %r\n",
286 __FUNCTION__
, ReportText
, Status
));
291 This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the
292 handle, and adds it to ConOut and ErrOut.
298 IN EFI_HANDLE Handle
,
299 IN CONST CHAR16
*ReportText
303 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
305 DevicePath
= DevicePathFromHandle (Handle
);
306 if (DevicePath
== NULL
) {
307 DEBUG ((EFI_D_ERROR
, "%a: %s: handle %p: device path not found\n",
308 __FUNCTION__
, ReportText
, Handle
));
312 Status
= EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
313 if (EFI_ERROR (Status
)) {
314 DEBUG ((EFI_D_ERROR
, "%a: %s: adding to ConOut: %r\n", __FUNCTION__
,
315 ReportText
, Status
));
319 Status
= EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
320 if (EFI_ERROR (Status
)) {
321 DEBUG ((EFI_D_ERROR
, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__
,
322 ReportText
, Status
));
326 DEBUG ((EFI_D_VERBOSE
, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__
,
332 PlatformRegisterFvBootOption (
333 CONST EFI_GUID
*FileGuid
,
340 EFI_BOOT_MANAGER_LOAD_OPTION NewOption
;
341 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
342 UINTN BootOptionCount
;
343 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
344 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
345 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
347 Status
= gBS
->HandleProtocol (
349 &gEfiLoadedImageProtocolGuid
,
350 (VOID
**) &LoadedImage
352 ASSERT_EFI_ERROR (Status
);
354 EfiInitializeFwVolDevicepathNode (&FileNode
, FileGuid
);
355 DevicePath
= DevicePathFromHandle (LoadedImage
->DeviceHandle
);
356 ASSERT (DevicePath
!= NULL
);
357 DevicePath
= AppendDevicePathNode (
359 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
361 ASSERT (DevicePath
!= NULL
);
363 Status
= EfiBootManagerInitializeLoadOption (
365 LoadOptionNumberUnassigned
,
373 ASSERT_EFI_ERROR (Status
);
374 FreePool (DevicePath
);
376 BootOptions
= EfiBootManagerGetLoadOptions (
377 &BootOptionCount
, LoadOptionTypeBoot
380 OptionIndex
= EfiBootManagerFindLoadOption (
381 &NewOption
, BootOptions
, BootOptionCount
384 if (OptionIndex
== -1) {
385 Status
= EfiBootManagerAddLoadOptionVariable (&NewOption
, MAX_UINTN
);
386 ASSERT_EFI_ERROR (Status
);
388 EfiBootManagerFreeLoadOption (&NewOption
);
389 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
395 PlatformRegisterOptionsAndKeys (
403 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
406 // Register ENTER as CONTINUE key
408 Enter
.ScanCode
= SCAN_NULL
;
409 Enter
.UnicodeChar
= CHAR_CARRIAGE_RETURN
;
410 Status
= EfiBootManagerRegisterContinueKeyOption (0, &Enter
, NULL
);
411 ASSERT_EFI_ERROR (Status
);
414 // Map F2 and ESC to Boot Manager Menu
416 F2
.ScanCode
= SCAN_F2
;
417 F2
.UnicodeChar
= CHAR_NULL
;
418 Esc
.ScanCode
= SCAN_ESC
;
419 Esc
.UnicodeChar
= CHAR_NULL
;
420 Status
= EfiBootManagerGetBootManagerMenu (&BootOption
);
421 ASSERT_EFI_ERROR (Status
);
422 Status
= EfiBootManagerAddKeyOptionVariable (
423 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &F2
, NULL
425 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
426 Status
= EfiBootManagerAddKeyOptionVariable (
427 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &Esc
, NULL
429 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
434 // BDS Platform Functions
437 Do the platform init, can be customized by OEM/IBV
438 Possible things that can be done in PlatformBootManagerBeforeConsole:
439 > Update console variable: 1. include hot-plug devices;
440 > 2. Clear ConIn and add SOL for AMT
441 > Register new Driver#### or Boot####
442 > Register new Key####: e.g.: F12
443 > Signal ReadyToLock event
444 > Authentication action: 1. connect Auth devices;
445 > 2. Identify auto logon user.
449 PlatformBootManagerBeforeConsole (
454 ESRT_MANAGEMENT_PROTOCOL
*EsrtManagement
;
456 if (GetBootModeHob() == BOOT_ON_FLASH_UPDATE
) {
457 DEBUG ((DEBUG_INFO
, "ProcessCapsules Before EndOfDxe ......\n"));
458 Status
= ProcessCapsules ();
459 DEBUG ((DEBUG_INFO
, "ProcessCapsules returned %r\n", Status
));
461 Status
= gBS
->LocateProtocol (&gEsrtManagementProtocolGuid
, NULL
,
462 (VOID
**)&EsrtManagement
);
463 if (!EFI_ERROR (Status
)) {
464 EsrtManagement
->SyncEsrtFmp ();
469 // Signal EndOfDxe PI Event
471 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid
);
474 // Locate the PCI root bridges and make the PCI bus driver connect each,
475 // non-recursively. This will produce a number of child handles with PciIo on
478 FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid
, NULL
, Connect
);
481 // Find all display class PCI devices (using the handles from the previous
482 // step), and connect them non-recursively. This should produce a number of
483 // child handles with GOPs on them.
485 FilterAndProcess (&gEfiPciIoProtocolGuid
, IsPciDisplay
, Connect
);
488 // Now add the device path of all handles with GOP on them to ConOut and
491 FilterAndProcess (&gEfiGraphicsOutputProtocolGuid
, NULL
, AddOutput
);
494 // Add the hardcoded short-form USB keyboard device path to ConIn.
496 EfiBootManagerUpdateConsoleVariable (ConIn
,
497 (EFI_DEVICE_PATH_PROTOCOL
*)&mUsbKeyboard
, NULL
);
500 // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
502 ASSERT (FixedPcdGet8 (PcdDefaultTerminalType
) == 4);
503 CopyGuid (&mSerialConsole
.TermType
.Guid
, &gEfiTtyTermGuid
);
505 EfiBootManagerUpdateConsoleVariable (ConIn
,
506 (EFI_DEVICE_PATH_PROTOCOL
*)&mSerialConsole
, NULL
);
507 EfiBootManagerUpdateConsoleVariable (ConOut
,
508 (EFI_DEVICE_PATH_PROTOCOL
*)&mSerialConsole
, NULL
);
509 EfiBootManagerUpdateConsoleVariable (ErrOut
,
510 (EFI_DEVICE_PATH_PROTOCOL
*)&mSerialConsole
, NULL
);
513 // Register platform-specific boot options and keyboard shortcuts.
515 PlatformRegisterOptionsAndKeys ();
519 Do the platform specific action after the console is ready
520 Possible things that can be done in PlatformBootManagerAfterConsole:
521 > Console post action:
522 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
523 > Signal console ready platform customized event
524 > Run diagnostics like memory testing
525 > Connect certain devices
526 > Dispatch aditional option roms
527 > Special boot: e.g.: USB boot, enter UI
531 PlatformBootManagerAfterConsole (
535 ESRT_MANAGEMENT_PROTOCOL
*EsrtManagement
;
539 // Show the splash screen.
541 Status
= BootLogoEnableLogo ();
542 if (EFI_ERROR (Status
)) {
543 Print (L
"Press ESCAPE for boot options ");
546 // Connect the rest of the devices.
548 EfiBootManagerConnectAll ();
550 Status
= gBS
->LocateProtocol (&gEsrtManagementProtocolGuid
, NULL
,
551 (VOID
**)&EsrtManagement
);
552 if (!EFI_ERROR (Status
)) {
553 EsrtManagement
->SyncEsrtFmp ();
556 if (GetBootModeHob() == BOOT_ON_FLASH_UPDATE
) {
557 DEBUG((DEBUG_INFO
, "ProcessCapsules After EndOfDxe ......\n"));
558 Status
= ProcessCapsules ();
559 DEBUG((DEBUG_INFO
, "ProcessCapsules returned %r\n", Status
));
563 // Enumerate all possible boot options.
565 EfiBootManagerRefreshAllBootOption ();
568 // Register UEFI Shell
570 PlatformRegisterFvBootOption (
571 &gUefiShellFileGuid
, L
"UEFI Shell", LOAD_OPTION_ACTIVE
576 This function is called each second during the boot manager waits the
579 @param TimeoutRemain The remaining timeout.
583 PlatformBootManagerWaitCallback (
587 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black
;
588 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White
;
592 Timeout
= PcdGet16 (PcdPlatformBootTimeOut
);
594 Black
.Raw
= 0x00000000;
595 White
.Raw
= 0x00FFFFFF;
597 Status
= BootLogoUpdateProgress (
600 L
"Press ESCAPE for boot options",
602 (Timeout
- TimeoutRemain
) * 100 / Timeout
,
605 if (EFI_ERROR (Status
)) {