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