From 1832f8a9b02d00977ca1e079bd9e0369763df14c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 14 Jul 2020 18:24:02 +0100 Subject: [PATCH] [efi] Claim SNP devices early in efi_download_start() Claiming the SNP devices has the side effect of raising the TPL to iPXE's normal operating level of TPL_CALLBACK (see the commit message for c89a446 ("[efi] Run at TPL_CALLBACK to protect against UEFI timers") for details). This must happen before executing any code that relies upon the TPL having been raised to TPL_CALLBACK. The call to efi_snp_claim() in efi_download_start() currently happens only after the call to xfer_open(). Calling xfer_open() will typically result in a retry timer being started, which will result in a call to currticks() in order to initialise the timer. The call to currticks() will drop to TPL_APPLICATION and restore to TPL_CALLBACK in order to allow a timer tick to occur. Since this call happened before the call to efi_snp_claim(), the restored TPL is incorrect. This in turn results in efi_snp_claim() recording the incorrect original TPL, causing efi_snp_release() to eventually restore the incorrect TPL, causing the system to lock up when ExitBootServices() is called at TPL_CALLBACK. Fix by moving the call to efi_snp_claim() to the start of efi_download_start(). Debugged-by: Jarrod Johnson Debugged-by: He He4 Huang Debugged-by: James Wang Signed-off-by: Michael Brown --- src/interface/efi/efi_download.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/interface/efi/efi_download.c b/src/interface/efi/efi_download.c index 1218852e2..8d12bd57c 100644 --- a/src/interface/efi/efi_download.c +++ b/src/interface/efi/efi_download.c @@ -138,8 +138,11 @@ efi_download_start ( IPXE_DOWNLOAD_PROTOCOL *This __unused, struct efi_download_file *file; int rc; + efi_snp_claim(); + file = malloc ( sizeof ( struct efi_download_file ) ); if ( file == NULL ) { + efi_snp_release(); return EFI_OUT_OF_RESOURCES; } @@ -147,10 +150,10 @@ efi_download_start ( IPXE_DOWNLOAD_PROTOCOL *This __unused, rc = xfer_open ( &file->xfer, LOCATION_URI_STRING, Url ); if ( rc ) { free ( file ); + efi_snp_release(); return EFIRC ( rc ); } - efi_snp_claim(); file->pos = 0; file->data_callback = DataCallback; file->finish_callback = FinishCallback;