From: Laszlo Ersek <lersek@redhat.com>
To: edk2-devel-01 <edk2-devel@lists.01.org>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>,
Jordan Justen <jordan.l.justen@intel.com>,
Ruiyu Ni <ruiyu.ni@intel.com>,
Anthony Perard <anthony.perard@citrix.com>,
Julien Grall <julien.grall@linaro.org>
Subject: [PATCH 4/5] OvmfPkg/PlatformBootManagerLib: print EDKII_OS_LOADER_DETAIL to ConOut
Date: Thu, 23 Nov 2017 00:58:48 +0100 [thread overview]
Message-ID: <20171122235849.4177-5-lersek@redhat.com> (raw)
In-Reply-To: <20171122235849.4177-1-lersek@redhat.com>
Parse and print the EDKII_OS_LOADER_DETAIL debug codes from
UefiBootManagerLib (when it acts as part of BdsDxe -- not as part of
UiApp, for example). In effect this displays LoadImage() and StartImage()
attempts and failures on the splash screen, visibly to end-users.
While at it, print two other (earlier) console messages about boot option
generation and boot option filtering / reordering.
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Julien Grall <julien.grall@linaro.org>
Ref: https://bugzilla.redhat.com/show_bug.cgi?id=1515418
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
Notes:
We can port this later to ArmVirtPkg. For that, first we'll have to
replace commit 59541d41633c ("ArmVirtPkg: remove status code support",
2017-07-05) with a port of commit a6d594c5fabd ("OvmfPkg: use StatusCode
Router and Handler from MdeModulePkg", 2016-08-03).
OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf | 4 +
OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.h | 15 +
OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c | 8 +
OvmfPkg/Library/PlatformBootManagerLib/StatusCodeHandler.c | 298 ++++++++++++++++++++
4 files changed, 325 insertions(+)
diff --git a/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
index 27789b7377bc..36901fc39d95 100644
--- a/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
+++ b/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
@@ -21,24 +21,25 @@ [Defines]
LIBRARY_CLASS = PlatformBootManagerLib|DXE_DRIVER
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources]
BdsPlatform.c
PlatformData.c
QemuKernel.c
+ StatusCodeHandler.c
BdsPlatform.h
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
SourceLevelDebugPkg/SourceLevelDebugPkg.dec
OvmfPkg/OvmfPkg.dec
[LibraryClasses]
BaseLib
MemoryAllocationLib
@@ -54,28 +55,31 @@ [LibraryClasses]
QemuFwCfgLib
QemuFwCfgS3Lib
LoadLinuxLib
QemuBootOrderLib
UefiLib
[Pcd]
gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfHostBridgePciDevId
gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut
gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdShellFile
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDebugCodeOsLoaderDetail
[Pcd.IA32, Pcd.X64]
gEfiMdePkgTokenSpaceGuid.PcdFSBClock
[Protocols]
gEfiDecompressProtocolGuid
gEfiPciRootBridgeIoProtocolGuid
gEfiS3SaveStateProtocolGuid # PROTOCOL SOMETIMES_CONSUMED
gEfiDxeSmmReadyToLockProtocolGuid # PROTOCOL SOMETIMES_PRODUCED
gEfiLoadedImageProtocolGuid # PROTOCOL SOMETIMES_PRODUCED
gEfiFirmwareVolume2ProtocolGuid # PROTOCOL SOMETIMES_CONSUMED
+ gEfiRscHandlerProtocolGuid # PROTOCOL SOMETIMES_CONSUMED
[Guids]
gEfiXenInfoGuid
gEfiEndOfDxeEventGroupGuid
gRootBridgesConnectedEventGroupGuid
+ gEdkiiStatusCodeDataTypeOsLoaderDetailGuid
diff --git a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.h b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.h
index 97ffbb514825..493cfee85f54 100644
--- a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.h
+++ b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.h
@@ -183,13 +183,28 @@ PlatformInitializeConsole (
/**
Loads and boots UEFI Linux via the FwCfg interface.
@retval EFI_NOT_FOUND - The Linux kernel was not found
**/
EFI_STATUS
TryRunningQemuKernel (
VOID
);
+/**
+ Register a status code handler for printing EDKII_OS_LOADER_DETAIL reports to
+ the console.
+
+ @retval EFI_SUCCESS The status code handler has been successfully
+ registered.
+
+ @return Error codes propagated from boot services and from
+ EFI_RSC_HANDLER_PROTOCOL.
+**/
+EFI_STATUS
+RegisterStatusCodeHandler (
+ VOID
+ );
+
#endif // _PLATFORM_SPECIFIC_BDS_PLATFORM_H_
diff --git a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c
index 025252e72b39..429f2926d2af 100644
--- a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c
+++ b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c
@@ -1454,35 +1454,43 @@ Routine Description:
BootLogoEnableLogo ();
//
// Perform some platform specific connect sequence
//
PlatformBdsConnectSequence ();
//
// Process QEMU's -kernel command line option
//
TryRunningQemuKernel ();
+ AsciiPrint (
+ "%a: auto-generating trailing boot options for bootable devices\n",
+ gEfiCallerBaseName
+ );
EfiBootManagerRefreshAllBootOption ();
//
// Register UEFI Shell
//
PlatformRegisterFvBootOption (
PcdGetPtr (PcdShellFile), L"EFI Internal Shell", LOAD_OPTION_ACTIVE
);
+ AsciiPrint ("%a: filtering and reordering boot options\n",
+ gEfiCallerBaseName);
RemoveStaleFvFileOptions ();
SetBootOrderFromQemu ();
+
+ RegisterStatusCodeHandler ();
}
/**
This notification function is invoked when an instance of the
EFI_DEVICE_PATH_PROTOCOL is produced.
@param Event The event that occurred
@param Context For EFI compatibility. Not used.
**/
VOID
EFIAPI
diff --git a/OvmfPkg/Library/PlatformBootManagerLib/StatusCodeHandler.c b/OvmfPkg/Library/PlatformBootManagerLib/StatusCodeHandler.c
new file mode 100644
index 000000000000..cec4fb6ed6ce
--- /dev/null
+++ b/OvmfPkg/Library/PlatformBootManagerLib/StatusCodeHandler.c
@@ -0,0 +1,298 @@
+/** @file
+ Register a status code handler for printing EDKII_OS_LOADER_DETAIL reports to
+ the console.
+
+ This feature enables users that are not accustomed to analyzing the OVMF
+ debug log to glean some information about UEFI boot option processing
+ (loading and starting).
+
+ Copyright (C) 2017, Red Hat, Inc.
+
+ This program and the accompanying materials are licensed and made available
+ under the terms and conditions of the BSD License which accompanies this
+ distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
+ WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#include <Guid/StatusCodeDataTypeOsLoaderDetail.h>
+#include <Protocol/ReportStatusCodeHandler.h>
+
+#include "BdsPlatform.h"
+
+
+/**
+ Handle status codes reported through ReportStatusCodeLib /
+ EFI_STATUS_CODE_PROTOCOL.ReportStatusCode(). Format matching status codes to
+ the system console.
+
+ The highest TPL at which this handler can be registered with
+ EFI_RSC_HANDLER_PROTOCOL.Register() is TPL_NOTIFY. That's because
+ AsciiPrint() uses EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL internally.
+
+ The parameter list of this function precisely matches that of
+ EFI_STATUS_CODE_PROTOCOL.ReportStatusCode().
+
+ The return status of this function is ignored by the caller, but the function
+ still returns sensible codes:
+
+ @retval EFI_SUCCESS The status code has been processed; either as
+ a no-op, due to filtering, or by formatting it
+ to the system console.
+
+ @retval EFI_INVALID_PARAMETER Unknown or malformed contents have been
+ detected in EFI_STATUS_CODE_DATA, or in the
+ EDKII_OS_LOADER_DETAIL payload within
+ EFI_STATUS_CODE_DATA.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+HandleStatusCode (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN EFI_GUID *CallerId,
+ IN EFI_STATUS_CODE_DATA *Data
+ )
+{
+ EDKII_OS_LOADER_DETAIL *OsLoaderDetail;
+ UINT8 *VariableSizeData;
+ CHAR16 *Description;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ BOOLEAN DevPathStringIsDynamic;
+ CHAR16 *DevPathString;
+ EFI_STATUS Status;
+
+ //
+ // Ignore all status codes other than OsLoaderDetail.
+ //
+ if (Value != PcdGet32 (PcdDebugCodeOsLoaderDetail)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // The status codes we are interested in are emitted by UefiBootManagerLib.
+ // UefiBootManagerLib is built into several drivers and applications, e.g.
+ // BdsDxe and UiApp. Process (i.e., print to the console) only those status
+ // codes that come from BdsDxe; that is, from the driver module that this
+ // PlatformBootManagerLib instance is also built into.
+ //
+ if (!CompareGuid (CallerId, &gEfiCallerIdGuid)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Sanity checks -- now that Value has been validated, we have expectations
+ // to enforce.
+ //
+ if ((Data == NULL) ||
+ (Data->HeaderSize < sizeof *Data) ||
+ (Data->Size < sizeof *OsLoaderDetail) ||
+ (!CompareGuid (&Data->Type,
+ &gEdkiiStatusCodeDataTypeOsLoaderDetailGuid))) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: unknown or malformed data for status code 0x%x\n",
+ __FUNCTION__,
+ PcdGet32 (PcdDebugCodeOsLoaderDetail)
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OsLoaderDetail = (EDKII_OS_LOADER_DETAIL *)(
+ (UINT8 *)Data + Data->HeaderSize
+ );
+
+ //
+ // More sanity checks. The additions on the RHS are carried out in UINTN and
+ // cannot overflow.
+ //
+ if (Data->Size < (sizeof *OsLoaderDetail +
+ OsLoaderDetail->DescriptionSize +
+ OsLoaderDetail->DevicePathSize)) {
+ DEBUG ((DEBUG_ERROR, "%a: malformed EDKII_OS_LOADER_DETAIL\n",
+ __FUNCTION__));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Extract the known variable size fields from the payload.
+ //
+ VariableSizeData = (UINT8 *)(OsLoaderDetail + 1);
+
+ Description = (CHAR16 *)VariableSizeData;
+ VariableSizeData += OsLoaderDetail->DescriptionSize;
+
+ DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)VariableSizeData;
+ VariableSizeData += OsLoaderDetail->DevicePathSize;
+
+ ASSERT (VariableSizeData - (UINT8 *)OsLoaderDetail <= Data->Size);
+
+ //
+ // Prepare the extracted variable size fields for printing.
+ //
+ if (OsLoaderDetail->DescriptionSize == 0) {
+ Description = L"<no description available>";
+ }
+
+ DevPathStringIsDynamic = FALSE;
+ if (OsLoaderDetail->DevicePathSize == 0) {
+ DevPathString = L"<no device path available>";
+ } else {
+ DevPathString = ConvertDevicePathToText (
+ DevicePath,
+ FALSE, // DisplayOnly
+ FALSE // AllowShortcuts
+ );
+ if (DevPathString == NULL) {
+ DevPathString = L"<out of memory while formatting device path>";
+ } else {
+ DevPathStringIsDynamic = TRUE;
+ }
+ }
+
+ //
+ // Print the message to the console.
+ //
+ switch (OsLoaderDetail->Type) {
+ case EDKII_OS_LOADER_DETAIL_TYPE_LOAD:
+ case EDKII_OS_LOADER_DETAIL_TYPE_START:
+ AsciiPrint (
+ "%a: %a Boot%04x \"%s\" from %s\n",
+ gEfiCallerBaseName,
+ (OsLoaderDetail->Type == EDKII_OS_LOADER_DETAIL_TYPE_LOAD ?
+ "loading" :
+ "starting"),
+ OsLoaderDetail->BootOptionNumber,
+ Description,
+ DevPathString
+ );
+ break;
+
+ case EDKII_OS_LOADER_DETAIL_TYPE_LOAD_ERROR:
+ case EDKII_OS_LOADER_DETAIL_TYPE_START_ERROR:
+ AsciiPrint (
+ "%a: failed to %a Boot%04x \"%s\" from %s: %r\n",
+ gEfiCallerBaseName,
+ (OsLoaderDetail->Type == EDKII_OS_LOADER_DETAIL_TYPE_LOAD_ERROR ?
+ "load" :
+ "start"),
+ OsLoaderDetail->BootOptionNumber,
+ Description,
+ DevPathString,
+ OsLoaderDetail->Status
+ );
+ break;
+
+ default:
+ DEBUG ((DEBUG_ERROR, "%a: unknown EDKII_OS_LOADER_DETAIL.Type 0x%x\n",
+ __FUNCTION__, OsLoaderDetail->Type));
+ Status = EFI_INVALID_PARAMETER;
+ goto ReleaseDevPathString;
+ }
+
+ Status = EFI_SUCCESS;
+
+ReleaseDevPathString:
+ if (DevPathStringIsDynamic) {
+ FreePool (DevPathString);
+ }
+ return Status;
+}
+
+
+/**
+ Unregister HandleStatusCode() at ExitBootServices().
+
+ (See EFI_RSC_HANDLER_PROTOCOL in Volume 3 of the Platform Init spec.)
+
+ @param[in] Event Event whose notification function is being invoked.
+
+ @param[in] Context Pointer to EFI_RSC_HANDLER_PROTOCOL, originally looked up
+ when HandleStatusCode() was registered.
+**/
+STATIC
+VOID
+EFIAPI
+UnregisterAtExitBootServices (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_RSC_HANDLER_PROTOCOL *StatusCodeRouter;
+
+ StatusCodeRouter = Context;
+ StatusCodeRouter->Unregister (HandleStatusCode);
+}
+
+
+/**
+ Register a status code handler for printing EDKII_OS_LOADER_DETAIL reports to
+ the console.
+
+ @retval EFI_SUCCESS The status code handler has been successfully
+ registered.
+
+ @return Error codes propagated from boot services and from
+ EFI_RSC_HANDLER_PROTOCOL.
+**/
+EFI_STATUS
+RegisterStatusCodeHandler (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_RSC_HANDLER_PROTOCOL *StatusCodeRouter;
+ EFI_EVENT ExitBootEvent;
+
+ Status = gBS->LocateProtocol (&gEfiRscHandlerProtocolGuid,
+ NULL /* Registration */, (VOID **)&StatusCodeRouter);
+ //
+ // This protocol is provided by the ReportStatusCodeRouterRuntimeDxe driver
+ // that we build into the firmware image. Given that PlatformBootManagerLib
+ // is used as part of BdsDxe, and BDS Entry occurs after all DXE drivers have
+ // been dispatched, the EFI_RSC_HANDLER_PROTOCOL is available at this point.
+ //
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Register the handler callback.
+ //
+ Status = StatusCodeRouter->Register (HandleStatusCode, TPL_CALLBACK);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: failed to register status code handler: %r\n",
+ __FUNCTION__, Status));
+ return Status;
+ }
+
+ //
+ // Status code reporting and routing/handling extend into OS runtime. Since
+ // we don't want our handler to survive the BDS phase, we have to unregister
+ // the callback at ExitBootServices(). (See EFI_RSC_HANDLER_PROTOCOL in
+ // Volume 3 of the Platform Init spec.)
+ //
+ Status = gBS->CreateEvent (
+ EVT_SIGNAL_EXIT_BOOT_SERVICES, // Type
+ TPL_CALLBACK, // NotifyTpl
+ UnregisterAtExitBootServices, // NotifyFunction
+ StatusCodeRouter, // NotifyContext
+ &ExitBootEvent // Event
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // We have to unregister the callback right now, and fail the function.
+ //
+ DEBUG ((DEBUG_ERROR, "%a: failed to create ExitBootServices() event: %r\n",
+ __FUNCTION__, Status));
+ StatusCodeRouter->Unregister (HandleStatusCode);
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
--
2.14.1.3.gb7cf6e02401b
next prev parent reply other threads:[~2017-11-22 23:54 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-11-22 23:58 [PATCH 0/5] MdeModulePkg, OvmfPkg: more easily visible boot progress reporting Laszlo Ersek
2017-11-22 23:58 ` [PATCH 1/5] MdeModulePkg/BdsDxe: fall back to a Boot Manager Menu loop before hanging Laszlo Ersek
2017-11-23 3:43 ` Ni, Ruiyu
2017-11-23 13:09 ` Laszlo Ersek
2017-11-27 16:27 ` Laszlo Ersek
2017-11-22 23:58 ` [PATCH 2/5] MdeModulePkg: introduce the EDKII_OS_LOADER_DETAIL status code payload Laszlo Ersek
2017-11-22 23:58 ` [PATCH 3/5] MdeModulePkg/UefiBootManagerLib: report EDKII_OS_LOADER_DETAIL status code Laszlo Ersek
2017-11-23 5:21 ` Ni, Ruiyu
2017-11-23 14:03 ` Laszlo Ersek
2017-11-23 14:53 ` Ni, Ruiyu
2017-11-23 17:08 ` Laszlo Ersek
2017-11-23 23:00 ` Ni, Ruiyu
2017-11-22 23:58 ` Laszlo Ersek [this message]
2017-11-22 23:58 ` [PATCH 5/5] OvmfPkg: disable EFI_DEBUG_CODE reporting in RELEASE builds Laszlo Ersek
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20171122235849.4177-5-lersek@redhat.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox