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/DevicePathLib.h>
20 #include <Library/PcdLib.h>
21 #include <Library/QemuBootOrderLib.h>
22 #include <Library/UefiBootManagerLib.h>
23 #include <Protocol/DevicePath.h>
24 #include <Protocol/GraphicsOutput.h>
25 #include <Protocol/LoadedImage.h>
26 #include <Protocol/PciIo.h>
27 #include <Protocol/PciRootBridgeIo.h>
28 #include <Guid/EventGroup.h>
29 #include <Guid/RootBridgesConnectedEventGroup.h>
31 #include "PlatformBm.h"
33 #define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }
38 VENDOR_DEVICE_PATH SerialDxe
;
39 UART_DEVICE_PATH Uart
;
40 VENDOR_DEFINED_DEVICE_PATH TermType
;
41 EFI_DEVICE_PATH_PROTOCOL End
;
42 } PLATFORM_SERIAL_CONSOLE
;
45 #define SERIAL_DXE_FILE_GUID { \
46 0xD3987D4B, 0x971A, 0x435F, \
47 { 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } \
50 STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole
= {
52 // VENDOR_DEVICE_PATH SerialDxe
55 { HARDWARE_DEVICE_PATH
, HW_VENDOR_DP
, DP_NODE_LEN (VENDOR_DEVICE_PATH
) },
60 // UART_DEVICE_PATH Uart
63 { MESSAGING_DEVICE_PATH
, MSG_UART_DP
, DP_NODE_LEN (UART_DEVICE_PATH
) },
65 FixedPcdGet64 (PcdUartDefaultBaudRate
), // BaudRate
66 FixedPcdGet8 (PcdUartDefaultDataBits
), // DataBits
67 FixedPcdGet8 (PcdUartDefaultParity
), // Parity
68 FixedPcdGet8 (PcdUartDefaultStopBits
) // StopBits
72 // VENDOR_DEFINED_DEVICE_PATH TermType
76 MESSAGING_DEVICE_PATH
, MSG_VENDOR_DP
,
77 DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH
)
80 // Guid to be filled in dynamically
85 // EFI_DEVICE_PATH_PROTOCOL End
88 END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
89 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL
)
96 USB_CLASS_DEVICE_PATH Keyboard
;
97 EFI_DEVICE_PATH_PROTOCOL End
;
98 } PLATFORM_USB_KEYBOARD
;
101 STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard
= {
103 // USB_CLASS_DEVICE_PATH Keyboard
107 MESSAGING_DEVICE_PATH
, MSG_USB_CLASS_DP
,
108 DP_NODE_LEN (USB_CLASS_DEVICE_PATH
)
110 0xFFFF, // VendorId: any
111 0xFFFF, // ProductId: any
112 3, // DeviceClass: HID
113 1, // DeviceSubClass: boot
114 1 // DeviceProtocol: keyboard
118 // EFI_DEVICE_PATH_PROTOCOL End
121 END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
122 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL
)
128 Check if the handle satisfies a particular condition.
130 @param[in] Handle The handle to check.
131 @param[in] ReportText A caller-allocated string passed in for reporting
132 purposes. It must never be NULL.
134 @retval TRUE The condition is satisfied.
135 @retval FALSE Otherwise. This includes the case when the condition could not
136 be fully evaluated due to an error.
140 (EFIAPI
*FILTER_FUNCTION
) (
141 IN EFI_HANDLE Handle
,
142 IN CONST CHAR16
*ReportText
149 @param[in] Handle The handle to process.
150 @param[in] ReportText A caller-allocated string passed in for reporting
151 purposes. It must never be NULL.
155 (EFIAPI
*CALLBACK_FUNCTION
) (
156 IN EFI_HANDLE Handle
,
157 IN CONST CHAR16
*ReportText
161 Locate all handles that carry the specified protocol, filter them with a
162 callback function, and pass each handle that passes the filter to another
165 @param[in] ProtocolGuid The protocol to look for.
167 @param[in] Filter The filter function to pass each handle to. If this
168 parameter is NULL, then all handles are processed.
170 @param[in] Process The callback function to pass each handle to that
176 IN EFI_GUID
*ProtocolGuid
,
177 IN FILTER_FUNCTION Filter OPTIONAL
,
178 IN CALLBACK_FUNCTION Process
186 Status
= gBS
->LocateHandleBuffer (ByProtocol
, ProtocolGuid
,
187 NULL
/* SearchKey */, &NoHandles
, &Handles
);
188 if (EFI_ERROR (Status
)) {
190 // This is not an error, just an informative condition.
192 DEBUG ((EFI_D_VERBOSE
, "%a: %g: %r\n", __FUNCTION__
, ProtocolGuid
,
197 ASSERT (NoHandles
> 0);
198 for (Idx
= 0; Idx
< NoHandles
; ++Idx
) {
199 CHAR16
*DevicePathText
;
200 STATIC CHAR16 Fallback
[] = L
"<device path unavailable>";
203 // The ConvertDevicePathToText() function handles NULL input transparently.
205 DevicePathText
= ConvertDevicePathToText (
206 DevicePathFromHandle (Handles
[Idx
]),
207 FALSE
, // DisplayOnly
208 FALSE
// AllowShortcuts
210 if (DevicePathText
== NULL
) {
211 DevicePathText
= Fallback
;
214 if (Filter
== NULL
|| Filter (Handles
[Idx
], DevicePathText
)) {
215 Process (Handles
[Idx
], DevicePathText
);
218 if (DevicePathText
!= Fallback
) {
219 FreePool (DevicePathText
);
222 gBS
->FreePool (Handles
);
227 This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.
233 IN EFI_HANDLE Handle
,
234 IN CONST CHAR16
*ReportText
238 EFI_PCI_IO_PROTOCOL
*PciIo
;
241 Status
= gBS
->HandleProtocol (Handle
, &gEfiPciIoProtocolGuid
,
243 if (EFI_ERROR (Status
)) {
245 // This is not an error worth reporting.
250 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, 0 /* Offset */,
251 sizeof Pci
/ sizeof (UINT32
), &Pci
);
252 if (EFI_ERROR (Status
)) {
253 DEBUG ((EFI_D_ERROR
, "%a: %s: %r\n", __FUNCTION__
, ReportText
, Status
));
257 return IS_PCI_DISPLAY (&Pci
);
262 This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking
263 the matching driver to produce all first-level child handles.
269 IN EFI_HANDLE Handle
,
270 IN CONST CHAR16
*ReportText
275 Status
= gBS
->ConnectController (
276 Handle
, // ControllerHandle
277 NULL
, // DriverImageHandle
278 NULL
, // RemainingDevicePath -- produce all children
281 DEBUG ((EFI_ERROR (Status
) ? EFI_D_ERROR
: EFI_D_VERBOSE
, "%a: %s: %r\n",
282 __FUNCTION__
, ReportText
, Status
));
287 This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the
288 handle, and adds it to ConOut and ErrOut.
294 IN EFI_HANDLE Handle
,
295 IN CONST CHAR16
*ReportText
299 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
301 DevicePath
= DevicePathFromHandle (Handle
);
302 if (DevicePath
== NULL
) {
303 DEBUG ((EFI_D_ERROR
, "%a: %s: handle %p: device path not found\n",
304 __FUNCTION__
, ReportText
, Handle
));
308 Status
= EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
309 if (EFI_ERROR (Status
)) {
310 DEBUG ((EFI_D_ERROR
, "%a: %s: adding to ConOut: %r\n", __FUNCTION__
,
311 ReportText
, Status
));
315 Status
= EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
316 if (EFI_ERROR (Status
)) {
317 DEBUG ((EFI_D_ERROR
, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__
,
318 ReportText
, Status
));
322 DEBUG ((EFI_D_VERBOSE
, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__
,
328 PlatformRegisterFvBootOption (
336 EFI_BOOT_MANAGER_LOAD_OPTION NewOption
;
337 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
338 UINTN BootOptionCount
;
339 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
340 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
341 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
343 Status
= gBS
->HandleProtocol (
345 &gEfiLoadedImageProtocolGuid
,
346 (VOID
**) &LoadedImage
348 ASSERT_EFI_ERROR (Status
);
350 EfiInitializeFwVolDevicepathNode (&FileNode
, FileGuid
);
351 DevicePath
= DevicePathFromHandle (LoadedImage
->DeviceHandle
);
352 ASSERT (DevicePath
!= NULL
);
353 DevicePath
= AppendDevicePathNode (
355 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
357 ASSERT (DevicePath
!= NULL
);
359 Status
= EfiBootManagerInitializeLoadOption (
361 LoadOptionNumberUnassigned
,
369 ASSERT_EFI_ERROR (Status
);
370 FreePool (DevicePath
);
372 BootOptions
= EfiBootManagerGetLoadOptions (
373 &BootOptionCount
, LoadOptionTypeBoot
376 OptionIndex
= EfiBootManagerFindLoadOption (
377 &NewOption
, BootOptions
, BootOptionCount
380 if (OptionIndex
== -1) {
381 Status
= EfiBootManagerAddLoadOptionVariable (&NewOption
, MAX_UINTN
);
382 ASSERT_EFI_ERROR (Status
);
384 EfiBootManagerFreeLoadOption (&NewOption
);
385 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
391 PlatformRegisterOptionsAndKeys (
399 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
402 // Register ENTER as CONTINUE key
404 Enter
.ScanCode
= SCAN_NULL
;
405 Enter
.UnicodeChar
= CHAR_CARRIAGE_RETURN
;
406 Status
= EfiBootManagerRegisterContinueKeyOption (0, &Enter
, NULL
);
407 ASSERT_EFI_ERROR (Status
);
410 // Map F2 and ESC to Boot Manager Menu
412 F2
.ScanCode
= SCAN_F2
;
413 F2
.UnicodeChar
= CHAR_NULL
;
414 Esc
.ScanCode
= SCAN_ESC
;
415 Esc
.UnicodeChar
= CHAR_NULL
;
416 Status
= EfiBootManagerGetBootManagerMenu (&BootOption
);
417 ASSERT_EFI_ERROR (Status
);
418 Status
= EfiBootManagerAddKeyOptionVariable (
419 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &F2
, NULL
421 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
422 Status
= EfiBootManagerAddKeyOptionVariable (
423 NULL
, (UINT16
) BootOption
.OptionNumber
, 0, &Esc
, NULL
425 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_ALREADY_STARTED
);
427 // Register UEFI Shell
429 PlatformRegisterFvBootOption (
430 PcdGetPtr (PcdShellFile
), L
"EFI Internal Shell", LOAD_OPTION_ACTIVE
436 // BDS Platform Functions
439 Do the platform init, can be customized by OEM/IBV
440 Possible things that can be done in PlatformBootManagerBeforeConsole:
441 > Update console variable: 1. include hot-plug devices;
442 > 2. Clear ConIn and add SOL for AMT
443 > Register new Driver#### or Boot####
444 > Register new Key####: e.g.: F12
445 > Signal ReadyToLock event
446 > Authentication action: 1. connect Auth devices;
447 > 2. Identify auto logon user.
451 PlatformBootManagerBeforeConsole (
456 // Signal EndOfDxe PI Event
458 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid
);
461 // Locate the PCI root bridges and make the PCI bus driver connect each,
462 // non-recursively. This will produce a number of child handles with PciIo on
465 FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid
, NULL
, Connect
);
468 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
470 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid
);
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 CopyGuid (&mSerialConsole
.TermType
.Guid
,
495 PcdGetPtr (PcdTerminalTypeGuidBuffer
));
496 EfiBootManagerUpdateConsoleVariable (ConIn
,
497 (EFI_DEVICE_PATH_PROTOCOL
*)&mSerialConsole
, NULL
);
498 EfiBootManagerUpdateConsoleVariable (ConOut
,
499 (EFI_DEVICE_PATH_PROTOCOL
*)&mSerialConsole
, NULL
);
500 EfiBootManagerUpdateConsoleVariable (ErrOut
,
501 (EFI_DEVICE_PATH_PROTOCOL
*)&mSerialConsole
, NULL
);
504 // Set the front page timeout from the QEMU configuration.
506 PcdSet16 (PcdPlatformBootTimeOut
, GetFrontPageTimeoutFromQemu ());
509 // Register platform-specific boot options and keyboard shortcuts.
511 PlatformRegisterOptionsAndKeys ();
515 Do the platform specific action after the console is ready
516 Possible things that can be done in PlatformBootManagerAfterConsole:
517 > Console post action:
518 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
519 > Signal console ready platform customized event
520 > Run diagnostics like memory testing
521 > Connect certain devices
522 > Dispatch aditional option roms
523 > Special boot: e.g.: USB boot, enter UI
527 PlatformBootManagerAfterConsole (
532 // Show the splash screen.
534 EnableQuietBoot (PcdGetPtr (PcdLogoFile
));
537 // Connect the rest of the devices.
542 // Process QEMU's -kernel command line option. Note that the kernel booted
543 // this way should receive ACPI tables, which is why we connect all devices
544 // first (see above) -- PCI enumeration blocks ACPI table installation, if
545 // there is a PCI host.
547 TryRunningQemuKernel ();
549 BdsLibEnumerateAllBootOption (BootOptionList
);
550 SetBootOrderFromQemu (BootOptionList
);
552 // The BootOrder variable may have changed, reload the in-memory list with
555 BdsLibBuildOptionFromVar (BootOptionList
, L
"BootOrder");
559 This function is called each second during the boot manager waits the
562 @param TimeoutRemain The remaining timeout.
566 PlatformBootManagerWaitCallback (