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/GraphicsOutput.h>
29 #include <Protocol/LoadedImage.h>
30 #include <Protocol/PciIo.h>
31 #include <Protocol/PciRootBridgeIo.h>
32 #include <Guid/EventGroup.h>
33 #include <Guid/TtyTerm.h>
35 #include "PlatformBm.h"
37 #define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }
41 VENDOR_DEVICE_PATH SerialDxe
;
42 UART_DEVICE_PATH Uart
;
43 VENDOR_DEFINED_DEVICE_PATH TermType
;
44 EFI_DEVICE_PATH_PROTOCOL End
;
45 } PLATFORM_SERIAL_CONSOLE
;
48 #define SERIAL_DXE_FILE_GUID { \
49 0xD3987D4B, 0x971A, 0x435F, \
50 { 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } \
53 STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole
= {
55 // VENDOR_DEVICE_PATH SerialDxe
58 { HARDWARE_DEVICE_PATH
, HW_VENDOR_DP
, DP_NODE_LEN (VENDOR_DEVICE_PATH
) },
63 // UART_DEVICE_PATH Uart
66 { MESSAGING_DEVICE_PATH
, MSG_UART_DP
, DP_NODE_LEN (UART_DEVICE_PATH
) },
68 FixedPcdGet64 (PcdUartDefaultBaudRate
), // BaudRate
69 FixedPcdGet8 (PcdUartDefaultDataBits
), // DataBits
70 FixedPcdGet8 (PcdUartDefaultParity
), // Parity
71 FixedPcdGet8 (PcdUartDefaultStopBits
) // StopBits
75 // VENDOR_DEFINED_DEVICE_PATH TermType
79 MESSAGING_DEVICE_PATH
, MSG_VENDOR_DP
,
80 DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH
)
83 // Guid to be filled in dynamically
88 // EFI_DEVICE_PATH_PROTOCOL End
91 END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
92 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL
)
99 USB_CLASS_DEVICE_PATH Keyboard
;
100 EFI_DEVICE_PATH_PROTOCOL End
;
101 } PLATFORM_USB_KEYBOARD
;
104 STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard
= {
106 // USB_CLASS_DEVICE_PATH Keyboard
110 MESSAGING_DEVICE_PATH
, MSG_USB_CLASS_DP
,
111 DP_NODE_LEN (USB_CLASS_DEVICE_PATH
)
113 0xFFFF, // VendorId: any
114 0xFFFF, // ProductId: any
115 3, // DeviceClass: HID
116 1, // DeviceSubClass: boot
117 1 // DeviceProtocol: keyboard
121 // EFI_DEVICE_PATH_PROTOCOL End
124 END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
125 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL
)
131 Check if the handle satisfies a particular condition.
133 @param[in] Handle The handle to check.
134 @param[in] ReportText A caller-allocated string passed in for reporting
135 purposes. It must never be NULL.
137 @retval TRUE The condition is satisfied.
138 @retval FALSE Otherwise. This includes the case when the condition could not
139 be fully evaluated due to an error.
143 (EFIAPI
*FILTER_FUNCTION
) (
144 IN EFI_HANDLE Handle
,
145 IN CONST CHAR16
*ReportText
152 @param[in] Handle The handle to process.
153 @param[in] ReportText A caller-allocated string passed in for reporting
154 purposes. It must never be NULL.
158 (EFIAPI
*CALLBACK_FUNCTION
) (
159 IN EFI_HANDLE Handle
,
160 IN CONST CHAR16
*ReportText
164 Locate all handles that carry the specified protocol, filter them with a
165 callback function, and pass each handle that passes the filter to another
168 @param[in] ProtocolGuid The protocol to look for.
170 @param[in] Filter The filter function to pass each handle to. If this
171 parameter is NULL, then all handles are processed.
173 @param[in] Process The callback function to pass each handle to that
179 IN EFI_GUID
*ProtocolGuid
,
180 IN FILTER_FUNCTION Filter OPTIONAL
,
181 IN CALLBACK_FUNCTION Process
189 Status
= gBS
->LocateHandleBuffer (ByProtocol
, ProtocolGuid
,
190 NULL
/* SearchKey */, &NoHandles
, &Handles
);
191 if (EFI_ERROR (Status
)) {
193 // This is not an error, just an informative condition.
195 DEBUG ((EFI_D_VERBOSE
, "%a: %g: %r\n", __FUNCTION__
, ProtocolGuid
,
200 ASSERT (NoHandles
> 0);
201 for (Idx
= 0; Idx
< NoHandles
; ++Idx
) {
202 CHAR16
*DevicePathText
;
203 STATIC CHAR16 Fallback
[] = L
"<device path unavailable>";
206 // The ConvertDevicePathToText() function handles NULL input transparently.
208 DevicePathText
= ConvertDevicePathToText (
209 DevicePathFromHandle (Handles
[Idx
]),
210 FALSE
, // DisplayOnly
211 FALSE
// AllowShortcuts
213 if (DevicePathText
== NULL
) {
214 DevicePathText
= Fallback
;
217 if (Filter
== NULL
|| Filter (Handles
[Idx
], DevicePathText
)) {
218 Process (Handles
[Idx
], DevicePathText
);
221 if (DevicePathText
!= Fallback
) {
222 FreePool (DevicePathText
);
225 gBS
->FreePool (Handles
);
230 This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.
236 IN EFI_HANDLE Handle
,
237 IN CONST CHAR16
*ReportText
241 EFI_PCI_IO_PROTOCOL
*PciIo
;
244 Status
= gBS
->HandleProtocol (Handle
, &gEfiPciIoProtocolGuid
,
246 if (EFI_ERROR (Status
)) {
248 // This is not an error worth reporting.
253 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, 0 /* Offset */,
254 sizeof Pci
/ sizeof (UINT32
), &Pci
);
255 if (EFI_ERROR (Status
)) {
256 DEBUG ((EFI_D_ERROR
, "%a: %s: %r\n", __FUNCTION__
, ReportText
, Status
));
260 return IS_PCI_DISPLAY (&Pci
);
265 This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking
266 the matching driver to produce all first-level child handles.
272 IN EFI_HANDLE Handle
,
273 IN CONST CHAR16
*ReportText
278 Status
= gBS
->ConnectController (
279 Handle
, // ControllerHandle
280 NULL
, // DriverImageHandle
281 NULL
, // RemainingDevicePath -- produce all children
284 DEBUG ((EFI_ERROR (Status
) ? EFI_D_ERROR
: EFI_D_VERBOSE
, "%a: %s: %r\n",
285 __FUNCTION__
, ReportText
, Status
));
290 This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the
291 handle, and adds it to ConOut and ErrOut.
297 IN EFI_HANDLE Handle
,
298 IN CONST CHAR16
*ReportText
302 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
304 DevicePath
= DevicePathFromHandle (Handle
);
305 if (DevicePath
== NULL
) {
306 DEBUG ((EFI_D_ERROR
, "%a: %s: handle %p: device path not found\n",
307 __FUNCTION__
, ReportText
, Handle
));
311 Status
= EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
312 if (EFI_ERROR (Status
)) {
313 DEBUG ((EFI_D_ERROR
, "%a: %s: adding to ConOut: %r\n", __FUNCTION__
,
314 ReportText
, Status
));
318 Status
= EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
319 if (EFI_ERROR (Status
)) {
320 DEBUG ((EFI_D_ERROR
, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__
,
321 ReportText
, Status
));
325 DEBUG ((EFI_D_VERBOSE
, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__
,
331 PlatformRegisterFvBootOption (
332 CONST EFI_GUID
*FileGuid
,
339 EFI_BOOT_MANAGER_LOAD_OPTION NewOption
;
340 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
341 UINTN BootOptionCount
;
342 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
343 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
344 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
346 Status
= gBS
->HandleProtocol (
348 &gEfiLoadedImageProtocolGuid
,
349 (VOID
**) &LoadedImage
351 ASSERT_EFI_ERROR (Status
);
353 EfiInitializeFwVolDevicepathNode (&FileNode
, FileGuid
);
354 DevicePath
= DevicePathFromHandle (LoadedImage
->DeviceHandle
);
355 ASSERT (DevicePath
!= NULL
);
356 DevicePath
= AppendDevicePathNode (
358 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
360 ASSERT (DevicePath
!= NULL
);
362 Status
= EfiBootManagerInitializeLoadOption (
364 LoadOptionNumberUnassigned
,
372 ASSERT_EFI_ERROR (Status
);
373 FreePool (DevicePath
);
375 BootOptions
= EfiBootManagerGetLoadOptions (
376 &BootOptionCount
, LoadOptionTypeBoot
379 OptionIndex
= EfiBootManagerFindLoadOption (
380 &NewOption
, BootOptions
, BootOptionCount
383 if (OptionIndex
== -1) {
384 Status
= EfiBootManagerAddLoadOptionVariable (&NewOption
, MAX_UINTN
);
385 ASSERT_EFI_ERROR (Status
);
387 EfiBootManagerFreeLoadOption (&NewOption
);
388 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
394 PlatformRegisterOptionsAndKeys (
402 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
405 // Register ENTER as CONTINUE key
407 Enter
.ScanCode
= SCAN_NULL
;
408 Enter
.UnicodeChar
= CHAR_CARRIAGE_RETURN
;
409 Status
= EfiBootManagerRegisterContinueKeyOption (0, &Enter
, NULL
);
410 ASSERT_EFI_ERROR (Status
);
413 // Map F2 and ESC to Boot Manager Menu
415 F2
.ScanCode
= SCAN_F2
;
416 F2
.UnicodeChar
= CHAR_NULL
;
417 Esc
.ScanCode
= SCAN_ESC
;
418 Esc
.UnicodeChar
= CHAR_NULL
;
419 Status
= EfiBootManagerGetBootManagerMenu (&BootOption
);
420 ASSERT_EFI_ERROR (Status
);
421 Status
= EfiBootManagerAddKeyOptionVariable (
422 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &F2
, NULL
424 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
425 Status
= EfiBootManagerAddKeyOptionVariable (
426 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &Esc
, NULL
428 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
433 // BDS Platform Functions
436 Do the platform init, can be customized by OEM/IBV
437 Possible things that can be done in PlatformBootManagerBeforeConsole:
438 > Update console variable: 1. include hot-plug devices;
439 > 2. Clear ConIn and add SOL for AMT
440 > Register new Driver#### or Boot####
441 > Register new Key####: e.g.: F12
442 > Signal ReadyToLock event
443 > Authentication action: 1. connect Auth devices;
444 > 2. Identify auto logon user.
448 PlatformBootManagerBeforeConsole (
454 if (GetBootModeHob() == BOOT_ON_FLASH_UPDATE
) {
455 DEBUG ((DEBUG_INFO
, "ProcessCapsules Before EndOfDxe ......\n"));
456 Status
= ProcessCapsules ();
457 DEBUG ((DEBUG_INFO
, "ProcessCapsules returned %r\n", Status
));
461 // Signal EndOfDxe PI Event
463 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid
);
466 // Locate the PCI root bridges and make the PCI bus driver connect each,
467 // non-recursively. This will produce a number of child handles with PciIo on
470 FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid
, NULL
, Connect
);
473 // Find all display class PCI devices (using the handles from the previous
474 // step), and connect them non-recursively. This should produce a number of
475 // child handles with GOPs on them.
477 FilterAndProcess (&gEfiPciIoProtocolGuid
, IsPciDisplay
, Connect
);
480 // Now add the device path of all handles with GOP on them to ConOut and
483 FilterAndProcess (&gEfiGraphicsOutputProtocolGuid
, NULL
, AddOutput
);
486 // Add the hardcoded short-form USB keyboard device path to ConIn.
488 EfiBootManagerUpdateConsoleVariable (ConIn
,
489 (EFI_DEVICE_PATH_PROTOCOL
*)&mUsbKeyboard
, NULL
);
492 // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
494 ASSERT (FixedPcdGet8 (PcdDefaultTerminalType
) == 4);
495 CopyGuid (&mSerialConsole
.TermType
.Guid
, &gEfiTtyTermGuid
);
497 EfiBootManagerUpdateConsoleVariable (ConIn
,
498 (EFI_DEVICE_PATH_PROTOCOL
*)&mSerialConsole
, NULL
);
499 EfiBootManagerUpdateConsoleVariable (ConOut
,
500 (EFI_DEVICE_PATH_PROTOCOL
*)&mSerialConsole
, NULL
);
501 EfiBootManagerUpdateConsoleVariable (ErrOut
,
502 (EFI_DEVICE_PATH_PROTOCOL
*)&mSerialConsole
, NULL
);
505 // Register platform-specific boot options and keyboard shortcuts.
507 PlatformRegisterOptionsAndKeys ();
511 Do the platform specific action after the console is ready
512 Possible things that can be done in PlatformBootManagerAfterConsole:
513 > Console post action:
514 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
515 > Signal console ready platform customized event
516 > Run diagnostics like memory testing
517 > Connect certain devices
518 > Dispatch aditional option roms
519 > Special boot: e.g.: USB boot, enter UI
523 PlatformBootManagerAfterConsole (
530 // Show the splash screen.
532 Status
= BootLogoEnableLogo ();
533 if (EFI_ERROR (Status
)) {
534 Print (L
"Press ESCAPE for boot options ");
537 // Connect the rest of the devices.
539 EfiBootManagerConnectAll ();
541 if (GetBootModeHob() == BOOT_ON_FLASH_UPDATE
) {
542 DEBUG((DEBUG_INFO
, "ProcessCapsules After EndOfDxe ......\n"));
543 Status
= ProcessCapsules ();
544 DEBUG((DEBUG_INFO
, "ProcessCapsules returned %r\n", Status
));
548 // Enumerate all possible boot options.
550 EfiBootManagerRefreshAllBootOption ();
553 // Register UEFI Shell
555 PlatformRegisterFvBootOption (
556 &gUefiShellFileGuid
, L
"UEFI Shell", LOAD_OPTION_ACTIVE
561 This function is called each second during the boot manager waits the
564 @param TimeoutRemain The remaining timeout.
568 PlatformBootManagerWaitCallback (
572 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black
;
573 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White
;
577 Timeout
= PcdGet16 (PcdPlatformBootTimeOut
);
579 Black
.Raw
= 0x00000000;
580 White
.Raw
= 0x00FFFFFF;
582 Status
= BootLogoUpdateProgress (
585 L
"Press ESCAPE for boot options",
587 (Timeout
- TimeoutRemain
) * 100 / Timeout
,
590 if (EFI_ERROR (Status
)) {