diff options
| author | Michael Brown | 2018-02-20 11:56:31 +0100 |
|---|---|---|
| committer | Michael Brown | 2018-02-20 11:56:31 +0100 |
| commit | c89a446cf09f30a121ae21d91f4a1aa071044084 (patch) | |
| tree | d9b8a253fc68ac4e97221ad5dfae8707c5bab873 /src/interface/efi/efi_snp.c | |
| parent | [xhci] Consume event TRB before reporting completion to USB core (diff) | |
| download | ipxe-c89a446cf09f30a121ae21d91f4a1aa071044084.tar.gz ipxe-c89a446cf09f30a121ae21d91f4a1aa071044084.tar.xz ipxe-c89a446cf09f30a121ae21d91f4a1aa071044084.zip | |
[efi] Run at TPL_CALLBACK to protect against UEFI timers
As noted in the comments, UEFI manages to combines the all of the
worst aspects of both a polling design (inefficiency and inability to
sleep until something interesting happens) and of an interrupt-driven
design (the complexity of code that could be preempted at any time,
thanks to UEFI timers).
This causes problems in particular for UEFI USB keyboards: the
keyboard driver calls UsbAsyncInterruptTransfer() to set up a periodic
timer which is used to poll the USB bus. This poll may interrupt a
critical section within iPXE, typically resulting in list corruption
and either a hang or reboot.
Work around this problem by mirroring the BIOS design, in which we run
with interrupts disabled almost all of the time.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/interface/efi/efi_snp.c')
| -rw-r--r-- | src/interface/efi/efi_snp.c | 12 |
1 files changed, 12 insertions, 0 deletions
diff --git a/src/interface/efi/efi_snp.c b/src/interface/efi/efi_snp.c index 263a25ac6..88d999bf0 100644 --- a/src/interface/efi/efi_snp.c +++ b/src/interface/efi/efi_snp.c @@ -45,6 +45,9 @@ static LIST_HEAD ( efi_snp_devices ); /** Network devices are currently claimed for use by iPXE */ static int efi_snp_claimed; +/** TPL prior to network devices being claimed */ +static EFI_TPL efi_snp_old_tpl; + /* Downgrade user experience if configured to do so * * The default UEFI user experience for network boot is somewhat @@ -1895,8 +1898,13 @@ struct efi_snp_device * last_opened_snpdev ( void ) { * @v delta Claim count change */ void efi_snp_add_claim ( int delta ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_snp_device *snpdev; + /* Raise TPL if we are about to claim devices */ + if ( ! efi_snp_claimed ) + efi_snp_old_tpl = bs->RaiseTPL ( TPL_CALLBACK ); + /* Claim SNP devices */ efi_snp_claimed += delta; assert ( efi_snp_claimed >= 0 ); @@ -1904,4 +1912,8 @@ void efi_snp_add_claim ( int delta ) { /* Update SNP mode state for each interface */ list_for_each_entry ( snpdev, &efi_snp_devices, list ) efi_snp_set_state ( snpdev ); + + /* Restore TPL if we have released devices */ + if ( ! efi_snp_claimed ) + bs->RestoreTPL ( efi_snp_old_tpl ); } |
