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/DevicePathLib.h>
22 #include <Library/PcdLib.h>
23 #include <Library/UefiBootManagerLib.h>
24 #include <Library/UefiLib.h>
25 #include <Protocol/DevicePath.h>
26 #include <Protocol/GraphicsOutput.h>
27 #include <Protocol/LoadedImage.h>
28 #include <Protocol/PciIo.h>
29 #include <Protocol/PciRootBridgeIo.h>
30 #include <Guid/EventGroup.h>
31 #include <Guid/TtyTerm.h>
33 #include "PlatformBm.h"
35 #define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }
39 VENDOR_DEVICE_PATH SerialDxe
;
40 UART_DEVICE_PATH Uart
;
41 VENDOR_DEFINED_DEVICE_PATH TermType
;
42 EFI_DEVICE_PATH_PROTOCOL End
;
43 } PLATFORM_SERIAL_CONSOLE
;
46 #define SERIAL_DXE_FILE_GUID { \
47 0xD3987D4B, 0x971A, 0x435F, \
48 { 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } \
51 STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole
= {
53 // VENDOR_DEVICE_PATH SerialDxe
56 { HARDWARE_DEVICE_PATH
, HW_VENDOR_DP
, DP_NODE_LEN (VENDOR_DEVICE_PATH
) },
61 // UART_DEVICE_PATH Uart
64 { MESSAGING_DEVICE_PATH
, MSG_UART_DP
, DP_NODE_LEN (UART_DEVICE_PATH
) },
66 FixedPcdGet64 (PcdUartDefaultBaudRate
), // BaudRate
67 FixedPcdGet8 (PcdUartDefaultDataBits
), // DataBits
68 FixedPcdGet8 (PcdUartDefaultParity
), // Parity
69 FixedPcdGet8 (PcdUartDefaultStopBits
) // StopBits
73 // VENDOR_DEFINED_DEVICE_PATH TermType
77 MESSAGING_DEVICE_PATH
, MSG_VENDOR_DP
,
78 DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH
)
81 // Guid to be filled in dynamically
86 // EFI_DEVICE_PATH_PROTOCOL End
89 END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
90 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL
)
97 USB_CLASS_DEVICE_PATH Keyboard
;
98 EFI_DEVICE_PATH_PROTOCOL End
;
99 } PLATFORM_USB_KEYBOARD
;
102 STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard
= {
104 // USB_CLASS_DEVICE_PATH Keyboard
108 MESSAGING_DEVICE_PATH
, MSG_USB_CLASS_DP
,
109 DP_NODE_LEN (USB_CLASS_DEVICE_PATH
)
111 0xFFFF, // VendorId: any
112 0xFFFF, // ProductId: any
113 3, // DeviceClass: HID
114 1, // DeviceSubClass: boot
115 1 // DeviceProtocol: keyboard
119 // EFI_DEVICE_PATH_PROTOCOL End
122 END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
123 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL
)
129 Check if the handle satisfies a particular condition.
131 @param[in] Handle The handle to check.
132 @param[in] ReportText A caller-allocated string passed in for reporting
133 purposes. It must never be NULL.
135 @retval TRUE The condition is satisfied.
136 @retval FALSE Otherwise. This includes the case when the condition could not
137 be fully evaluated due to an error.
141 (EFIAPI
*FILTER_FUNCTION
) (
142 IN EFI_HANDLE Handle
,
143 IN CONST CHAR16
*ReportText
150 @param[in] Handle The handle to process.
151 @param[in] ReportText A caller-allocated string passed in for reporting
152 purposes. It must never be NULL.
156 (EFIAPI
*CALLBACK_FUNCTION
) (
157 IN EFI_HANDLE Handle
,
158 IN CONST CHAR16
*ReportText
162 Locate all handles that carry the specified protocol, filter them with a
163 callback function, and pass each handle that passes the filter to another
166 @param[in] ProtocolGuid The protocol to look for.
168 @param[in] Filter The filter function to pass each handle to. If this
169 parameter is NULL, then all handles are processed.
171 @param[in] Process The callback function to pass each handle to that
177 IN EFI_GUID
*ProtocolGuid
,
178 IN FILTER_FUNCTION Filter OPTIONAL
,
179 IN CALLBACK_FUNCTION Process
187 Status
= gBS
->LocateHandleBuffer (ByProtocol
, ProtocolGuid
,
188 NULL
/* SearchKey */, &NoHandles
, &Handles
);
189 if (EFI_ERROR (Status
)) {
191 // This is not an error, just an informative condition.
193 DEBUG ((EFI_D_VERBOSE
, "%a: %g: %r\n", __FUNCTION__
, ProtocolGuid
,
198 ASSERT (NoHandles
> 0);
199 for (Idx
= 0; Idx
< NoHandles
; ++Idx
) {
200 CHAR16
*DevicePathText
;
201 STATIC CHAR16 Fallback
[] = L
"<device path unavailable>";
204 // The ConvertDevicePathToText() function handles NULL input transparently.
206 DevicePathText
= ConvertDevicePathToText (
207 DevicePathFromHandle (Handles
[Idx
]),
208 FALSE
, // DisplayOnly
209 FALSE
// AllowShortcuts
211 if (DevicePathText
== NULL
) {
212 DevicePathText
= Fallback
;
215 if (Filter
== NULL
|| Filter (Handles
[Idx
], DevicePathText
)) {
216 Process (Handles
[Idx
], DevicePathText
);
219 if (DevicePathText
!= Fallback
) {
220 FreePool (DevicePathText
);
223 gBS
->FreePool (Handles
);
228 This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.
234 IN EFI_HANDLE Handle
,
235 IN CONST CHAR16
*ReportText
239 EFI_PCI_IO_PROTOCOL
*PciIo
;
242 Status
= gBS
->HandleProtocol (Handle
, &gEfiPciIoProtocolGuid
,
244 if (EFI_ERROR (Status
)) {
246 // This is not an error worth reporting.
251 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, 0 /* Offset */,
252 sizeof Pci
/ sizeof (UINT32
), &Pci
);
253 if (EFI_ERROR (Status
)) {
254 DEBUG ((EFI_D_ERROR
, "%a: %s: %r\n", __FUNCTION__
, ReportText
, Status
));
258 return IS_PCI_DISPLAY (&Pci
);
263 This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking
264 the matching driver to produce all first-level child handles.
270 IN EFI_HANDLE Handle
,
271 IN CONST CHAR16
*ReportText
276 Status
= gBS
->ConnectController (
277 Handle
, // ControllerHandle
278 NULL
, // DriverImageHandle
279 NULL
, // RemainingDevicePath -- produce all children
282 DEBUG ((EFI_ERROR (Status
) ? EFI_D_ERROR
: EFI_D_VERBOSE
, "%a: %s: %r\n",
283 __FUNCTION__
, ReportText
, Status
));
288 This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the
289 handle, and adds it to ConOut and ErrOut.
295 IN EFI_HANDLE Handle
,
296 IN CONST CHAR16
*ReportText
300 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
302 DevicePath
= DevicePathFromHandle (Handle
);
303 if (DevicePath
== NULL
) {
304 DEBUG ((EFI_D_ERROR
, "%a: %s: handle %p: device path not found\n",
305 __FUNCTION__
, ReportText
, Handle
));
309 Status
= EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
310 if (EFI_ERROR (Status
)) {
311 DEBUG ((EFI_D_ERROR
, "%a: %s: adding to ConOut: %r\n", __FUNCTION__
,
312 ReportText
, Status
));
316 Status
= EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
317 if (EFI_ERROR (Status
)) {
318 DEBUG ((EFI_D_ERROR
, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__
,
319 ReportText
, Status
));
323 DEBUG ((EFI_D_VERBOSE
, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__
,
329 PlatformRegisterFvBootOption (
330 CONST EFI_GUID
*FileGuid
,
337 EFI_BOOT_MANAGER_LOAD_OPTION NewOption
;
338 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
339 UINTN BootOptionCount
;
340 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
341 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
342 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
344 Status
= gBS
->HandleProtocol (
346 &gEfiLoadedImageProtocolGuid
,
347 (VOID
**) &LoadedImage
349 ASSERT_EFI_ERROR (Status
);
351 EfiInitializeFwVolDevicepathNode (&FileNode
, FileGuid
);
352 DevicePath
= DevicePathFromHandle (LoadedImage
->DeviceHandle
);
353 ASSERT (DevicePath
!= NULL
);
354 DevicePath
= AppendDevicePathNode (
356 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
358 ASSERT (DevicePath
!= NULL
);
360 Status
= EfiBootManagerInitializeLoadOption (
362 LoadOptionNumberUnassigned
,
370 ASSERT_EFI_ERROR (Status
);
371 FreePool (DevicePath
);
373 BootOptions
= EfiBootManagerGetLoadOptions (
374 &BootOptionCount
, LoadOptionTypeBoot
377 OptionIndex
= EfiBootManagerFindLoadOption (
378 &NewOption
, BootOptions
, BootOptionCount
381 if (OptionIndex
== -1) {
382 Status
= EfiBootManagerAddLoadOptionVariable (&NewOption
, MAX_UINTN
);
383 ASSERT_EFI_ERROR (Status
);
385 EfiBootManagerFreeLoadOption (&NewOption
);
386 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
392 PlatformRegisterOptionsAndKeys (
400 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
403 // Register ENTER as CONTINUE key
405 Enter
.ScanCode
= SCAN_NULL
;
406 Enter
.UnicodeChar
= CHAR_CARRIAGE_RETURN
;
407 Status
= EfiBootManagerRegisterContinueKeyOption (0, &Enter
, NULL
);
408 ASSERT_EFI_ERROR (Status
);
411 // Map F2 and ESC to Boot Manager Menu
413 F2
.ScanCode
= SCAN_F2
;
414 F2
.UnicodeChar
= CHAR_NULL
;
415 Esc
.ScanCode
= SCAN_ESC
;
416 Esc
.UnicodeChar
= CHAR_NULL
;
417 Status
= EfiBootManagerGetBootManagerMenu (&BootOption
);
418 ASSERT_EFI_ERROR (Status
);
419 Status
= EfiBootManagerAddKeyOptionVariable (
420 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &F2
, NULL
422 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
423 Status
= EfiBootManagerAddKeyOptionVariable (
424 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &Esc
, NULL
426 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
431 // BDS Platform Functions
434 Do the platform init, can be customized by OEM/IBV
435 Possible things that can be done in PlatformBootManagerBeforeConsole:
436 > Update console variable: 1. include hot-plug devices;
437 > 2. Clear ConIn and add SOL for AMT
438 > Register new Driver#### or Boot####
439 > Register new Key####: e.g.: F12
440 > Signal ReadyToLock event
441 > Authentication action: 1. connect Auth devices;
442 > 2. Identify auto logon user.
446 PlatformBootManagerBeforeConsole (
451 // Signal EndOfDxe PI Event
453 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid
);
456 // Locate the PCI root bridges and make the PCI bus driver connect each,
457 // non-recursively. This will produce a number of child handles with PciIo on
460 FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid
, NULL
, Connect
);
463 // Find all display class PCI devices (using the handles from the previous
464 // step), and connect them non-recursively. This should produce a number of
465 // child handles with GOPs on them.
467 FilterAndProcess (&gEfiPciIoProtocolGuid
, IsPciDisplay
, Connect
);
470 // Now add the device path of all handles with GOP on them to ConOut and
473 FilterAndProcess (&gEfiGraphicsOutputProtocolGuid
, NULL
, AddOutput
);
476 // Add the hardcoded short-form USB keyboard device path to ConIn.
478 EfiBootManagerUpdateConsoleVariable (ConIn
,
479 (EFI_DEVICE_PATH_PROTOCOL
*)&mUsbKeyboard
, NULL
);
482 // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
484 ASSERT (FixedPcdGet8 (PcdDefaultTerminalType
) == 4);
485 CopyGuid (&mSerialConsole
.TermType
.Guid
, &gEfiTtyTermGuid
);
487 EfiBootManagerUpdateConsoleVariable (ConIn
,
488 (EFI_DEVICE_PATH_PROTOCOL
*)&mSerialConsole
, NULL
);
489 EfiBootManagerUpdateConsoleVariable (ConOut
,
490 (EFI_DEVICE_PATH_PROTOCOL
*)&mSerialConsole
, NULL
);
491 EfiBootManagerUpdateConsoleVariable (ErrOut
,
492 (EFI_DEVICE_PATH_PROTOCOL
*)&mSerialConsole
, NULL
);
495 // Register platform-specific boot options and keyboard shortcuts.
497 PlatformRegisterOptionsAndKeys ();
501 Do the platform specific action after the console is ready
502 Possible things that can be done in PlatformBootManagerAfterConsole:
503 > Console post action:
504 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
505 > Signal console ready platform customized event
506 > Run diagnostics like memory testing
507 > Connect certain devices
508 > Dispatch aditional option roms
509 > Special boot: e.g.: USB boot, enter UI
513 PlatformBootManagerAfterConsole (
520 // Show the splash screen.
522 Status
= BootLogoEnableLogo ();
523 if (EFI_ERROR (Status
)) {
524 Print (L
"Press ESCAPE for boot options ");
527 // Connect the rest of the devices.
529 EfiBootManagerConnectAll ();
532 // Enumerate all possible boot options.
534 EfiBootManagerRefreshAllBootOption ();
537 // Register UEFI Shell
539 PlatformRegisterFvBootOption (
540 &gUefiShellFileGuid
, L
"UEFI Shell", LOAD_OPTION_ACTIVE
545 This function is called each second during the boot manager waits the
548 @param TimeoutRemain The remaining timeout.
552 PlatformBootManagerWaitCallback (
556 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black
;
557 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White
;
561 Timeout
= PcdGet16 (PcdPlatformBootTimeOut
);
563 Black
.Raw
= 0x00000000;
564 White
.Raw
= 0x00FFFFFF;
566 Status
= BootLogoUpdateProgress (
569 L
"Press ESCAPE for boot options",
571 (Timeout
- TimeoutRemain
) * 100 / Timeout
,
574 if (EFI_ERROR (Status
)) {