mirror of
https://github.com/ipxe/ipxe
synced 2025-12-06 17:30:26 +03:00
[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:
@@ -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 );
|
||||
|
||||
|
||||
@@ -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" ) );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user