]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
Add Local APIC Library class defining APIs for common Local APIC operations. Add...
[mirror_edk2.git] / UefiCpuPkg / Library / BaseXApicX2ApicLib / BaseXApicX2ApicLib.c
... / ...
CommitLineData
1/** @file\r
2 Local APIC Library.\r
3\r
4 This local APIC library instance supports x2APIC capable processors\r
5 which have xAPIC and x2APIC modes.\r
6\r
7 Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
8 This program and the accompanying materials\r
9 are licensed and made available under the terms and conditions of the BSD License\r
10 which accompanies this distribution. The full text of the license may be found at\r
11 http://opensource.org/licenses/bsd-license.php\r
12\r
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
15\r
16**/\r
17\r
18#include <Register/LocalApic.h>\r
19\r
20#include <Library/BaseLib.h>\r
21#include <Library/DebugLib.h>\r
22#include <Library/LocalApicLib.h>\r
23#include <Library/IoLib.h>\r
24#include <Library/TimerLib.h>\r
25#include <Library/PcdLib.h>\r
26\r
27//\r
28// Library internal functions\r
29//\r
30\r
31/**\r
32 Read from a local APIC register.\r
33\r
34 This function reads from a local APIC register either in xAPIC or x2APIC mode.\r
35 It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be\r
36 accessed using multiple 32-bit loads or stores, so this function only performs\r
37 32-bit read.\r
38\r
39 @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.\r
40 It must be 16-byte aligned.\r
41\r
42 @return 32-bit Value read from the register.\r
43**/\r
44UINT32\r
45EFIAPI\r
46ReadLocalApicReg (\r
47 IN UINTN MmioOffset\r
48 )\r
49{\r
50 UINT32 MsrIndex;\r
51\r
52 ASSERT ((MmioOffset & 0xf) == 0);\r
53\r
54 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
55 return MmioRead32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + MmioOffset);\r
56 } else {\r
57 //\r
58 // DFR is not supported in x2APIC mode.\r
59 //\r
60 ASSERT (MmioOffset != XAPIC_ICR_DFR_OFFSET);\r
61 //\r
62 // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It\r
63 // is not supported in this function for simplicity.\r
64 //\r
65 ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);\r
66\r
67 MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;\r
68 return AsmReadMsr32 (MsrIndex);\r
69 }\r
70}\r
71\r
72/**\r
73 Write to a local APIC register.\r
74\r
75 This function writes to a local APIC register either in xAPIC or x2APIC mode.\r
76 It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be\r
77 accessed using multiple 32-bit loads or stores, so this function only performs\r
78 32-bit write.\r
79\r
80 if the register index is invalid or unsupported in current APIC mode, then ASSERT.\r
81\r
82 @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.\r
83 It must be 16-byte aligned.\r
84 @param Value Value to be written to the register.\r
85**/\r
86VOID\r
87EFIAPI\r
88WriteLocalApicReg (\r
89 IN UINTN MmioOffset,\r
90 IN UINT32 Value\r
91 )\r
92{\r
93 UINT32 MsrIndex;\r
94\r
95 ASSERT ((MmioOffset & 0xf) == 0);\r
96\r
97 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
98 MmioWrite32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + MmioOffset, Value);\r
99 } else {\r
100 //\r
101 // DFR is not supported in x2APIC mode.\r
102 //\r
103 ASSERT (MmioOffset != XAPIC_ICR_DFR_OFFSET);\r
104 //\r
105 // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It\r
106 // is not supported in this function for simplicity.\r
107 //\r
108 ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);\r
109 ASSERT (MmioOffset != XAPIC_ICR_LOW_OFFSET);\r
110\r
111 MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;\r
112 //\r
113 // The serializing semantics of WRMSR are relaxed when writing to the APIC registers.\r
114 // Use memory fence here to force the serializing semantics to be consisent with xAPIC mode.\r
115 //\r
116 MemoryFence ();\r
117 AsmWriteMsr32 (MsrIndex, Value);\r
118 }\r
119}\r
120\r
121/**\r
122 Send an IPI by writing to ICR.\r
123\r
124 This function returns after the IPI has been accepted by the target processor. \r
125\r
126 @param IcrLow 32-bit value to be written to the low half of ICR.\r
127 @param ApicId APIC ID of the target processor if this IPI is targeted for a specific processor.\r
128**/\r
129VOID\r
130SendIpi (\r
131 IN UINT32 IcrLow,\r
132 IN UINT32 ApicId\r
133 )\r
134{\r
135 UINT64 MsrValue;\r
136 LOCAL_APIC_ICR_LOW IcrLowReg;\r
137\r
138 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
139 ASSERT (ApicId <= 0xff);\r
140\r
141 //\r
142 // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent.\r
143 //\r
144 MmioWrite32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + XAPIC_ICR_HIGH_OFFSET, ApicId << 24);\r
145 MmioWrite32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + XAPIC_ICR_LOW_OFFSET, IcrLow);\r
146 do {\r
147 IcrLowReg.Uint32 = MmioRead32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + XAPIC_ICR_LOW_OFFSET);\r
148 } while (IcrLowReg.Bits.DeliveryStatus != 0);\r
149 } else {\r
150 //\r
151 // For x2APIC, A single MSR write to the Interrupt Command Register is required for dispatching an \r
152 // interrupt in x2APIC mode.\r
153 //\r
154 MsrValue = (((UINT64)ApicId) << 32) | IcrLow;\r
155 AsmWriteMsr64 (X2APIC_MSR_ICR_ADDRESS, MsrValue);\r
156 }\r
157}\r
158\r
159//\r
160// Library API implementation functions\r
161//\r
162\r
163/**\r
164 Get the current local APIC mode.\r
165\r
166 If local APIC is disabled, then ASSERT.\r
167\r
168 @retval LOCAL_APIC_MODE_XAPIC current APIC mode is xAPIC.\r
169 @retval LOCAL_APIC_MODE_X2APIC current APIC mode is x2APIC.\r
170**/\r
171UINTN\r
172EFIAPI\r
173GetApicMode (\r
174 VOID\r
175 )\r
176{\r
177 MSR_IA32_APIC_BASE ApicBaseMsr;\r
178\r
179 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);\r
180 //\r
181 // Local APIC should have been enabled\r
182 //\r
183 ASSERT (ApicBaseMsr.Bits.En != 0);\r
184 if (ApicBaseMsr.Bits.Extd != 0) {\r
185 return LOCAL_APIC_MODE_X2APIC;\r
186 } else {\r
187 return LOCAL_APIC_MODE_XAPIC;\r
188 }\r
189}\r
190\r
191/**\r
192 Set the current local APIC mode.\r
193\r
194 If the specified local APIC mode is not valid, then ASSERT.\r
195 If the specified local APIC mode can't be set as current, then ASSERT.\r
196\r
197 @param ApicMode APIC mode to be set.\r
198**/\r
199VOID\r
200EFIAPI\r
201SetApicMode (\r
202 IN UINTN ApicMode\r
203 )\r
204{\r
205 UINTN CurrentMode;\r
206 MSR_IA32_APIC_BASE ApicBaseMsr;\r
207\r
208 CurrentMode = GetApicMode ();\r
209 if (CurrentMode == LOCAL_APIC_MODE_XAPIC) {\r
210 switch (ApicMode) {\r
211 case LOCAL_APIC_MODE_XAPIC:\r
212 break;\r
213 case LOCAL_APIC_MODE_X2APIC:\r
214 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);\r
215 ApicBaseMsr.Bits.Extd = 1;\r
216 AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);\r
217 break;\r
218 default:\r
219 ASSERT (FALSE);\r
220 }\r
221 } else {\r
222 switch (ApicMode) {\r
223 case LOCAL_APIC_MODE_XAPIC:\r
224 //\r
225 // Transition from x2APIC mode to xAPIC mode is a two-step process:\r
226 // x2APIC -> Local APIC disabled -> xAPIC\r
227 //\r
228 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);\r
229 ApicBaseMsr.Bits.Extd = 0;\r
230 ApicBaseMsr.Bits.En = 0;\r
231 AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);\r
232 ApicBaseMsr.Bits.En = 1;\r
233 AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);\r
234 break;\r
235 case LOCAL_APIC_MODE_X2APIC:\r
236 break;\r
237 default:\r
238 ASSERT (FALSE);\r
239 }\r
240 }\r
241}\r
242\r
243/**\r
244 Get the initial local APIC ID of the executing processor assigned by hardware upon power on or reset.\r
245\r
246 In xAPIC mode, the initial local APIC ID is 8-bit, and may be different from current APIC ID.\r
247 In x2APIC mode, the local APIC ID can't be changed and there is no concept of initial APIC ID. In this case, \r
248 the 32-bit local APIC ID is returned as initial APIC ID.\r
249\r
250 @return 32-bit initial local APIC ID of the executing processor.\r
251**/\r
252UINT32\r
253EFIAPI\r
254GetInitialApicId (\r
255 VOID\r
256 )\r
257{\r
258 UINT32 RegEbx;\r
259\r
260 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
261 AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);\r
262 return RegEbx >> 24;\r
263 } else {\r
264 return GetApicId ();\r
265 }\r
266}\r
267\r
268/**\r
269 Get the local APIC ID of the executing processor.\r
270\r
271 @return 32-bit local APIC ID of the executing processor.\r
272**/\r
273UINT32\r
274EFIAPI\r
275GetApicId (\r
276 VOID\r
277 )\r
278{\r
279 UINT32 ApicId;\r
280\r
281 ApicId = ReadLocalApicReg (XAPIC_ID_OFFSET);\r
282 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
283 ApicId >>= 24;\r
284 }\r
285 return ApicId;\r
286}\r
287\r
288/**\r
289 Send a SMI IPI to a specified target processor.\r
290\r
291 This function returns after the IPI has been accepted by the target processor. \r
292\r
293 @param ApicId Specify the local APIC ID of the target processor.\r
294**/\r
295VOID\r
296EFIAPI\r
297SendSmiIpi (\r
298 IN UINT32 ApicId\r
299 )\r
300{\r
301 LOCAL_APIC_ICR_LOW IcrLow;\r
302\r
303 IcrLow.Uint32 = 0;\r
304 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;\r
305 IcrLow.Bits.Level = 1;\r
306 SendIpi (IcrLow.Uint32, ApicId);\r
307}\r
308\r
309/**\r
310 Send a SMI IPI to all processors excluding self.\r
311\r
312 This function returns after the IPI has been accepted by the target processors. \r
313**/\r
314VOID\r
315EFIAPI\r
316SendSmiIpiAllExcludingSelf (\r
317 VOID\r
318 )\r
319{\r
320 LOCAL_APIC_ICR_LOW IcrLow;\r
321\r
322 IcrLow.Uint32 = 0;\r
323 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;\r
324 IcrLow.Bits.Level = 1;\r
325 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
326 SendIpi (IcrLow.Uint32, 0);\r
327}\r
328\r
329/**\r
330 Send an INIT IPI to a specified target processor.\r
331\r
332 This function returns after the IPI has been accepted by the target processor. \r
333\r
334 @param ApicId Specify the local APIC ID of the target processor.\r
335**/\r
336VOID\r
337EFIAPI\r
338SendInitIpi (\r
339 IN UINT32 ApicId\r
340 )\r
341{\r
342 LOCAL_APIC_ICR_LOW IcrLow;\r
343\r
344 IcrLow.Uint32 = 0;\r
345 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;\r
346 IcrLow.Bits.Level = 1;\r
347 SendIpi (IcrLow.Uint32, ApicId);\r
348}\r
349\r
350/**\r
351 Send an INIT IPI to all processors excluding self.\r
352\r
353 This function returns after the IPI has been accepted by the target processors. \r
354**/\r
355VOID\r
356EFIAPI\r
357SendInitIpiAllExcludingSelf (\r
358 VOID\r
359 )\r
360{\r
361 LOCAL_APIC_ICR_LOW IcrLow;\r
362\r
363 IcrLow.Uint32 = 0;\r
364 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;\r
365 IcrLow.Bits.Level = 1;\r
366 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
367 SendIpi (IcrLow.Uint32, 0);\r
368}\r
369\r
370/**\r
371 Send an INIT-Start-up-Start-up IPI sequence to a specified target processor.\r
372\r
373 This function returns after the IPI has been accepted by the target processor. \r
374\r
375 if StartupRoutine >= 1M, then ASSERT.\r
376 if StartupRoutine is not multiple of 4K, then ASSERT.\r
377\r
378 @param ApicId Specify the local APIC ID of the target processor.\r
379 @param StartupRoutine Points to a start-up routine which is below 1M physical\r
380 address and 4K aligned.\r
381**/\r
382VOID\r
383EFIAPI\r
384SendInitSipiSipi (\r
385 IN UINT32 ApicId,\r
386 IN UINT32 StartupRoutine\r
387 )\r
388{\r
389 LOCAL_APIC_ICR_LOW IcrLow;\r
390\r
391 ASSERT (StartupRoutine < 0x100000);\r
392 ASSERT ((StartupRoutine & 0xfff) == 0);\r
393\r
394 SendInitIpi (ApicId);\r
395 MicroSecondDelay (10);\r
396 IcrLow.Uint32 = 0;\r
397 IcrLow.Bits.Vector = (StartupRoutine >> 12);\r
398 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;\r
399 IcrLow.Bits.Level = 1;\r
400 SendIpi (IcrLow.Uint32, ApicId);\r
401 MicroSecondDelay (200);\r
402 SendIpi (IcrLow.Uint32, ApicId);\r
403}\r
404\r
405/**\r
406 Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self.\r
407\r
408 This function returns after the IPI has been accepted by the target processors. \r
409\r
410 if StartupRoutine >= 1M, then ASSERT.\r
411 if StartupRoutine is not multiple of 4K, then ASSERT.\r
412\r
413 @param StartupRoutine Points to a start-up routine which is below 1M physical\r
414 address and 4K aligned.\r
415**/\r
416VOID\r
417EFIAPI\r
418SendInitSipiSipiAllExcludingSelf (\r
419 IN UINT32 StartupRoutine\r
420 )\r
421{\r
422 LOCAL_APIC_ICR_LOW IcrLow;\r
423\r
424 ASSERT (StartupRoutine < 0x100000);\r
425 ASSERT ((StartupRoutine & 0xfff) == 0);\r
426\r
427 SendInitIpiAllExcludingSelf ();\r
428 MicroSecondDelay (10);\r
429 IcrLow.Uint32 = 0;\r
430 IcrLow.Bits.Vector = (StartupRoutine >> 12);\r
431 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;\r
432 IcrLow.Bits.Level = 1;\r
433 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
434 SendIpi (IcrLow.Uint32, 0);\r
435 MicroSecondDelay (200);\r
436 SendIpi (IcrLow.Uint32, 0);\r
437}\r
438\r
439/**\r
440 Programming Virtual Wire Mode.\r
441\r
442 This function programs the local APIC for virtual wire mode following\r
443 the example described in chapter A.3 of the MP 1.4 spec.\r
444\r
445 IOxAPIC is not involved in this type of virtual wire mode.\r
446**/\r
447VOID\r
448EFIAPI\r
449ProgramVirtualWireMode (\r
450 VOID\r
451 )\r
452{\r
453 LOCAL_APIC_SVR Svr;\r
454 LOCAL_APIC_LVT_LINT Lint;\r
455\r
456 //\r
457 // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.\r
458 //\r
459 Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);\r
460 Svr.Bits.SpuriousVector = 0xf;\r
461 Svr.Bits.SoftwareEnable = 1;\r
462 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);\r
463\r
464 //\r
465 // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high.\r
466 //\r
467 Lint.Uint32 = ReadLocalApicReg (XAPIC_LINT0_VECTOR_OFFSET);\r
468 Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT;\r
469 Lint.Bits.InputPinPolarity = 0;\r
470 Lint.Bits.TriggerMode = 0;\r
471 Lint.Bits.Mask = 0;\r
472 WriteLocalApicReg (XAPIC_LINT0_VECTOR_OFFSET, Lint.Uint32);\r
473\r
474 //\r
475 // Program the LINT0 vector entry as NMI. Not masked, edge, active high.\r
476 //\r
477 Lint.Uint32 = ReadLocalApicReg (XAPIC_LINT1_VECTOR_OFFSET);\r
478 Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI;\r
479 Lint.Bits.InputPinPolarity = 0;\r
480 Lint.Bits.TriggerMode = 0;\r
481 Lint.Bits.Mask = 0;\r
482 WriteLocalApicReg (XAPIC_LINT1_VECTOR_OFFSET, Lint.Uint32);\r
483}\r
484\r
485/**\r
486 Get the divide value from the DCR (Divide Configuration Register) by which\r
487 the processor's bus clock is divided to form the time base for the APIC timer.\r
488\r
489 @return The divide value is one of 1,2,4,8,16,32,64,128.\r
490**/\r
491UINTN\r
492EFIAPI\r
493GetApicTimerDivisor (\r
494 VOID\r
495 )\r
496{\r
497 UINT32 DivideValue;\r
498 LOCAL_APIC_DCR Dcr;\r
499\r
500 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);\r
501 DivideValue = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);\r
502 DivideValue = (DivideValue + 1) & 0x7;\r
503 return ((UINTN)1) << DivideValue;\r
504}\r
505\r
506/**\r
507 Read the initial count value from the init-count register.\r
508\r
509 @return The initial count value read from the init-count register.\r
510**/\r
511UINT32\r
512EFIAPI\r
513GetApicTimerInitCount (\r
514 VOID\r
515 )\r
516{\r
517 return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET);\r
518}\r
519\r
520/**\r
521 Read the current count value from the current-count register.\r
522\r
523 @return The current count value read from the current-count register.\r
524**/\r
525UINT32\r
526EFIAPI\r
527GetApicTimerCurrentCount (\r
528 VOID\r
529 )\r
530{\r
531 return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET);\r
532}\r
533\r
534/**\r
535 Initialize the local APIC timer.\r
536\r
537 The local APIC timer is initialized and enabled.\r
538\r
539 @param DivideValue The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.\r
540 If it is 0, then use the current divide value in the DCR.\r
541 @param InitCount The initial count value.\r
542 @param PeriodicMode If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.\r
543 @param Vector The timer interrupt vector number.\r
544**/\r
545VOID\r
546EFIAPI\r
547InitializeApicTimer (\r
548 IN UINTN DivideValue,\r
549 IN UINT32 InitCount,\r
550 IN BOOLEAN PeriodicMode,\r
551 IN UINT8 Vector\r
552 )\r
553{\r
554 LOCAL_APIC_SVR Svr;\r
555 LOCAL_APIC_DCR Dcr;\r
556 LOCAL_APIC_LVT_TIMER LvtTimer;\r
557 UINT32 Divisor;\r
558\r
559 //\r
560 // Ensure local APIC is in software-enabled state.\r
561 //\r
562 Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);\r
563 Svr.Bits.SoftwareEnable = 1;\r
564 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);\r
565\r
566 //\r
567 // Program init-count register.\r
568 //\r
569 WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);\r
570\r
571 if (DivideValue != 0) {\r
572 ASSERT (DivideValue <= 128);\r
573 ASSERT (DivideValue == GetPowerOfTwo32((UINT32)DivideValue));\r
574 Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7);\r
575\r
576 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);\r
577 Dcr.Bits.DivideValue1 = (Divisor & 0x3);\r
578 Dcr.Bits.DivideValue2 = (Divisor >> 2);\r
579 WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32); \r
580 }\r
581\r
582 //\r
583 // Enable APIC timer interrupt with specified timer mode.\r
584 //\r
585 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
586 if (PeriodicMode) {\r
587 LvtTimer.Bits.TimerMode = 1;\r
588 } else {\r
589 LvtTimer.Bits.TimerMode = 0;\r
590 }\r
591 LvtTimer.Bits.Mask = 0;\r
592 LvtTimer.Bits.Vector = Vector;\r
593 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
594}\r
595\r
596/**\r
597 Enable the local APIC timer interrupt.\r
598**/\r
599VOID\r
600EFIAPI\r
601EnableApicTimerInterrupt (\r
602 VOID\r
603 )\r
604{\r
605 LOCAL_APIC_LVT_TIMER LvtTimer;\r
606\r
607 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
608 LvtTimer.Bits.Mask = 0;\r
609 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
610}\r
611\r
612/**\r
613 Disable the local APIC timer interrupt.\r
614**/\r
615VOID\r
616EFIAPI\r
617DisableApicTimerInterrupt (\r
618 VOID\r
619 )\r
620{\r
621 LOCAL_APIC_LVT_TIMER LvtTimer;\r
622\r
623 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
624 LvtTimer.Bits.Mask = 1;\r
625 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
626}\r
627\r
628/**\r
629 Get the local APIC timer interrupt state.\r
630\r
631 @retval TRUE The local APIC timer interrupt is enabled.\r
632 @retval FALSE The local APIC timer interrupt is disabled.\r
633**/\r
634BOOLEAN\r
635EFIAPI\r
636GetApicTimerInterruptState (\r
637 VOID\r
638 )\r
639{\r
640 LOCAL_APIC_LVT_TIMER LvtTimer;\r
641\r
642 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
643 return (BOOLEAN)(LvtTimer.Bits.Mask == 0);\r
644}\r
645\r
646/**\r
647 Send EOI to the local APIC.\r
648**/\r
649VOID\r
650EFIAPI\r
651SendApicEoi (\r
652 VOID\r
653 )\r
654{\r
655 WriteLocalApicReg (XAPIC_EOI_OFFSET, 0);\r
656}\r
657\r