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