mirror of
https://github.com/ipxe/ipxe
synced 2025-12-30 13:11:11 +03:00
[efi] Avoid dropping below TPL as at entry to iPXE
iPXE will currently drop to TPL_APPLICATION whenever the current system time is obtained via currticks(), since the system time mechanism relies on a timer that can fire only when the TPL is below TPL_CALLBACK. This can cause unexpected behaviour if the system time is obtained in the middle of an API call into iPXE by external code. For example, MnpDxe sets up a 10ms periodic timer running at TPL_CALLBACK to poll the underling EFI_SIMPLE_NETWORK_PROTOCOL device for received packets. If the resulting poll within iPXE happens to hit a code path that requires obtaining the current system time (e.g. due to reception of an STP packet, which affects iPXE's blocked link timer), then iPXE will end up temporarily dropping to TPL_APPLICATION. This can potentially result in retriggering the MnpDxe periodic timer, causing code to be unexpectedly re-entered. Fix by recording the external TPL at any entry point into iPXE and dropping only as far as this external TPL, rather than dropping unconditionally to TPL_APPLICATION. The side effect of this change is that iPXE's view of the current system time will be frozen for the duration of any API calls made into iPXE by external code at TPL_CALLBACK or above. Since any such external code is already responsible for allowing execution at TPL_APPLICATION to occur, then this should not cause a problem in practice. Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -551,7 +551,6 @@ efi_usb_control_transfer ( EFI_USB_IO_PROTOCOL *usbio,
|
||||
EFI_USB_DATA_DIRECTION direction,
|
||||
UINT32 timeout, VOID *data, UINTN len,
|
||||
UINT32 *status ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
struct efi_usb_interface *usbintf =
|
||||
container_of ( usbio, struct efi_usb_interface, usbio );
|
||||
struct efi_usb_device *usbdev = usbintf->usbdev;
|
||||
@@ -559,7 +558,7 @@ efi_usb_control_transfer ( EFI_USB_IO_PROTOCOL *usbio,
|
||||
USB_REQUEST_TYPE ( packet->Request ) );
|
||||
unsigned int value = le16_to_cpu ( packet->Value );
|
||||
unsigned int index = le16_to_cpu ( packet->Index );
|
||||
EFI_TPL saved_tpl;
|
||||
struct efi_saved_tpl tpl;
|
||||
int rc;
|
||||
|
||||
DBGC2 ( usbdev, "USBDEV %s control %04x:%04x:%04x:%04x %s %dms "
|
||||
@@ -569,7 +568,7 @@ efi_usb_control_transfer ( EFI_USB_IO_PROTOCOL *usbio,
|
||||
( ( size_t ) len ) );
|
||||
|
||||
/* Raise TPL */
|
||||
saved_tpl = bs->RaiseTPL ( TPL_CALLBACK );
|
||||
efi_raise_tpl ( &tpl );
|
||||
|
||||
/* Clear status */
|
||||
*status = 0;
|
||||
@@ -613,7 +612,7 @@ efi_usb_control_transfer ( EFI_USB_IO_PROTOCOL *usbio,
|
||||
|
||||
err_control:
|
||||
err_change_config:
|
||||
bs->RestoreTPL ( saved_tpl );
|
||||
efi_restore_tpl ( &tpl );
|
||||
return EFIRC ( rc );
|
||||
}
|
||||
|
||||
@@ -631,12 +630,11 @@ efi_usb_control_transfer ( EFI_USB_IO_PROTOCOL *usbio,
|
||||
static EFI_STATUS EFIAPI
|
||||
efi_usb_bulk_transfer ( EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint, VOID *data,
|
||||
UINTN *len, UINTN timeout, UINT32 *status ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
struct efi_usb_interface *usbintf =
|
||||
container_of ( usbio, struct efi_usb_interface, usbio );
|
||||
struct efi_usb_device *usbdev = usbintf->usbdev;
|
||||
size_t actual = *len;
|
||||
EFI_TPL saved_tpl;
|
||||
struct efi_saved_tpl tpl;
|
||||
int rc;
|
||||
|
||||
DBGC2 ( usbdev, "USBDEV %s bulk %s %p+%zx %dms\n", usbintf->name,
|
||||
@@ -644,7 +642,7 @@ efi_usb_bulk_transfer ( EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint, VOID *data,
|
||||
( ( size_t ) *len ), ( ( unsigned int ) timeout ) );
|
||||
|
||||
/* Raise TPL */
|
||||
saved_tpl = bs->RaiseTPL ( TPL_CALLBACK );
|
||||
efi_raise_tpl ( &tpl );
|
||||
|
||||
/* Clear status */
|
||||
*status = 0;
|
||||
@@ -659,7 +657,7 @@ efi_usb_bulk_transfer ( EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint, VOID *data,
|
||||
}
|
||||
|
||||
err_transfer:
|
||||
bs->RestoreTPL ( saved_tpl );
|
||||
efi_restore_tpl ( &tpl );
|
||||
return EFIRC ( rc );
|
||||
}
|
||||
|
||||
@@ -678,12 +676,11 @@ static EFI_STATUS EFIAPI
|
||||
efi_usb_sync_interrupt_transfer ( EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint,
|
||||
VOID *data, UINTN *len, UINTN timeout,
|
||||
UINT32 *status ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
struct efi_usb_interface *usbintf =
|
||||
container_of ( usbio, struct efi_usb_interface, usbio );
|
||||
struct efi_usb_device *usbdev = usbintf->usbdev;
|
||||
size_t actual = *len;
|
||||
EFI_TPL saved_tpl;
|
||||
struct efi_saved_tpl tpl;
|
||||
int rc;
|
||||
|
||||
DBGC2 ( usbdev, "USBDEV %s sync intr %s %p+%zx %dms\n", usbintf->name,
|
||||
@@ -691,7 +688,7 @@ efi_usb_sync_interrupt_transfer ( EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint,
|
||||
( ( size_t ) *len ), ( ( unsigned int ) timeout ) );
|
||||
|
||||
/* Raise TPL */
|
||||
saved_tpl = bs->RaiseTPL ( TPL_CALLBACK );
|
||||
efi_raise_tpl ( &tpl );
|
||||
|
||||
/* Clear status */
|
||||
*status = 0;
|
||||
@@ -706,7 +703,7 @@ efi_usb_sync_interrupt_transfer ( EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint,
|
||||
}
|
||||
|
||||
err_transfer:
|
||||
bs->RestoreTPL ( saved_tpl );
|
||||
efi_restore_tpl ( &tpl );
|
||||
return EFIRC ( rc );
|
||||
}
|
||||
|
||||
@@ -727,11 +724,10 @@ efi_usb_async_interrupt_transfer ( EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint,
|
||||
BOOLEAN start, UINTN interval, UINTN len,
|
||||
EFI_ASYNC_USB_TRANSFER_CALLBACK callback,
|
||||
VOID *context ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
struct efi_usb_interface *usbintf =
|
||||
container_of ( usbio, struct efi_usb_interface, usbio );
|
||||
struct efi_usb_device *usbdev = usbintf->usbdev;
|
||||
EFI_TPL saved_tpl;
|
||||
struct efi_saved_tpl tpl;
|
||||
int rc;
|
||||
|
||||
DBGC2 ( usbdev, "USBDEV %s async intr %s len %#zx int %d %p/%p\n",
|
||||
@@ -741,7 +737,7 @@ efi_usb_async_interrupt_transfer ( EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint,
|
||||
callback, context );
|
||||
|
||||
/* Raise TPL */
|
||||
saved_tpl = bs->RaiseTPL ( TPL_CALLBACK );
|
||||
efi_raise_tpl ( &tpl );
|
||||
|
||||
/* Start/stop transfer as applicable */
|
||||
if ( start ) {
|
||||
@@ -763,7 +759,7 @@ efi_usb_async_interrupt_transfer ( EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint,
|
||||
}
|
||||
|
||||
err_start:
|
||||
bs->RestoreTPL ( saved_tpl );
|
||||
efi_restore_tpl ( &tpl );
|
||||
return EFIRC ( rc );
|
||||
}
|
||||
|
||||
@@ -959,9 +955,9 @@ efi_usb_get_string_descriptor ( EFI_USB_IO_PROTOCOL *usbio, UINT16 language,
|
||||
container_of ( usbio, struct efi_usb_interface, usbio );
|
||||
struct efi_usb_device *usbdev = usbintf->usbdev;
|
||||
struct usb_descriptor_header header;
|
||||
struct efi_saved_tpl tpl;
|
||||
VOID *buffer;
|
||||
size_t len;
|
||||
EFI_TPL saved_tpl;
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
|
||||
@@ -969,7 +965,7 @@ efi_usb_get_string_descriptor ( EFI_USB_IO_PROTOCOL *usbio, UINT16 language,
|
||||
usbintf->name, language, index );
|
||||
|
||||
/* Raise TPL */
|
||||
saved_tpl = bs->RaiseTPL ( TPL_CALLBACK );
|
||||
efi_raise_tpl ( &tpl );
|
||||
|
||||
/* Read descriptor header */
|
||||
if ( ( rc = usb_get_descriptor ( usbdev->func->usb, 0,
|
||||
@@ -1012,7 +1008,7 @@ efi_usb_get_string_descriptor ( EFI_USB_IO_PROTOCOL *usbio, UINT16 language,
|
||||
memset ( ( buffer + len - sizeof ( header ) ), 0, sizeof ( **string ) );
|
||||
|
||||
/* Restore TPL */
|
||||
bs->RestoreTPL ( saved_tpl );
|
||||
efi_restore_tpl ( &tpl );
|
||||
|
||||
/* Return allocated string */
|
||||
*string = buffer;
|
||||
@@ -1023,7 +1019,7 @@ efi_usb_get_string_descriptor ( EFI_USB_IO_PROTOCOL *usbio, UINT16 language,
|
||||
err_alloc:
|
||||
err_len:
|
||||
err_get_header:
|
||||
bs->RestoreTPL ( saved_tpl );
|
||||
efi_restore_tpl ( &tpl );
|
||||
return EFIRC ( rc );
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user