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