diff --git a/src/include/ipxe/efi/efi.h b/src/include/ipxe/efi/efi.h index 9554a6ad7..a73ef0959 100644 --- a/src/include/ipxe/efi/efi.h +++ b/src/include/ipxe/efi/efi.h @@ -84,6 +84,12 @@ struct efi_saved_tpl { EFI_TPL previous; }; +/** An EFI dropped task priority level */ +struct efi_dropped_tpl { + /** Current TPL */ + EFI_TPL current; +}; + /** An EFI protocol used by iPXE */ struct efi_protocol { /** GUID */ @@ -408,6 +414,8 @@ extern EFI_STATUS efi_init ( EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab ); extern void efi_raise_tpl ( struct efi_saved_tpl *tpl ); extern void efi_restore_tpl ( struct efi_saved_tpl *tpl ); +extern void efi_drop_tpl ( struct efi_dropped_tpl *tpl ); +extern void efi_undrop_tpl ( struct efi_dropped_tpl *tpl ); extern int efi_open_untyped ( EFI_HANDLE handle, EFI_GUID *protocol, void **interface ); extern int efi_open_unsafe_untyped ( EFI_HANDLE handle, EFI_GUID *protocol, diff --git a/src/interface/efi/efi_connect.c b/src/interface/efi/efi_connect.c index f4747cf6b..a4de78b78 100644 --- a/src/interface/efi/efi_connect.c +++ b/src/interface/efi/efi_connect.c @@ -59,6 +59,7 @@ int efi_connect ( EFI_HANDLE device, EFI_HANDLE driver ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_HANDLE driverlist[2] = { driver, NULL }; EFI_HANDLE *drivers = ( driver ? driverlist : NULL ); + struct efi_dropped_tpl tpl; EFI_STATUS efirc; int rc; @@ -67,9 +68,9 @@ int efi_connect ( EFI_HANDLE device, EFI_HANDLE driver ) { DBGC ( device, "%s driver at %s TPL\n", ( driver ? efi_handle_name ( driver ) : "any" ), efi_tpl_name ( efi_external_tpl ) ); - bs->RestoreTPL ( efi_external_tpl ); + efi_drop_tpl ( &tpl ); efirc = bs->ConnectController ( device, drivers, NULL, TRUE ); - bs->RaiseTPL ( efi_internal_tpl ); + efi_undrop_tpl ( &tpl ); if ( efirc != 0 ) { rc = -EEFI_CONNECT ( efirc ); DBGC ( device, "EFI %s could not connect: %s\n", @@ -89,6 +90,7 @@ int efi_connect ( EFI_HANDLE device, EFI_HANDLE driver ) { */ int efi_disconnect ( EFI_HANDLE device, EFI_HANDLE driver ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + struct efi_dropped_tpl tpl; EFI_STATUS efirc; int rc; @@ -97,9 +99,9 @@ int efi_disconnect ( EFI_HANDLE device, EFI_HANDLE driver ) { DBGC ( device, "%s driver at %s TPL\n", ( driver ? efi_handle_name ( driver ) : "any" ), efi_tpl_name ( efi_external_tpl ) ); - bs->RestoreTPL ( efi_external_tpl ); + efi_drop_tpl ( &tpl ); efirc = bs->DisconnectController ( device, driver, NULL ); - bs->RaiseTPL ( efi_internal_tpl ); + efi_undrop_tpl ( &tpl ); if ( ( efirc != 0 ) && ( efirc != EFI_NOT_FOUND ) ) { rc = -EEFI ( efirc ); DBGC ( device, "EFI %s could not disconnect: %s\n", diff --git a/src/interface/efi/efi_entropy.c b/src/interface/efi/efi_entropy.c index b6bd12ccc..abd1018f3 100644 --- a/src/interface/efi/efi_entropy.c +++ b/src/interface/efi/efi_entropy.c @@ -50,6 +50,9 @@ struct entropy_source efitick_entropy __entropy_source ( ENTROPY_FALLBACK ); /** Event used to wait for timer tick */ static EFI_EVENT tick; +/** Dropped TPL */ +static struct efi_dropped_tpl efi_entropy_tpl; + /** * Enable entropy gathering * @@ -61,7 +64,7 @@ static int efi_entropy_enable ( void ) { int rc; /* Drop to external TPL to allow timer tick event to take place */ - bs->RestoreTPL ( efi_external_tpl ); + efi_drop_tpl ( &efi_entropy_tpl ); /* Create timer tick event */ if ( ( efirc = bs->CreateEvent ( EVT_TIMER, TPL_NOTIFY, NULL, NULL, @@ -92,7 +95,7 @@ static void efi_entropy_disable ( void ) { bs->CloseEvent ( tick ); /* Return to internal TPL */ - bs->RaiseTPL ( efi_internal_tpl ); + efi_undrop_tpl ( &efi_entropy_tpl ); } /** diff --git a/src/interface/efi/efi_init.c b/src/interface/efi/efi_init.c index ac62ea747..9fd2d0c6b 100644 --- a/src/interface/efi/efi_init.c +++ b/src/interface/efi/efi_init.c @@ -392,7 +392,7 @@ void efi_raise_tpl ( struct efi_saved_tpl *tpl ) { } /** - * Restore task priority level + * Restore saved task priority level * * @v tpl Saved TPL */ @@ -405,3 +405,31 @@ void efi_restore_tpl ( struct efi_saved_tpl *tpl ) { /* Restore TPL */ bs->RestoreTPL ( tpl->current ); } + +/** + * Drop task priority level temporarily to external level + * + * @v tpl Dropped TPL + */ +void efi_drop_tpl ( struct efi_dropped_tpl *tpl ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + + /* Raise TPL temporarily to discover current TPL */ + tpl->current = bs->RaiseTPL ( TPL_HIGH_LEVEL ); + bs->RestoreTPL ( tpl->current ); + + /* Drop to external TPL */ + bs->RestoreTPL ( efi_external_tpl ); +} + +/** + * Restore dropped task priority level + * + * @v tpl Dropped TPL + */ +void efi_undrop_tpl ( struct efi_dropped_tpl *tpl ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + + /* Raise back to original TPL */ + bs->RaiseTPL ( tpl->current ); +} diff --git a/src/interface/efi/efi_timer.c b/src/interface/efi/efi_timer.c index ffb899c86..66817f8f7 100644 --- a/src/interface/efi/efi_timer.c +++ b/src/interface/efi/efi_timer.c @@ -77,7 +77,7 @@ static void efi_udelay ( unsigned long usecs ) { * @ret ticks Current time, in ticks */ static unsigned long efi_currticks ( void ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + struct efi_dropped_tpl tpl; /* UEFI manages to ingeniously combine the worst aspects of * both polling and interrupt-driven designs. There is no way @@ -137,8 +137,8 @@ static unsigned long efi_currticks ( void ) { if ( efi_shutdown_in_progress ) { efi_jiffies++; } else { - bs->RestoreTPL ( efi_external_tpl ); - bs->RaiseTPL ( efi_internal_tpl ); + efi_drop_tpl ( &tpl ); + efi_undrop_tpl ( &tpl ); } return ( efi_jiffies * ( TICKS_PER_SEC / EFI_JIFFIES_PER_SEC ) );