1c2c66affSColin Finck /*
2c2c66affSColin Finck * PROJECT: ReactOS HAL
3c2c66affSColin Finck * LICENSE: GNU GPL - See COPYING in the top level directory
4c2c66affSColin Finck * FILE: hal/halx86/apic/apic.c
5c2c66affSColin Finck * PURPOSE: HAL APIC Management and Control Code
6c2c66affSColin Finck * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
764e52088STimo Kreuzer * REFERENCES: https://web.archive.org/web/20190407074221/http://www.joseflores.com/docs/ExploringIrql.html
8c2c66affSColin Finck * http://www.codeproject.com/KB/system/soviet_kernel_hack.aspx
9c2c66affSColin Finck * http://bbs.unixmap.net/thread-2022-1-1.html
1064e52088STimo Kreuzer * https://www.codemachine.com/article_interruptdispatching.html
1164e52088STimo Kreuzer * https://www.osronline.com/article.cfm%5Earticle=211.htm
12c2c66affSColin Finck */
13c2c66affSColin Finck
14c2c66affSColin Finck /* INCLUDES *******************************************************************/
15c2c66affSColin Finck
16c2c66affSColin Finck #include <hal.h>
1772435039STimo Kreuzer #include "apicp.h"
18c2c66affSColin Finck #define NDEBUG
19c2c66affSColin Finck #include <debug.h>
20c2c66affSColin Finck
21c2c66affSColin Finck #ifndef _M_AMD64
2264e52088STimo Kreuzer #define APIC_LAZY_IRQL
23c2c66affSColin Finck #endif
24c2c66affSColin Finck
25c2c66affSColin Finck /* GLOBALS ********************************************************************/
26c2c66affSColin Finck
27c2c66affSColin Finck ULONG ApicVersion;
28c2c66affSColin Finck UCHAR HalpVectorToIndex[256];
29c2c66affSColin Finck
30c2c66affSColin Finck #ifndef _M_AMD64
31c2c66affSColin Finck const UCHAR
32c2c66affSColin Finck HalpIRQLtoTPR[32] =
33c2c66affSColin Finck {
34c2c66affSColin Finck 0x00, /* 0 PASSIVE_LEVEL */
35c2c66affSColin Finck 0x3d, /* 1 APC_LEVEL */
36c2c66affSColin Finck 0x41, /* 2 DISPATCH_LEVEL */
37c2c66affSColin Finck 0x41, /* 3 \ */
38c2c66affSColin Finck 0x51, /* 4 \ */
39c2c66affSColin Finck 0x61, /* 5 | */
40c2c66affSColin Finck 0x71, /* 6 | */
41c2c66affSColin Finck 0x81, /* 7 | */
42c2c66affSColin Finck 0x91, /* 8 | */
43c2c66affSColin Finck 0xa1, /* 9 | */
44c2c66affSColin Finck 0xb1, /* 10 | */
45c2c66affSColin Finck 0xb1, /* 11 | */
46c2c66affSColin Finck 0xb1, /* 12 | */
47c2c66affSColin Finck 0xb1, /* 13 | */
48c2c66affSColin Finck 0xb1, /* 14 | */
49c2c66affSColin Finck 0xb1, /* 15 DEVICE IRQL */
50c2c66affSColin Finck 0xb1, /* 16 | */
51c2c66affSColin Finck 0xb1, /* 17 | */
52c2c66affSColin Finck 0xb1, /* 18 | */
53c2c66affSColin Finck 0xb1, /* 19 | */
54c2c66affSColin Finck 0xb1, /* 20 | */
55c2c66affSColin Finck 0xb1, /* 21 | */
56c2c66affSColin Finck 0xb1, /* 22 | */
57c2c66affSColin Finck 0xb1, /* 23 | */
58c2c66affSColin Finck 0xb1, /* 24 | */
59c2c66affSColin Finck 0xb1, /* 25 / */
60c2c66affSColin Finck 0xb1, /* 26 / */
61c2c66affSColin Finck 0xc1, /* 27 PROFILE_LEVEL */
62c2c66affSColin Finck 0xd1, /* 28 CLOCK2_LEVEL */
63c2c66affSColin Finck 0xe1, /* 29 IPI_LEVEL */
64c2c66affSColin Finck 0xef, /* 30 POWER_LEVEL */
65c2c66affSColin Finck 0xff, /* 31 HIGH_LEVEL */
66c2c66affSColin Finck };
67c2c66affSColin Finck
68c2c66affSColin Finck const KIRQL
69c2c66affSColin Finck HalVectorToIRQL[16] =
70c2c66affSColin Finck {
71c2c66affSColin Finck 0, /* 00 PASSIVE_LEVEL */
72c2c66affSColin Finck 0xff, /* 10 */
73c2c66affSColin Finck 0xff, /* 20 */
74c2c66affSColin Finck 1, /* 3D APC_LEVEL */
75c2c66affSColin Finck 2, /* 41 DISPATCH_LEVEL */
76c2c66affSColin Finck 4, /* 50 \ */
77c2c66affSColin Finck 5, /* 60 \ */
78c2c66affSColin Finck 6, /* 70 | */
79c2c66affSColin Finck 7, /* 80 DEVICE IRQL */
80c2c66affSColin Finck 8, /* 90 | */
81c2c66affSColin Finck 9, /* A0 / */
82c2c66affSColin Finck 10, /* B0 / */
83c2c66affSColin Finck 27, /* C1 PROFILE_LEVEL */
84c2c66affSColin Finck 28, /* D1 CLOCK2_LEVEL */
85c2c66affSColin Finck 29, /* E1 IPI_LEVEL / EF POWER_LEVEL */
86c2c66affSColin Finck 31, /* FF HIGH_LEVEL */
87c2c66affSColin Finck };
88c2c66affSColin Finck #endif
89c2c66affSColin Finck
90c2c66affSColin Finck /* PRIVATE FUNCTIONS **********************************************************/
91c2c66affSColin Finck
92c2c66affSColin Finck FORCEINLINE
93c2c66affSColin Finck ULONG
IOApicRead(UCHAR Register)94c2c66affSColin Finck IOApicRead(UCHAR Register)
95c2c66affSColin Finck {
96c2c66affSColin Finck /* Select the register, then do the read */
97b7a149fcSTimo Kreuzer ASSERT(Register <= 0x3F);
98b7a149fcSTimo Kreuzer WRITE_REGISTER_ULONG((PULONG)(IOAPIC_BASE + IOAPIC_IOREGSEL), Register);
99b7a149fcSTimo Kreuzer return READ_REGISTER_ULONG((PULONG)(IOAPIC_BASE + IOAPIC_IOWIN));
100c2c66affSColin Finck }
101c2c66affSColin Finck
102c2c66affSColin Finck FORCEINLINE
103c2c66affSColin Finck VOID
IOApicWrite(UCHAR Register,ULONG Value)104c2c66affSColin Finck IOApicWrite(UCHAR Register, ULONG Value)
105c2c66affSColin Finck {
106c2c66affSColin Finck /* Select the register, then do the write */
107b7a149fcSTimo Kreuzer ASSERT(Register <= 0x3F);
108b7a149fcSTimo Kreuzer WRITE_REGISTER_ULONG((PULONG)(IOAPIC_BASE + IOAPIC_IOREGSEL), Register);
109b7a149fcSTimo Kreuzer WRITE_REGISTER_ULONG((PULONG)(IOAPIC_BASE + IOAPIC_IOWIN), Value);
110c2c66affSColin Finck }
111c2c66affSColin Finck
112c2c66affSColin Finck FORCEINLINE
113c2c66affSColin Finck VOID
ApicWriteIORedirectionEntry(UCHAR Index,IOAPIC_REDIRECTION_REGISTER ReDirReg)114c2c66affSColin Finck ApicWriteIORedirectionEntry(
115c2c66affSColin Finck UCHAR Index,
116c2c66affSColin Finck IOAPIC_REDIRECTION_REGISTER ReDirReg)
117c2c66affSColin Finck {
118b7a149fcSTimo Kreuzer ASSERT(Index < APIC_MAX_IRQ);
119c2c66affSColin Finck IOApicWrite(IOAPIC_REDTBL + 2 * Index, ReDirReg.Long0);
120c2c66affSColin Finck IOApicWrite(IOAPIC_REDTBL + 2 * Index + 1, ReDirReg.Long1);
121c2c66affSColin Finck }
122c2c66affSColin Finck
123c2c66affSColin Finck FORCEINLINE
124c2c66affSColin Finck IOAPIC_REDIRECTION_REGISTER
ApicReadIORedirectionEntry(UCHAR Index)125c2c66affSColin Finck ApicReadIORedirectionEntry(
126c2c66affSColin Finck UCHAR Index)
127c2c66affSColin Finck {
128c2c66affSColin Finck IOAPIC_REDIRECTION_REGISTER ReDirReg;
129c2c66affSColin Finck
130b7a149fcSTimo Kreuzer ASSERT(Index < APIC_MAX_IRQ);
131c2c66affSColin Finck ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Index);
132c2c66affSColin Finck ReDirReg.Long1 = IOApicRead(IOAPIC_REDTBL + 2 * Index + 1);
133c2c66affSColin Finck
134c2c66affSColin Finck return ReDirReg;
135c2c66affSColin Finck }
136c2c66affSColin Finck
137c2c66affSColin Finck FORCEINLINE
138c2c66affSColin Finck VOID
ApicRequestSelfInterrupt(IN UCHAR Vector,UCHAR TriggerMode)13916e988d1STimo Kreuzer ApicRequestSelfInterrupt(IN UCHAR Vector, UCHAR TriggerMode)
140c2c66affSColin Finck {
1416eccbe27SThomas Faber ULONG Flags;
14216e988d1STimo Kreuzer APIC_INTERRUPT_COMMAND_REGISTER Icr;
1436eccbe27SThomas Faber APIC_INTERRUPT_COMMAND_REGISTER IcrStatus;
1446eccbe27SThomas Faber
1456eccbe27SThomas Faber /*
1466eccbe27SThomas Faber * The IRR registers are spaced 16 bytes apart and hold 32 status bits each.
1476eccbe27SThomas Faber * Pre-compute the register and bit that match our vector.
1486eccbe27SThomas Faber */
1496eccbe27SThomas Faber ULONG VectorHigh = Vector / 32;
1506eccbe27SThomas Faber ULONG VectorLow = Vector % 32;
1516eccbe27SThomas Faber ULONG Irr = APIC_IRR + 0x10 * VectorHigh;
1526eccbe27SThomas Faber ULONG IrrBit = 1UL << VectorLow;
153c2c66affSColin Finck
154c2c66affSColin Finck /* Setup the command register */
15516e988d1STimo Kreuzer Icr.Long0 = 0;
15616e988d1STimo Kreuzer Icr.Vector = Vector;
15716e988d1STimo Kreuzer Icr.MessageType = APIC_MT_Fixed;
15816e988d1STimo Kreuzer Icr.TriggerMode = TriggerMode;
15916e988d1STimo Kreuzer Icr.DestinationShortHand = APIC_DSH_Self;
160c2c66affSColin Finck
1616eccbe27SThomas Faber /* Disable interrupts so that we can change IRR without being interrupted */
1626eccbe27SThomas Faber Flags = __readeflags();
1636eccbe27SThomas Faber _disable();
1646eccbe27SThomas Faber
1656eccbe27SThomas Faber /* Wait for the APIC to be idle */
1666eccbe27SThomas Faber do
1676eccbe27SThomas Faber {
1686eccbe27SThomas Faber IcrStatus.Long0 = ApicRead(APIC_ICR0);
1696eccbe27SThomas Faber } while (IcrStatus.DeliveryStatus);
1706eccbe27SThomas Faber
171c2c66affSColin Finck /* Write the low dword to send the interrupt */
17216e988d1STimo Kreuzer ApicWrite(APIC_ICR0, Icr.Long0);
1736eccbe27SThomas Faber
1746eccbe27SThomas Faber /* Wait until we see the interrupt request.
1756eccbe27SThomas Faber * It will stay in requested state until we re-enable interrupts.
1766eccbe27SThomas Faber */
1776eccbe27SThomas Faber while (!(ApicRead(Irr) & IrrBit))
1786eccbe27SThomas Faber {
1796eccbe27SThomas Faber NOTHING;
1806eccbe27SThomas Faber }
1816eccbe27SThomas Faber
1826eccbe27SThomas Faber /* Finally, restore the original interrupt state */
1836eccbe27SThomas Faber if (Flags & EFLAGS_INTERRUPT_MASK)
1846eccbe27SThomas Faber {
1856eccbe27SThomas Faber _enable();
1866eccbe27SThomas Faber }
187c2c66affSColin Finck }
188c2c66affSColin Finck
189c2c66affSColin Finck FORCEINLINE
190c2c66affSColin Finck VOID
ApicSendEOI(void)191c2c66affSColin Finck ApicSendEOI(void)
192c2c66affSColin Finck {
193235d7472STimo Kreuzer ApicWrite(APIC_EOI, 0);
194c2c66affSColin Finck }
195c2c66affSColin Finck
196c2c66affSColin Finck FORCEINLINE
197c2c66affSColin Finck KIRQL
ApicGetProcessorIrql(VOID)198c2c66affSColin Finck ApicGetProcessorIrql(VOID)
199c2c66affSColin Finck {
200c2c66affSColin Finck /* Read the TPR and convert it to an IRQL */
201c2c66affSColin Finck return TprToIrql(ApicRead(APIC_PPR));
202c2c66affSColin Finck }
203c2c66affSColin Finck
204c2c66affSColin Finck FORCEINLINE
205c2c66affSColin Finck KIRQL
ApicGetCurrentIrql(VOID)206c2c66affSColin Finck ApicGetCurrentIrql(VOID)
207c2c66affSColin Finck {
208c2c66affSColin Finck #ifdef _M_AMD64
209c2c66affSColin Finck return (KIRQL)__readcr8();
210c2c66affSColin Finck #elif defined(APIC_LAZY_IRQL)
211c2c66affSColin Finck /* Return the field in the PCR */
212c2c66affSColin Finck return (KIRQL)__readfsbyte(FIELD_OFFSET(KPCR, Irql));
213c2c66affSColin Finck #else
214c2c66affSColin Finck /* Read the TPR and convert it to an IRQL */
215c2c66affSColin Finck return TprToIrql(ApicRead(APIC_TPR));
216c2c66affSColin Finck #endif
217c2c66affSColin Finck }
218c2c66affSColin Finck
219c2c66affSColin Finck FORCEINLINE
220c2c66affSColin Finck VOID
ApicSetIrql(KIRQL Irql)221c2c66affSColin Finck ApicSetIrql(KIRQL Irql)
222c2c66affSColin Finck {
223c2c66affSColin Finck #ifdef _M_AMD64
224c2c66affSColin Finck __writecr8(Irql);
225c2c66affSColin Finck #elif defined(APIC_LAZY_IRQL)
226c2c66affSColin Finck __writefsbyte(FIELD_OFFSET(KPCR, Irql), Irql);
227c2c66affSColin Finck #else
228c2c66affSColin Finck /* Convert IRQL and write the TPR */
229c2c66affSColin Finck ApicWrite(APIC_TPR, IrqlToTpr(Irql));
230c2c66affSColin Finck #endif
231c2c66affSColin Finck }
232c2c66affSColin Finck #define ApicRaiseIrql ApicSetIrql
233c2c66affSColin Finck
234c2c66affSColin Finck #ifdef APIC_LAZY_IRQL
235c2c66affSColin Finck FORCEINLINE
236c2c66affSColin Finck VOID
ApicLowerIrql(KIRQL Irql)237c2c66affSColin Finck ApicLowerIrql(KIRQL Irql)
238c2c66affSColin Finck {
239c2c66affSColin Finck __writefsbyte(FIELD_OFFSET(KPCR, Irql), Irql);
240c2c66affSColin Finck
241c2c66affSColin Finck /* Is the new Irql lower than set in the TPR? */
242c2c66affSColin Finck if (Irql < KeGetPcr()->IRR)
243c2c66affSColin Finck {
244c2c66affSColin Finck /* Save the new hard IRQL in the IRR field */
245c2c66affSColin Finck KeGetPcr()->IRR = Irql;
246c2c66affSColin Finck
247c2c66affSColin Finck /* Need to lower it back */
248c2c66affSColin Finck ApicWrite(APIC_TPR, IrqlToTpr(Irql));
249c2c66affSColin Finck }
250c2c66affSColin Finck }
251c2c66affSColin Finck #else
252c2c66affSColin Finck #define ApicLowerIrql ApicSetIrql
253c2c66affSColin Finck #endif
254c2c66affSColin Finck
255c2c66affSColin Finck UCHAR
256c2c66affSColin Finck FASTCALL
HalpIrqToVector(UCHAR Irq)257c2c66affSColin Finck HalpIrqToVector(UCHAR Irq)
258c2c66affSColin Finck {
259c2c66affSColin Finck IOAPIC_REDIRECTION_REGISTER ReDirReg;
260c2c66affSColin Finck
261c2c66affSColin Finck /* Read low dword of the redirection entry */
262c2c66affSColin Finck ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Irq);
263c2c66affSColin Finck
264c2c66affSColin Finck /* Return the vector */
265c2c66affSColin Finck return (UCHAR)ReDirReg.Vector;
266c2c66affSColin Finck }
267c2c66affSColin Finck
268c2c66affSColin Finck KIRQL
269c2c66affSColin Finck FASTCALL
HalpVectorToIrql(UCHAR Vector)270c2c66affSColin Finck HalpVectorToIrql(UCHAR Vector)
271c2c66affSColin Finck {
272c2c66affSColin Finck return TprToIrql(Vector);
273c2c66affSColin Finck }
274c2c66affSColin Finck
275c2c66affSColin Finck UCHAR
276c2c66affSColin Finck FASTCALL
HalpVectorToIrq(UCHAR Vector)277c2c66affSColin Finck HalpVectorToIrq(UCHAR Vector)
278c2c66affSColin Finck {
279c2c66affSColin Finck return HalpVectorToIndex[Vector];
280c2c66affSColin Finck }
281c2c66affSColin Finck
282c2c66affSColin Finck VOID
283c2c66affSColin Finck NTAPI
HalpSendEOI(VOID)284c2c66affSColin Finck HalpSendEOI(VOID)
285c2c66affSColin Finck {
286c2c66affSColin Finck ApicSendEOI();
287c2c66affSColin Finck }
288c2c66affSColin Finck
289c2c66affSColin Finck VOID
290c2c66affSColin Finck NTAPI
ApicInitializeLocalApic(ULONG Cpu)291c2c66affSColin Finck ApicInitializeLocalApic(ULONG Cpu)
292c2c66affSColin Finck {
293ffb20d33SRatin Gao APIC_BASE_ADDRESS_REGISTER BaseRegister;
294c2c66affSColin Finck APIC_SPURIOUS_INERRUPT_REGISTER SpIntRegister;
295c2c66affSColin Finck LVT_REGISTER LvtEntry;
296c2c66affSColin Finck
297c2c66affSColin Finck /* Enable the APIC if it wasn't yet */
2980d902063SJustin Miller BaseRegister.LongLong = __readmsr(MSR_APIC_BASE);
299c2c66affSColin Finck BaseRegister.Enable = 1;
300c2c66affSColin Finck BaseRegister.BootStrapCPUCore = (Cpu == 0);
3010d902063SJustin Miller __writemsr(MSR_APIC_BASE, BaseRegister.LongLong);
302c2c66affSColin Finck
303c2c66affSColin Finck /* Set spurious vector and SoftwareEnable to 1 */
304c2c66affSColin Finck SpIntRegister.Long = ApicRead(APIC_SIVR);
305c2c66affSColin Finck SpIntRegister.Vector = APIC_SPURIOUS_VECTOR;
306c2c66affSColin Finck SpIntRegister.SoftwareEnable = 1;
307c2c66affSColin Finck SpIntRegister.FocusCPUCoreChecking = 0;
308c2c66affSColin Finck ApicWrite(APIC_SIVR, SpIntRegister.Long);
309c2c66affSColin Finck
310c2c66affSColin Finck /* Read the version and save it globally */
311c2c66affSColin Finck if (Cpu == 0) ApicVersion = ApicRead(APIC_VER);
312c2c66affSColin Finck
313c2c66affSColin Finck /* Set the mode to flat (max 8 CPUs supported!) */
314c2c66affSColin Finck ApicWrite(APIC_DFR, APIC_DF_Flat);
315c2c66affSColin Finck
316c2c66affSColin Finck /* Set logical apic ID */
317c2c66affSColin Finck ApicWrite(APIC_LDR, ApicLogicalId(Cpu) << 24);
318c2c66affSColin Finck
319c2c66affSColin Finck /* Set the spurious ISR */
320c2c66affSColin Finck KeRegisterInterruptHandler(APIC_SPURIOUS_VECTOR, ApicSpuriousService);
321c2c66affSColin Finck
322c2c66affSColin Finck /* Create a template LVT */
323c2c66affSColin Finck LvtEntry.Long = 0;
3246a5472a7SSerge Gautherie LvtEntry.Vector = APIC_FREE_VECTOR;
325c2c66affSColin Finck LvtEntry.MessageType = APIC_MT_Fixed;
326c2c66affSColin Finck LvtEntry.DeliveryStatus = 0;
327c2c66affSColin Finck LvtEntry.RemoteIRR = 0;
328c2c66affSColin Finck LvtEntry.TriggerMode = APIC_TGM_Edge;
329c2c66affSColin Finck LvtEntry.Mask = 1;
330c2c66affSColin Finck LvtEntry.TimerMode = 0;
331c2c66affSColin Finck
332c2c66affSColin Finck /* Initialize and mask LVTs */
333c2c66affSColin Finck ApicWrite(APIC_TMRLVTR, LvtEntry.Long);
334c2c66affSColin Finck ApicWrite(APIC_THRMLVTR, LvtEntry.Long);
335c2c66affSColin Finck ApicWrite(APIC_PCLVTR, LvtEntry.Long);
336c2c66affSColin Finck ApicWrite(APIC_EXT0LVTR, LvtEntry.Long);
337c2c66affSColin Finck ApicWrite(APIC_EXT1LVTR, LvtEntry.Long);
338c2c66affSColin Finck ApicWrite(APIC_EXT2LVTR, LvtEntry.Long);
339c2c66affSColin Finck ApicWrite(APIC_EXT3LVTR, LvtEntry.Long);
340c2c66affSColin Finck
341c2c66affSColin Finck /* LINT0 */
342c2c66affSColin Finck LvtEntry.Vector = APIC_SPURIOUS_VECTOR;
343c2c66affSColin Finck LvtEntry.MessageType = APIC_MT_ExtInt;
344c2c66affSColin Finck ApicWrite(APIC_LINT0, LvtEntry.Long);
345c2c66affSColin Finck
346c2c66affSColin Finck /* Enable LINT1 (NMI) */
347c2c66affSColin Finck LvtEntry.Mask = 0;
348c2c66affSColin Finck LvtEntry.Vector = APIC_NMI_VECTOR;
349c2c66affSColin Finck LvtEntry.MessageType = APIC_MT_NMI;
350c2c66affSColin Finck LvtEntry.TriggerMode = APIC_TGM_Level;
351c2c66affSColin Finck ApicWrite(APIC_LINT1, LvtEntry.Long);
352c2c66affSColin Finck
353c2c66affSColin Finck /* Enable error LVTR */
354c2c66affSColin Finck LvtEntry.Vector = APIC_ERROR_VECTOR;
355c2c66affSColin Finck LvtEntry.MessageType = APIC_MT_Fixed;
356c2c66affSColin Finck ApicWrite(APIC_ERRLVTR, LvtEntry.Long);
357c2c66affSColin Finck
358c2c66affSColin Finck /* Set the IRQL from the PCR */
359c2c66affSColin Finck ApicSetIrql(KeGetPcr()->Irql);
360c2c66affSColin Finck #ifdef APIC_LAZY_IRQL
361c2c66affSColin Finck /* Save the new hard IRQL in the IRR field */
362c2c66affSColin Finck KeGetPcr()->IRR = KeGetPcr()->Irql;
363c2c66affSColin Finck #endif
364c2c66affSColin Finck }
365c2c66affSColin Finck
366c2c66affSColin Finck UCHAR
367c2c66affSColin Finck NTAPI
HalpAllocateSystemInterrupt(_In_ UCHAR Irq,_In_ UCHAR Vector)368c2c66affSColin Finck HalpAllocateSystemInterrupt(
36964e52088STimo Kreuzer _In_ UCHAR Irq,
37064e52088STimo Kreuzer _In_ UCHAR Vector)
371c2c66affSColin Finck {
372c2c66affSColin Finck IOAPIC_REDIRECTION_REGISTER ReDirReg;
373c2c66affSColin Finck
3746a5472a7SSerge Gautherie ASSERT(Irq < APIC_MAX_IRQ);
37564e52088STimo Kreuzer ASSERT(HalpVectorToIndex[Vector] == APIC_FREE_VECTOR);
376c2c66affSColin Finck
377c2c66affSColin Finck /* Setup a redirection entry */
378c2c66affSColin Finck ReDirReg.Vector = Vector;
379*def2fe5dSTimo Kreuzer ReDirReg.MessageType = APIC_MT_LowestPriority;
380c2c66affSColin Finck ReDirReg.DestinationMode = APIC_DM_Logical;
381c2c66affSColin Finck ReDirReg.DeliveryStatus = 0;
382c2c66affSColin Finck ReDirReg.Polarity = 0;
383c2c66affSColin Finck ReDirReg.RemoteIRR = 0;
384c2c66affSColin Finck ReDirReg.TriggerMode = APIC_TGM_Edge;
385c2c66affSColin Finck ReDirReg.Mask = 1;
386c2c66affSColin Finck ReDirReg.Reserved = 0;
387c2c66affSColin Finck ReDirReg.Destination = 0;
388c2c66affSColin Finck
389c2c66affSColin Finck /* Initialize entry */
390b7a149fcSTimo Kreuzer ApicWriteIORedirectionEntry(Irq, ReDirReg);
391c2c66affSColin Finck
39264e52088STimo Kreuzer /* Save irq in the table */
39364e52088STimo Kreuzer HalpVectorToIndex[Vector] = Irq;
39464e52088STimo Kreuzer
39564e52088STimo Kreuzer return Vector;
39664e52088STimo Kreuzer }
39764e52088STimo Kreuzer
39864e52088STimo Kreuzer ULONG
39964e52088STimo Kreuzer NTAPI
HalpGetRootInterruptVector(_In_ ULONG BusInterruptLevel,_In_ ULONG BusInterruptVector,_Out_ PKIRQL OutIrql,_Out_ PKAFFINITY OutAffinity)40064e52088STimo Kreuzer HalpGetRootInterruptVector(
40164e52088STimo Kreuzer _In_ ULONG BusInterruptLevel,
40264e52088STimo Kreuzer _In_ ULONG BusInterruptVector,
40364e52088STimo Kreuzer _Out_ PKIRQL OutIrql,
40464e52088STimo Kreuzer _Out_ PKAFFINITY OutAffinity)
40564e52088STimo Kreuzer {
40664e52088STimo Kreuzer UCHAR Vector;
40764e52088STimo Kreuzer KIRQL Irql;
40864e52088STimo Kreuzer
40964e52088STimo Kreuzer /* Get the vector currently registered */
41064e52088STimo Kreuzer Vector = HalpIrqToVector(BusInterruptLevel);
41164e52088STimo Kreuzer
41264e52088STimo Kreuzer /* Check if it's used */
4136a5472a7SSerge Gautherie if (Vector != APIC_FREE_VECTOR)
41464e52088STimo Kreuzer {
41564e52088STimo Kreuzer /* Calculate IRQL */
41664e52088STimo Kreuzer NT_ASSERT(HalpVectorToIndex[Vector] == BusInterruptLevel);
41764e52088STimo Kreuzer *OutIrql = HalpVectorToIrql(Vector);
41864e52088STimo Kreuzer }
41964e52088STimo Kreuzer else
42064e52088STimo Kreuzer {
42164e52088STimo Kreuzer ULONG Offset;
42264e52088STimo Kreuzer
42364e52088STimo Kreuzer /* Outer loop to find alternative slots, when all IRQLs are in use */
42464e52088STimo Kreuzer for (Offset = 0; Offset < 15; Offset++)
42564e52088STimo Kreuzer {
42664e52088STimo Kreuzer /* Loop allowed IRQL range */
42764e52088STimo Kreuzer for (Irql = CLOCK_LEVEL - 1; Irql >= CMCI_LEVEL; Irql--)
42864e52088STimo Kreuzer {
42964e52088STimo Kreuzer /* Calculate the vactor */
43064e52088STimo Kreuzer Vector = IrqlToTpr(Irql) + Offset;
43164e52088STimo Kreuzer
43264e52088STimo Kreuzer /* Check if the vector is free */
43364e52088STimo Kreuzer if (HalpVectorToIrq(Vector) == APIC_FREE_VECTOR)
43464e52088STimo Kreuzer {
43564e52088STimo Kreuzer /* Found one, allocate the interrupt */
43664e52088STimo Kreuzer Vector = HalpAllocateSystemInterrupt(BusInterruptLevel, Vector);
43764e52088STimo Kreuzer *OutIrql = Irql;
43864e52088STimo Kreuzer goto Exit;
43964e52088STimo Kreuzer }
44064e52088STimo Kreuzer }
44164e52088STimo Kreuzer }
44264e52088STimo Kreuzer
44364e52088STimo Kreuzer DPRINT1("Failed to get an interrupt vector for IRQ %lu\n", BusInterruptLevel);
44464e52088STimo Kreuzer *OutAffinity = 0;
44564e52088STimo Kreuzer *OutIrql = 0;
44664e52088STimo Kreuzer return 0;
44764e52088STimo Kreuzer }
44864e52088STimo Kreuzer
44964e52088STimo Kreuzer Exit:
45064e52088STimo Kreuzer
45164e52088STimo Kreuzer *OutAffinity = HalpDefaultInterruptAffinity;
45264e52088STimo Kreuzer ASSERT(HalpDefaultInterruptAffinity);
45364e52088STimo Kreuzer
454c2c66affSColin Finck return Vector;
455c2c66affSColin Finck }
456c2c66affSColin Finck
457c2c66affSColin Finck VOID
458c2c66affSColin Finck NTAPI
ApicInitializeIOApic(VOID)459c2c66affSColin Finck ApicInitializeIOApic(VOID)
460c2c66affSColin Finck {
461c2c66affSColin Finck PHARDWARE_PTE Pte;
462c2c66affSColin Finck IOAPIC_REDIRECTION_REGISTER ReDirReg;
463c2c66affSColin Finck UCHAR Index;
464c2c66affSColin Finck ULONG Vector;
465c2c66affSColin Finck
466c2c66affSColin Finck /* Map the I/O Apic page */
467c2c66affSColin Finck Pte = HalAddressToPte(IOAPIC_BASE);
468c2c66affSColin Finck Pte->PageFrameNumber = IOAPIC_PHYS_BASE / PAGE_SIZE;
469c2c66affSColin Finck Pte->Valid = 1;
470c2c66affSColin Finck Pte->Write = 1;
471c2c66affSColin Finck Pte->Owner = 1;
472c2c66affSColin Finck Pte->CacheDisable = 1;
473c2c66affSColin Finck Pte->Global = 1;
474c2c66affSColin Finck _ReadWriteBarrier();
475c2c66affSColin Finck
476c2c66affSColin Finck /* Setup a redirection entry */
4776a5472a7SSerge Gautherie ReDirReg.Vector = APIC_FREE_VECTOR;
478*def2fe5dSTimo Kreuzer ReDirReg.MessageType = APIC_MT_Fixed;
479c2c66affSColin Finck ReDirReg.DestinationMode = APIC_DM_Physical;
480c2c66affSColin Finck ReDirReg.DeliveryStatus = 0;
481c2c66affSColin Finck ReDirReg.Polarity = 0;
482c2c66affSColin Finck ReDirReg.RemoteIRR = 0;
483c2c66affSColin Finck ReDirReg.TriggerMode = APIC_TGM_Edge;
484c2c66affSColin Finck ReDirReg.Mask = 1;
485c2c66affSColin Finck ReDirReg.Reserved = 0;
486c2c66affSColin Finck ReDirReg.Destination = 0;
487c2c66affSColin Finck
488c2c66affSColin Finck /* Loop all table entries */
489b7a149fcSTimo Kreuzer for (Index = 0; Index < APIC_MAX_IRQ; Index++)
490c2c66affSColin Finck {
491c2c66affSColin Finck /* Initialize entry */
492b7a149fcSTimo Kreuzer ApicWriteIORedirectionEntry(Index, ReDirReg);
493c2c66affSColin Finck }
494c2c66affSColin Finck
495c2c66affSColin Finck /* Init the vactor to index table */
496c2c66affSColin Finck for (Vector = 0; Vector <= 255; Vector++)
497c2c66affSColin Finck {
498b7a149fcSTimo Kreuzer HalpVectorToIndex[Vector] = APIC_FREE_VECTOR;
499c2c66affSColin Finck }
500c2c66affSColin Finck
501aa3ef4c6STimo Kreuzer /* Enable the timer interrupt (but keep it masked) */
502c2c66affSColin Finck ReDirReg.Vector = APIC_CLOCK_VECTOR;
503*def2fe5dSTimo Kreuzer ReDirReg.MessageType = APIC_MT_Fixed;
504c2c66affSColin Finck ReDirReg.DestinationMode = APIC_DM_Physical;
505c2c66affSColin Finck ReDirReg.TriggerMode = APIC_TGM_Edge;
506aa3ef4c6STimo Kreuzer ReDirReg.Mask = 1;
507c2c66affSColin Finck ReDirReg.Destination = ApicRead(APIC_ID);
508b7a149fcSTimo Kreuzer ApicWriteIORedirectionEntry(APIC_CLOCK_INDEX, ReDirReg);
509c2c66affSColin Finck }
510c2c66affSColin Finck
511c2c66affSColin Finck VOID
512c2c66affSColin Finck NTAPI
HalpInitializePICs(IN BOOLEAN EnableInterrupts)513c2c66affSColin Finck HalpInitializePICs(IN BOOLEAN EnableInterrupts)
514c2c66affSColin Finck {
515c2c66affSColin Finck ULONG_PTR EFlags;
516c2c66affSColin Finck
517c2c66affSColin Finck /* Save EFlags and disable interrupts */
518c2c66affSColin Finck EFlags = __readeflags();
519c2c66affSColin Finck _disable();
520c2c66affSColin Finck
521c2c66affSColin Finck /* Initialize and mask the PIC */
522361b6e39SColin Finck HalpInitializeLegacyPICs();
523c2c66affSColin Finck
524c2c66affSColin Finck /* Initialize the I/O APIC */
525c2c66affSColin Finck ApicInitializeIOApic();
526c2c66affSColin Finck
527c2c66affSColin Finck /* Manually reserve some vectors */
528b7a149fcSTimo Kreuzer HalpVectorToIndex[APC_VECTOR] = APIC_RESERVED_VECTOR;
529b7a149fcSTimo Kreuzer HalpVectorToIndex[DISPATCH_VECTOR] = APIC_RESERVED_VECTOR;
530c2c66affSColin Finck HalpVectorToIndex[APIC_CLOCK_VECTOR] = 8;
53179aaee6aSTimo Kreuzer HalpVectorToIndex[CLOCK_IPI_VECTOR] = APIC_RESERVED_VECTOR;
532b7a149fcSTimo Kreuzer HalpVectorToIndex[APIC_SPURIOUS_VECTOR] = APIC_RESERVED_VECTOR;
533c2c66affSColin Finck
534c2c66affSColin Finck /* Set interrupt handlers in the IDT */
535c2c66affSColin Finck KeRegisterInterruptHandler(APIC_CLOCK_VECTOR, HalpClockInterrupt);
53679aaee6aSTimo Kreuzer KeRegisterInterruptHandler(CLOCK_IPI_VECTOR, HalpClockIpi);
537c2c66affSColin Finck #ifndef _M_AMD64
538c2c66affSColin Finck KeRegisterInterruptHandler(APC_VECTOR, HalpApcInterrupt);
539c2c66affSColin Finck KeRegisterInterruptHandler(DISPATCH_VECTOR, HalpDispatchInterrupt);
540c2c66affSColin Finck #endif
541c2c66affSColin Finck
542c2c66affSColin Finck /* Register the vectors for APC and dispatch interrupts */
543c2c66affSColin Finck HalpRegisterVector(IDT_INTERNAL, 0, APC_VECTOR, APC_LEVEL);
544c2c66affSColin Finck HalpRegisterVector(IDT_INTERNAL, 0, DISPATCH_VECTOR, DISPATCH_LEVEL);
545c2c66affSColin Finck
546c2c66affSColin Finck /* Restore interrupt state */
547c2c66affSColin Finck if (EnableInterrupts) EFlags |= EFLAGS_INTERRUPT_MASK;
548c2c66affSColin Finck __writeeflags(EFlags);
549c2c66affSColin Finck }
550c2c66affSColin Finck
551c2c66affSColin Finck
552c2c66affSColin Finck /* SOFTWARE INTERRUPT TRAPS ***************************************************/
553c2c66affSColin Finck
554c2c66affSColin Finck #ifndef _M_AMD64
555c2c66affSColin Finck VOID
556c2c66affSColin Finck DECLSPEC_NORETURN
557c2c66affSColin Finck FASTCALL
HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame)558c2c66affSColin Finck HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame)
559c2c66affSColin Finck {
560c2c66affSColin Finck KPROCESSOR_MODE ProcessorMode;
561c2c66affSColin Finck KIRQL OldIrql;
562c2c66affSColin Finck ASSERT(ApicGetProcessorIrql() == APC_LEVEL);
563c2c66affSColin Finck
564c2c66affSColin Finck /* Enter trap */
565c2c66affSColin Finck KiEnterInterruptTrap(TrapFrame);
566c2c66affSColin Finck
567c2c66affSColin Finck #ifdef APIC_LAZY_IRQL
568c2c66affSColin Finck if (!HalBeginSystemInterrupt(APC_LEVEL, APC_VECTOR, &OldIrql))
569c2c66affSColin Finck {
570c2c66affSColin Finck /* "Spurious" interrupt, exit the interrupt */
571c2c66affSColin Finck KiEoiHelper(TrapFrame);
572c2c66affSColin Finck }
573c2c66affSColin Finck #else
574c2c66affSColin Finck /* Save the old IRQL */
575c2c66affSColin Finck OldIrql = ApicGetCurrentIrql();
576c2c66affSColin Finck ASSERT(OldIrql < APC_LEVEL);
577c2c66affSColin Finck #endif
578c2c66affSColin Finck
579c2c66affSColin Finck /* Raise to APC_LEVEL */
580c2c66affSColin Finck ApicRaiseIrql(APC_LEVEL);
581c2c66affSColin Finck
582c2c66affSColin Finck /* End the interrupt */
583c2c66affSColin Finck ApicSendEOI();
584c2c66affSColin Finck
585c2c66affSColin Finck /* Kernel or user APC? */
586c2c66affSColin Finck if (KiUserTrap(TrapFrame)) ProcessorMode = UserMode;
587c2c66affSColin Finck else if (TrapFrame->EFlags & EFLAGS_V86_MASK) ProcessorMode = UserMode;
588c2c66affSColin Finck else ProcessorMode = KernelMode;
589c2c66affSColin Finck
590c2c66affSColin Finck /* Enable interrupts and call the kernel's APC interrupt handler */
591c2c66affSColin Finck _enable();
592c2c66affSColin Finck KiDeliverApc(ProcessorMode, NULL, TrapFrame);
593c2c66affSColin Finck
594c2c66affSColin Finck /* Disable interrupts */
595c2c66affSColin Finck _disable();
596c2c66affSColin Finck
597c2c66affSColin Finck /* Restore the old IRQL */
598c2c66affSColin Finck ApicLowerIrql(OldIrql);
599c2c66affSColin Finck
600c2c66affSColin Finck /* Exit the interrupt */
601c2c66affSColin Finck KiEoiHelper(TrapFrame);
602c2c66affSColin Finck }
603c2c66affSColin Finck
604c2c66affSColin Finck VOID
605c2c66affSColin Finck DECLSPEC_NORETURN
606c2c66affSColin Finck FASTCALL
HalpDispatchInterruptHandler(IN PKTRAP_FRAME TrapFrame)607c2c66affSColin Finck HalpDispatchInterruptHandler(IN PKTRAP_FRAME TrapFrame)
608c2c66affSColin Finck {
609c2c66affSColin Finck KIRQL OldIrql;
610c2c66affSColin Finck ASSERT(ApicGetProcessorIrql() == DISPATCH_LEVEL);
611c2c66affSColin Finck
612c2c66affSColin Finck /* Enter trap */
613c2c66affSColin Finck KiEnterInterruptTrap(TrapFrame);
614c2c66affSColin Finck
615c2c66affSColin Finck #ifdef APIC_LAZY_IRQL
616c2c66affSColin Finck if (!HalBeginSystemInterrupt(DISPATCH_LEVEL, DISPATCH_VECTOR, &OldIrql))
617c2c66affSColin Finck {
618c2c66affSColin Finck /* "Spurious" interrupt, exit the interrupt */
619c2c66affSColin Finck KiEoiHelper(TrapFrame);
620c2c66affSColin Finck }
621c2c66affSColin Finck #else
622c2c66affSColin Finck /* Get the current IRQL */
623c2c66affSColin Finck OldIrql = ApicGetCurrentIrql();
624c2c66affSColin Finck ASSERT(OldIrql < DISPATCH_LEVEL);
625c2c66affSColin Finck #endif
626c2c66affSColin Finck
627c2c66affSColin Finck /* Raise to DISPATCH_LEVEL */
628c2c66affSColin Finck ApicRaiseIrql(DISPATCH_LEVEL);
629c2c66affSColin Finck
630c2c66affSColin Finck /* End the interrupt */
631c2c66affSColin Finck ApicSendEOI();
632c2c66affSColin Finck
633c2c66affSColin Finck /* Enable interrupts and call the kernel's DPC interrupt handler */
634c2c66affSColin Finck _enable();
635c2c66affSColin Finck KiDispatchInterrupt();
636c2c66affSColin Finck _disable();
637c2c66affSColin Finck
638c2c66affSColin Finck /* Restore the old IRQL */
639c2c66affSColin Finck ApicLowerIrql(OldIrql);
640c2c66affSColin Finck
641c2c66affSColin Finck /* Exit the interrupt */
642c2c66affSColin Finck KiEoiHelper(TrapFrame);
643c2c66affSColin Finck }
644c2c66affSColin Finck #endif
645c2c66affSColin Finck
646c2c66affSColin Finck
647c2c66affSColin Finck /* SOFTWARE INTERRUPTS ********************************************************/
648c2c66affSColin Finck
649c2c66affSColin Finck
650c2c66affSColin Finck VOID
651c2c66affSColin Finck FASTCALL
HalRequestSoftwareInterrupt(IN KIRQL Irql)652c2c66affSColin Finck HalRequestSoftwareInterrupt(IN KIRQL Irql)
653c2c66affSColin Finck {
654c2c66affSColin Finck /* Convert irql to vector and request an interrupt */
65516e988d1STimo Kreuzer ApicRequestSelfInterrupt(IrqlToSoftVector(Irql), APIC_TGM_Edge);
656c2c66affSColin Finck }
657c2c66affSColin Finck
658c2c66affSColin Finck VOID
659c2c66affSColin Finck FASTCALL
HalClearSoftwareInterrupt(IN KIRQL Irql)660c2c66affSColin Finck HalClearSoftwareInterrupt(
661c2c66affSColin Finck IN KIRQL Irql)
662c2c66affSColin Finck {
663c2c66affSColin Finck /* Nothing to do */
664c2c66affSColin Finck }
665c2c66affSColin Finck
666c2c66affSColin Finck
667c2c66affSColin Finck /* SYSTEM INTERRUPTS **********************************************************/
668c2c66affSColin Finck
669c2c66affSColin Finck BOOLEAN
670c2c66affSColin Finck NTAPI
HalEnableSystemInterrupt(IN ULONG Vector,IN KIRQL Irql,IN KINTERRUPT_MODE InterruptMode)671c2c66affSColin Finck HalEnableSystemInterrupt(
672c2c66affSColin Finck IN ULONG Vector,
673c2c66affSColin Finck IN KIRQL Irql,
674c2c66affSColin Finck IN KINTERRUPT_MODE InterruptMode)
675c2c66affSColin Finck {
676c2c66affSColin Finck IOAPIC_REDIRECTION_REGISTER ReDirReg;
677c2c66affSColin Finck PKPRCB Prcb = KeGetCurrentPrcb();
678c2c66affSColin Finck UCHAR Index;
679c2c66affSColin Finck ASSERT(Irql <= HIGH_LEVEL);
680c2c66affSColin Finck ASSERT((IrqlToTpr(Irql) & 0xF0) == (Vector & 0xF0));
681c2c66affSColin Finck
682c2c66affSColin Finck /* Get the irq for this vector */
683c2c66affSColin Finck Index = HalpVectorToIndex[Vector];
684c2c66affSColin Finck
685c2c66affSColin Finck /* Check if its valid */
6866a5472a7SSerge Gautherie if (Index == APIC_FREE_VECTOR)
687c2c66affSColin Finck {
688c2c66affSColin Finck /* Interrupt is not in use */
689c2c66affSColin Finck return FALSE;
690c2c66affSColin Finck }
691c2c66affSColin Finck
692c2c66affSColin Finck /* Read the redirection entry */
693c2c66affSColin Finck ReDirReg = ApicReadIORedirectionEntry(Index);
694c2c66affSColin Finck
695c2c66affSColin Finck /* Check if the interrupt was unused */
696c2c66affSColin Finck if (ReDirReg.Vector != Vector)
697c2c66affSColin Finck {
698c2c66affSColin Finck ReDirReg.Vector = Vector;
699*def2fe5dSTimo Kreuzer ReDirReg.MessageType = APIC_MT_LowestPriority;
700c2c66affSColin Finck ReDirReg.DestinationMode = APIC_DM_Logical;
701c2c66affSColin Finck ReDirReg.Destination = 0;
702c2c66affSColin Finck }
703c2c66affSColin Finck
704c2c66affSColin Finck /* Check if the destination is logical */
705c2c66affSColin Finck if (ReDirReg.DestinationMode == APIC_DM_Logical)
706c2c66affSColin Finck {
707c2c66affSColin Finck /* Set the bit for this cpu */
708c2c66affSColin Finck ReDirReg.Destination |= ApicLogicalId(Prcb->Number);
709c2c66affSColin Finck }
710c2c66affSColin Finck
711c2c66affSColin Finck /* Set the trigger mode */
712c2c66affSColin Finck ReDirReg.TriggerMode = 1 - InterruptMode;
713c2c66affSColin Finck
714c2c66affSColin Finck /* Now unmask it */
715c2c66affSColin Finck ReDirReg.Mask = FALSE;
716c2c66affSColin Finck
717c2c66affSColin Finck /* Write back the entry */
718c2c66affSColin Finck ApicWriteIORedirectionEntry(Index, ReDirReg);
719c2c66affSColin Finck
720c2c66affSColin Finck return TRUE;
721c2c66affSColin Finck }
722c2c66affSColin Finck
723c2c66affSColin Finck VOID
724c2c66affSColin Finck NTAPI
HalDisableSystemInterrupt(IN ULONG Vector,IN KIRQL Irql)725c2c66affSColin Finck HalDisableSystemInterrupt(
726c2c66affSColin Finck IN ULONG Vector,
727c2c66affSColin Finck IN KIRQL Irql)
728c2c66affSColin Finck {
729c2c66affSColin Finck IOAPIC_REDIRECTION_REGISTER ReDirReg;
730c2c66affSColin Finck UCHAR Index;
731c2c66affSColin Finck ASSERT(Irql <= HIGH_LEVEL);
732c2c66affSColin Finck ASSERT(Vector < RTL_NUMBER_OF(HalpVectorToIndex));
733c2c66affSColin Finck
734c2c66affSColin Finck Index = HalpVectorToIndex[Vector];
735c2c66affSColin Finck
736c2c66affSColin Finck /* Read lower dword of redirection entry */
737c2c66affSColin Finck ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Index);
738c2c66affSColin Finck
739c2c66affSColin Finck /* Mask it */
740c2c66affSColin Finck ReDirReg.Mask = 1;
741c2c66affSColin Finck
742c2c66affSColin Finck /* Write back lower dword */
743b7a149fcSTimo Kreuzer IOApicWrite(IOAPIC_REDTBL + 2 * Index, ReDirReg.Long0);
744c2c66affSColin Finck }
745c2c66affSColin Finck
746c2c66affSColin Finck #ifndef _M_AMD64
747c2c66affSColin Finck BOOLEAN
748c2c66affSColin Finck NTAPI
HalBeginSystemInterrupt(IN KIRQL Irql,IN ULONG Vector,OUT PKIRQL OldIrql)749c2c66affSColin Finck HalBeginSystemInterrupt(
750c2c66affSColin Finck IN KIRQL Irql,
751c2c66affSColin Finck IN ULONG Vector,
752c2c66affSColin Finck OUT PKIRQL OldIrql)
753c2c66affSColin Finck {
754c2c66affSColin Finck KIRQL CurrentIrql;
755c2c66affSColin Finck
756c2c66affSColin Finck /* Get the current IRQL */
757c2c66affSColin Finck CurrentIrql = ApicGetCurrentIrql();
758c2c66affSColin Finck
759c2c66affSColin Finck #ifdef APIC_LAZY_IRQL
760c2c66affSColin Finck /* Check if this interrupt is allowed */
761c2c66affSColin Finck if (CurrentIrql >= Irql)
762c2c66affSColin Finck {
763c2c66affSColin Finck IOAPIC_REDIRECTION_REGISTER RedirReg;
764c2c66affSColin Finck UCHAR Index;
765c2c66affSColin Finck
766c2c66affSColin Finck /* It is not, set the real Irql in the TPR! */
767c2c66affSColin Finck ApicWrite(APIC_TPR, IrqlToTpr(CurrentIrql));
768c2c66affSColin Finck
769c2c66affSColin Finck /* Save the new hard IRQL in the IRR field */
770c2c66affSColin Finck KeGetPcr()->IRR = CurrentIrql;
771c2c66affSColin Finck
772c2c66affSColin Finck /* End this interrupt */
773c2c66affSColin Finck ApicSendEOI();
774c2c66affSColin Finck
775c2c66affSColin Finck /* Get the irq for this vector */
776c2c66affSColin Finck Index = HalpVectorToIndex[Vector];
777c2c66affSColin Finck
778b7a149fcSTimo Kreuzer /* Check if it's valid */
779b7a149fcSTimo Kreuzer if (Index < APIC_MAX_IRQ)
780c2c66affSColin Finck {
781c2c66affSColin Finck /* Read the I/O redirection entry */
782c2c66affSColin Finck RedirReg = ApicReadIORedirectionEntry(Index);
783c2c66affSColin Finck
784c2c66affSColin Finck /* Re-request the interrupt to be handled later */
78516e988d1STimo Kreuzer ApicRequestSelfInterrupt(Vector, (UCHAR)RedirReg.TriggerMode);
786c2c66affSColin Finck }
787c2c66affSColin Finck else
788c2c66affSColin Finck {
789b7a149fcSTimo Kreuzer /* This should be a reserved vector! */
790b7a149fcSTimo Kreuzer ASSERT(Index == APIC_RESERVED_VECTOR);
791b7a149fcSTimo Kreuzer
792c2c66affSColin Finck /* Re-request the interrupt to be handled later */
79316e988d1STimo Kreuzer ApicRequestSelfInterrupt(Vector, APIC_TGM_Edge);
794c2c66affSColin Finck }
795c2c66affSColin Finck
796c2c66affSColin Finck /* Pretend it was a spurious interrupt */
797c2c66affSColin Finck return FALSE;
798c2c66affSColin Finck }
799c2c66affSColin Finck #endif
800c2c66affSColin Finck /* Save the current IRQL */
801c2c66affSColin Finck *OldIrql = CurrentIrql;
802c2c66affSColin Finck
803c2c66affSColin Finck /* Set the new IRQL */
804c2c66affSColin Finck ApicRaiseIrql(Irql);
805c2c66affSColin Finck
806c2c66affSColin Finck /* Turn on interrupts */
807c2c66affSColin Finck _enable();
808c2c66affSColin Finck
809c2c66affSColin Finck /* Success */
810c2c66affSColin Finck return TRUE;
811c2c66affSColin Finck }
812c2c66affSColin Finck
813c2c66affSColin Finck VOID
814c2c66affSColin Finck NTAPI
HalEndSystemInterrupt(IN KIRQL OldIrql,IN PKTRAP_FRAME TrapFrame)815c2c66affSColin Finck HalEndSystemInterrupt(
816c2c66affSColin Finck IN KIRQL OldIrql,
817c2c66affSColin Finck IN PKTRAP_FRAME TrapFrame)
818c2c66affSColin Finck {
819c2c66affSColin Finck /* Send an EOI */
820c2c66affSColin Finck ApicSendEOI();
821c2c66affSColin Finck
822c2c66affSColin Finck /* Restore the old IRQL */
823c2c66affSColin Finck ApicLowerIrql(OldIrql);
824c2c66affSColin Finck }
825c2c66affSColin Finck
826c2c66affSColin Finck
827c2c66affSColin Finck /* IRQL MANAGEMENT ************************************************************/
828c2c66affSColin Finck
829c2c66affSColin Finck KIRQL
830c2c66affSColin Finck NTAPI
KeGetCurrentIrql(VOID)831c2c66affSColin Finck KeGetCurrentIrql(VOID)
832c2c66affSColin Finck {
833c2c66affSColin Finck /* Read the current TPR and convert it to an IRQL */
834c2c66affSColin Finck return ApicGetCurrentIrql();
835c2c66affSColin Finck }
836c2c66affSColin Finck
837c2c66affSColin Finck VOID
838c2c66affSColin Finck FASTCALL
KfLowerIrql(IN KIRQL OldIrql)839c2c66affSColin Finck KfLowerIrql(
840c2c66affSColin Finck IN KIRQL OldIrql)
841c2c66affSColin Finck {
842c2c66affSColin Finck #if DBG
843c2c66affSColin Finck /* Validate correct lower */
844c2c66affSColin Finck if (OldIrql > ApicGetCurrentIrql())
845c2c66affSColin Finck {
846c2c66affSColin Finck /* Crash system */
847c2c66affSColin Finck KeBugCheck(IRQL_NOT_LESS_OR_EQUAL);
848c2c66affSColin Finck }
849c2c66affSColin Finck #endif
850c2c66affSColin Finck /* Set the new IRQL */
851c2c66affSColin Finck ApicLowerIrql(OldIrql);
852c2c66affSColin Finck }
853c2c66affSColin Finck
854c2c66affSColin Finck KIRQL
855c2c66affSColin Finck FASTCALL
KfRaiseIrql(IN KIRQL NewIrql)856c2c66affSColin Finck KfRaiseIrql(
857c2c66affSColin Finck IN KIRQL NewIrql)
858c2c66affSColin Finck {
859c2c66affSColin Finck KIRQL OldIrql;
860c2c66affSColin Finck
861c2c66affSColin Finck /* Read the current IRQL */
862c2c66affSColin Finck OldIrql = ApicGetCurrentIrql();
863c2c66affSColin Finck #if DBG
864c2c66affSColin Finck /* Validate correct raise */
865c2c66affSColin Finck if (OldIrql > NewIrql)
866c2c66affSColin Finck {
867c2c66affSColin Finck /* Crash system */
868c2c66affSColin Finck KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL);
869c2c66affSColin Finck }
870c2c66affSColin Finck #endif
871c2c66affSColin Finck /* Convert the new IRQL to a TPR value and write the register */
872c2c66affSColin Finck ApicRaiseIrql(NewIrql);
873c2c66affSColin Finck
874c2c66affSColin Finck /* Return old IRQL */
875c2c66affSColin Finck return OldIrql;
876c2c66affSColin Finck }
877c2c66affSColin Finck
878c2c66affSColin Finck KIRQL
879c2c66affSColin Finck NTAPI
KeRaiseIrqlToDpcLevel(VOID)880c2c66affSColin Finck KeRaiseIrqlToDpcLevel(VOID)
881c2c66affSColin Finck {
882c2c66affSColin Finck return KfRaiseIrql(DISPATCH_LEVEL);
883c2c66affSColin Finck }
884c2c66affSColin Finck
885c2c66affSColin Finck KIRQL
886c2c66affSColin Finck NTAPI
KeRaiseIrqlToSynchLevel(VOID)887c2c66affSColin Finck KeRaiseIrqlToSynchLevel(VOID)
888c2c66affSColin Finck {
889c2c66affSColin Finck return KfRaiseIrql(SYNCH_LEVEL);
890c2c66affSColin Finck }
891c2c66affSColin Finck
892c2c66affSColin Finck #endif /* !_M_AMD64 */
893c2c66affSColin Finck
894