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