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>
8 This program and the accompanying materials are licensed and made available
9 under the terms and conditions of the BSD License which accompanies this
10 distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
14 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include <IndustryStandard/Pci22.h>
19 #include <Library/BootLogoLib.h>
20 #include <Library/DevicePathLib.h>
21 #include <Library/PcdLib.h>
22 #include <Library/QemuBootOrderLib.h>
23 #include <Library/UefiBootManagerLib.h>
24 #include <Protocol/DevicePath.h>
25 #include <Protocol/GraphicsOutput.h>
26 #include <Protocol/LoadedImage.h>
27 #include <Protocol/PciIo.h>
28 #include <Protocol/PciRootBridgeIo.h>
29 #include <Guid/EventGroup.h>
30 #include <Guid/RootBridgesConnectedEventGroup.h>
32 #include "PlatformBm.h"
34 #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 (
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
);
428 // Register UEFI Shell
430 PlatformRegisterFvBootOption (
431 PcdGetPtr (PcdShellFile
), L
"EFI Internal Shell", LOAD_OPTION_ACTIVE
437 // BDS Platform Functions
440 Do the platform init, can be customized by OEM/IBV
441 Possible things that can be done in PlatformBootManagerBeforeConsole:
442 > Update console variable: 1. include hot-plug devices;
443 > 2. Clear ConIn and add SOL for AMT
444 > Register new Driver#### or Boot####
445 > Register new Key####: e.g.: F12
446 > Signal ReadyToLock event
447 > Authentication action: 1. connect Auth devices;
448 > 2. Identify auto logon user.
452 PlatformBootManagerBeforeConsole (
457 // Signal EndOfDxe PI Event
459 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid
);
462 // Locate the PCI root bridges and make the PCI bus driver connect each,
463 // non-recursively. This will produce a number of child handles with PciIo on
466 FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid
, NULL
, Connect
);
469 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
471 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid
);
474 // Find all display class PCI devices (using the handles from the previous
475 // step), and connect them non-recursively. This should produce a number of
476 // child handles with GOPs on them.
478 FilterAndProcess (&gEfiPciIoProtocolGuid
, IsPciDisplay
, Connect
);
481 // Now add the device path of all handles with GOP on them to ConOut and
484 FilterAndProcess (&gEfiGraphicsOutputProtocolGuid
, NULL
, AddOutput
);
487 // Add the hardcoded short-form USB keyboard device path to ConIn.
489 EfiBootManagerUpdateConsoleVariable (ConIn
,
490 (EFI_DEVICE_PATH_PROTOCOL
*)&mUsbKeyboard
, NULL
);
493 // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
495 CopyGuid (&mSerialConsole
.TermType
.Guid
,
496 PcdGetPtr (PcdTerminalTypeGuidBuffer
));
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 // Set the front page timeout from the QEMU configuration.
507 PcdSet16 (PcdPlatformBootTimeOut
, GetFrontPageTimeoutFromQemu ());
510 // Register platform-specific boot options and keyboard shortcuts.
512 PlatformRegisterOptionsAndKeys ();
516 Do the platform specific action after the console is ready
517 Possible things that can be done in PlatformBootManagerAfterConsole:
518 > Console post action:
519 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
520 > Signal console ready platform customized event
521 > Run diagnostics like memory testing
522 > Connect certain devices
523 > Dispatch aditional option roms
524 > Special boot: e.g.: USB boot, enter UI
528 PlatformBootManagerAfterConsole (
533 // Show the splash screen.
536 ImageFormatBmp
, // ImageFormat
537 PcdGetPtr (PcdLogoFile
), // Logo
538 EdkiiPlatformLogoDisplayAttributeCenter
, // Attribute
544 // Connect the rest of the devices.
546 EfiBootManagerConnectAll ();
549 // Process QEMU's -kernel command line option. Note that the kernel booted
550 // this way should receive ACPI tables, which is why we connect all devices
551 // first (see above) -- PCI enumeration blocks ACPI table installation, if
552 // there is a PCI host.
554 TryRunningQemuKernel ();
557 // Enumerate all possible boot options, then filter and reorder them based on
558 // the QEMU configuration.
560 EfiBootManagerRefreshAllBootOption ();
561 SetBootOrderFromQemu ();
565 This function is called each second during the boot manager waits the
568 @param TimeoutRemain The remaining timeout.
572 PlatformBootManagerWaitCallback (
576 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black
;
577 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White
;
580 Timeout
= PcdGet16 (PcdPlatformBootTimeOut
);
582 Black
.Raw
= 0x00000000;
583 White
.Raw
= 0x00FFFFFF;
585 BootLogoUpdateProgress (
588 L
"Start boot option",
590 (Timeout
- TimeoutRemain
) * 100 / Timeout
,