5.2.9 ConvertPointer()

UEFI Boot Service drivers must never use this service.

This service may be required by UEFI Runtime Drivers if the UEFI Runtime Driver is required to convert pointer values that use physical addresses to pointer values that use virtual addresses. A UEFI Runtime driver must only call ConvertPointer() from an event notification function for an event of type EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE or a GUIDed event of type EFI_EVENT_GROUP_VIRTUAL_ADDRESS_CHANGE.

Caution: Notification functions for events signaled when SetVirtualAddressMap() is called by an OS Loader or OS Kernel are not allowed to use any of the UEFI boot services, UEFI Console Services, or UEFI Protocol Services either directly or indirectly because those services are no longer available when SetVirtualAddressMap() is called. Instead, this type of notification function typically uses ConvertPointer() to convert pointers within data structures that are managed by the UEFI runtime driver from physical addresses to virtual addresses.

UEFI system firmware takes care of most of the physical to virtual address translations that a UEFI Runtime Driver requires. For example, all of the code and data sections in the UEFI Runtime Driver image are automatically fixed up for proper execution at the virtual address ranges provided by the operating system when the operating system calls the UEFI Runtime Service SetVirtualAddressMap().

If a UEFI Runtime Driver caches pointer values in global variables, or a UEFI Runtime Driver allocates buffers from EfiRuntimeServicesData, those pointer values must be converted from physical addresses to virtual address using the virtual address ranges provided by the operating system when the operating system calls the UEFI Runtime Service SetVirtualAddressMap(). If allocated buffers contain more pointers, then those pointer values must also be converted.

In these more complex scenarios, the order of the conversions is critical because the algorithm in the UEFI Runtime Driver must guarantee that no virtual addresses in the execution of the notification actually function because the event notification function on SetVirtualAddressMap() only executes in physical mode.

The following code fragment shows how a UEFI Runtime Driver can create an event whose notification function is executed in physical mode when the OS Loader or OS Kernel calls SetVirtualAddressMap(). There are two methods to create a SetVirtualAddressMap() event. This example shows the preferred method that uses CreateEventEx() to pass in the GUID of gEfiEventVirtualAddressChangeGuid. The alternate method uses CreateEvent() or CreateEventEx() with an event type of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE. The created event is declared as a global variable. and makes the event available if the UEFI Runtime Driver needs to close the event if UEFI Runtime Driver is unloaded. The code fragments that follow this example show how ConvertPointer() may be used from NotifySetVirtualAddressMap(), the event notification function from this example.

Example 74-Create a Set Virtual Address Map event

#include <Uefi.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Guid/EventGroup.h>
//
// Global variable for the SetVirtualAddressMap event
//
EFI_EVENT mSetVirtualAddressMapEvent = NULL;
EFI_STATUS Status;
//
// Create a Set Virtual Address Map event.
//
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL, // Type
TPL_NOTIFY, // NotifyTpl
NotifySetVirtualAddressMap, // NotifyFunction
NULL, // NotifyContext
&gEfiEventVirtualAddressChangeGuid, // EventGroup
&mSetVirtualAddressMapEvent // Event
);
if (EFI_ERROR (Status)) {
return Status;
}

The following code fragment shows how ConvertPointer() is used to convert a global variable functioning as a pointer from a physical address to that with a virtual address.

The flag EFI_OPTIONAL_PTR tells ConvertPointer() to not perform a conversion if the physical address of the pointer is NULL. This is useful if it is legal for some of the pointer values to be NULL and the NULL value needs to be preserved after the conversion. The only other legal value for this field is 0 The conversion should be performed unconditionally.

Example 75-Convert a global pointer from physical to virtual

#include <Uefi.h>
#include <Library/UefiRuntimeServicesTableLib.h>
VOID *gGlobalPointer;
VOID
EFIAPI
NotifySetVirtualAddressMap (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
Status = gRT->ConvertPointer (
EFI_OPTIONAL_PTR,
(VOID **)&gGlobalPointer
);
}

The code fragment in Example 76, below, is identical to 75, above, but uses the function EfiConvertPointer() from the EDK II library UefiRuntimeLib to call the UEFI Runtime Service ConvertPointer().

#include <Uefi.h>
#include <Library/UefiRuntimeLib.h>
VOID *gGlobalPointer;
VOID
EFIAPI
NotifySetVirtualAddressMap (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
Status = EfiConvertPointer (
EFI_OPTIONAL_PTR,
(VOID **)&gGlobalPointer
);
}

Example 76-Using UefiRuntimeLib to convert a pointer

The EDK II library UefiRuntimeLib also provides the function EfiConvertFunctionPointer() to convert a function pointer from a physical address to a virtual address. On supported CPU architectures where there is no distinction between a data pointer and a function pointer, EfiConvertPointer() and EfiConvertFunctionPointer() are identical. On other CPU architectures such as IPF, where function calls are made through a PLABEL, converting a function pointer is more complex. The EDK II library UefiRuntimeLib helps hide these CPU specific details so the UEFI Driver sources can be the same for all supported CPU architectures.

Since the UEFI system firmware automatically converts functions in code sections of a UEFI Runtime Driver image from physical addresses to virtual addresses, EfiConvertFunctionPointer() is required only if a UEFI Driver caches a function pointer in a global variable or an allocated buffer.

Example 77-Using UefiRuntimeLib to convert a function pointer

#include <Uefi.h>
#include <Library/UefiRuntimeLib.h>
typedef
VOID
(EFIAPI *EFI_EXAMPLE_FUNCTION)(
IN VOID *Context
);
EFI_EXAMPLE_FUNCTION gGlobalFunctionPointer;
VOID
EFIAPI
NotifySetVirtualAddressMap (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
Status = EfiConvertFunctionPointer (
EFI_OPTIONAL_PTR,
(VOID **)&gGlobalFunctionPointer
);
}

The EDK II library UefiRuntimeLib also provides helper function call EfiConvertList() to convert all the pointer values in a doubly linked list of type LIST_ENTRY. All the nodes in the linked list are traversed and the forward and backward link in each node is converted from a physical address to a virtual address.

Once this conversion is performed, the linked list cannot be accessed again in this function because all the pointer values are now virtual addresses. If the contents of the linked list contain structures with more pointer values that also need to be converted, those conversions must be performed prior to calling EfiConvertList().

Example 78-Using UefiRuntimeLib to convert a linked list

#include <Uefi.h>
#include <Library/UefiRuntimeLib.h>
LIST_ENTRY gGlobalList = INITIALIZE_LIST_HEAD_VARIABLE (gGlobalList);
VOID
EFIAPI
NotifySetVirtualAddressMap (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
Status = EfiConvertList (EFI_OPTIONAL_PTR, &gGlobalList);
}