[efi] Wrap a selection of runtime services calls

Allow DEBUG=efi_wrap to trace various runtime services calls as well
as the existing boot services calls.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2025-11-13 14:38:12 +00:00
parent 925af2b4d7
commit 3383474653
2 changed files with 249 additions and 7 deletions

View File

@@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/efi.h>
extern void efi_wrap_bs ( EFI_BOOT_SERVICES *wrapped );
extern void efi_wrap_rs ( EFI_RUNTIME_SERVICES *wrapped );
extern void efi_wrap_systab ( int global );
extern void efi_unwrap ( void );

View File

@@ -40,6 +40,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Colour for debug messages */
#define colour &efi_systab
/** Maximum size for hex dumps */
#define EFI_WRAP_DUMP_MAX 128
/** Number of lines to prescroll when needed */
#define EFI_WRAP_PRESCROLL 16
@@ -55,6 +58,12 @@ static EFI_BOOT_SERVICES *efi_bs_orig;
/** Backup of original EFI boot services table */
static EFI_BOOT_SERVICES efi_bs_copy;
/** Original EFI runtime services table pointer */
static EFI_RUNTIME_SERVICES *efi_rs_orig;
/** Backup of original EFI runtime services table */
static EFI_RUNTIME_SERVICES efi_rs_copy;
/**
* Convert EFI status code to text
*
@@ -189,6 +198,43 @@ static const char * efi_timer_delay ( EFI_TIMER_DELAY type ) {
}
}
/**
* Convert EFI time to text
*
* @v time Time, or NULL
* @ret text Time as text
*/
static const char * efi_time ( EFI_TIME *time ) {
static char buf[ 20 /* "xxxx-xx-xx xx:xx:xx" + NUL */ ];
if ( ! time )
return "<NULL>";
snprintf ( buf, sizeof ( buf ), "%04d-%02d-%02d %02d:%02d:%02d",
time->Year, time->Month, time->Day, time->Hour,
time->Minute, time->Second );
return buf;
}
/**
* Convert EFI reset type to text
*
* @v type Reset type
* @ret text Reset type as text
*/
static const char * efi_reset_type ( EFI_RESET_TYPE type ) {
static char buf[ 11 /* "0xXXXXXXXX" + NUL */ ];
switch ( type ) {
case EfiResetCold: return "Cold";
case EfiResetWarm: return "Warm";
case EfiResetShutdown: return "Shutdown";
case EfiResetPlatformSpecific: return "PlatformSpecific";
default:
snprintf ( buf, sizeof ( buf ), "%#x", type );
return buf;
}
}
/**
* Pre-scroll display to create space for output lines
*
@@ -837,11 +883,11 @@ efi_stall_wrapper ( UINTN microseconds ) {
void *retaddr = __builtin_return_address ( 0 );
EFI_STATUS efirc;
DBGC2 ( colour, "Stall ( %ld.%06lds ) ",
DBGCP ( colour, "Stall ( %ld.%06lds ) ",
( ( unsigned long ) ( microseconds / 1000000 ) ),
( ( unsigned long ) ( microseconds % 1000000 ) ) );
efirc = bs->Stall ( microseconds );
DBGC2 ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr );
DBGCP ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr );
return efirc;
}
@@ -1195,6 +1241,169 @@ efi_create_event_ex_wrapper ( UINT32 type, EFI_TPL notify_tpl,
return efirc;
}
/**
* Wrap GetTime()
*
*/
static EFI_STATUS EFIAPI
efi_get_time_wrapper ( EFI_TIME *time, EFI_TIME_CAPABILITIES *cap ) {
EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
void *retaddr = __builtin_return_address ( 0 );
EFI_STATUS efirc;
DBGCP ( colour, "GetTime() " );
efirc = rs->GetTime ( time, cap );
DBGCP ( colour, "= %s ( %s ) -> %p\n",
efi_status ( efirc ), efi_time ( time ), retaddr );
return efirc;
}
/**
* Wrap SetTime()
*
*/
static EFI_STATUS EFIAPI
efi_set_time_wrapper ( EFI_TIME *time ) {
EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
void *retaddr = __builtin_return_address ( 0 );
EFI_STATUS efirc;
DBGC ( colour, "SetTime ( %s ) ", efi_time ( time ) );
efirc = rs->SetTime ( time );
DBGC ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr );
return efirc;
}
/**
* Wrap GetWakeupTime()
*
*/
static EFI_STATUS EFIAPI
efi_get_wakeup_time_wrapper ( BOOLEAN *enabled, BOOLEAN *pending,
EFI_TIME *time ) {
EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
void *retaddr = __builtin_return_address ( 0 );
EFI_STATUS efirc;
DBGC ( colour, "GetWakeupTime() " );
efirc = rs->GetWakeupTime ( enabled, pending, time );
DBGC ( colour, "= %s ( %s, %s, %s ) -> %p\n", efi_status ( efirc ),
efi_boolean ( *enabled ), efi_boolean ( *pending ),
efi_time ( time ), retaddr );
return efirc;
}
/**
* Wrap SetWakeupTime()
*
*/
static EFI_STATUS EFIAPI
efi_set_wakeup_time_wrapper ( BOOLEAN enable, EFI_TIME *time ) {
EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
void *retaddr = __builtin_return_address ( 0 );
EFI_STATUS efirc;
DBGC ( colour, "SetWakeupTime ( %s, %s ) ",
efi_boolean ( enable ), efi_time ( time ) );
efirc = rs->SetWakeupTime ( enable, time );
DBGC ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr );
return efirc;
}
/**
* Wrap GetVariable()
*
*/
static EFI_STATUS EFIAPI
efi_get_variable_wrapper ( CHAR16 *name, EFI_GUID *guid, UINT32 *attrs,
UINTN *len, VOID *data ) {
EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
void *retaddr = __builtin_return_address ( 0 );
size_t dumplen;
EFI_STATUS efirc;
DBGC ( colour, "GetVariable ( %s:%ls, %#llx ) ",
efi_guid_ntoa ( guid ), name, ( ( unsigned long long ) *len ) );
efirc = rs->GetVariable ( name, guid, attrs, len, data );
DBGC ( colour, "= %s ( %#llx",
efi_status ( efirc ), ( ( unsigned long long ) *len ) );
if ( DBG_EXTRA && ( efirc == 0 ) ) {
dumplen = *len;
if ( dumplen > EFI_WRAP_DUMP_MAX )
dumplen = EFI_WRAP_DUMP_MAX;
DBGC2 ( colour, ",\n" );
DBGC2_HD ( colour, data, dumplen );
if ( dumplen != *len )
DBGC2 ( colour, "... " );
} else {
DBGC ( colour, " " );
}
DBGC ( colour, ") -> %p\n", retaddr );
return efirc;
}
/**
* Wrap GetNextVariableName()
*
*/
static EFI_STATUS EFIAPI
efi_get_next_variable_name_wrapper ( UINTN *len, CHAR16 *name,
EFI_GUID *guid ) {
EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
void *retaddr = __builtin_return_address ( 0 );
EFI_STATUS efirc;
DBGC ( colour, "GetNextVariableName ( %#llx, %s:%ls ) ",
( ( unsigned long long ) *len ), efi_guid_ntoa ( guid ), name );
efirc = rs->GetNextVariableName ( len, name, guid );
DBGC ( colour, "= %s ( %#llx, %s:%ls ) -> %p\n", efi_status ( efirc ),
( ( unsigned long long ) *len ), efi_guid_ntoa ( guid ), name,
retaddr );
return efirc;
}
/**
* Wrap SetVariable()
*
*/
static EFI_STATUS EFIAPI
efi_set_variable_wrapper ( CHAR16 *name, EFI_GUID *guid, UINT32 attrs,
UINTN len, VOID *data ) {
EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
void *retaddr = __builtin_return_address ( 0 );
EFI_STATUS efirc;
DBGC ( colour, "SetVariable ( %s:%ls, %#02x",
efi_guid_ntoa ( guid ), name, attrs );
if ( len ) {
DBGC ( colour, ",\n" );
DBGC_HD ( colour, data, len );
DBGC ( colour, ") " );
} else {
DBGC ( colour, ", %#llx, %p ) ",
( ( unsigned long long ) len ), data );
}
efirc = rs->SetVariable ( name, guid, attrs, len, data );
DBGC ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr );
return efirc;
}
/**
* Wrap ResetSystem()
*
*/
static VOID EFIAPI
efi_reset_system_wrapper ( EFI_RESET_TYPE type, EFI_STATUS status,
UINTN len, VOID *data ) {
EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
void *retaddr = __builtin_return_address ( 0 );
DBGC ( colour, "ResetSystem ( %s, %s, %#llx, %p ) -> %p\n",
efi_reset_type ( type ), efi_status ( status ),
( ( unsigned long long ) len ), data, retaddr );
rs->ResetSystem ( type, status, len, data );
}
/**
* Wrap a boot services table
*
@@ -1258,14 +1467,40 @@ void efi_wrap_bs ( EFI_BOOT_SERVICES *wrapper ) {
wrapper->CreateEventEx = efi_create_event_ex_wrapper;
}
/**
* Wrap a runtime services table
*
* @v wrapper Runtime services table to wrap
*/
void efi_wrap_rs ( EFI_RUNTIME_SERVICES *wrapper ) {
EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
/* Do nothing unless debugging is enabled */
if ( ! DBG_LOG )
return;
/* Build boot services table wrapper */
memcpy ( wrapper, rs, sizeof ( *wrapper ) );
wrapper->GetTime = efi_get_time_wrapper;
wrapper->SetTime = efi_set_time_wrapper;
wrapper->GetWakeupTime = efi_get_wakeup_time_wrapper;
wrapper->SetWakeupTime = efi_set_wakeup_time_wrapper;
wrapper->GetVariable = efi_get_variable_wrapper;
wrapper->GetNextVariableName = efi_get_next_variable_name_wrapper;
wrapper->SetVariable = efi_set_variable_wrapper;
wrapper->ResetSystem = efi_reset_system_wrapper;
}
/**
* Wrap the public EFI system table
*
* @v global Patch global boot services table in-place
*/
void efi_wrap_systab ( int global ) {
static EFI_BOOT_SERVICES local;
EFI_BOOT_SERVICES *wrapper;
static EFI_BOOT_SERVICES local_bs;
static EFI_RUNTIME_SERVICES local_rs;
EFI_BOOT_SERVICES *bs;
EFI_RUNTIME_SERVICES *rs;
/* Do nothing unless debugging is enabled */
if ( ! DBG_LOG )
@@ -1275,7 +1510,9 @@ void efi_wrap_systab ( int global ) {
if ( ! efi_systab_pub ) {
efi_systab_pub = efi_systab;
efi_bs_orig = efi_systab_pub->BootServices;
efi_rs_orig = efi_systab_pub->RuntimeServices;
memcpy ( &efi_bs_copy, efi_bs_orig, sizeof ( efi_bs_copy ) );
memcpy ( &efi_rs_copy, efi_rs_orig, sizeof ( efi_rs_copy ) );
}
/* Construct and use private system table */
@@ -1283,13 +1520,17 @@ void efi_wrap_systab ( int global ) {
memcpy ( &efi_systab_priv, efi_systab_pub,
sizeof ( efi_systab_priv ) );
efi_systab_priv.BootServices = &efi_bs_copy;
efi_systab_priv.RuntimeServices = &efi_rs_copy;
efi_systab = &efi_systab_priv;
}
/* Wrap global or local boot services table as applicable */
wrapper = ( global ? efi_bs_orig : &local );
efi_wrap_bs ( wrapper );
efi_systab_pub->BootServices = wrapper;
bs = ( global ? efi_bs_orig : &local_bs );
rs = ( global ? efi_rs_orig : &local_rs );
efi_wrap_bs ( bs );
efi_wrap_rs ( rs );
efi_systab_pub->BootServices = bs;
efi_systab_pub->RuntimeServices = rs;
DBGC ( colour, "WRAP installed %s wrappers\n",
( global ? "global" : "local" ) );
}