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 - 2008, 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/PciIo.h>
26 #include <Protocol/PciRootBridgeIo.h>
27 #include <Guid/EventGroup.h>
28 #include <Guid/RootBridgesConnectedEventGroup.h>
30 #include "PlatformBm.h"
32 #define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }
37 VENDOR_DEVICE_PATH SerialDxe
;
38 UART_DEVICE_PATH Uart
;
39 VENDOR_DEFINED_DEVICE_PATH TermType
;
40 EFI_DEVICE_PATH_PROTOCOL End
;
41 } PLATFORM_SERIAL_CONSOLE
;
44 #define SERIAL_DXE_FILE_GUID { \
45 0xD3987D4B, 0x971A, 0x435F, \
46 { 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } \
49 STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole
= {
51 // VENDOR_DEVICE_PATH SerialDxe
54 { HARDWARE_DEVICE_PATH
, HW_VENDOR_DP
, DP_NODE_LEN (VENDOR_DEVICE_PATH
) },
59 // UART_DEVICE_PATH Uart
62 { MESSAGING_DEVICE_PATH
, MSG_UART_DP
, DP_NODE_LEN (UART_DEVICE_PATH
) },
64 FixedPcdGet64 (PcdUartDefaultBaudRate
), // BaudRate
65 FixedPcdGet8 (PcdUartDefaultDataBits
), // DataBits
66 FixedPcdGet8 (PcdUartDefaultParity
), // Parity
67 FixedPcdGet8 (PcdUartDefaultStopBits
) // StopBits
71 // VENDOR_DEFINED_DEVICE_PATH TermType
75 MESSAGING_DEVICE_PATH
, MSG_VENDOR_DP
,
76 DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH
)
79 // Guid to be filled in dynamically
84 // EFI_DEVICE_PATH_PROTOCOL End
87 END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
88 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL
)
95 USB_CLASS_DEVICE_PATH Keyboard
;
96 EFI_DEVICE_PATH_PROTOCOL End
;
97 } PLATFORM_USB_KEYBOARD
;
100 STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard
= {
102 // USB_CLASS_DEVICE_PATH Keyboard
106 MESSAGING_DEVICE_PATH
, MSG_USB_CLASS_DP
,
107 DP_NODE_LEN (USB_CLASS_DEVICE_PATH
)
109 0xFFFF, // VendorId: any
110 0xFFFF, // ProductId: any
111 3, // DeviceClass: HID
112 1, // DeviceSubClass: boot
113 1 // DeviceProtocol: keyboard
117 // EFI_DEVICE_PATH_PROTOCOL End
120 END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
,
121 DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL
)
127 Check if the handle satisfies a particular condition.
129 @param[in] Handle The handle to check.
130 @param[in] ReportText A caller-allocated string passed in for reporting
131 purposes. It must never be NULL.
133 @retval TRUE The condition is satisfied.
134 @retval FALSE Otherwise. This includes the case when the condition could not
135 be fully evaluated due to an error.
139 (EFIAPI
*FILTER_FUNCTION
) (
140 IN EFI_HANDLE Handle
,
141 IN CONST CHAR16
*ReportText
148 @param[in] Handle The handle to process.
149 @param[in] ReportText A caller-allocated string passed in for reporting
150 purposes. It must never be NULL.
154 (EFIAPI
*CALLBACK_FUNCTION
) (
155 IN EFI_HANDLE Handle
,
156 IN CONST CHAR16
*ReportText
160 Locate all handles that carry the specified protocol, filter them with a
161 callback function, and pass each handle that passes the filter to another
164 @param[in] ProtocolGuid The protocol to look for.
166 @param[in] Filter The filter function to pass each handle to. If this
167 parameter is NULL, then all handles are processed.
169 @param[in] Process The callback function to pass each handle to that
175 IN EFI_GUID
*ProtocolGuid
,
176 IN FILTER_FUNCTION Filter OPTIONAL
,
177 IN CALLBACK_FUNCTION Process
185 Status
= gBS
->LocateHandleBuffer (ByProtocol
, ProtocolGuid
,
186 NULL
/* SearchKey */, &NoHandles
, &Handles
);
187 if (EFI_ERROR (Status
)) {
189 // This is not an error, just an informative condition.
191 DEBUG ((EFI_D_VERBOSE
, "%a: %g: %r\n", __FUNCTION__
, ProtocolGuid
,
196 ASSERT (NoHandles
> 0);
197 for (Idx
= 0; Idx
< NoHandles
; ++Idx
) {
198 CHAR16
*DevicePathText
;
199 STATIC CHAR16 Fallback
[] = L
"<device path unavailable>";
202 // The ConvertDevicePathToText() function handles NULL input transparently.
204 DevicePathText
= ConvertDevicePathToText (
205 DevicePathFromHandle (Handles
[Idx
]),
206 FALSE
, // DisplayOnly
207 FALSE
// AllowShortcuts
209 if (DevicePathText
== NULL
) {
210 DevicePathText
= Fallback
;
213 if (Filter
== NULL
|| Filter (Handles
[Idx
], DevicePathText
)) {
214 Process (Handles
[Idx
], DevicePathText
);
217 if (DevicePathText
!= Fallback
) {
218 FreePool (DevicePathText
);
221 gBS
->FreePool (Handles
);
226 This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.
232 IN EFI_HANDLE Handle
,
233 IN CONST CHAR16
*ReportText
237 EFI_PCI_IO_PROTOCOL
*PciIo
;
240 Status
= gBS
->HandleProtocol (Handle
, &gEfiPciIoProtocolGuid
,
242 if (EFI_ERROR (Status
)) {
244 // This is not an error worth reporting.
249 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, 0 /* Offset */,
250 sizeof Pci
/ sizeof (UINT32
), &Pci
);
251 if (EFI_ERROR (Status
)) {
252 DEBUG ((EFI_D_ERROR
, "%a: %s: %r\n", __FUNCTION__
, ReportText
, Status
));
256 return IS_PCI_DISPLAY (&Pci
);
261 This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking
262 the matching driver to produce all first-level child handles.
268 IN EFI_HANDLE Handle
,
269 IN CONST CHAR16
*ReportText
274 Status
= gBS
->ConnectController (
275 Handle
, // ControllerHandle
276 NULL
, // DriverImageHandle
277 NULL
, // RemainingDevicePath -- produce all children
280 DEBUG ((EFI_ERROR (Status
) ? EFI_D_ERROR
: EFI_D_VERBOSE
, "%a: %s: %r\n",
281 __FUNCTION__
, ReportText
, Status
));
286 This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the
287 handle, and adds it to ConOut and ErrOut.
293 IN EFI_HANDLE Handle
,
294 IN CONST CHAR16
*ReportText
298 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
300 DevicePath
= DevicePathFromHandle (Handle
);
301 if (DevicePath
== NULL
) {
302 DEBUG ((EFI_D_ERROR
, "%a: %s: handle %p: device path not found\n",
303 __FUNCTION__
, ReportText
, Handle
));
307 Status
= EfiBootManagerUpdateConsoleVariable (ConOut
, DevicePath
, NULL
);
308 if (EFI_ERROR (Status
)) {
309 DEBUG ((EFI_D_ERROR
, "%a: %s: adding to ConOut: %r\n", __FUNCTION__
,
310 ReportText
, Status
));
314 Status
= EfiBootManagerUpdateConsoleVariable (ErrOut
, DevicePath
, NULL
);
315 if (EFI_ERROR (Status
)) {
316 DEBUG ((EFI_D_ERROR
, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__
,
317 ReportText
, Status
));
321 DEBUG ((EFI_D_VERBOSE
, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__
,
327 // BDS Platform Functions
330 Do the platform init, can be customized by OEM/IBV
331 Possible things that can be done in PlatformBootManagerBeforeConsole:
332 > Update console variable: 1. include hot-plug devices;
333 > 2. Clear ConIn and add SOL for AMT
334 > Register new Driver#### or Boot####
335 > Register new Key####: e.g.: F12
336 > Signal ReadyToLock event
337 > Authentication action: 1. connect Auth devices;
338 > 2. Identify auto logon user.
342 PlatformBootManagerBeforeConsole (
347 // Signal EndOfDxe PI Event
349 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid
);
352 // Locate the PCI root bridges and make the PCI bus driver connect each,
353 // non-recursively. This will produce a number of child handles with PciIo on
356 FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid
, NULL
, Connect
);
359 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
361 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid
);
364 // Find all display class PCI devices (using the handles from the previous
365 // step), and connect them non-recursively. This should produce a number of
366 // child handles with GOPs on them.
368 FilterAndProcess (&gEfiPciIoProtocolGuid
, IsPciDisplay
, Connect
);
371 // Now add the device path of all handles with GOP on them to ConOut and
374 FilterAndProcess (&gEfiGraphicsOutputProtocolGuid
, NULL
, AddOutput
);
377 // Add the hardcoded short-form USB keyboard device path to ConIn.
379 EfiBootManagerUpdateConsoleVariable (ConIn
,
380 (EFI_DEVICE_PATH_PROTOCOL
*)&mUsbKeyboard
, NULL
);
383 // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
385 CopyGuid (&mSerialConsole
.TermType
.Guid
,
386 PcdGetPtr (PcdTerminalTypeGuidBuffer
));
387 EfiBootManagerUpdateConsoleVariable (ConIn
,
388 (EFI_DEVICE_PATH_PROTOCOL
*)&mSerialConsole
, NULL
);
389 EfiBootManagerUpdateConsoleVariable (ConOut
,
390 (EFI_DEVICE_PATH_PROTOCOL
*)&mSerialConsole
, NULL
);
391 EfiBootManagerUpdateConsoleVariable (ErrOut
,
392 (EFI_DEVICE_PATH_PROTOCOL
*)&mSerialConsole
, NULL
);
396 Do the platform specific action after the console is ready
397 Possible things that can be done in PlatformBootManagerAfterConsole:
398 > Console post action:
399 > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
400 > Signal console ready platform customized event
401 > Run diagnostics like memory testing
402 > Connect certain devices
403 > Dispatch aditional option roms
404 > Special boot: e.g.: USB boot, enter UI
408 PlatformBootManagerAfterConsole (
413 // Show the splash screen.
415 EnableQuietBoot (PcdGetPtr (PcdLogoFile
));
418 // Connect the rest of the devices.
423 // Process QEMU's -kernel command line option. Note that the kernel booted
424 // this way should receive ACPI tables, which is why we connect all devices
425 // first (see above) -- PCI enumeration blocks ACPI table installation, if
426 // there is a PCI host.
428 TryRunningQemuKernel ();
430 BdsLibEnumerateAllBootOption (BootOptionList
);
431 SetBootOrderFromQemu (BootOptionList
);
433 // The BootOrder variable may have changed, reload the in-memory list with
436 BdsLibBuildOptionFromVar (BootOptionList
, L
"BootOrder");
438 PlatformBdsEnterFrontPage (GetFrontPageTimeoutFromQemu(), TRUE
);
442 Hook point after a boot attempt succeeds. We don't expect a boot option to
443 return, so the UEFI 2.0 specification defines that you will default to an
444 interactive mode and stop processing the BootOrder list in this case. This
445 is also a platform implementation and can be customized by IBV/OEM.
447 @param Option Pointer to Boot Option that succeeded to boot.
452 PlatformBdsBootSuccess (
453 IN BDS_COMMON_OPTION
*Option
459 Hook point after a boot attempt fails.
461 @param Option Pointer to Boot Option that failed to boot.
462 @param Status Status returned from failed boot.
463 @param ExitData Exit data returned from failed boot.
464 @param ExitDataSize Exit data size returned from failed boot.
469 PlatformBdsBootFail (
470 IN BDS_COMMON_OPTION
*Option
,
471 IN EFI_STATUS Status
,
473 IN UINTN ExitDataSize
479 This function locks platform flash that is not allowed to be updated during normal boot path.
480 The flash layout is platform specific.
484 PlatformBdsLockNonUpdatableFlash (
492 This function is called each second during the boot manager waits the
495 @param TimeoutRemain The remaining timeout.
499 PlatformBootManagerWaitCallback (