]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
Add DisableLvtInterrupts() for the Local APIC library class.
[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 Get the value of the local APIC version register.\r
290\r
291 @return the value of the local APIC version register.\r
292**/\r
293UINT32\r
294EFIAPI\r
295GetApicVersion (\r
296 VOID\r
297 )\r
298{\r
299 return ReadLocalApicReg (XAPIC_VERSION_OFFSET);\r
300}\r
301\r
302/**\r
303 Send a Fixed IPI to a specified target processor.\r
304\r
305 This function returns after the IPI has been accepted by the target processor. \r
306\r
307 @param ApicId The local APIC ID of the target processor.\r
308 @param Vector The vector number of the interrupt being sent.\r
309**/\r
310VOID\r
311EFIAPI\r
312SendFixedIpi (\r
313 IN UINT32 ApicId,\r
314 IN UINT8 Vector\r
315 )\r
316{\r
317 LOCAL_APIC_ICR_LOW IcrLow;\r
318\r
319 IcrLow.Uint32 = 0;\r
320 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;\r
321 IcrLow.Bits.Level = 1;\r
322 IcrLow.Bits.Vector = Vector;\r
323 SendIpi (IcrLow.Uint32, ApicId);\r
324}\r
325\r
326/**\r
327 Send a Fixed IPI to all processors excluding self.\r
328\r
329 This function returns after the IPI has been accepted by the target processors. \r
330\r
331 @param Vector The vector number of the interrupt being sent.\r
332**/\r
333VOID\r
334EFIAPI\r
335SendFixedIpiAllExcludingSelf (\r
336 IN UINT8 Vector\r
337 )\r
338{\r
339 LOCAL_APIC_ICR_LOW IcrLow;\r
340\r
341 IcrLow.Uint32 = 0;\r
342 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;\r
343 IcrLow.Bits.Level = 1;\r
344 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
345 IcrLow.Bits.Vector = Vector;\r
346 SendIpi (IcrLow.Uint32, 0);\r
347}\r
348\r
349/**\r
350 Send a SMI IPI to a specified target processor.\r
351\r
352 This function returns after the IPI has been accepted by the target processor. \r
353\r
354 @param ApicId Specify the local APIC ID of the target processor.\r
355**/\r
356VOID\r
357EFIAPI\r
358SendSmiIpi (\r
359 IN UINT32 ApicId\r
360 )\r
361{\r
362 LOCAL_APIC_ICR_LOW IcrLow;\r
363\r
364 IcrLow.Uint32 = 0;\r
365 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;\r
366 IcrLow.Bits.Level = 1;\r
367 SendIpi (IcrLow.Uint32, ApicId);\r
368}\r
369\r
370/**\r
371 Send a SMI IPI to all processors excluding self.\r
372\r
373 This function returns after the IPI has been accepted by the target processors. \r
374**/\r
375VOID\r
376EFIAPI\r
377SendSmiIpiAllExcludingSelf (\r
378 VOID\r
379 )\r
380{\r
381 LOCAL_APIC_ICR_LOW IcrLow;\r
382\r
383 IcrLow.Uint32 = 0;\r
384 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;\r
385 IcrLow.Bits.Level = 1;\r
386 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
387 SendIpi (IcrLow.Uint32, 0);\r
388}\r
389\r
390/**\r
391 Send an INIT IPI to a specified target processor.\r
392\r
393 This function returns after the IPI has been accepted by the target processor. \r
394\r
395 @param ApicId Specify the local APIC ID of the target processor.\r
396**/\r
397VOID\r
398EFIAPI\r
399SendInitIpi (\r
400 IN UINT32 ApicId\r
401 )\r
402{\r
403 LOCAL_APIC_ICR_LOW IcrLow;\r
404\r
405 IcrLow.Uint32 = 0;\r
406 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;\r
407 IcrLow.Bits.Level = 1;\r
408 SendIpi (IcrLow.Uint32, ApicId);\r
409}\r
410\r
411/**\r
412 Send an INIT IPI to all processors excluding self.\r
413\r
414 This function returns after the IPI has been accepted by the target processors. \r
415**/\r
416VOID\r
417EFIAPI\r
418SendInitIpiAllExcludingSelf (\r
419 VOID\r
420 )\r
421{\r
422 LOCAL_APIC_ICR_LOW IcrLow;\r
423\r
424 IcrLow.Uint32 = 0;\r
425 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;\r
426 IcrLow.Bits.Level = 1;\r
427 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
428 SendIpi (IcrLow.Uint32, 0);\r
429}\r
430\r
431/**\r
432 Send an INIT-Start-up-Start-up IPI sequence to a specified target processor.\r
433\r
434 This function returns after the IPI has been accepted by the target processor. \r
435\r
436 if StartupRoutine >= 1M, then ASSERT.\r
437 if StartupRoutine is not multiple of 4K, then ASSERT.\r
438\r
439 @param ApicId Specify the local APIC ID of the target processor.\r
440 @param StartupRoutine Points to a start-up routine which is below 1M physical\r
441 address and 4K aligned.\r
442**/\r
443VOID\r
444EFIAPI\r
445SendInitSipiSipi (\r
446 IN UINT32 ApicId,\r
447 IN UINT32 StartupRoutine\r
448 )\r
449{\r
450 LOCAL_APIC_ICR_LOW IcrLow;\r
451\r
452 ASSERT (StartupRoutine < 0x100000);\r
453 ASSERT ((StartupRoutine & 0xfff) == 0);\r
454\r
455 SendInitIpi (ApicId);\r
456 MicroSecondDelay (10);\r
457 IcrLow.Uint32 = 0;\r
458 IcrLow.Bits.Vector = (StartupRoutine >> 12);\r
459 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;\r
460 IcrLow.Bits.Level = 1;\r
461 SendIpi (IcrLow.Uint32, ApicId);\r
462 MicroSecondDelay (200);\r
463 SendIpi (IcrLow.Uint32, ApicId);\r
464}\r
465\r
466/**\r
467 Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self.\r
468\r
469 This function returns after the IPI has been accepted by the target processors. \r
470\r
471 if StartupRoutine >= 1M, then ASSERT.\r
472 if StartupRoutine is not multiple of 4K, then ASSERT.\r
473\r
474 @param StartupRoutine Points to a start-up routine which is below 1M physical\r
475 address and 4K aligned.\r
476**/\r
477VOID\r
478EFIAPI\r
479SendInitSipiSipiAllExcludingSelf (\r
480 IN UINT32 StartupRoutine\r
481 )\r
482{\r
483 LOCAL_APIC_ICR_LOW IcrLow;\r
484\r
485 ASSERT (StartupRoutine < 0x100000);\r
486 ASSERT ((StartupRoutine & 0xfff) == 0);\r
487\r
488 SendInitIpiAllExcludingSelf ();\r
489 MicroSecondDelay (10);\r
490 IcrLow.Uint32 = 0;\r
491 IcrLow.Bits.Vector = (StartupRoutine >> 12);\r
492 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;\r
493 IcrLow.Bits.Level = 1;\r
494 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
495 SendIpi (IcrLow.Uint32, 0);\r
496 MicroSecondDelay (200);\r
497 SendIpi (IcrLow.Uint32, 0);\r
498}\r
499\r
500/**\r
501 Programming Virtual Wire Mode.\r
502\r
503 This function programs the local APIC for virtual wire mode following\r
504 the example described in chapter A.3 of the MP 1.4 spec.\r
505\r
506 IOxAPIC is not involved in this type of virtual wire mode.\r
507**/\r
508VOID\r
509EFIAPI\r
510ProgramVirtualWireMode (\r
511 VOID\r
512 )\r
513{\r
514 LOCAL_APIC_SVR Svr;\r
515 LOCAL_APIC_LVT_LINT Lint;\r
516\r
517 //\r
518 // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.\r
519 //\r
520 Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);\r
521 Svr.Bits.SpuriousVector = 0xf;\r
522 Svr.Bits.SoftwareEnable = 1;\r
523 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);\r
524\r
525 //\r
526 // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high.\r
527 //\r
528 Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);\r
529 Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT;\r
530 Lint.Bits.InputPinPolarity = 0;\r
531 Lint.Bits.TriggerMode = 0;\r
532 Lint.Bits.Mask = 0;\r
533 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, Lint.Uint32);\r
534\r
535 //\r
536 // Program the LINT0 vector entry as NMI. Not masked, edge, active high.\r
537 //\r
538 Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);\r
539 Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI;\r
540 Lint.Bits.InputPinPolarity = 0;\r
541 Lint.Bits.TriggerMode = 0;\r
542 Lint.Bits.Mask = 0;\r
543 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32);\r
544}\r
545\r
546/**\r
547 Disable LINT0 & LINT1 interrupts.\r
548\r
549 This function sets the mask flag in the LVT LINT0 & LINT1 registers.\r
550**/\r
551VOID\r
552EFIAPI\r
553DisableLvtInterrupts (\r
554 VOID\r
555 )\r
556{\r
557 LOCAL_APIC_LVT_LINT LvtLint;\r
558\r
559 LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);\r
560 LvtLint.Bits.Mask = 1;\r
561 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, LvtLint.Uint32);\r
562\r
563 LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);\r
564 LvtLint.Bits.Mask = 1;\r
565 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, LvtLint.Uint32);\r
566}\r
567\r
568/**\r
569 Read the initial count value from the init-count register.\r
570\r
571 @return The initial count value read from the init-count register.\r
572**/\r
573UINT32\r
574EFIAPI\r
575GetApicTimerInitCount (\r
576 VOID\r
577 )\r
578{\r
579 return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET);\r
580}\r
581\r
582/**\r
583 Read the current count value from the current-count register.\r
584\r
585 @return The current count value read from the current-count register.\r
586**/\r
587UINT32\r
588EFIAPI\r
589GetApicTimerCurrentCount (\r
590 VOID\r
591 )\r
592{\r
593 return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET);\r
594}\r
595\r
596/**\r
597 Initialize the local APIC timer.\r
598\r
599 The local APIC timer is initialized and enabled.\r
600\r
601 @param DivideValue The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.\r
602 If it is 0, then use the current divide value in the DCR.\r
603 @param InitCount The initial count value.\r
604 @param PeriodicMode If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.\r
605 @param Vector The timer interrupt vector number.\r
606**/\r
607VOID\r
608EFIAPI\r
609InitializeApicTimer (\r
610 IN UINTN DivideValue,\r
611 IN UINT32 InitCount,\r
612 IN BOOLEAN PeriodicMode,\r
613 IN UINT8 Vector\r
614 )\r
615{\r
616 LOCAL_APIC_SVR Svr;\r
617 LOCAL_APIC_DCR Dcr;\r
618 LOCAL_APIC_LVT_TIMER LvtTimer;\r
619 UINT32 Divisor;\r
620\r
621 //\r
622 // Ensure local APIC is in software-enabled state.\r
623 //\r
624 Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);\r
625 Svr.Bits.SoftwareEnable = 1;\r
626 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);\r
627\r
628 //\r
629 // Program init-count register.\r
630 //\r
631 WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);\r
632\r
633 if (DivideValue != 0) {\r
634 ASSERT (DivideValue <= 128);\r
635 ASSERT (DivideValue == GetPowerOfTwo32((UINT32)DivideValue));\r
636 Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7);\r
637\r
638 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);\r
639 Dcr.Bits.DivideValue1 = (Divisor & 0x3);\r
640 Dcr.Bits.DivideValue2 = (Divisor >> 2);\r
641 WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32); \r
642 }\r
643\r
644 //\r
645 // Enable APIC timer interrupt with specified timer mode.\r
646 //\r
647 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
648 if (PeriodicMode) {\r
649 LvtTimer.Bits.TimerMode = 1;\r
650 } else {\r
651 LvtTimer.Bits.TimerMode = 0;\r
652 }\r
653 LvtTimer.Bits.Mask = 0;\r
654 LvtTimer.Bits.Vector = Vector;\r
655 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
656}\r
657\r
658/**\r
659 Get the state of the local APIC timer.\r
660\r
661 @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.\r
662 @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.\r
663 @param Vector Return the timer interrupt vector number.\r
664**/\r
665VOID\r
666EFIAPI\r
667GetApicTimerState (\r
668 OUT UINTN *DivideValue OPTIONAL,\r
669 OUT BOOLEAN *PeriodicMode OPTIONAL,\r
670 OUT UINT8 *Vector OPTIONAL\r
671 )\r
672{\r
673 UINT32 Divisor;\r
674 LOCAL_APIC_DCR Dcr;\r
675 LOCAL_APIC_LVT_TIMER LvtTimer;\r
676\r
677 if (DivideValue != NULL) {\r
678 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);\r
679 Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);\r
680 Divisor = (Divisor + 1) & 0x7;\r
681 *DivideValue = ((UINTN)1) << Divisor;\r
682 }\r
683\r
684 if (PeriodicMode != NULL || Vector != NULL) {\r
685 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
686 if (PeriodicMode != NULL) {\r
687 if (LvtTimer.Bits.TimerMode == 1) {\r
688 *PeriodicMode = TRUE;\r
689 } else {\r
690 *PeriodicMode = FALSE;\r
691 }\r
692 }\r
693 if (Vector != NULL) {\r
694 *Vector = (UINT8) LvtTimer.Bits.Vector;\r
695 }\r
696 }\r
697}\r
698\r
699/**\r
700 Enable the local APIC timer interrupt.\r
701**/\r
702VOID\r
703EFIAPI\r
704EnableApicTimerInterrupt (\r
705 VOID\r
706 )\r
707{\r
708 LOCAL_APIC_LVT_TIMER LvtTimer;\r
709\r
710 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
711 LvtTimer.Bits.Mask = 0;\r
712 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
713}\r
714\r
715/**\r
716 Disable the local APIC timer interrupt.\r
717**/\r
718VOID\r
719EFIAPI\r
720DisableApicTimerInterrupt (\r
721 VOID\r
722 )\r
723{\r
724 LOCAL_APIC_LVT_TIMER LvtTimer;\r
725\r
726 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
727 LvtTimer.Bits.Mask = 1;\r
728 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
729}\r
730\r
731/**\r
732 Get the local APIC timer interrupt state.\r
733\r
734 @retval TRUE The local APIC timer interrupt is enabled.\r
735 @retval FALSE The local APIC timer interrupt is disabled.\r
736**/\r
737BOOLEAN\r
738EFIAPI\r
739GetApicTimerInterruptState (\r
740 VOID\r
741 )\r
742{\r
743 LOCAL_APIC_LVT_TIMER LvtTimer;\r
744\r
745 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
746 return (BOOLEAN)(LvtTimer.Bits.Mask == 0);\r
747}\r
748\r
749/**\r
750 Send EOI to the local APIC.\r
751**/\r
752VOID\r
753EFIAPI\r
754SendApicEoi (\r
755 VOID\r
756 )\r
757{\r
758 WriteLocalApicReg (XAPIC_EOI_OFFSET, 0);\r
759}\r
760\r