mirror of
https://github.com/ipxe/ipxe
synced 2026-02-28 03:11:18 +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>
|
#include <ipxe/efi/efi.h>
|
||||||
|
|
||||||
extern void efi_wrap_bs ( EFI_BOOT_SERVICES *wrapped );
|
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_wrap_systab ( int global );
|
||||||
extern void efi_unwrap ( void );
|
extern void efi_unwrap ( void );
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||||||
/** Colour for debug messages */
|
/** Colour for debug messages */
|
||||||
#define colour &efi_systab
|
#define colour &efi_systab
|
||||||
|
|
||||||
|
/** Maximum size for hex dumps */
|
||||||
|
#define EFI_WRAP_DUMP_MAX 128
|
||||||
|
|
||||||
/** Number of lines to prescroll when needed */
|
/** Number of lines to prescroll when needed */
|
||||||
#define EFI_WRAP_PRESCROLL 16
|
#define EFI_WRAP_PRESCROLL 16
|
||||||
|
|
||||||
@@ -55,6 +58,12 @@ static EFI_BOOT_SERVICES *efi_bs_orig;
|
|||||||
/** Backup of original EFI boot services table */
|
/** Backup of original EFI boot services table */
|
||||||
static EFI_BOOT_SERVICES efi_bs_copy;
|
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
|
* 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
|
* Pre-scroll display to create space for output lines
|
||||||
*
|
*
|
||||||
@@ -837,11 +883,11 @@ efi_stall_wrapper ( UINTN microseconds ) {
|
|||||||
void *retaddr = __builtin_return_address ( 0 );
|
void *retaddr = __builtin_return_address ( 0 );
|
||||||
EFI_STATUS efirc;
|
EFI_STATUS efirc;
|
||||||
|
|
||||||
DBGC2 ( colour, "Stall ( %ld.%06lds ) ",
|
DBGCP ( colour, "Stall ( %ld.%06lds ) ",
|
||||||
( ( unsigned long ) ( microseconds / 1000000 ) ),
|
( ( unsigned long ) ( microseconds / 1000000 ) ),
|
||||||
( ( unsigned long ) ( microseconds % 1000000 ) ) );
|
( ( unsigned long ) ( microseconds % 1000000 ) ) );
|
||||||
efirc = bs->Stall ( microseconds );
|
efirc = bs->Stall ( microseconds );
|
||||||
DBGC2 ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr );
|
DBGCP ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr );
|
||||||
return efirc;
|
return efirc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1195,6 +1241,169 @@ efi_create_event_ex_wrapper ( UINT32 type, EFI_TPL notify_tpl,
|
|||||||
return efirc;
|
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
|
* Wrap a boot services table
|
||||||
*
|
*
|
||||||
@@ -1258,14 +1467,40 @@ void efi_wrap_bs ( EFI_BOOT_SERVICES *wrapper ) {
|
|||||||
wrapper->CreateEventEx = efi_create_event_ex_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
|
* Wrap the public EFI system table
|
||||||
*
|
*
|
||||||
* @v global Patch global boot services table in-place
|
* @v global Patch global boot services table in-place
|
||||||
*/
|
*/
|
||||||
void efi_wrap_systab ( int global ) {
|
void efi_wrap_systab ( int global ) {
|
||||||
static EFI_BOOT_SERVICES local;
|
static EFI_BOOT_SERVICES local_bs;
|
||||||
EFI_BOOT_SERVICES *wrapper;
|
static EFI_RUNTIME_SERVICES local_rs;
|
||||||
|
EFI_BOOT_SERVICES *bs;
|
||||||
|
EFI_RUNTIME_SERVICES *rs;
|
||||||
|
|
||||||
/* Do nothing unless debugging is enabled */
|
/* Do nothing unless debugging is enabled */
|
||||||
if ( ! DBG_LOG )
|
if ( ! DBG_LOG )
|
||||||
@@ -1275,7 +1510,9 @@ void efi_wrap_systab ( int global ) {
|
|||||||
if ( ! efi_systab_pub ) {
|
if ( ! efi_systab_pub ) {
|
||||||
efi_systab_pub = efi_systab;
|
efi_systab_pub = efi_systab;
|
||||||
efi_bs_orig = efi_systab_pub->BootServices;
|
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_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 */
|
/* Construct and use private system table */
|
||||||
@@ -1283,13 +1520,17 @@ void efi_wrap_systab ( int global ) {
|
|||||||
memcpy ( &efi_systab_priv, efi_systab_pub,
|
memcpy ( &efi_systab_priv, efi_systab_pub,
|
||||||
sizeof ( efi_systab_priv ) );
|
sizeof ( efi_systab_priv ) );
|
||||||
efi_systab_priv.BootServices = &efi_bs_copy;
|
efi_systab_priv.BootServices = &efi_bs_copy;
|
||||||
|
efi_systab_priv.RuntimeServices = &efi_rs_copy;
|
||||||
efi_systab = &efi_systab_priv;
|
efi_systab = &efi_systab_priv;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wrap global or local boot services table as applicable */
|
/* Wrap global or local boot services table as applicable */
|
||||||
wrapper = ( global ? efi_bs_orig : &local );
|
bs = ( global ? efi_bs_orig : &local_bs );
|
||||||
efi_wrap_bs ( wrapper );
|
rs = ( global ? efi_rs_orig : &local_rs );
|
||||||
efi_systab_pub->BootServices = wrapper;
|
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",
|
DBGC ( colour, "WRAP installed %s wrappers\n",
|
||||||
( global ? "global" : "local" ) );
|
( global ? "global" : "local" ) );
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user