From 33834746537d18e899559470970706d37ae2722b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 13 Nov 2025 14:38:12 +0000 Subject: [PATCH] [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 --- src/include/ipxe/efi/efi_wrap.h | 1 + src/interface/efi/efi_wrap.c | 255 +++++++++++++++++++++++++++++++- 2 files changed, 249 insertions(+), 7 deletions(-) diff --git a/src/include/ipxe/efi/efi_wrap.h b/src/include/ipxe/efi/efi_wrap.h index d1e970bde..1cae3d2db 100644 --- a/src/include/ipxe/efi/efi_wrap.h +++ b/src/include/ipxe/efi/efi_wrap.h @@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include 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 ); diff --git a/src/interface/efi/efi_wrap.c b/src/interface/efi/efi_wrap.c index 936074f2a..320a32f02 100644 --- a/src/interface/efi/efi_wrap.c +++ b/src/interface/efi/efi_wrap.c @@ -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 ""; + 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" ) ); }