summaryrefslogtreecommitdiffstats
path: root/src/interface/efi/efi_timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interface/efi/efi_timer.c')
-rw-r--r--src/interface/efi/efi_timer.c41
1 files changed, 35 insertions, 6 deletions
diff --git a/src/interface/efi/efi_timer.c b/src/interface/efi/efi_timer.c
index 0ffe2a1a..8fe307ce 100644
--- a/src/interface/efi/efi_timer.c
+++ b/src/interface/efi/efi_timer.c
@@ -76,11 +76,36 @@ 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;
- /* EFI provides no clean way for device drivers to shut down
- * in preparation for handover to a booted operating system.
- * The platform firmware simply doesn't bother to call the
- * drivers' Stop() methods. Instead, drivers must register an
+ /* UEFI manages to ingeniously combine the worst aspects of
+ * both polling and interrupt-driven designs. There is no way
+ * to support proper interrupt-driven operation, since there
+ * is no way to hook in an interrupt service routine. A
+ * mockery of interrupts is provided by UEFI timers, which
+ * trigger at a preset rate and can fire at any time.
+ *
+ * We therefore have all of the downsides of a polling design
+ * (inefficiency and inability to sleep until something
+ * interesting happens) combined with all of the downsides of
+ * an interrupt-driven design (the complexity of code that
+ * could be preempted at any time).
+ *
+ * The UEFI specification expects us to litter the entire
+ * codebase with calls to RaiseTPL() as needed for sections of
+ * code that are not reentrant. Since this doesn't actually
+ * gain us any substantive benefits (since even with such
+ * calls we would still be suffering from the limitations of a
+ * polling design), we instead choose to run at TPL_CALLBACK
+ * almost all of the time, dropping to TPL_APPLICATION to
+ * allow timer ticks to occur.
+ *
+ *
+ * For added excitement, UEFI provides no clean way for device
+ * drivers to shut down in preparation for handover to a
+ * booted operating system. The platform firmware simply
+ * doesn't bother to call the drivers' Stop() methods.
+ * Instead, all non-trivial drivers must register an
* EVT_SIGNAL_EXIT_BOOT_SERVICES event to be signalled when
* ExitBootServices() is called, and clean up without any
* reference to the EFI driver model.
@@ -97,10 +122,14 @@ static unsigned long efi_currticks ( void ) {
* the API lazily assumes that the host system continues to
* travel through time in the usual direction. Work around
* EFI's violation of this assumption by falling back to a
- * simple free-running monotonic counter.
+ * simple free-running monotonic counter during shutdown.
*/
- if ( efi_shutdown_in_progress )
+ if ( efi_shutdown_in_progress ) {
efi_jiffies++;
+ } else {
+ bs->RestoreTPL ( TPL_APPLICATION );
+ bs->RaiseTPL ( TPL_CALLBACK );
+ }
return ( efi_jiffies * ( TICKS_PER_SEC / EFI_JIFFIES_PER_SEC ) );
}