|
@@ -76,11 +76,36 @@ static void efi_udelay ( unsigned long usecs ) {
|
76
|
76
|
* @ret ticks Current time, in ticks
|
77
|
77
|
*/
|
78
|
78
|
static unsigned long efi_currticks ( void ) {
|
|
79
|
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
79
|
80
|
|
80
|
|
- /* EFI provides no clean way for device drivers to shut down
|
81
|
|
- * in preparation for handover to a booted operating system.
|
82
|
|
- * The platform firmware simply doesn't bother to call the
|
83
|
|
- * drivers' Stop() methods. Instead, drivers must register an
|
|
81
|
+ /* UEFI manages to ingeniously combine the worst aspects of
|
|
82
|
+ * both polling and interrupt-driven designs. There is no way
|
|
83
|
+ * to support proper interrupt-driven operation, since there
|
|
84
|
+ * is no way to hook in an interrupt service routine. A
|
|
85
|
+ * mockery of interrupts is provided by UEFI timers, which
|
|
86
|
+ * trigger at a preset rate and can fire at any time.
|
|
87
|
+ *
|
|
88
|
+ * We therefore have all of the downsides of a polling design
|
|
89
|
+ * (inefficiency and inability to sleep until something
|
|
90
|
+ * interesting happens) combined with all of the downsides of
|
|
91
|
+ * an interrupt-driven design (the complexity of code that
|
|
92
|
+ * could be preempted at any time).
|
|
93
|
+ *
|
|
94
|
+ * The UEFI specification expects us to litter the entire
|
|
95
|
+ * codebase with calls to RaiseTPL() as needed for sections of
|
|
96
|
+ * code that are not reentrant. Since this doesn't actually
|
|
97
|
+ * gain us any substantive benefits (since even with such
|
|
98
|
+ * calls we would still be suffering from the limitations of a
|
|
99
|
+ * polling design), we instead choose to run at TPL_CALLBACK
|
|
100
|
+ * almost all of the time, dropping to TPL_APPLICATION to
|
|
101
|
+ * allow timer ticks to occur.
|
|
102
|
+ *
|
|
103
|
+ *
|
|
104
|
+ * For added excitement, UEFI provides no clean way for device
|
|
105
|
+ * drivers to shut down in preparation for handover to a
|
|
106
|
+ * booted operating system. The platform firmware simply
|
|
107
|
+ * doesn't bother to call the drivers' Stop() methods.
|
|
108
|
+ * Instead, all non-trivial drivers must register an
|
84
|
109
|
* EVT_SIGNAL_EXIT_BOOT_SERVICES event to be signalled when
|
85
|
110
|
* ExitBootServices() is called, and clean up without any
|
86
|
111
|
* reference to the EFI driver model.
|
|
@@ -97,10 +122,14 @@ static unsigned long efi_currticks ( void ) {
|
97
|
122
|
* the API lazily assumes that the host system continues to
|
98
|
123
|
* travel through time in the usual direction. Work around
|
99
|
124
|
* EFI's violation of this assumption by falling back to a
|
100
|
|
- * simple free-running monotonic counter.
|
|
125
|
+ * simple free-running monotonic counter during shutdown.
|
101
|
126
|
*/
|
102
|
|
- if ( efi_shutdown_in_progress )
|
|
127
|
+ if ( efi_shutdown_in_progress ) {
|
103
|
128
|
efi_jiffies++;
|
|
129
|
+ } else {
|
|
130
|
+ bs->RestoreTPL ( TPL_APPLICATION );
|
|
131
|
+ bs->RaiseTPL ( TPL_CALLBACK );
|
|
132
|
+ }
|
104
|
133
|
|
105
|
134
|
return ( efi_jiffies * ( TICKS_PER_SEC / EFI_JIFFIES_PER_SEC ) );
|
106
|
135
|
}
|