5.2.10 InstallConfigurationTable()

This service is used to add, update, or remove an entry in the list of configuration table entries maintained in the UEFI System Table. These entries are typically used to pass information from the UEFI pre-boot environment to the operating system environment.

The configuration table entries are composed of a GUID and a pointer to a buffer. The GUID defines the type of memory that the buffer must use. If an operating system requires a configuration table entry that is allocated from a memory type that is not preserved after ExitBootServices(), then the OS Loader or OS Kernel must make a copy of the data structure prior calling ExitBootServices().

A UEFI Driver has a limited set of options to pass information into the operating system environment. These include:

  • Protocols

  • UEFI Variables

  • Configuration Table Entries

The services required to locate protocols in the Handle Database are not available after ExitBootServices(), so information passed up through protocols must be located by the OS Loader or OS Kernel prior to calling ExitBootServices(). UEFI Variables are good for small amounts of data, but may consume the scarce variable resources and access to variable storage may be slower than system memory. A configuration table entry is good for larger amounts of data generated each boot and it is stored in system memory. The UEFI Specification defines a set of GUIDs for standard configuration table entries that includes:

  • ACPI Tables

  • SMBIOS Tables

  • SAL System Table (IPF only)

  • MPS Tables

  • Debug Image Info Tables

  • Image Execution Information Table

  • Exported HII Database

  • User Information Table

  • Capsules

  • UNDI Configuration Table

Most of these usages are handled by the UEFI system firmware. The one usage impacting UEFI Drivers is the UNDI Configuration Table that is produced by a UEFI UNDI Driver for a Network Interface Controller (NIC). UEFI Drivers are allowed to define new GUIDs for new configuration table entries to pass information from the UEFI pre-boot environment to the OS environment.

The following code fragment shows how an UNDI driver can add or update an UNDI Configuration Table entry to the list of configuration table entries maintained in the UEFI System Table.

Example 79-Add or update a configuration table entry
#include <Uefi.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/MemoryAllocationLib.h>

EFI_STATUS Status;
UNDI_CONFIG_TABLE *UndiConfigTable;

//
// Allocate and zero UNDI_CONFIG_TABLE from EfiRuntimeServicesData
//
UndiConfigTable = (UNDI_CONFIG_TABLE *)AllocateRuntimeZeroPool (
                sizeof (UNDI_CONFIG_TABLE)
                );

//
// Initialize UNDI_CONFIG_TABLE
//

//
// Add or update a configuration table
//
Status = gBS->InstallConfigurationTable (
                &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
                &UndiConfigTable
                );
if (EFI_ERROR (Status)) {
  return Status;
}

The code fragment below shows how an UNDI driver can remove an UNDI

Configuration Table entry from the list of configuration table entries maintained in the UEFI System Table.

Example 80-Add or update a configuration table entry
#include <Uefi.h>
#include <Library/UefiBootServicesTableLib.h>

EFI_STATUS Status;

//
// Remove a configuration table
//
Status = gBS->InstallConfigurationTable (
                &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
                NULL
                );
if (EFI_ERROR (Status)) {
  return Status;
}

5.2.10.1 WaitForEvent()

This service stops execution until an event is signaled and is only allowed to be called at a priority level of TPL_APPLICATION. This means that WaitForEvent() may not be used from an event notification function because event notification functions always execute at priority levels above TPL_APPLICATION. If a UEFI Driver needs to know the current state of an event, the CheckEvent() service should be used instead of WaitForEvent(). WaitForEvent() may be used by UEFI Applications. The typical use case is to wait for input from a device such as a keyboard or mouse as part of a user interface. There are a few older protocols that UEFI Drivers may produce that interact with the user and the implementation of these protocols could use WaitForEvent(). For example, the SetOptions() function in the Driver Configuration Protocol.

The following code fragment shows how WaitForEvent() is used to wait for one of two events to be signaled. One event is signaled if a key is pressed on the console input device from the UEFI System Table. The other event is a one-shot timer that is signaled after waiting for 1 second. WaitForEvent() does not return until either a key is pressed or 1 second has passed. This can be used to wait for a key and also update the console with status information once a second. Status is set to EFI_SUCCESS is a key is pressed and EFI_TIMEOUT if no key is pressed.

Example 81-Wait for key press or timer event
#include <Uefi.h>
#include <Library/UefiBootServicesTableLib.h>

EFI_STATUS Status;
EFI_EVENT WaitList[2];
UINTN Index;

//
// Add ConIn event from the UEFI System Table to the array of events
//
WaitList[0] = &gST->ConIn->WaitForKey;

//
// Add timer event that fires in 1 second to the array of events
//
Status = gBS->CreateEvent (
                EVT_TIMER | EVT_NOTIFY_WAIT,  // Type
                TPL_NOTIFY,                   // NotifyTpl
                NULL,                         // NotifyFunction
                NULL,                         // NotifyContext
                &WaitList[1]                  // Event
                );
if (EFI_ERROR (Status)) {
  return Status;
}

Status = gBS->SetTimer (
                WaitList[1],
                TimerRelative,
                EFI_TIMER_PERIOD_SECONDS (1)
                );
if (EFI_ERROR (Status)) {
  gBS->CloseEvent (WaitList[1]);
  return Status;
}

//
// Wait for the console input or the timer to be signaled
//
Status = gBS->WaitForEvent (2, WaitList, &Index);

//
// Close the timer event
//
gBS->CloseEvent (WaitList[1]);

//
// If the timer event expired return EFI_TIMEOUT
//
if (!EFI_ERROR (Status) && Index == 1) {
  Status = EFI_TIMEOUT;
}