]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
Fix a bug about the iSCSI DHCP dependency issue.
[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
6e3e4d70 7 Copyright (c) 2010 - 2013, 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
6e3e4d70 293 In xAPIC mode, the initial local APIC ID may be different from current APIC ID.\r
bf73cc4b 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
6e3e4d70
JF
305 UINT32 ApicId;\r
306 UINT32 MaxCpuIdIndex;\r
bf73cc4b 307 UINT32 RegEbx;\r
308\r
309 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
6e3e4d70
JF
310 //\r
311 // Get the max index of basic CPUID\r
312 //\r
313 AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);\r
314 //\r
315 // If CPUID Leaf B is supported, \r
316 // Then the initial 32-bit APIC ID = CPUID.0BH:EDX\r
317 // Else the initial 8-bit APIC ID = CPUID.1:EBX[31:24]\r
318 //\r
319 if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {\r
320 AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, NULL, NULL, NULL, &ApicId);\r
321 return ApicId;\r
322 }\r
bf73cc4b 323 AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);\r
324 return RegEbx >> 24;\r
325 } else {\r
326 return GetApicId ();\r
327 }\r
328}\r
329\r
330/**\r
331 Get the local APIC ID of the executing processor.\r
332\r
333 @return 32-bit local APIC ID of the executing processor.\r
334**/\r
335UINT32\r
336EFIAPI\r
337GetApicId (\r
338 VOID\r
339 )\r
340{\r
341 UINT32 ApicId;\r
6e3e4d70 342 UINT32 InitApicId;\r
bf73cc4b 343\r
344 ApicId = ReadLocalApicReg (XAPIC_ID_OFFSET);\r
345 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
6e3e4d70 346 ApicId = ((InitApicId = GetInitialApicId ()) < 0x100) ? (ApicId >> 24) : InitApicId;\r
bf73cc4b 347 }\r
6e3e4d70 348\r
bf73cc4b 349 return ApicId;\r
350}\r
351\r
ae40aef1 352/**\r
353 Get the value of the local APIC version register.\r
354\r
355 @return the value of the local APIC version register.\r
356**/\r
357UINT32\r
358EFIAPI\r
359GetApicVersion (\r
360 VOID\r
361 )\r
362{\r
363 return ReadLocalApicReg (XAPIC_VERSION_OFFSET);\r
364}\r
365\r
366/**\r
367 Send a Fixed IPI to a specified target processor.\r
368\r
369 This function returns after the IPI has been accepted by the target processor. \r
370\r
371 @param ApicId The local APIC ID of the target processor.\r
372 @param Vector The vector number of the interrupt being sent.\r
373**/\r
374VOID\r
375EFIAPI\r
376SendFixedIpi (\r
377 IN UINT32 ApicId,\r
378 IN UINT8 Vector\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_FIXED;\r
385 IcrLow.Bits.Level = 1;\r
386 IcrLow.Bits.Vector = Vector;\r
387 SendIpi (IcrLow.Uint32, ApicId);\r
388}\r
389\r
390/**\r
391 Send a Fixed IPI to all processors excluding self.\r
392\r
393 This function returns after the IPI has been accepted by the target processors. \r
394\r
395 @param Vector The vector number of the interrupt being sent.\r
396**/\r
397VOID\r
398EFIAPI\r
399SendFixedIpiAllExcludingSelf (\r
400 IN UINT8 Vector\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_FIXED;\r
407 IcrLow.Bits.Level = 1;\r
408 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
409 IcrLow.Bits.Vector = Vector;\r
410 SendIpi (IcrLow.Uint32, 0);\r
411}\r
412\r
bf73cc4b 413/**\r
414 Send a SMI IPI to a specified target processor.\r
415\r
416 This function returns after the IPI has been accepted by the target processor. \r
417\r
418 @param ApicId Specify the local APIC ID of the target processor.\r
419**/\r
420VOID\r
421EFIAPI\r
422SendSmiIpi (\r
423 IN UINT32 ApicId\r
424 )\r
425{\r
426 LOCAL_APIC_ICR_LOW IcrLow;\r
427\r
428 IcrLow.Uint32 = 0;\r
429 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;\r
430 IcrLow.Bits.Level = 1;\r
431 SendIpi (IcrLow.Uint32, ApicId);\r
432}\r
433\r
434/**\r
435 Send a SMI IPI to all processors excluding self.\r
436\r
437 This function returns after the IPI has been accepted by the target processors. \r
438**/\r
439VOID\r
440EFIAPI\r
441SendSmiIpiAllExcludingSelf (\r
442 VOID\r
443 )\r
444{\r
445 LOCAL_APIC_ICR_LOW IcrLow;\r
446\r
447 IcrLow.Uint32 = 0;\r
448 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;\r
449 IcrLow.Bits.Level = 1;\r
450 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
451 SendIpi (IcrLow.Uint32, 0);\r
452}\r
453\r
454/**\r
455 Send an INIT IPI to a specified target processor.\r
456\r
457 This function returns after the IPI has been accepted by the target processor. \r
458\r
459 @param ApicId Specify the local APIC ID of the target processor.\r
460**/\r
461VOID\r
462EFIAPI\r
463SendInitIpi (\r
464 IN UINT32 ApicId\r
465 )\r
466{\r
467 LOCAL_APIC_ICR_LOW IcrLow;\r
468\r
469 IcrLow.Uint32 = 0;\r
470 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;\r
471 IcrLow.Bits.Level = 1;\r
472 SendIpi (IcrLow.Uint32, ApicId);\r
473}\r
474\r
475/**\r
476 Send an INIT IPI to all processors excluding self.\r
477\r
478 This function returns after the IPI has been accepted by the target processors. \r
479**/\r
480VOID\r
481EFIAPI\r
482SendInitIpiAllExcludingSelf (\r
483 VOID\r
484 )\r
485{\r
486 LOCAL_APIC_ICR_LOW IcrLow;\r
487\r
488 IcrLow.Uint32 = 0;\r
489 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;\r
490 IcrLow.Bits.Level = 1;\r
491 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
492 SendIpi (IcrLow.Uint32, 0);\r
493}\r
494\r
495/**\r
496 Send an INIT-Start-up-Start-up IPI sequence to a specified target processor.\r
497\r
498 This function returns after the IPI has been accepted by the target processor. \r
499\r
500 if StartupRoutine >= 1M, then ASSERT.\r
501 if StartupRoutine is not multiple of 4K, then ASSERT.\r
502\r
503 @param ApicId Specify the local APIC ID of the target processor.\r
504 @param StartupRoutine Points to a start-up routine which is below 1M physical\r
505 address and 4K aligned.\r
506**/\r
507VOID\r
508EFIAPI\r
509SendInitSipiSipi (\r
510 IN UINT32 ApicId,\r
511 IN UINT32 StartupRoutine\r
512 )\r
513{\r
514 LOCAL_APIC_ICR_LOW IcrLow;\r
515\r
516 ASSERT (StartupRoutine < 0x100000);\r
517 ASSERT ((StartupRoutine & 0xfff) == 0);\r
518\r
519 SendInitIpi (ApicId);\r
520 MicroSecondDelay (10);\r
521 IcrLow.Uint32 = 0;\r
522 IcrLow.Bits.Vector = (StartupRoutine >> 12);\r
523 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;\r
524 IcrLow.Bits.Level = 1;\r
525 SendIpi (IcrLow.Uint32, ApicId);\r
526 MicroSecondDelay (200);\r
527 SendIpi (IcrLow.Uint32, ApicId);\r
528}\r
529\r
530/**\r
531 Send an INIT-Start-up-Start-up IPI sequence 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
535 if StartupRoutine >= 1M, then ASSERT.\r
536 if StartupRoutine is not multiple of 4K, then ASSERT.\r
537\r
538 @param StartupRoutine Points to a start-up routine which is below 1M physical\r
539 address and 4K aligned.\r
540**/\r
541VOID\r
542EFIAPI\r
543SendInitSipiSipiAllExcludingSelf (\r
544 IN UINT32 StartupRoutine\r
545 )\r
546{\r
547 LOCAL_APIC_ICR_LOW IcrLow;\r
548\r
549 ASSERT (StartupRoutine < 0x100000);\r
550 ASSERT ((StartupRoutine & 0xfff) == 0);\r
551\r
552 SendInitIpiAllExcludingSelf ();\r
553 MicroSecondDelay (10);\r
554 IcrLow.Uint32 = 0;\r
555 IcrLow.Bits.Vector = (StartupRoutine >> 12);\r
556 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;\r
557 IcrLow.Bits.Level = 1;\r
558 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
559 SendIpi (IcrLow.Uint32, 0);\r
560 MicroSecondDelay (200);\r
561 SendIpi (IcrLow.Uint32, 0);\r
562}\r
563\r
564/**\r
565 Programming Virtual Wire Mode.\r
566\r
567 This function programs the local APIC for virtual wire mode following\r
568 the example described in chapter A.3 of the MP 1.4 spec.\r
569\r
570 IOxAPIC is not involved in this type of virtual wire mode.\r
571**/\r
572VOID\r
573EFIAPI\r
574ProgramVirtualWireMode (\r
575 VOID\r
576 )\r
577{\r
578 LOCAL_APIC_SVR Svr;\r
579 LOCAL_APIC_LVT_LINT Lint;\r
580\r
581 //\r
582 // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.\r
583 //\r
584 Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);\r
585 Svr.Bits.SpuriousVector = 0xf;\r
586 Svr.Bits.SoftwareEnable = 1;\r
587 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);\r
588\r
589 //\r
590 // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high.\r
591 //\r
ae40aef1 592 Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);\r
bf73cc4b 593 Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT;\r
594 Lint.Bits.InputPinPolarity = 0;\r
595 Lint.Bits.TriggerMode = 0;\r
596 Lint.Bits.Mask = 0;\r
ae40aef1 597 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, Lint.Uint32);\r
bf73cc4b 598\r
599 //\r
600 // Program the LINT0 vector entry as NMI. Not masked, edge, active high.\r
601 //\r
ae40aef1 602 Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);\r
bf73cc4b 603 Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI;\r
604 Lint.Bits.InputPinPolarity = 0;\r
605 Lint.Bits.TriggerMode = 0;\r
606 Lint.Bits.Mask = 0;\r
ae40aef1 607 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32);\r
bf73cc4b 608}\r
609\r
b1b8c631 610/**\r
611 Disable LINT0 & LINT1 interrupts.\r
612\r
613 This function sets the mask flag in the LVT LINT0 & LINT1 registers.\r
614**/\r
615VOID\r
616EFIAPI\r
617DisableLvtInterrupts (\r
618 VOID\r
619 )\r
620{\r
621 LOCAL_APIC_LVT_LINT LvtLint;\r
622\r
623 LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);\r
624 LvtLint.Bits.Mask = 1;\r
625 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, LvtLint.Uint32);\r
626\r
627 LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);\r
628 LvtLint.Bits.Mask = 1;\r
629 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, LvtLint.Uint32);\r
630}\r
631\r
bf73cc4b 632/**\r
633 Read the initial count value from the init-count register.\r
634\r
635 @return The initial count value read from the init-count register.\r
636**/\r
637UINT32\r
638EFIAPI\r
639GetApicTimerInitCount (\r
640 VOID\r
641 )\r
642{\r
643 return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET);\r
644}\r
645\r
646/**\r
647 Read the current count value from the current-count register.\r
648\r
649 @return The current count value read from the current-count register.\r
650**/\r
651UINT32\r
652EFIAPI\r
653GetApicTimerCurrentCount (\r
654 VOID\r
655 )\r
656{\r
657 return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET);\r
658}\r
659\r
660/**\r
661 Initialize the local APIC timer.\r
662\r
663 The local APIC timer is initialized and enabled.\r
664\r
665 @param DivideValue The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.\r
666 If it is 0, then use the current divide value in the DCR.\r
667 @param InitCount The initial count value.\r
668 @param PeriodicMode If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.\r
669 @param Vector The timer interrupt vector number.\r
670**/\r
671VOID\r
672EFIAPI\r
673InitializeApicTimer (\r
674 IN UINTN DivideValue,\r
675 IN UINT32 InitCount,\r
676 IN BOOLEAN PeriodicMode,\r
677 IN UINT8 Vector\r
678 )\r
679{\r
680 LOCAL_APIC_SVR Svr;\r
681 LOCAL_APIC_DCR Dcr;\r
682 LOCAL_APIC_LVT_TIMER LvtTimer;\r
683 UINT32 Divisor;\r
684\r
685 //\r
686 // Ensure local APIC is in software-enabled state.\r
687 //\r
688 Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);\r
689 Svr.Bits.SoftwareEnable = 1;\r
690 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);\r
691\r
692 //\r
693 // Program init-count register.\r
694 //\r
695 WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);\r
696\r
697 if (DivideValue != 0) {\r
698 ASSERT (DivideValue <= 128);\r
699 ASSERT (DivideValue == GetPowerOfTwo32((UINT32)DivideValue));\r
700 Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7);\r
701\r
702 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);\r
703 Dcr.Bits.DivideValue1 = (Divisor & 0x3);\r
704 Dcr.Bits.DivideValue2 = (Divisor >> 2);\r
705 WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32); \r
706 }\r
707\r
708 //\r
709 // Enable APIC timer interrupt with specified timer mode.\r
710 //\r
711 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
712 if (PeriodicMode) {\r
713 LvtTimer.Bits.TimerMode = 1;\r
714 } else {\r
715 LvtTimer.Bits.TimerMode = 0;\r
716 }\r
717 LvtTimer.Bits.Mask = 0;\r
718 LvtTimer.Bits.Vector = Vector;\r
719 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
720}\r
721\r
ae40aef1 722/**\r
723 Get the state of the local APIC timer.\r
724\r
725 @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.\r
726 @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.\r
727 @param Vector Return the timer interrupt vector number.\r
728**/\r
729VOID\r
730EFIAPI\r
731GetApicTimerState (\r
732 OUT UINTN *DivideValue OPTIONAL,\r
733 OUT BOOLEAN *PeriodicMode OPTIONAL,\r
734 OUT UINT8 *Vector OPTIONAL\r
735 )\r
736{\r
737 UINT32 Divisor;\r
738 LOCAL_APIC_DCR Dcr;\r
739 LOCAL_APIC_LVT_TIMER LvtTimer;\r
740\r
741 if (DivideValue != NULL) {\r
742 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);\r
743 Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);\r
744 Divisor = (Divisor + 1) & 0x7;\r
745 *DivideValue = ((UINTN)1) << Divisor;\r
746 }\r
747\r
748 if (PeriodicMode != NULL || Vector != NULL) {\r
749 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
750 if (PeriodicMode != NULL) {\r
751 if (LvtTimer.Bits.TimerMode == 1) {\r
752 *PeriodicMode = TRUE;\r
753 } else {\r
754 *PeriodicMode = FALSE;\r
755 }\r
756 }\r
757 if (Vector != NULL) {\r
758 *Vector = (UINT8) LvtTimer.Bits.Vector;\r
759 }\r
760 }\r
761}\r
762\r
bf73cc4b 763/**\r
764 Enable the local APIC timer interrupt.\r
765**/\r
766VOID\r
767EFIAPI\r
768EnableApicTimerInterrupt (\r
769 VOID\r
770 )\r
771{\r
772 LOCAL_APIC_LVT_TIMER LvtTimer;\r
773\r
774 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
775 LvtTimer.Bits.Mask = 0;\r
776 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
777}\r
778\r
779/**\r
780 Disable the local APIC timer interrupt.\r
781**/\r
782VOID\r
783EFIAPI\r
784DisableApicTimerInterrupt (\r
785 VOID\r
786 )\r
787{\r
788 LOCAL_APIC_LVT_TIMER LvtTimer;\r
789\r
790 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
791 LvtTimer.Bits.Mask = 1;\r
792 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
793}\r
794\r
795/**\r
796 Get the local APIC timer interrupt state.\r
797\r
798 @retval TRUE The local APIC timer interrupt is enabled.\r
799 @retval FALSE The local APIC timer interrupt is disabled.\r
800**/\r
801BOOLEAN\r
802EFIAPI\r
803GetApicTimerInterruptState (\r
804 VOID\r
805 )\r
806{\r
807 LOCAL_APIC_LVT_TIMER LvtTimer;\r
808\r
809 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
810 return (BOOLEAN)(LvtTimer.Bits.Mask == 0);\r
811}\r
812\r
813/**\r
814 Send EOI to the local APIC.\r
815**/\r
816VOID\r
817EFIAPI\r
818SendApicEoi (\r
819 VOID\r
820 )\r
821{\r
822 WriteLocalApicReg (XAPIC_EOI_OFFSET, 0);\r
823}\r
824\r
5f867ad0 825/**\r
826 Get the 32-bit address that a device should use to send a Message Signaled \r
827 Interrupt (MSI) to the Local APIC of the currently executing processor.\r
828\r
829 @return 32-bit address used to send an MSI to the Local APIC.\r
830**/\r
831UINT32\r
832EFIAPI \r
833GetApicMsiAddress (\r
834 VOID\r
835 )\r
836{\r
837 LOCAL_APIC_MSI_ADDRESS MsiAddress;\r
838\r
839 //\r
840 // Return address for an MSI interrupt to be delivered only to the APIC ID \r
841 // of the currently executing processor.\r
842 //\r
843 MsiAddress.Uint32 = 0;\r
844 MsiAddress.Bits.BaseAddress = 0xFEE;\r
845 MsiAddress.Bits.DestinationId = GetApicId ();\r
846 return MsiAddress.Uint32;\r
847}\r
848 \r
849/**\r
850 Get the 64-bit data value that a device should use to send a Message Signaled \r
851 Interrupt (MSI) to the Local APIC of the currently executing processor.\r
852\r
853 If Vector is not in range 0x10..0xFE, then ASSERT().\r
854 If DeliveryMode is not supported, then ASSERT().\r
855 \r
856 @param Vector The 8-bit interrupt vector associated with the MSI. \r
857 Must be in the range 0x10..0xFE\r
858 @param DeliveryMode A 3-bit value that specifies how the recept of the MSI \r
859 is handled. The only supported values are:\r
860 0: LOCAL_APIC_DELIVERY_MODE_FIXED\r
861 1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY\r
862 2: LOCAL_APIC_DELIVERY_MODE_SMI\r
863 4: LOCAL_APIC_DELIVERY_MODE_NMI\r
864 5: LOCAL_APIC_DELIVERY_MODE_INIT\r
865 7: LOCAL_APIC_DELIVERY_MODE_EXTINT\r
866 \r
867 @param LevelTriggered TRUE specifies a level triggered interrupt. \r
868 FALSE specifies an edge triggered interrupt.\r
869 @param AssertionLevel Ignored if LevelTriggered is FALSE.\r
870 TRUE specifies a level triggered interrupt that active \r
871 when the interrupt line is asserted.\r
872 FALSE specifies a level triggered interrupt that active \r
873 when the interrupt line is deasserted.\r
874\r
875 @return 64-bit data value used to send an MSI to the Local APIC.\r
876**/\r
877UINT64\r
878EFIAPI \r
879GetApicMsiValue (\r
880 IN UINT8 Vector,\r
881 IN UINTN DeliveryMode,\r
882 IN BOOLEAN LevelTriggered,\r
883 IN BOOLEAN AssertionLevel\r
884 )\r
885{\r
886 LOCAL_APIC_MSI_DATA MsiData;\r
887\r
888 ASSERT (Vector >= 0x10 && Vector <= 0xFE);\r
889 ASSERT (DeliveryMode < 8 && DeliveryMode != 6 && DeliveryMode != 3);\r
890 \r
891 MsiData.Uint64 = 0;\r
892 MsiData.Bits.Vector = Vector;\r
893 MsiData.Bits.DeliveryMode = (UINT32)DeliveryMode;\r
894 if (LevelTriggered) {\r
895 MsiData.Bits.TriggerMode = 1;\r
896 if (AssertionLevel) {\r
897 MsiData.Bits.Level = 1;\r
898 }\r
899 }\r
900 return MsiData.Uint64;\r
901}\r