xref: /reactos/hal/halx86/apic/apic.c (revision def2fe5d)
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