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.#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.#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
);
}
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.#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()
.#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);
}
Last modified 2yr ago