xref: /reactos/hal/halx86/apic/apicp.h (revision 9393fc32)
1 /*
2  * PROJECT:     ReactOS Kernel
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Header file for APIC hal
5  * COPYRIGHT:   Copyright 2011 Timo Kreuzer <timo.kreuzer@reactos.org>
6  *              Copyright 2021 Justin Miller <justinmiller100@gmail.com>
7  */
8 
9 #pragma once
10 
11 #ifdef _M_AMD64
12     #define LOCAL_APIC_BASE 0xFFFFFFFFFFFE0000ULL
13     #define IOAPIC_BASE 0xFFFFFFFFFFFE1000ULL
14 
15     /* Vectors */
16     #define APC_VECTOR           0x1F // IRQL 01 (APC_LEVEL) - KiApcInterrupt
17     #define DISPATCH_VECTOR      0x2F // IRQL 02 (DISPATCH_LEVEL) - KiDpcInterrupt
18     #define CMCI_VECTOR          0x35 // IRQL 05 (CMCI_LEVEL) - HalpInterruptCmciService
19     #define APIC_CLOCK_VECTOR    0xD1 // IRQL 13 (CLOCK_LEVEL), IRQ 8 - HalpTimerClockInterrupt
20     #define CLOCK_IPI_VECTOR     0xD2 // IRQL 13 (CLOCK_LEVEL) - HalpTimerClockIpiRoutine
21     #define REBOOT_VECTOR        0xD7 // IRQL 15 (PROFILE_LEVEL) - HalpInterruptRebootService
22     #define STUB_VECTOR          0xD8 // IRQL 15 (PROFILE_LEVEL) - HalpInterruptStubService
23     #define APIC_SPURIOUS_VECTOR 0xDF // IRQL 13 (CLOCK_LEVEL) - HalpInterruptSpuriousService
24     #define APIC_IPI_VECTOR      0xE1 // IRQL 14 (IPI_LEVEL) - KiIpiInterrupt
25     #define APIC_ERROR_VECTOR    0xE2 // IRQL 14 (IPI_LEVEL) - HalpInterruptLocalErrorService
26     #define POWERFAIL_VECTOR     0xE3 // IRQL 14 (POWER_LEVEL) : HalpInterruptDeferredRecoveryService
27     #define APIC_PROFILE_VECTOR  0xFD // IRQL 15 (PROFILE_LEVEL) - HalpTimerProfileInterrupt
28     #define APIC_PERF_VECTOR     0xFE // IRQL 15 (PROFILE_LEVEL) - HalpPerfInterrupt
29     #define APIC_NMI_VECTOR      0xFF
30 
31     #define IrqlToTpr(Irql) (Irql << 4)
32     #define IrqlToSoftVector(Irql) ((Irql << 4)|0xf)
33     #define TprToIrql(Tpr) ((KIRQL)(Tpr >> 4))
34     #define CLOCK2_LEVEL CLOCK_LEVEL
35 #else
36     #define LOCAL_APIC_BASE  0xFFFE0000
37     #define IOAPIC_BASE 0xFFFE1000
38 
39     /* Vectors */
40     #define APIC_SPURIOUS_VECTOR 0x1f
41     #define APC_VECTOR           0x3D // IRQL 01
42     #define DISPATCH_VECTOR      0x41 // IRQL 02
43     #define APIC_GENERIC_VECTOR  0xC1 // IRQL 27
44     #define APIC_CLOCK_VECTOR    0xD1 // IRQL 28
45     #define APIC_SYNCH_VECTOR    0xD1 // IRQL 28
46     #define APIC_IPI_VECTOR      0xE1 // IRQL 29
47     #define APIC_ERROR_VECTOR    0xE3
48     #define POWERFAIL_VECTOR     0xEF // IRQL 30
49     #define APIC_PROFILE_VECTOR  0xFD // IRQL 31
50     #define APIC_PERF_VECTOR     0xFE
51     #define APIC_NMI_VECTOR      0xFF
52 
53     #define IrqlToTpr(Irql) (HalpIRQLtoTPR[Irql])
54     #define IrqlToSoftVector(Irql) IrqlToTpr(Irql)
55     #define TprToIrql(Tpr)  (HalVectorToIRQL[Tpr >> 4])
56 #endif
57 
58 #define APIC_MAX_IRQ 24
59 #define APIC_FREE_VECTOR 0xFF
60 #define APIC_RESERVED_VECTOR 0xFE
61 
62 /* The IMCR is supported by two read/writable or write-only I/O ports,
63    22h and 23h, which receive address and data respectively.
64    To access the IMCR, write a value of 70h to I/O port 22h, which selects the IMCR.
65    Then write the data to I/O port 23h. The power-on default value is zero,
66    which connects the NMI and 8259 INTR lines directly to the BSP.
67    Writing a value of 01h forces the NMI and 8259 INTR signals to pass through the APIC.
68 */
69 #define IMCR_ADDRESS_PORT  (PUCHAR)0x0022
70 #define IMCR_DATA_PORT     (PUCHAR)0x0023
71 #define IMCR_SELECT        0x70
72 #define IMCR_PIC_DIRECT    0x00
73 #define IMCR_PIC_VIA_APIC  0x01
74 
75 
76 /* APIC Register Address Map */
77 typedef enum _APIC_REGISTER
78 {
79     APIC_ID       = 0x0020, /* Local APIC ID Register (R/W) */
80     APIC_VER      = 0x0030, /* Local APIC Version Register (R) */
81     APIC_TPR      = 0x0080, /* Task Priority Register (R/W) */
82     APIC_APR      = 0x0090, /* Arbitration Priority Register (R) */
83     APIC_PPR      = 0x00A0, /* Processor Priority Register (R) */
84     APIC_EOI      = 0x00B0, /* EOI Register (W) */
85     APIC_RRR      = 0x00C0, /* Remote Read Register () */
86     APIC_LDR      = 0x00D0, /* Logical Destination Register (R/W) */
87     APIC_DFR      = 0x00E0, /* Destination Format Register (0-27 R, 28-31 R/W) */
88     APIC_SIVR     = 0x00F0, /* Spurious Interrupt Vector Register (0-3 R, 4-9 R/W) */
89     APIC_ISR      = 0x0100, /* Interrupt Service Register 0-255 (R) */
90     APIC_TMR      = 0x0180, /* Trigger Mode Register 0-255 (R) */
91     APIC_IRR      = 0x0200, /* Interrupt Request Register 0-255 (r) */
92     APIC_ESR      = 0x0280, /* Error Status Register (R) */
93     APIC_ICR0     = 0x0300, /* Interrupt Command Register 0-31 (R/W) */
94     APIC_ICR1     = 0x0310, /* Interrupt Command Register 32-63 (R/W) */
95     APIC_TMRLVTR  = 0x0320, /* Timer Local Vector Table (R/W) */
96     APIC_THRMLVTR = 0x0330, /* Thermal Local Vector Table */
97     APIC_PCLVTR   = 0x0340, /* Performance Counter Local Vector Table (R/W) */
98     APIC_LINT0    = 0x0350, /* LINT0 Local Vector Table (R/W) */
99     APIC_LINT1    = 0x0360, /* LINT1 Local Vector Table (R/W) */
100     APIC_ERRLVTR  = 0x0370, /* Error Local Vector Table (R/W) */
101     APIC_TICR     = 0x0380, /* Initial Count Register for Timer (R/W) */
102     APIC_TCCR     = 0x0390, /* Current Count Register for Timer (R) */
103     APIC_TDCR     = 0x03E0, /* Timer Divide Configuration Register (R/W) */
104     APIC_EAFR     = 0x0400, /* extended APIC Feature register (R/W) */
105     APIC_EACR     = 0x0410, /* Extended APIC Control Register (R/W) */
106     APIC_SEOI     = 0x0420, /* Specific End Of Interrupt Register (W) */
107     APIC_EXT0LVTR = 0x0500, /* Extended Interrupt 0 Local Vector Table */
108     APIC_EXT1LVTR = 0x0510, /* Extended Interrupt 1 Local Vector Table */
109     APIC_EXT2LVTR = 0x0520, /* Extended Interrupt 2 Local Vector Table */
110     APIC_EXT3LVTR = 0x0530  /* Extended Interrupt 3 Local Vector Table */
111 } APIC_REGISTER;
112 
113 #define MSR_APIC_BASE 0x0000001B
114 #define IOAPIC_PHYS_BASE 0xFEC00000
115 #define APIC_CLOCK_INDEX 8
116 #define ApicLogicalId(Cpu) ((UCHAR)(1<< Cpu))
117 
118 /* The following definitions are based on AMD documentation.
119    They differ slightly in Intel documentation. */
120 
121 /* Message Type (Intel: "Delivery Mode") */
122 typedef enum _APIC_MT
123 {
124     APIC_MT_Fixed = 0,
125     APIC_MT_LowestPriority = 1,
126     APIC_MT_SMI = 2,
127     APIC_MT_RemoteRead = 3,
128     APIC_MT_NMI = 4,
129     APIC_MT_INIT = 5,
130     APIC_MT_Startup = 6,
131     APIC_MT_ExtInt = 7,
132 } APIC_MT;
133 
134 /* Trigger Mode */
135 typedef enum _APIC_TGM
136 {
137     APIC_TGM_Edge,
138     APIC_TGM_Level
139 } APIC_TGM;
140 
141 /* Destination Mode */
142 typedef enum _APIC_DM
143 {
144     APIC_DM_Physical,
145     APIC_DM_Logical
146 } APIC_DM;
147 
148 /* Destination Short Hand */
149 typedef enum _APIC_DSH
150 {
151     APIC_DSH_Destination,
152     APIC_DSH_Self,
153     APIC_DSH_AllIncludingSelf,
154     APIC_DSH_AllExclusingSelf
155 } APIC_DSH;
156 
157 /* Write Constants */
158 typedef enum _APIC_DF
159 {
160     APIC_DF_Flat = 0xFFFFFFFF,
161     APIC_DF_Cluster = 0x0FFFFFFF
162 } APIC_DF;
163 
164 /* Remote Read Status */
165 typedef enum _APIC_RRS
166 {
167     APIC_RRS_Invalid = 0,
168     APIC_RRS_Pending = 1,
169     APIC_RRS_Done = 2
170 } APIC_RRS;
171 
172 /* Timer Constants */
173 enum _TIMER_DV
174 {
175     TIMER_DV_DivideBy2 = 0,
176     TIMER_DV_DivideBy4 = 1,
177     TIMER_DV_DivideBy8 = 2,
178     TIMER_DV_DivideBy16 = 3,
179     TIMER_DV_DivideBy32 = 8,
180     TIMER_DV_DivideBy64 = 9,
181     TIMER_DV_DivideBy128 = 10,
182     TIMER_DV_DivideBy1 = 11,
183 } TIMER_DV;
184 
185 #include <pshpack1.h>
186 typedef union _APIC_BASE_ADRESS_REGISTER
187 {
188     UINT64 LongLong;
189     struct
190     {
191         UINT64 Reserved1:8;
192         UINT64 BootStrapCPUCore:1;
193         UINT64 Reserved2:2;
194         UINT64 Enable:1;
195         UINT64 BaseAddress:40;
196         UINT64 ReservedMBZ:12;
197     };
198 } APIC_BASE_ADRESS_REGISTER;
199 
200 typedef union _APIC_SPURIOUS_INERRUPT_REGISTER
201 {
202     UINT32 Long;
203     struct
204     {
205         UINT32 Vector:8;
206         UINT32 SoftwareEnable:1;
207         UINT32 FocusCPUCoreChecking:1;
208         UINT32 ReservedMBZ:22;
209     };
210 } APIC_SPURIOUS_INERRUPT_REGISTER;
211 
212 typedef union _APIC_VERSION_REGISTER
213 {
214     UINT32 Long;
215     struct
216     {
217         UINT32 Version:8;
218         UINT32 ReservedMBZ:8;
219         UINT32 MaxLVT:8;
220         UINT32 ReservedMBZ1:7;
221         UINT32 ExtRegSpacePresent:1;
222     };
223 } APIC_VERSION_REGISTER;
224 
225 typedef union _APIC_EXTENDED_CONTROL_REGISTER
226 {
227     UINT32 Long;
228     struct
229     {
230         UINT32 Version:1;
231         UINT32 SEOIEnable:1;
232         UINT32 ExtApicIdEnable:1;
233         UINT32 ReservedMBZ:29;
234     };
235 } APIC_EXTENDED_CONTROL_REGISTER;
236 
237 typedef union _APIC_INTERRUPT_COMMAND_REGISTER
238 {
239     UINT64 LongLong;
240     struct
241     {
242         UINT32 Long0;
243         UINT32 Long1;
244     };
245     struct
246     {
247         UINT64 Vector:8;
248         UINT64 MessageType:3;
249         UINT64 DestinationMode:1;
250         UINT64 DeliveryStatus:1;
251         UINT64 ReservedMBZ:1;
252         UINT64 Level:1;
253         UINT64 TriggerMode:1;
254         UINT64 RemoteReadStatus:2; /* Intel: Reserved */
255         UINT64 DestinationShortHand:2;
256         UINT64 Reserved2MBZ:36;
257         UINT64 Destination:8;
258     };
259 } APIC_INTERRUPT_COMMAND_REGISTER;
260 
261 typedef union _LVT_REGISTER
262 {
263     UINT32 Long;
264     struct
265     {
266         UINT32 Vector:8;
267         UINT32 MessageType:3;
268         UINT32 ReservedMBZ:1;
269         UINT32 DeliveryStatus:1;
270         UINT32 Reserved1MBZ:1;
271         UINT32 RemoteIRR:1;
272         UINT32 TriggerMode:1;
273         UINT32 Mask:1;
274         UINT32 TimerMode:1;
275         UINT32 Reserved2MBZ:13;
276     };
277 } LVT_REGISTER;
278 
279 /* IOAPIC offsets */
280 enum
281 {
282     IOAPIC_IOREGSEL = 0x00,
283     IOAPIC_IOWIN    = 0x10
284 };
285 
286 /* IOAPIC Constants */
287 enum
288 {
289     IOAPIC_ID  = 0x00,
290     IOAPIC_VER = 0x01,
291     IOAPIC_ARB = 0x02,
292     IOAPIC_REDTBL = 0x10
293 };
294 
295 typedef union _IOAPIC_REDIRECTION_REGISTER
296 {
297     UINT64 LongLong;
298     struct
299     {
300         UINT32 Long0;
301         UINT32 Long1;
302     };
303     struct
304     {
305         UINT64 Vector:8;
306         UINT64 DeliveryMode:3;
307         UINT64 DestinationMode:1;
308         UINT64 DeliveryStatus:1;
309         UINT64 Polarity:1;
310         UINT64 RemoteIRR:1;
311         UINT64 TriggerMode:1;
312         UINT64 Mask:1;
313         UINT64 Reserved:39;
314         UINT64 Destination:8;
315     };
316 } IOAPIC_REDIRECTION_REGISTER;
317 #include <poppack.h>
318 
319 FORCEINLINE
320 ULONG
321 ApicRead(APIC_REGISTER Register)
322 {
323     return READ_REGISTER_ULONG((PULONG)(APIC_BASE + Register));
324 }
325 
326 FORCEINLINE
327 VOID
328 ApicWrite(APIC_REGISTER Register, ULONG Value)
329 {
330     WRITE_REGISTER_ULONG((PULONG)(APIC_BASE + Register), Value);
331 }
332 
333 VOID
334 NTAPI
335 ApicInitializeTimer(ULONG Cpu);
336 
337 VOID
338 NTAPI
339 HalInitializeProfiling(VOID);
340 
341 VOID
342 NTAPI
343 HalpInitApicInfo(IN PLOADER_PARAMETER_BLOCK KeLoaderBlock);
344 
345 VOID __cdecl ApicSpuriousService(VOID);
346