13.1 Driver Diagnostics Protocol Implementations

The implementation of the Driver Diagnostics Protocols for a specific driver is typically found in the file DriverDiagnostics.c. Appendix A contains a template for

DriverDiagnostics.c, a file for a UEFI Driver. This file typically contains the following: - Add global variable for the EFI_DRIVER_DIAGNOSTICS_PROTOCOL instance to DriverDiagnostics.c. - Add global variable for the EFI_DRIVER_DIAGNOSTICS2_PROTOCOL instance to DriverDiagnostics.c.

  • Add Static table of diagnostics result messages as Unicode strings to DriverDiagnostics.c.
  • Implementation of the RunDiagnostics() service
  • Install all the Driver Diagnostics Protocols in the driver entry point.
  • If the UEFI Driver supports the unload feature, uninstall all the Driver Diagnostics Protocols in the Unload() function.

The Driver Diagnostics Protocols provide diagnostics result messages in one or more languages. At a minimum, the protocols should support the English language. The Driver Diagnostic Protocol advertises the languages it supports in a data field called SupportedLanguages. This data field is a null-terminated ASCII string that contains one or more 3 character ISO 639-2 language codes with no separator character. The Driver Diagnostic 2 Protocol also advertises the languages it supports in a data field called SupportedLanguages. This data filed is a null-terminated ASCII string that contains one or more RFC 4646 language codes separated by semicolons (';').

A consumer of the Driver Diagnostics Protocols may parse the SupportedLanguages data field to determine if the protocol supports a language in which the consumer is interested. This data field can also be used by the implementation of the Driver Diagnostics Protocols to see if diagnostics result messages are available in the requested language.

Example 144, below, shows the protocol interface structure for the Driver Diagnostic Protocol and the following Example 145 shows the protocol interface structure for the Driver Diagnostics 2 Protocol for reference. Both are composed of one service called RunDiagnostics() and a data field called SupportedLanguages.

Example 144-Driver Diagnostics Protocol
typedef struct _EFI_DRIVER_DIAGNOSTICS_PROTOCOL EFI_DRIVER_DIAGNOSTICS_PROTOCOL;

///
/// Used to perform diagnostics on a controller that an EFI Driver is managing.
///
struct _EFI_DRIVER_DIAGNOSTICS_PROTOCOL {
  EFI_DRIVER_DIAGNOSTICS_RUN_DIAGNOSTICS RunDiagnostics;
  ///
  /// A Null-terminated ASCII string that contains one or more ISO 639-2
  /// language codes. This is the list of language codes that this protocol
  /// supports.
  ///
  CHAR8 *SupportedLanguages;
};
Example 145-Driver Diagnostics 2 Protocol
typedef struct _EFI_DRIVER_DIAGNOSTICS2_PROTOCOL EFI_DRIVER_DIAGNOSTICS2_PROTOCOL;

///
/// Used to perform diagnostics on a controller that an EFI Driver is managing.
///
struct _EFI_DRIVER_DIAGNOSTICS2_PROTOCOL {
  EFI_DRIVER_DIAGNOSTICS2_RUN_DIAGNOSTICS RunDiagnostics;
  ///
  /// A Null-terminated ASCII string that contains one or more RFC 4646
  /// language codes. This is the list of language codes that this protocol
  /// supports.
  ///
  CHAR8 *SupportedLanguages;
};

UEFI Drivers declare global variables for the Driver Diagnostics Protocol and Driver Diagnostics 2 Protocol instances produced. The SupportedLanguages fields are typically initialized by the UEFI Driver in the declaration for the specific set of language the UEFI Driver supports. The example below shows how the Driver Diagnostics Protocols are typically declared in a driver, and in this case declared to support both English and French.

Example 146-Driver Diagnostics Protocol declaration
#include <Uefi.h>
#include <Protocol/DriverDiagnostics.h>
#include <Protocol/DriverDiagnostics2.h>

GLOBAL_REMOVE_IF_UNREFERENCED
EFI_DRIVER_DIAGNOSTICS_PROTOCOL gAbcDriverDiagnostics = {
  (EFI_DRIVER_DIAGNOSTICS_RUN_DIAGNOSTICS) AbcRunDiagnostics,
  "engfra"
};

GLOBAL_REMOVE_IF_UNREFERENCED
EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gAbcDriverDiagnostics2 = {
  AbcRunDiagnostics,
  "en;fr"
};

The implementations of the Driver Diagnostics Protocol change in complexity depending on the type of UEFI Driver Model driver. A device driver is the simplest to implement. A bus driver or a hybrid driver may be more complex because it may provide diagnostics for both the bus controller and the child controllers. These implementations are discussed later in this chapter.

The EFI_DRIVER_DIAGNOSTICS_PROTOCOL and EFI_DRIVER_DIAGNOSTICS2_PROTOCOL are installed onto the driver's image handle. It is possible for a driver to produce more than one instance of the Driver Diagnostics Protocols. All additional instances of the Driver Diagnostics Protocols must be installed onto new handles.

The Driver Diagnostics Protocols can either be installed directly using the UEFI Boot Service InstallMultipleProtocolInterfaces(). However, the EDK II library UefiLib provides a number of helper functions to install the Driver Diagnostics Protocols. The helper functions that are covered in more detail in Chapter 7 are:

  • EfiLibInstallAllDriverProtocols()
  • EfiLibInstallAllDriverProtocols2()

If an error is generated installing any of the Driver Diagnostics Protocol instances, then the entire driver should fail and return a error status such as EFI_ABORTED. If a UEFI Driver implements the Unload() feature, any Driver Diagnostics Protocol instances installed in the driver entry point must be uninstalled in the Unload() function.

The implementation of the Driver Diagnostics Protocols for a specific driver is typically found in the file DriverDiagnostics.c. This file contains the instances of the EFI_DRIVER_DIAGNOSTICS_PROTOCOL and EFI_DRIVER_DIAGNOSTICS2_PROTOCOL along with the implementation of RunDiagnostics(). Appendix A contains a template for a DriverDiagnostics.c file for a UEFI Driver.