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 Hook point after a boot attempt succeeds. We don't expect a boot option to
560 return, so the UEFI 2.0 specification defines that you will default to an
561 interactive mode and stop processing the BootOrder list in this case. This
562 is also a platform implementation and can be customized by IBV/OEM.
564 @param Option Pointer to Boot Option that succeeded to boot.
569 PlatformBdsBootSuccess (
570 IN BDS_COMMON_OPTION
*Option
576 Hook point after a boot attempt fails.
578 @param Option Pointer to Boot Option that failed to boot.
579 @param Status Status returned from failed boot.
580 @param ExitData Exit data returned from failed boot.
581 @param ExitDataSize Exit data size returned from failed boot.
586 PlatformBdsBootFail (
587 IN BDS_COMMON_OPTION
*Option
,
588 IN EFI_STATUS Status
,
590 IN UINTN ExitDataSize
596 This function locks platform flash that is not allowed to be updated during normal boot path.
597 The flash layout is platform specific.
601 PlatformBdsLockNonUpdatableFlash (
609 This function is called each second during the boot manager waits the
612 @param TimeoutRemain The remaining timeout.
616 PlatformBootManagerWaitCallback (