]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[efi] Wrap a selection of runtime services calls
authorMichael Brown <mcb30@ipxe.org>
Thu, 13 Nov 2025 14:38:12 +0000 (14:38 +0000)
committerMichael Brown <mcb30@ipxe.org>
Thu, 13 Nov 2025 15:02:03 +0000 (15:02 +0000)
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>
src/include/ipxe/efi/efi_wrap.h
src/interface/efi/efi_wrap.c

index d1e970bde481064fc09f51486faf8e39ddb995cf..1cae3d2db8f48741fff2f7b2eadccc77319160dc 100644 (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 );
 
index 936074f2a5769e7844ba12fa68a3a164e3f7c20c..320a32f0243aaa6de5c8529d8e54c196e43a08b6 100644 (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" ) );
 }