TianoCore EDK2 master
Loading...
Searching...
No Matches
Timer.c
Go to the documentation of this file.
1
10
11#include "Timer.h"
12
13//
14// The handle onto which the Timer Architectural Protocol will be installed
15//
16EFI_HANDLE mTimerHandle = NULL;
17
18//
19// The Timer Architectural Protocol that this driver produces
20//
26};
27
28//
29// Pointer to the CPU Architectural Protocol instance
30//
32
33//
34// Pointer to the Legacy 8259 Protocol instance
35//
36EFI_LEGACY_8259_PROTOCOL *mLegacy8259;
37
38//
39// The notification function to call on every timer interrupt.
40// A bug in the compiler prevents us from initializing this here.
41//
42EFI_TIMER_NOTIFY mTimerNotifyFunction;
43
44//
45// The current period of the timer interrupt
46//
47volatile UINT64 mTimerPeriod = 0;
48
49//
50// Worker Functions
51//
52
58VOID
60 IN UINT16 Count
61 )
62{
63 IoWrite8 (TIMER_CONTROL_PORT, 0x36);
64 IoWrite8 (TIMER0_COUNT_PORT, (UINT8)(Count & 0xff));
65 IoWrite8 (TIMER0_COUNT_PORT, (UINT8)((Count >> 8) & 0xff));
66}
67
74VOID
75EFIAPI
77 IN EFI_EXCEPTION_TYPE InterruptType,
78 IN EFI_SYSTEM_CONTEXT SystemContext
79 )
80{
81 STATIC NESTED_INTERRUPT_STATE NestedInterruptState;
82 EFI_TPL OriginalTPL;
83
84 OriginalTPL = NestedInterruptRaiseTPL ();
85
86 mLegacy8259->EndOfInterrupt (mLegacy8259, Efi8259Irq0);
87
88 if (mTimerNotifyFunction != NULL) {
89 //
90 // @bug : This does not handle missed timer interrupts
91 //
92 mTimerNotifyFunction (mTimerPeriod);
93 }
94
95 NestedInterruptRestoreTPL (OriginalTPL, SystemContext, &NestedInterruptState);
96}
97
130EFIAPI
134 )
135{
136 //
137 // Check for invalid parameters
138 //
139 if ((NotifyFunction == NULL) && (mTimerNotifyFunction == NULL)) {
140 return EFI_INVALID_PARAMETER;
141 }
142
143 if ((NotifyFunction != NULL) && (mTimerNotifyFunction != NULL)) {
144 return EFI_ALREADY_STARTED;
145 }
146
147 mTimerNotifyFunction = NotifyFunction;
148
149 return EFI_SUCCESS;
150}
151
181EFIAPI
184 IN UINT64 TimerPeriod
185 )
186{
187 UINT64 TimerCount;
188
189 //
190 // The basic clock is 1.19318 MHz or 0.119318 ticks per 100 ns.
191 // TimerPeriod * 0.119318 = 8254 timer divisor. Using integer arithmetic
192 // TimerCount = (TimerPeriod * 119318)/1000000.
193 //
194 // Round up to next highest integer. This guarantees that the timer is
195 // equal to or slightly longer than the requested time.
196 // TimerCount = ((TimerPeriod * 119318) + 500000)/1000000
197 //
198 // Note that a TimerCount of 0 is equivalent to a count of 65,536
199 //
200 // Since TimerCount is limited to 16 bits for IA32, TimerPeriod is limited
201 // to 20 bits.
202 //
203 if (TimerPeriod == 0) {
204 //
205 // Disable timer interrupt for a TimerPeriod of 0
206 //
207 mLegacy8259->DisableIrq (mLegacy8259, Efi8259Irq0);
208 } else {
209 //
210 // Convert TimerPeriod into 8254 counts
211 //
212 TimerCount = DivU64x32 (MultU64x32 (119318, (UINT32)TimerPeriod) + 500000, 1000000);
213
214 //
215 // Check for overflow
216 //
217 if (TimerCount >= 65536) {
218 TimerCount = 0;
219 TimerPeriod = MAX_TIMER_TICK_DURATION;
220 }
221
222 //
223 // Program the 8254 timer with the new count value
224 //
225 SetPitCount ((UINT16)TimerCount);
226
227 //
228 // Enable timer interrupt
229 //
230 mLegacy8259->EnableIrq (mLegacy8259, Efi8259Irq0, FALSE);
231 }
232
233 //
234 // Save the new timer period
235 //
236 mTimerPeriod = TimerPeriod;
237
238 return EFI_SUCCESS;
239}
240
258EFIAPI
261 OUT UINT64 *TimerPeriod
262 )
263{
264 if (TimerPeriod == NULL) {
265 return EFI_INVALID_PARAMETER;
266 }
267
268 *TimerPeriod = mTimerPeriod;
269
270 return EFI_SUCCESS;
271}
272
291EFIAPI
294 )
295{
296 EFI_STATUS Status;
297 UINT16 IRQMask;
298 EFI_TPL OriginalTPL;
299
300 //
301 // If the timer interrupt is enabled, then the registered handler will be invoked.
302 //
303 Status = mLegacy8259->GetMask (mLegacy8259, NULL, NULL, &IRQMask, NULL);
304 ASSERT_EFI_ERROR (Status);
305 if ((IRQMask & 0x1) == 0) {
306 //
307 // Invoke the registered handler
308 //
309 OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
310
311 if (mTimerNotifyFunction != NULL) {
312 //
313 // @bug : This does not handle missed timer interrupts
314 //
315 mTimerNotifyFunction (mTimerPeriod);
316 }
317
318 gBS->RestoreTPL (OriginalTPL);
319 } else {
320 return EFI_UNSUPPORTED;
321 }
322
323 return EFI_SUCCESS;
324}
325
338EFIAPI
340 IN EFI_HANDLE ImageHandle,
341 IN EFI_SYSTEM_TABLE *SystemTable
342 )
343{
344 EFI_STATUS Status;
345 UINT32 TimerVector;
346
347 //
348 // Initialize the pointer to our notify function.
349 //
350 mTimerNotifyFunction = NULL;
351
352 //
353 // Make sure the Timer Architectural Protocol is not already installed in the system
354 //
355 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiTimerArchProtocolGuid);
356
357 //
358 // Find the CPU architectural protocol.
359 //
360 Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&mCpu);
361 ASSERT_EFI_ERROR (Status);
362
363 //
364 // Find the Legacy8259 protocol.
365 //
366 Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **)&mLegacy8259);
367 ASSERT_EFI_ERROR (Status);
368
369 //
370 // Force the timer to be disabled
371 //
372 Status = TimerDriverSetTimerPeriod (&mTimer, 0);
373 ASSERT_EFI_ERROR (Status);
374
375 //
376 // Get the interrupt vector number corresponding to IRQ0 from the 8259 driver
377 //
378 TimerVector = 0;
379 Status = mLegacy8259->GetVector (mLegacy8259, Efi8259Irq0, (UINT8 *)&TimerVector);
380 ASSERT_EFI_ERROR (Status);
381
382 //
383 // Install interrupt handler for 8254 Timer #0 (ISA IRQ0)
384 //
385 Status = mCpu->RegisterInterruptHandler (mCpu, TimerVector, TimerInterruptHandler);
386 ASSERT_EFI_ERROR (Status);
387
388 //
389 // Force the timer to be enabled at its default period
390 //
391 Status = TimerDriverSetTimerPeriod (&mTimer, DEFAULT_TIMER_TICK_DURATION);
392 ASSERT_EFI_ERROR (Status);
393
394 //
395 // Install the Timer Architectural Protocol onto a new handle
396 //
397 Status = gBS->InstallMultipleProtocolInterfaces (
398 &mTimerHandle,
399 &gEfiTimerArchProtocolGuid,
400 &mTimer,
401 NULL
402 );
403 ASSERT_EFI_ERROR (Status);
404
405 return Status;
406}
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
UINT64 EFIAPI DivU64x32(IN UINT64 Dividend, IN UINT32 Divisor)
Definition: DivU64x32.c:29
UINT64 EFIAPI MultU64x32(IN UINT64 Multiplicand, IN UINT32 Multiplier)
Definition: MultU64x32.c:27
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:445
#define ASSERT_PROTOCOL_ALREADY_INSTALLED(Handle, Guid)
Definition: DebugLib.h:508
UINT8 EFIAPI IoWrite8(IN UINTN Port, IN UINT8 Value)
Definition: IoLibArmVirt.c:200
INTN EFI_EXCEPTION_TYPE
Definition: DebugSupport.h:35
VOID(EFIAPI * EFI_TIMER_NOTIFY)(IN UINT64 Time)
Definition: Timer.h:41
VOID EFIAPI NestedInterruptRestoreTPL(IN EFI_TPL InterruptedTPL, IN OUT EFI_SYSTEM_CONTEXT SystemContext, IN OUT NESTED_INTERRUPT_STATE *IsrState)
Definition: Tpl.c:93
EFI_TPL EFIAPI NestedInterruptRaiseTPL(VOID)
Definition: Tpl.c:29
EFI_STATUS EFIAPI TimerDriverInitialize(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
Definition: Timer.c:339
VOID SetPitCount(IN UINT16 Count)
Definition: Timer.c:59
EFI_STATUS EFIAPI TimerDriverRegisterHandler(IN EFI_TIMER_ARCH_PROTOCOL *This, IN EFI_TIMER_NOTIFY NotifyFunction)
Definition: Timer.c:131
EFI_STATUS EFIAPI TimerDriverGetTimerPeriod(IN EFI_TIMER_ARCH_PROTOCOL *This, OUT UINT64 *TimerPeriod)
Definition: Timer.c:259
EFI_STATUS EFIAPI TimerDriverSetTimerPeriod(IN EFI_TIMER_ARCH_PROTOCOL *This, IN UINT64 TimerPeriod)
Definition: Timer.c:182
EFI_STATUS EFIAPI TimerDriverGenerateSoftInterrupt(IN EFI_TIMER_ARCH_PROTOCOL *This)
Definition: Timer.c:292
VOID EFIAPI TimerInterruptHandler(IN EFI_EXCEPTION_TYPE InterruptType, IN EFI_SYSTEM_CONTEXT SystemContext)
Definition: Timer.c:76
VOID EFIAPI NotifyFunction(IN EFI_EVENT Event, IN VOID *Context)
Definition: ScsiBus.c:1492
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
UINTN EFI_TPL
Definition: UefiBaseType.h:41
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS