iPXE
Defines | Functions | Variables
efi_timer.c File Reference

iPXE timer API for EFI More...

#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <ipxe/timer.h>
#include <ipxe/init.h>
#include <ipxe/efi/efi.h>

Go to the source code of this file.

Defines

#define EFI_JIFFIES_PER_SEC   32
 Number of jiffies per second.
#define colour   &efi_jiffies
 Colour for debug messages.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static void efi_udelay (unsigned long usecs)
 Delay for a fixed number of microseconds.
static unsigned long efi_currticks (void)
 Get current system time in ticks.
static EFIAPI void efi_tick (EFI_EVENT event __unused, void *context __unused)
 Timer tick.
static void efi_tick_startup (void)
 Start timer tick.
static void efi_tick_shutdown (int booting __unused)
 Stop timer tick.
struct startup_fn
efi_tick_startup_fn 
__startup_fn (STARTUP_EARLY)
 Timer tick startup function.
struct timer efi_timer __timer (TIMER_NORMAL)
 EFI timer.

Variables

static unsigned long efi_jiffies
 Current tick count.
static EFI_EVENT efi_tick_event
 Timer tick event.

Detailed Description

iPXE timer API for EFI

Definition in file efi_timer.c.


Define Documentation

#define EFI_JIFFIES_PER_SEC   32

Number of jiffies per second.

This is a policy decision.

Definition at line 44 of file efi_timer.c.

Referenced by efi_currticks(), and efi_tick_startup().

#define colour   &efi_jiffies

Colour for debug messages.

Definition at line 53 of file efi_timer.c.

Referenced by ansicol_define(), ansicol_set(), colour_exec(), efi_tick_shutdown(), efi_tick_startup(), and efi_udelay().


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static void efi_udelay ( unsigned long  usecs) [static]

Delay for a fixed number of microseconds.

Parameters:
usecsNumber of microseconds for which to delay

Definition at line 60 of file efi_timer.c.

References EFI_SYSTEM_TABLE::BootServices, colour, DBGC, EEFI, efi_systab, rc, EFI_BOOT_SERVICES::Stall, and strerror().

                                               {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        EFI_STATUS efirc;
        int rc;

        if ( ( efirc = bs->Stall ( usecs ) ) != 0 ) {
                rc = -EEFI ( efirc );
                DBGC ( colour, "EFI could not delay for %ldus: %s\n",
                       usecs, strerror ( rc ) );
                /* Probably screwed */
        }
}
static unsigned long efi_currticks ( void  ) [static]

Get current system time in ticks.

Return values:
ticksCurrent time, in ticks

Definition at line 78 of file efi_timer.c.

References EFI_SYSTEM_TABLE::BootServices, efi_jiffies, EFI_JIFFIES_PER_SEC, efi_shutdown_in_progress, efi_systab, EFI_BOOT_SERVICES::RaiseTPL, EFI_BOOT_SERVICES::RestoreTPL, TICKS_PER_SEC, TPL_APPLICATION, and TPL_CALLBACK.

                                            {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;

        /* 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.
         *
         * Unfortunately, all timers silently stop working when
         * ExitBootServices() is called.  Even more unfortunately, and
         * for no discernible reason, this happens before any
         * EVT_SIGNAL_EXIT_BOOT_SERVICES events are signalled.  The
         * net effect of this entertaining design choice is that any
         * timeout loops on the shutdown path (e.g. for gracefully
         * closing outstanding TCP connections) may wait indefinitely.
         *
         * There is no way to report failure from currticks(), since
         * 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 during shutdown.
         */
        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 ) );
}
static EFIAPI void efi_tick ( EFI_EVENT event  __unused,
void *context  __unused 
) [static]

Timer tick.

Parameters:
eventTimer tick event
contextEvent context

Definition at line 143 of file efi_timer.c.

References efi_jiffies.

Referenced by efi_tick_startup().

                                                       {

        /* Increment tick count */
        efi_jiffies++;
}
static void efi_tick_startup ( void  ) [static]

Start timer tick.

Definition at line 154 of file efi_timer.c.

References EFI_SYSTEM_TABLE::BootServices, colour, EFI_BOOT_SERVICES::CreateEvent, DBGC, EEFI, EFI_JIFFIES_PER_SEC, efi_systab, efi_tick(), efi_tick_event, EVT_NOTIFY_SIGNAL, EVT_TIMER, NULL, rc, EFI_BOOT_SERVICES::SetTimer, strerror(), TimerPeriodic, and TPL_CALLBACK.

                                      {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        EFI_STATUS efirc;
        int rc;

        /* Create timer tick event */
        if ( ( efirc = bs->CreateEvent ( ( EVT_TIMER | EVT_NOTIFY_SIGNAL ),
                                         TPL_CALLBACK, efi_tick, NULL,
                                         &efi_tick_event ) ) != 0 ) {
                rc = -EEFI ( efirc );
                DBGC ( colour, "EFI could not create timer tick: %s\n",
                       strerror ( rc ) );
                /* Nothing we can do about it */
                return;
        }

        /* Start timer tick */
        if ( ( efirc = bs->SetTimer ( efi_tick_event, TimerPeriodic,
                                      ( 10000000 / EFI_JIFFIES_PER_SEC ) ))!=0){
                rc = -EEFI ( efirc );
                DBGC ( colour, "EFI could not start timer tick: %s\n",
                       strerror ( rc ) );
                /* Nothing we can do about it */
                return;
        }
        DBGC ( colour, "EFI timer started at %d ticks per second\n",
               EFI_JIFFIES_PER_SEC );
}
static void efi_tick_shutdown ( int booting  __unused) [static]

Stop timer tick.

Parameters:
bootingSystem is shutting down in order to boot

Definition at line 188 of file efi_timer.c.

References EFI_SYSTEM_TABLE::BootServices, EFI_BOOT_SERVICES::CloseEvent, colour, DBGC, EEFI, efi_systab, efi_tick_event, rc, EFI_BOOT_SERVICES::SetTimer, strerror(), and TimerCancel.

                                                       {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        EFI_STATUS efirc;
        int rc;

        /* Stop timer tick */
        if ( ( efirc = bs->SetTimer ( efi_tick_event, TimerCancel, 0 ) ) != 0 ){
                rc = -EEFI ( efirc );
                DBGC ( colour, "EFI could not stop timer tick: %s\n",
                       strerror ( rc ) );
                /* Self-destruct initiated */
                return;
        }
        DBGC ( colour, "EFI timer stopped\n" );

        /* Destroy timer tick event */
        if ( ( efirc = bs->CloseEvent ( efi_tick_event ) ) != 0 ) {
                rc = -EEFI ( efirc );
                DBGC ( colour, "EFI could not destroy timer tick: %s\n",
                       strerror ( rc ) );
                /* Probably non-fatal */
                return;
        }
}
struct startup_fn efi_tick_startup_fn __startup_fn ( STARTUP_EARLY  ) [read]

Timer tick startup function.

struct timer efi_timer __timer ( TIMER_NORMAL  ) [read]

EFI timer.


Variable Documentation

unsigned long efi_jiffies [static]

Current tick count.

Definition at line 47 of file efi_timer.c.

Referenced by efi_currticks(), and efi_tick().

Timer tick event.

Definition at line 50 of file efi_timer.c.

Referenced by efi_tick_shutdown(), and efi_tick_startup().