mirror of
https://gitlab.com/qemu-project/ipxe.git
synced 2025-11-03 07:59:06 +08:00
Compare commits
8 Commits
uri
...
efi_watchd
| Author | SHA1 | Date | |
|---|---|---|---|
| 81e3351b9b | |||
| 562c74e1ea | |||
| 0f4cc4b5a7 | |||
| a046da21a4 | |||
| 3ad27fbe78 | |||
| b6045a8cbb | |||
| 51612b6e69 | |||
| 236299baa3 |
@ -576,7 +576,7 @@ static int nii_issue_cpb_db ( struct nii_nic *nii, unsigned int op, void *cpb,
|
||||
cdb.IFnum = nii->nii->IfNum;
|
||||
|
||||
/* Raise task priority level */
|
||||
tpl = bs->RaiseTPL ( TPL_CALLBACK );
|
||||
tpl = bs->RaiseTPL ( efi_internal_tpl );
|
||||
|
||||
/* Issue command */
|
||||
DBGC2 ( nii, "NII %s issuing %02x:%04x ifnum %d%s%s\n",
|
||||
|
||||
@ -164,6 +164,10 @@ static int snpnet_transmit ( struct net_device *netdev,
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
|
||||
/* Do nothing if shutdown is in progress */
|
||||
if ( efi_shutdown_in_progress )
|
||||
return -ECANCELED;
|
||||
|
||||
/* Defer the packet if there is already a transmission in progress */
|
||||
if ( snp->txbuf ) {
|
||||
netdev_tx_defer ( netdev, iobuf );
|
||||
@ -283,6 +287,10 @@ static void snpnet_poll_rx ( struct net_device *netdev ) {
|
||||
*/
|
||||
static void snpnet_poll ( struct net_device *netdev ) {
|
||||
|
||||
/* Do nothing if shutdown is in progress */
|
||||
if ( efi_shutdown_in_progress )
|
||||
return;
|
||||
|
||||
/* Process any TX completions */
|
||||
snpnet_poll_tx ( netdev );
|
||||
|
||||
@ -426,8 +434,9 @@ static void snpnet_close ( struct net_device *netdev ) {
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
|
||||
/* Shut down NIC */
|
||||
if ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) {
|
||||
/* Shut down NIC (unless whole system shutdown is in progress) */
|
||||
if ( ( ! efi_shutdown_in_progress ) &&
|
||||
( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( snp, "SNP %s could not shut down: %s\n",
|
||||
netdev->name, strerror ( rc ) );
|
||||
@ -589,8 +598,9 @@ void snpnet_stop ( struct efi_device *efidev ) {
|
||||
/* Unregister network device */
|
||||
unregister_netdev ( netdev );
|
||||
|
||||
/* Stop SNP protocol */
|
||||
if ( ( efirc = snp->snp->Stop ( snp->snp ) ) != 0 ) {
|
||||
/* Stop SNP protocol (unless whole system shutdown is in progress) */
|
||||
if ( ( ! efi_shutdown_in_progress ) &&
|
||||
( ( efirc = snp->snp->Stop ( snp->snp ) ) != 0 ) ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( device, "SNP %s could not stop: %s\n",
|
||||
efi_handle_name ( device ), strerror ( rc ) );
|
||||
|
||||
@ -481,6 +481,7 @@ static struct pci_device_id intelx_nics[] = {
|
||||
PCI_ROM ( 0x8086, 0x15ab, "x552", "X552", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x15c8, "x553t", "X553/X557-AT", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x15ce, "x553-sfp", "X553 (SFP+)", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x15e4, "x553a", "X553", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x15e5, "x553", "X553", 0 ),
|
||||
};
|
||||
|
||||
|
||||
@ -3459,14 +3459,36 @@ static int xhci_probe ( struct pci_device *pci ) {
|
||||
static void xhci_remove ( struct pci_device *pci ) {
|
||||
struct xhci_device *xhci = pci_get_drvdata ( pci );
|
||||
struct usb_bus *bus = xhci->bus;
|
||||
uint16_t command;
|
||||
|
||||
/* Some systems are observed to disable bus mastering on
|
||||
* Thunderbolt controllers before we get a chance to shut
|
||||
* down. Detect this and avoid attempting any DMA operations,
|
||||
* which are guaranteed to fail and may end up spuriously
|
||||
* completing after the operating system kernel starts up.
|
||||
*/
|
||||
pci_read_config_word ( pci, PCI_COMMAND, &command );
|
||||
if ( ! ( command & PCI_COMMAND_MASTER ) ) {
|
||||
DBGC ( xhci, "XHCI %s DMA was disabled\n", xhci->name );
|
||||
xhci_fail ( xhci );
|
||||
}
|
||||
|
||||
/* Unregister and free USB bus */
|
||||
unregister_usb_bus ( bus );
|
||||
free_usb_bus ( bus );
|
||||
|
||||
/* Reset device and undo any PCH-specific fixes */
|
||||
xhci_reset ( xhci );
|
||||
if ( xhci->quirks & XHCI_PCH )
|
||||
xhci_pch_undo ( xhci, pci );
|
||||
|
||||
/* Release ownership back to BIOS */
|
||||
xhci_legacy_release ( xhci );
|
||||
|
||||
/* Unmap registers */
|
||||
iounmap ( xhci->regs );
|
||||
|
||||
/* Free device */
|
||||
free ( xhci );
|
||||
}
|
||||
|
||||
|
||||
@ -223,6 +223,7 @@ extern EFI_HANDLE efi_image_handle;
|
||||
extern EFI_LOADED_IMAGE_PROTOCOL *efi_loaded_image;
|
||||
extern EFI_DEVICE_PATH_PROTOCOL *efi_loaded_image_path;
|
||||
extern EFI_SYSTEM_TABLE *efi_systab;
|
||||
extern EFI_TPL efi_internal_tpl;
|
||||
extern EFI_TPL efi_external_tpl;
|
||||
extern int efi_shutdown_in_progress;
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/efi/efi.h>
|
||||
|
||||
extern EFI_SYSTEM_TABLE * efi_wrap_systab ( void );
|
||||
extern EFI_BOOT_SERVICES * efi_wrap_bs ( void );
|
||||
extern void efi_wrap ( EFI_HANDLE handle );
|
||||
|
||||
#endif /* _IPXE_EFI_WRAP_H */
|
||||
|
||||
@ -104,8 +104,8 @@ static void efi_entropy_disable ( void ) {
|
||||
/* Close timer tick event */
|
||||
bs->CloseEvent ( tick );
|
||||
|
||||
/* Return to TPL_CALLBACK */
|
||||
bs->RaiseTPL ( TPL_CALLBACK );
|
||||
/* Return to internal TPL */
|
||||
bs->RaiseTPL ( efi_internal_tpl );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -47,6 +47,9 @@ EFI_DEVICE_PATH_PROTOCOL *efi_loaded_image_path;
|
||||
*/
|
||||
EFI_SYSTEM_TABLE * _C2 ( PLATFORM, _systab );
|
||||
|
||||
/** Internal task priority level */
|
||||
EFI_TPL efi_internal_tpl = TPL_CALLBACK;
|
||||
|
||||
/** External task priority level */
|
||||
EFI_TPL efi_external_tpl = TPL_APPLICATION;
|
||||
|
||||
@ -79,6 +82,17 @@ static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle );
|
||||
static EFIAPI void efi_shutdown_hook ( EFI_EVENT event __unused,
|
||||
void *context __unused ) {
|
||||
|
||||
/* This callback is invoked at TPL_NOTIFY in order to ensure
|
||||
* that we have an opportunity to shut down cleanly before
|
||||
* other shutdown hooks perform destructive operations such as
|
||||
* disabling the IOMMU.
|
||||
*
|
||||
* Modify the internal task priority level so that no code
|
||||
* attempts to raise from TPL_NOTIFY to TPL_CALLBACK (which
|
||||
* would trigger a fatal exception).
|
||||
*/
|
||||
efi_internal_tpl = TPL_NOTIFY;
|
||||
|
||||
/* Mark shutdown as being in progress, to indicate that large
|
||||
* parts of the system (e.g. timers) are no longer functional.
|
||||
*/
|
||||
@ -273,7 +287,7 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
|
||||
* bother doing so when ExitBootServices() is called.
|
||||
*/
|
||||
if ( ( efirc = bs->CreateEvent ( EVT_SIGNAL_EXIT_BOOT_SERVICES,
|
||||
TPL_CALLBACK, efi_shutdown_hook,
|
||||
TPL_NOTIFY, efi_shutdown_hook,
|
||||
NULL, &efi_shutdown_event ) ) != 0 ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( systab, "EFI could not create ExitBootServices event: "
|
||||
@ -316,9 +330,13 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
|
||||
static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle __unused ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
EFI_SYSTEM_TABLE *systab = efi_systab;
|
||||
struct efi_saved_tpl tpl;
|
||||
|
||||
DBGC ( systab, "EFI image unloading\n" );
|
||||
|
||||
/* Raise TPL */
|
||||
efi_raise_tpl ( &tpl );
|
||||
|
||||
/* Shut down */
|
||||
shutdown_exit();
|
||||
|
||||
@ -336,6 +354,9 @@ static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle __unused ) {
|
||||
|
||||
DBGC ( systab, "EFI image unloaded\n" );
|
||||
|
||||
/* Restore TPL */
|
||||
efi_restore_tpl ( &tpl );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -366,7 +387,7 @@ __attribute__ (( noreturn )) void __stack_chk_fail ( void ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Raise task priority level to TPL_CALLBACK
|
||||
* Raise task priority level to internal level
|
||||
*
|
||||
* @v tpl Saved TPL
|
||||
*/
|
||||
@ -377,7 +398,7 @@ void efi_raise_tpl ( struct efi_saved_tpl *tpl ) {
|
||||
tpl->previous = efi_external_tpl;
|
||||
|
||||
/* Raise TPL and record previous TPL as new external TPL */
|
||||
tpl->current = bs->RaiseTPL ( TPL_CALLBACK );
|
||||
tpl->current = bs->RaiseTPL ( efi_internal_tpl );
|
||||
efi_external_tpl = tpl->current;
|
||||
}
|
||||
|
||||
|
||||
@ -137,7 +137,7 @@ static unsigned long efi_currticks ( void ) {
|
||||
efi_jiffies++;
|
||||
} else {
|
||||
bs->RestoreTPL ( efi_external_tpl );
|
||||
bs->RaiseTPL ( TPL_CALLBACK );
|
||||
bs->RaiseTPL ( efi_internal_tpl );
|
||||
}
|
||||
|
||||
return ( efi_jiffies * ( TICKS_PER_SEC / EFI_JIFFIES_PER_SEC ) );
|
||||
|
||||
@ -34,6 +34,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <string.h>
|
||||
#include <ipxe/retry.h>
|
||||
#include <ipxe/timer.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/efi/efi.h>
|
||||
#include <ipxe/efi/efi_watchdog.h>
|
||||
|
||||
@ -80,3 +81,36 @@ static void efi_watchdog_expired ( struct retry_timer *timer,
|
||||
|
||||
/** Watchdog holdoff timer */
|
||||
struct retry_timer efi_watchdog = TIMER_INIT ( efi_watchdog_expired );
|
||||
|
||||
/**
|
||||
* Disable watching when shutting down to boot an operating system
|
||||
*
|
||||
* @v booting System is shutting down for OS boot
|
||||
*/
|
||||
static void efi_watchdog_shutdown ( int booting ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
|
||||
/* If we are shutting down to boot an operating system, then
|
||||
* disable the boot services watchdog timer. The UEFI
|
||||
* specification mandates that the platform firmware does this
|
||||
* as part of the ExitBootServices() call, but some platforms
|
||||
* (e.g. Hyper-V) are observed to occasionally forget to do
|
||||
* so, resulting in a reboot approximately five minutes after
|
||||
* starting the operating system.
|
||||
*/
|
||||
if ( booting &&
|
||||
( ( efirc = bs->SetWatchdogTimer ( 0, 0, 0, NULL ) ) != 0 ) ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( &efi_watchdog, "EFI could not disable watchdog timer: "
|
||||
"%s\n", strerror ( rc ) );
|
||||
/* Nothing we can do */
|
||||
}
|
||||
}
|
||||
|
||||
/** Watchdog startup/shutdown function */
|
||||
struct startup_fn efi_watchdog_startup_fn __startup_fn ( STARTUP_EARLY ) = {
|
||||
.name = "efi_watchdog",
|
||||
.shutdown = efi_watchdog_shutdown,
|
||||
};
|
||||
|
||||
@ -195,6 +195,47 @@ static const char * efi_timer_delay ( EFI_TIMER_DELAY type ) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump information about a loaded image
|
||||
*
|
||||
* @v handle Image handle
|
||||
*/
|
||||
static void efi_dump_image ( EFI_HANDLE handle ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
union {
|
||||
EFI_LOADED_IMAGE_PROTOCOL *image;
|
||||
void *intf;
|
||||
} loaded;
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
|
||||
/* Open loaded image protocol */
|
||||
if ( ( efirc = bs->OpenProtocol ( handle,
|
||||
&efi_loaded_image_protocol_guid,
|
||||
&loaded.intf, efi_image_handle, NULL,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( colour, "WRAP %s could not get loaded image protocol: "
|
||||
"%s\n", efi_handle_name ( handle ), strerror ( rc ) );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Dump image information */
|
||||
DBGC ( colour, "WRAP %s at base %p has protocols:\n",
|
||||
efi_handle_name ( handle ), loaded.image->ImageBase );
|
||||
DBGC_EFI_PROTOCOLS ( colour, handle );
|
||||
DBGC ( colour, "WRAP %s parent", efi_handle_name ( handle ) );
|
||||
DBGC ( colour, " %s\n", efi_handle_name ( loaded.image->ParentHandle ));
|
||||
DBGC ( colour, "WRAP %s device", efi_handle_name ( handle ) );
|
||||
DBGC ( colour, " %s\n", efi_handle_name ( loaded.image->DeviceHandle ));
|
||||
DBGC ( colour, "WRAP %s file", efi_handle_name ( handle ) );
|
||||
DBGC ( colour, " %s\n", efi_devpath_text ( loaded.image->FilePath ) );
|
||||
|
||||
/* Close loaded image protocol */
|
||||
bs->CloseProtocol ( handle, &efi_loaded_image_protocol_guid,
|
||||
efi_image_handle, NULL );
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap RaiseTPL()
|
||||
*
|
||||
@ -655,9 +696,9 @@ efi_load_image_wrapper ( BOOLEAN boot_policy, EFI_HANDLE parent_image_handle,
|
||||
DBGC ( colour, "%s ", efi_handle_name ( *image_handle ) );
|
||||
DBGC ( colour, ") -> %p\n", retaddr );
|
||||
|
||||
/* Wrap the new image */
|
||||
/* Dump information about loaded image */
|
||||
if ( efirc == 0 )
|
||||
efi_wrap ( *image_handle );
|
||||
efi_dump_image ( *image_handle );
|
||||
|
||||
return efirc;
|
||||
}
|
||||
@ -735,11 +776,14 @@ efi_exit_boot_services_wrapper ( EFI_HANDLE image_handle, UINTN map_key ) {
|
||||
void *retaddr = __builtin_return_address ( 0 );
|
||||
EFI_STATUS efirc;
|
||||
|
||||
DBGC ( colour, "ExitBootServices ( %s, %#llx ) ",
|
||||
DBGC ( colour, "ExitBootServices ( %s, %#llx ) -> %p\n",
|
||||
efi_handle_name ( image_handle ),
|
||||
( ( unsigned long long ) map_key ) );
|
||||
( ( unsigned long long ) map_key ), retaddr );
|
||||
efirc = bs->ExitBootServices ( image_handle, map_key );
|
||||
DBGC ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr );
|
||||
if ( efirc != 0 ) {
|
||||
DBGC ( colour, "ExitBootServices ( ... ) = %s -> %p\n",
|
||||
efi_status ( efirc ), retaddr );
|
||||
}
|
||||
return efirc;
|
||||
}
|
||||
|
||||
@ -1129,12 +1173,11 @@ efi_create_event_ex_wrapper ( UINT32 type, EFI_TPL notify_tpl,
|
||||
}
|
||||
|
||||
/**
|
||||
* Build table wrappers
|
||||
* Build boot services table wrapper
|
||||
*
|
||||
* @ret systab Wrapped system table
|
||||
* @ret bs Wrapped boot services table
|
||||
*/
|
||||
EFI_SYSTEM_TABLE * efi_wrap_systab ( void ) {
|
||||
static EFI_SYSTEM_TABLE efi_systab_wrapper;
|
||||
EFI_BOOT_SERVICES * efi_wrap_bs ( void ) {
|
||||
static EFI_BOOT_SERVICES efi_bs_wrapper;
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
|
||||
@ -1194,12 +1237,7 @@ EFI_SYSTEM_TABLE * efi_wrap_systab ( void ) {
|
||||
= efi_uninstall_multiple_protocol_interfaces_wrapper;
|
||||
efi_bs_wrapper.CreateEventEx = efi_create_event_ex_wrapper;
|
||||
|
||||
/* Build system table wrapper */
|
||||
memcpy ( &efi_systab_wrapper, efi_systab,
|
||||
sizeof ( efi_systab_wrapper ) );
|
||||
efi_systab_wrapper.BootServices = &efi_bs_wrapper;
|
||||
|
||||
return &efi_systab_wrapper;
|
||||
return &efi_bs_wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1208,42 +1246,20 @@ EFI_SYSTEM_TABLE * efi_wrap_systab ( void ) {
|
||||
* @v handle Image handle
|
||||
*/
|
||||
void efi_wrap ( EFI_HANDLE handle ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
union {
|
||||
EFI_LOADED_IMAGE_PROTOCOL *image;
|
||||
void *intf;
|
||||
} loaded;
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
static EFI_SYSTEM_TABLE efi_systab_copy;
|
||||
|
||||
/* Do nothing unless debugging is enabled */
|
||||
if ( ! DBG_LOG )
|
||||
return;
|
||||
|
||||
/* Open loaded image protocol */
|
||||
if ( ( efirc = bs->OpenProtocol ( handle,
|
||||
&efi_loaded_image_protocol_guid,
|
||||
&loaded.intf, efi_image_handle, NULL,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( colour, "WRAP %s could not get loaded image protocol: "
|
||||
"%s\n", efi_handle_name ( handle ), strerror ( rc ) );
|
||||
return;
|
||||
/* Construct modified system table */
|
||||
if ( efi_systab != &efi_systab_copy ) {
|
||||
memcpy ( &efi_systab_copy, efi_systab,
|
||||
sizeof ( efi_systab_copy ) );
|
||||
efi_systab->BootServices = efi_wrap_bs();
|
||||
efi_systab = &efi_systab_copy;
|
||||
}
|
||||
|
||||
/* Provide system table wrapper to image */
|
||||
loaded.image->SystemTable = efi_wrap_systab();
|
||||
DBGC ( colour, "WRAP %s at base %p has protocols:\n",
|
||||
efi_handle_name ( handle ), loaded.image->ImageBase );
|
||||
DBGC_EFI_PROTOCOLS ( colour, handle );
|
||||
DBGC ( colour, "WRAP %s parent", efi_handle_name ( handle ) );
|
||||
DBGC ( colour, " %s\n", efi_handle_name ( loaded.image->ParentHandle ));
|
||||
DBGC ( colour, "WRAP %s device", efi_handle_name ( handle ) );
|
||||
DBGC ( colour, " %s\n", efi_handle_name ( loaded.image->DeviceHandle ));
|
||||
DBGC ( colour, "WRAP %s file", efi_handle_name ( handle ) );
|
||||
DBGC ( colour, " %s\n", efi_devpath_text ( loaded.image->FilePath ) );
|
||||
|
||||
/* Close loaded image protocol */
|
||||
bs->CloseProtocol ( handle, &efi_loaded_image_protocol_guid,
|
||||
efi_image_handle, NULL );
|
||||
/* Dump image information */
|
||||
efi_dump_image ( handle );
|
||||
}
|
||||
|
||||
@ -308,6 +308,9 @@ if [ -n "${ISOIMG}" ] ; then
|
||||
${ISOARGS} "${ISODIR}"
|
||||
if isohybrid --version >/dev/null 2>&1 ; then
|
||||
ISOHYBRIDARGS=
|
||||
if [ -n "${EFI}" ] ; then
|
||||
ISOHYBRIDARGS="${ISOHYBRIDARGS} --uefi"
|
||||
fi
|
||||
if [ -n "${SOURCE_DATE_EPOCH:-}" ] ; then
|
||||
ISOHYBRIDARGS="${ISOHYBRIDARGS} --id ${SOURCE_DATE_EPOCH}"
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user