]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
1. Added SetLocalApicBaseAdress() and GetLocalApicBaseAddress() APIs in Local APIC...
[mirror_edk2.git] / UefiCpuPkg / Library / BaseXApicX2ApicLib / BaseXApicX2ApicLib.c
CommitLineData
bf73cc4b 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
a66e0c7d 7 Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>\r
bf73cc4b 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
bf73cc4b 25\r
26//\r
27// Library internal functions\r
28//\r
29\r
a66e0c7d 30/**\r
31 Retrieve the base address of local APIC.\r
32\r
33 @return The base address of local APIC.\r
34\r
35**/\r
36UINTN\r
37EFIAPI\r
38GetLocalApicBaseAddress (\r
39 VOID\r
40 )\r
41{\r
42 MSR_IA32_APIC_BASE ApicBaseMsr;\r
43 \r
44 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);\r
45 \r
46 return (UINTN)(LShiftU64 ((UINT64) ApicBaseMsr.Bits.ApicBaseHigh, 32)) +\r
47 (((UINTN)ApicBaseMsr.Bits.ApicBaseLow) << 12);\r
48}\r
49\r
50/**\r
51 Set the base address of local APIC.\r
52\r
53 If BaseAddress is not aligned on a 4KB boundary, then ASSERT().\r
54\r
55 @param[in] BaseAddress Local APIC base address to be set.\r
56\r
57**/\r
58VOID\r
59EFIAPI\r
60SetLocalApicBaseAddress (\r
61 IN UINTN BaseAddress\r
62 )\r
63{\r
64 MSR_IA32_APIC_BASE ApicBaseMsr;\r
65\r
66 ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);\r
67\r
68 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);\r
69\r
70 ApicBaseMsr.Bits.ApicBaseLow = (UINT32) (BaseAddress >> 12);\r
71 ApicBaseMsr.Bits.ApicBaseHigh = (UINT32) (RShiftU64((UINT64) BaseAddress, 32));\r
72\r
73 AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);\r
74}\r
75\r
bf73cc4b 76/**\r
77 Read from a local APIC register.\r
78\r
79 This function reads from a local APIC register either in xAPIC or x2APIC mode.\r
80 It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be\r
81 accessed using multiple 32-bit loads or stores, so this function only performs\r
82 32-bit read.\r
83\r
84 @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.\r
85 It must be 16-byte aligned.\r
86\r
87 @return 32-bit Value read from the register.\r
88**/\r
89UINT32\r
90EFIAPI\r
91ReadLocalApicReg (\r
92 IN UINTN MmioOffset\r
93 )\r
94{\r
95 UINT32 MsrIndex;\r
96\r
97 ASSERT ((MmioOffset & 0xf) == 0);\r
98\r
99 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
a66e0c7d 100 return MmioRead32 (GetLocalApicBaseAddress() + MmioOffset);\r
bf73cc4b 101 } else {\r
102 //\r
103 // DFR is not supported in x2APIC mode.\r
104 //\r
105 ASSERT (MmioOffset != XAPIC_ICR_DFR_OFFSET);\r
106 //\r
107 // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It\r
108 // is not supported in this function for simplicity.\r
109 //\r
110 ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);\r
111\r
112 MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;\r
113 return AsmReadMsr32 (MsrIndex);\r
114 }\r
115}\r
116\r
117/**\r
118 Write to a local APIC register.\r
119\r
120 This function writes to a local APIC register either in xAPIC or x2APIC mode.\r
121 It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be\r
122 accessed using multiple 32-bit loads or stores, so this function only performs\r
123 32-bit write.\r
124\r
125 if the register index is invalid or unsupported in current APIC mode, then ASSERT.\r
126\r
127 @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.\r
128 It must be 16-byte aligned.\r
129 @param Value Value to be written to the register.\r
130**/\r
131VOID\r
132EFIAPI\r
133WriteLocalApicReg (\r
134 IN UINTN MmioOffset,\r
135 IN UINT32 Value\r
136 )\r
137{\r
138 UINT32 MsrIndex;\r
139\r
140 ASSERT ((MmioOffset & 0xf) == 0);\r
141\r
142 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
a66e0c7d 143 MmioWrite32 (GetLocalApicBaseAddress() + MmioOffset, Value);\r
bf73cc4b 144 } else {\r
145 //\r
146 // DFR is not supported in x2APIC mode.\r
147 //\r
148 ASSERT (MmioOffset != XAPIC_ICR_DFR_OFFSET);\r
149 //\r
150 // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It\r
151 // is not supported in this function for simplicity.\r
152 //\r
153 ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);\r
154 ASSERT (MmioOffset != XAPIC_ICR_LOW_OFFSET);\r
155\r
156 MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;\r
157 //\r
158 // The serializing semantics of WRMSR are relaxed when writing to the APIC registers.\r
159 // Use memory fence here to force the serializing semantics to be consisent with xAPIC mode.\r
160 //\r
161 MemoryFence ();\r
162 AsmWriteMsr32 (MsrIndex, Value);\r
163 }\r
164}\r
165\r
166/**\r
167 Send an IPI by writing to ICR.\r
168\r
169 This function returns after the IPI has been accepted by the target processor. \r
170\r
171 @param IcrLow 32-bit value to be written to the low half of ICR.\r
172 @param ApicId APIC ID of the target processor if this IPI is targeted for a specific processor.\r
173**/\r
174VOID\r
175SendIpi (\r
176 IN UINT32 IcrLow,\r
177 IN UINT32 ApicId\r
178 )\r
179{\r
180 UINT64 MsrValue;\r
181 LOCAL_APIC_ICR_LOW IcrLowReg;\r
a66e0c7d 182 UINTN LocalApciBaseAddress;\r
bf73cc4b 183\r
184 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
185 ASSERT (ApicId <= 0xff);\r
186\r
187 //\r
188 // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent.\r
189 //\r
a66e0c7d 190 LocalApciBaseAddress = GetLocalApicBaseAddress();\r
191 MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET, ApicId << 24);\r
192 MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET, IcrLow);\r
bf73cc4b 193 do {\r
a66e0c7d 194 IcrLowReg.Uint32 = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET);\r
bf73cc4b 195 } while (IcrLowReg.Bits.DeliveryStatus != 0);\r
196 } else {\r
197 //\r
198 // For x2APIC, A single MSR write to the Interrupt Command Register is required for dispatching an \r
199 // interrupt in x2APIC mode.\r
200 //\r
23394428 201 MsrValue = LShiftU64 ((UINT64) ApicId, 32) | IcrLow;\r
bf73cc4b 202 AsmWriteMsr64 (X2APIC_MSR_ICR_ADDRESS, MsrValue);\r
203 }\r
204}\r
205\r
206//\r
207// Library API implementation functions\r
208//\r
209\r
210/**\r
211 Get the current local APIC mode.\r
212\r
213 If local APIC is disabled, then ASSERT.\r
214\r
215 @retval LOCAL_APIC_MODE_XAPIC current APIC mode is xAPIC.\r
216 @retval LOCAL_APIC_MODE_X2APIC current APIC mode is x2APIC.\r
217**/\r
218UINTN\r
219EFIAPI\r
220GetApicMode (\r
221 VOID\r
222 )\r
223{\r
224 MSR_IA32_APIC_BASE ApicBaseMsr;\r
225\r
226 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);\r
227 //\r
228 // Local APIC should have been enabled\r
229 //\r
230 ASSERT (ApicBaseMsr.Bits.En != 0);\r
231 if (ApicBaseMsr.Bits.Extd != 0) {\r
232 return LOCAL_APIC_MODE_X2APIC;\r
233 } else {\r
234 return LOCAL_APIC_MODE_XAPIC;\r
235 }\r
236}\r
237\r
238/**\r
239 Set the current local APIC mode.\r
240\r
241 If the specified local APIC mode is not valid, then ASSERT.\r
242 If the specified local APIC mode can't be set as current, then ASSERT.\r
243\r
244 @param ApicMode APIC mode to be set.\r
245**/\r
246VOID\r
247EFIAPI\r
248SetApicMode (\r
249 IN UINTN ApicMode\r
250 )\r
251{\r
252 UINTN CurrentMode;\r
253 MSR_IA32_APIC_BASE ApicBaseMsr;\r
254\r
255 CurrentMode = GetApicMode ();\r
256 if (CurrentMode == LOCAL_APIC_MODE_XAPIC) {\r
257 switch (ApicMode) {\r
258 case LOCAL_APIC_MODE_XAPIC:\r
259 break;\r
260 case LOCAL_APIC_MODE_X2APIC:\r
261 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);\r
262 ApicBaseMsr.Bits.Extd = 1;\r
263 AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);\r
264 break;\r
265 default:\r
266 ASSERT (FALSE);\r
267 }\r
268 } else {\r
269 switch (ApicMode) {\r
270 case LOCAL_APIC_MODE_XAPIC:\r
271 //\r
272 // Transition from x2APIC mode to xAPIC mode is a two-step process:\r
273 // x2APIC -> Local APIC disabled -> xAPIC\r
274 //\r
275 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);\r
276 ApicBaseMsr.Bits.Extd = 0;\r
277 ApicBaseMsr.Bits.En = 0;\r
278 AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);\r
279 ApicBaseMsr.Bits.En = 1;\r
280 AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);\r
281 break;\r
282 case LOCAL_APIC_MODE_X2APIC:\r
283 break;\r
284 default:\r
285 ASSERT (FALSE);\r
286 }\r
287 }\r
288}\r
289\r
290/**\r
291 Get the initial local APIC ID of the executing processor assigned by hardware upon power on or reset.\r
292\r
293 In xAPIC mode, the initial local APIC ID is 8-bit, and may be different from current APIC ID.\r
294 In x2APIC mode, the local APIC ID can't be changed and there is no concept of initial APIC ID. In this case, \r
295 the 32-bit local APIC ID is returned as initial APIC ID.\r
296\r
297 @return 32-bit initial local APIC ID of the executing processor.\r
298**/\r
299UINT32\r
300EFIAPI\r
301GetInitialApicId (\r
302 VOID\r
303 )\r
304{\r
305 UINT32 RegEbx;\r
306\r
307 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
308 AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);\r
309 return RegEbx >> 24;\r
310 } else {\r
311 return GetApicId ();\r
312 }\r
313}\r
314\r
315/**\r
316 Get the local APIC ID of the executing processor.\r
317\r
318 @return 32-bit local APIC ID of the executing processor.\r
319**/\r
320UINT32\r
321EFIAPI\r
322GetApicId (\r
323 VOID\r
324 )\r
325{\r
326 UINT32 ApicId;\r
327\r
328 ApicId = ReadLocalApicReg (XAPIC_ID_OFFSET);\r
329 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
330 ApicId >>= 24;\r
331 }\r
332 return ApicId;\r
333}\r
334\r
ae40aef1 335/**\r
336 Get the value of the local APIC version register.\r
337\r
338 @return the value of the local APIC version register.\r
339**/\r
340UINT32\r
341EFIAPI\r
342GetApicVersion (\r
343 VOID\r
344 )\r
345{\r
346 return ReadLocalApicReg (XAPIC_VERSION_OFFSET);\r
347}\r
348\r
349/**\r
350 Send a Fixed 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 The local APIC ID of the target processor.\r
355 @param Vector The vector number of the interrupt being sent.\r
356**/\r
357VOID\r
358EFIAPI\r
359SendFixedIpi (\r
360 IN UINT32 ApicId,\r
361 IN UINT8 Vector\r
362 )\r
363{\r
364 LOCAL_APIC_ICR_LOW IcrLow;\r
365\r
366 IcrLow.Uint32 = 0;\r
367 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;\r
368 IcrLow.Bits.Level = 1;\r
369 IcrLow.Bits.Vector = Vector;\r
370 SendIpi (IcrLow.Uint32, ApicId);\r
371}\r
372\r
373/**\r
374 Send a Fixed IPI to all processors excluding self.\r
375\r
376 This function returns after the IPI has been accepted by the target processors. \r
377\r
378 @param Vector The vector number of the interrupt being sent.\r
379**/\r
380VOID\r
381EFIAPI\r
382SendFixedIpiAllExcludingSelf (\r
383 IN UINT8 Vector\r
384 )\r
385{\r
386 LOCAL_APIC_ICR_LOW IcrLow;\r
387\r
388 IcrLow.Uint32 = 0;\r
389 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;\r
390 IcrLow.Bits.Level = 1;\r
391 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
392 IcrLow.Bits.Vector = Vector;\r
393 SendIpi (IcrLow.Uint32, 0);\r
394}\r
395\r
bf73cc4b 396/**\r
397 Send a SMI IPI to a specified target processor.\r
398\r
399 This function returns after the IPI has been accepted by the target processor. \r
400\r
401 @param ApicId Specify the local APIC ID of the target processor.\r
402**/\r
403VOID\r
404EFIAPI\r
405SendSmiIpi (\r
406 IN UINT32 ApicId\r
407 )\r
408{\r
409 LOCAL_APIC_ICR_LOW IcrLow;\r
410\r
411 IcrLow.Uint32 = 0;\r
412 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;\r
413 IcrLow.Bits.Level = 1;\r
414 SendIpi (IcrLow.Uint32, ApicId);\r
415}\r
416\r
417/**\r
418 Send a SMI IPI to all processors excluding self.\r
419\r
420 This function returns after the IPI has been accepted by the target processors. \r
421**/\r
422VOID\r
423EFIAPI\r
424SendSmiIpiAllExcludingSelf (\r
425 VOID\r
426 )\r
427{\r
428 LOCAL_APIC_ICR_LOW IcrLow;\r
429\r
430 IcrLow.Uint32 = 0;\r
431 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;\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}\r
436\r
437/**\r
438 Send an INIT IPI to a specified target processor.\r
439\r
440 This function returns after the IPI has been accepted by the target processor. \r
441\r
442 @param ApicId Specify the local APIC ID of the target processor.\r
443**/\r
444VOID\r
445EFIAPI\r
446SendInitIpi (\r
447 IN UINT32 ApicId\r
448 )\r
449{\r
450 LOCAL_APIC_ICR_LOW IcrLow;\r
451\r
452 IcrLow.Uint32 = 0;\r
453 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;\r
454 IcrLow.Bits.Level = 1;\r
455 SendIpi (IcrLow.Uint32, ApicId);\r
456}\r
457\r
458/**\r
459 Send an INIT IPI to all processors excluding self.\r
460\r
461 This function returns after the IPI has been accepted by the target processors. \r
462**/\r
463VOID\r
464EFIAPI\r
465SendInitIpiAllExcludingSelf (\r
466 VOID\r
467 )\r
468{\r
469 LOCAL_APIC_ICR_LOW IcrLow;\r
470\r
471 IcrLow.Uint32 = 0;\r
472 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;\r
473 IcrLow.Bits.Level = 1;\r
474 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
475 SendIpi (IcrLow.Uint32, 0);\r
476}\r
477\r
478/**\r
479 Send an INIT-Start-up-Start-up IPI sequence to a specified target processor.\r
480\r
481 This function returns after the IPI has been accepted by the target processor. \r
482\r
483 if StartupRoutine >= 1M, then ASSERT.\r
484 if StartupRoutine is not multiple of 4K, then ASSERT.\r
485\r
486 @param ApicId Specify the local APIC ID of the target processor.\r
487 @param StartupRoutine Points to a start-up routine which is below 1M physical\r
488 address and 4K aligned.\r
489**/\r
490VOID\r
491EFIAPI\r
492SendInitSipiSipi (\r
493 IN UINT32 ApicId,\r
494 IN UINT32 StartupRoutine\r
495 )\r
496{\r
497 LOCAL_APIC_ICR_LOW IcrLow;\r
498\r
499 ASSERT (StartupRoutine < 0x100000);\r
500 ASSERT ((StartupRoutine & 0xfff) == 0);\r
501\r
502 SendInitIpi (ApicId);\r
503 MicroSecondDelay (10);\r
504 IcrLow.Uint32 = 0;\r
505 IcrLow.Bits.Vector = (StartupRoutine >> 12);\r
506 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;\r
507 IcrLow.Bits.Level = 1;\r
508 SendIpi (IcrLow.Uint32, ApicId);\r
509 MicroSecondDelay (200);\r
510 SendIpi (IcrLow.Uint32, ApicId);\r
511}\r
512\r
513/**\r
514 Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self.\r
515\r
516 This function returns after the IPI has been accepted by the target processors. \r
517\r
518 if StartupRoutine >= 1M, then ASSERT.\r
519 if StartupRoutine is not multiple of 4K, then ASSERT.\r
520\r
521 @param StartupRoutine Points to a start-up routine which is below 1M physical\r
522 address and 4K aligned.\r
523**/\r
524VOID\r
525EFIAPI\r
526SendInitSipiSipiAllExcludingSelf (\r
527 IN UINT32 StartupRoutine\r
528 )\r
529{\r
530 LOCAL_APIC_ICR_LOW IcrLow;\r
531\r
532 ASSERT (StartupRoutine < 0x100000);\r
533 ASSERT ((StartupRoutine & 0xfff) == 0);\r
534\r
535 SendInitIpiAllExcludingSelf ();\r
536 MicroSecondDelay (10);\r
537 IcrLow.Uint32 = 0;\r
538 IcrLow.Bits.Vector = (StartupRoutine >> 12);\r
539 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;\r
540 IcrLow.Bits.Level = 1;\r
541 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
542 SendIpi (IcrLow.Uint32, 0);\r
543 MicroSecondDelay (200);\r
544 SendIpi (IcrLow.Uint32, 0);\r
545}\r
546\r
547/**\r
548 Programming Virtual Wire Mode.\r
549\r
550 This function programs the local APIC for virtual wire mode following\r
551 the example described in chapter A.3 of the MP 1.4 spec.\r
552\r
553 IOxAPIC is not involved in this type of virtual wire mode.\r
554**/\r
555VOID\r
556EFIAPI\r
557ProgramVirtualWireMode (\r
558 VOID\r
559 )\r
560{\r
561 LOCAL_APIC_SVR Svr;\r
562 LOCAL_APIC_LVT_LINT Lint;\r
563\r
564 //\r
565 // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.\r
566 //\r
567 Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);\r
568 Svr.Bits.SpuriousVector = 0xf;\r
569 Svr.Bits.SoftwareEnable = 1;\r
570 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);\r
571\r
572 //\r
573 // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high.\r
574 //\r
ae40aef1 575 Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);\r
bf73cc4b 576 Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT;\r
577 Lint.Bits.InputPinPolarity = 0;\r
578 Lint.Bits.TriggerMode = 0;\r
579 Lint.Bits.Mask = 0;\r
ae40aef1 580 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, Lint.Uint32);\r
bf73cc4b 581\r
582 //\r
583 // Program the LINT0 vector entry as NMI. Not masked, edge, active high.\r
584 //\r
ae40aef1 585 Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);\r
bf73cc4b 586 Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI;\r
587 Lint.Bits.InputPinPolarity = 0;\r
588 Lint.Bits.TriggerMode = 0;\r
589 Lint.Bits.Mask = 0;\r
ae40aef1 590 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32);\r
bf73cc4b 591}\r
592\r
b1b8c631 593/**\r
594 Disable LINT0 & LINT1 interrupts.\r
595\r
596 This function sets the mask flag in the LVT LINT0 & LINT1 registers.\r
597**/\r
598VOID\r
599EFIAPI\r
600DisableLvtInterrupts (\r
601 VOID\r
602 )\r
603{\r
604 LOCAL_APIC_LVT_LINT LvtLint;\r
605\r
606 LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);\r
607 LvtLint.Bits.Mask = 1;\r
608 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, LvtLint.Uint32);\r
609\r
610 LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);\r
611 LvtLint.Bits.Mask = 1;\r
612 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, LvtLint.Uint32);\r
613}\r
614\r
bf73cc4b 615/**\r
616 Read the initial count value from the init-count register.\r
617\r
618 @return The initial count value read from the init-count register.\r
619**/\r
620UINT32\r
621EFIAPI\r
622GetApicTimerInitCount (\r
623 VOID\r
624 )\r
625{\r
626 return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET);\r
627}\r
628\r
629/**\r
630 Read the current count value from the current-count register.\r
631\r
632 @return The current count value read from the current-count register.\r
633**/\r
634UINT32\r
635EFIAPI\r
636GetApicTimerCurrentCount (\r
637 VOID\r
638 )\r
639{\r
640 return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET);\r
641}\r
642\r
643/**\r
644 Initialize the local APIC timer.\r
645\r
646 The local APIC timer is initialized and enabled.\r
647\r
648 @param DivideValue The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.\r
649 If it is 0, then use the current divide value in the DCR.\r
650 @param InitCount The initial count value.\r
651 @param PeriodicMode If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.\r
652 @param Vector The timer interrupt vector number.\r
653**/\r
654VOID\r
655EFIAPI\r
656InitializeApicTimer (\r
657 IN UINTN DivideValue,\r
658 IN UINT32 InitCount,\r
659 IN BOOLEAN PeriodicMode,\r
660 IN UINT8 Vector\r
661 )\r
662{\r
663 LOCAL_APIC_SVR Svr;\r
664 LOCAL_APIC_DCR Dcr;\r
665 LOCAL_APIC_LVT_TIMER LvtTimer;\r
666 UINT32 Divisor;\r
667\r
668 //\r
669 // Ensure local APIC is in software-enabled state.\r
670 //\r
671 Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);\r
672 Svr.Bits.SoftwareEnable = 1;\r
673 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);\r
674\r
675 //\r
676 // Program init-count register.\r
677 //\r
678 WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);\r
679\r
680 if (DivideValue != 0) {\r
681 ASSERT (DivideValue <= 128);\r
682 ASSERT (DivideValue == GetPowerOfTwo32((UINT32)DivideValue));\r
683 Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7);\r
684\r
685 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);\r
686 Dcr.Bits.DivideValue1 = (Divisor & 0x3);\r
687 Dcr.Bits.DivideValue2 = (Divisor >> 2);\r
688 WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32); \r
689 }\r
690\r
691 //\r
692 // Enable APIC timer interrupt with specified timer mode.\r
693 //\r
694 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
695 if (PeriodicMode) {\r
696 LvtTimer.Bits.TimerMode = 1;\r
697 } else {\r
698 LvtTimer.Bits.TimerMode = 0;\r
699 }\r
700 LvtTimer.Bits.Mask = 0;\r
701 LvtTimer.Bits.Vector = Vector;\r
702 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
703}\r
704\r
ae40aef1 705/**\r
706 Get the state of the local APIC timer.\r
707\r
708 @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.\r
709 @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.\r
710 @param Vector Return the timer interrupt vector number.\r
711**/\r
712VOID\r
713EFIAPI\r
714GetApicTimerState (\r
715 OUT UINTN *DivideValue OPTIONAL,\r
716 OUT BOOLEAN *PeriodicMode OPTIONAL,\r
717 OUT UINT8 *Vector OPTIONAL\r
718 )\r
719{\r
720 UINT32 Divisor;\r
721 LOCAL_APIC_DCR Dcr;\r
722 LOCAL_APIC_LVT_TIMER LvtTimer;\r
723\r
724 if (DivideValue != NULL) {\r
725 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);\r
726 Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);\r
727 Divisor = (Divisor + 1) & 0x7;\r
728 *DivideValue = ((UINTN)1) << Divisor;\r
729 }\r
730\r
731 if (PeriodicMode != NULL || Vector != NULL) {\r
732 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
733 if (PeriodicMode != NULL) {\r
734 if (LvtTimer.Bits.TimerMode == 1) {\r
735 *PeriodicMode = TRUE;\r
736 } else {\r
737 *PeriodicMode = FALSE;\r
738 }\r
739 }\r
740 if (Vector != NULL) {\r
741 *Vector = (UINT8) LvtTimer.Bits.Vector;\r
742 }\r
743 }\r
744}\r
745\r
bf73cc4b 746/**\r
747 Enable the local APIC timer interrupt.\r
748**/\r
749VOID\r
750EFIAPI\r
751EnableApicTimerInterrupt (\r
752 VOID\r
753 )\r
754{\r
755 LOCAL_APIC_LVT_TIMER LvtTimer;\r
756\r
757 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
758 LvtTimer.Bits.Mask = 0;\r
759 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
760}\r
761\r
762/**\r
763 Disable the local APIC timer interrupt.\r
764**/\r
765VOID\r
766EFIAPI\r
767DisableApicTimerInterrupt (\r
768 VOID\r
769 )\r
770{\r
771 LOCAL_APIC_LVT_TIMER LvtTimer;\r
772\r
773 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
774 LvtTimer.Bits.Mask = 1;\r
775 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
776}\r
777\r
778/**\r
779 Get the local APIC timer interrupt state.\r
780\r
781 @retval TRUE The local APIC timer interrupt is enabled.\r
782 @retval FALSE The local APIC timer interrupt is disabled.\r
783**/\r
784BOOLEAN\r
785EFIAPI\r
786GetApicTimerInterruptState (\r
787 VOID\r
788 )\r
789{\r
790 LOCAL_APIC_LVT_TIMER LvtTimer;\r
791\r
792 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
793 return (BOOLEAN)(LvtTimer.Bits.Mask == 0);\r
794}\r
795\r
796/**\r
797 Send EOI to the local APIC.\r
798**/\r
799VOID\r
800EFIAPI\r
801SendApicEoi (\r
802 VOID\r
803 )\r
804{\r
805 WriteLocalApicReg (XAPIC_EOI_OFFSET, 0);\r
806}\r
807\r
5f867ad0 808/**\r
809 Get the 32-bit address that a device should use to send a Message Signaled \r
810 Interrupt (MSI) to the Local APIC of the currently executing processor.\r
811\r
812 @return 32-bit address used to send an MSI to the Local APIC.\r
813**/\r
814UINT32\r
815EFIAPI \r
816GetApicMsiAddress (\r
817 VOID\r
818 )\r
819{\r
820 LOCAL_APIC_MSI_ADDRESS MsiAddress;\r
821\r
822 //\r
823 // Return address for an MSI interrupt to be delivered only to the APIC ID \r
824 // of the currently executing processor.\r
825 //\r
826 MsiAddress.Uint32 = 0;\r
827 MsiAddress.Bits.BaseAddress = 0xFEE;\r
828 MsiAddress.Bits.DestinationId = GetApicId ();\r
829 return MsiAddress.Uint32;\r
830}\r
831 \r
832/**\r
833 Get the 64-bit data value that a device should use to send a Message Signaled \r
834 Interrupt (MSI) to the Local APIC of the currently executing processor.\r
835\r
836 If Vector is not in range 0x10..0xFE, then ASSERT().\r
837 If DeliveryMode is not supported, then ASSERT().\r
838 \r
839 @param Vector The 8-bit interrupt vector associated with the MSI. \r
840 Must be in the range 0x10..0xFE\r
841 @param DeliveryMode A 3-bit value that specifies how the recept of the MSI \r
842 is handled. The only supported values are:\r
843 0: LOCAL_APIC_DELIVERY_MODE_FIXED\r
844 1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY\r
845 2: LOCAL_APIC_DELIVERY_MODE_SMI\r
846 4: LOCAL_APIC_DELIVERY_MODE_NMI\r
847 5: LOCAL_APIC_DELIVERY_MODE_INIT\r
848 7: LOCAL_APIC_DELIVERY_MODE_EXTINT\r
849 \r
850 @param LevelTriggered TRUE specifies a level triggered interrupt. \r
851 FALSE specifies an edge triggered interrupt.\r
852 @param AssertionLevel Ignored if LevelTriggered is FALSE.\r
853 TRUE specifies a level triggered interrupt that active \r
854 when the interrupt line is asserted.\r
855 FALSE specifies a level triggered interrupt that active \r
856 when the interrupt line is deasserted.\r
857\r
858 @return 64-bit data value used to send an MSI to the Local APIC.\r
859**/\r
860UINT64\r
861EFIAPI \r
862GetApicMsiValue (\r
863 IN UINT8 Vector,\r
864 IN UINTN DeliveryMode,\r
865 IN BOOLEAN LevelTriggered,\r
866 IN BOOLEAN AssertionLevel\r
867 )\r
868{\r
869 LOCAL_APIC_MSI_DATA MsiData;\r
870\r
871 ASSERT (Vector >= 0x10 && Vector <= 0xFE);\r
872 ASSERT (DeliveryMode < 8 && DeliveryMode != 6 && DeliveryMode != 3);\r
873 \r
874 MsiData.Uint64 = 0;\r
875 MsiData.Bits.Vector = Vector;\r
876 MsiData.Bits.DeliveryMode = (UINT32)DeliveryMode;\r
877 if (LevelTriggered) {\r
878 MsiData.Bits.TriggerMode = 1;\r
879 if (AssertionLevel) {\r
880 MsiData.Bits.Level = 1;\r
881 }\r
882 }\r
883 return MsiData.Uint64;\r
884}\r