ReactOS 0.4.15-dev-7842-g558ab78
apicsmp.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS HAL
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: SMP specific APIC code
5 * COPYRIGHT: Copyright 2021 Timo Kreuzer <timo.kreuzer@reactos.org>
6 * Copyright 2023 Justin Miller <justin.miller@reactos.org>
7 */
8
9/* INCLUDES *******************************************************************/
10
11#include <hal.h>
12#include "apicp.h"
13#include <smp.h>
14
15#define NDEBUG
16#include <debug.h>
17
18
20
21/* INTERNAL FUNCTIONS *********************************************************/
22
62VOID
64 _In_ UCHAR DestinationProcessor,
66 _In_ APIC_MT MessageType,
67 _In_ APIC_TGM TriggerMode,
68 _In_ APIC_DSH DestinationShortHand)
69{
72
73 /* Disable interrupts so that we can change IRR without being interrupted */
75 _disable();
76
77 /* Wait for the APIC to be idle */
78 do
79 {
81 } while (Icr.DeliveryStatus);
82
83 /* Setup the command register */
84 Icr.LongLong = 0;
85 Icr.Vector = Vector;
86 Icr.MessageType = MessageType;
88 Icr.DeliveryStatus = 0;
89 Icr.Level = 0;
90 Icr.TriggerMode = TriggerMode;
91 Icr.RemoteReadStatus = 0;
92 Icr.DestinationShortHand = DestinationShortHand;
93 Icr.Destination = DestinationProcessor;
94
95 /* Write the low dword last to send the interrupt */
98
99 /* Finally, restore the original interrupt state */
101 {
102 _enable();
103 }
104}
105
106
107/* SMP SUPPORT FUNCTIONS ******************************************************/
108
109VOID
111 _In_ ULONG NTProcessorNumber,
112 _In_ PHYSICAL_ADDRESS StartupLoc)
113{
114 ASSERT(StartupLoc.HighPart == 0);
115 ASSERT((StartupLoc.QuadPart & 0xFFF) == 0);
116 ASSERT((StartupLoc.QuadPart & 0xFFF00FFF) == 0);
117
118 /* Init IPI */
119 ApicRequestGlobalInterrupt(HalpProcessorIdentity[NTProcessorNumber].LapicId, 0,
121
122 /* De-Assert Init IPI */
123 ApicRequestGlobalInterrupt(HalpProcessorIdentity[NTProcessorNumber].LapicId, 0,
125
126 /* Stall execution for a bit to give APIC time: MPS Spec - B.4 */
128
129 /* Startup IPI */
130 ApicRequestGlobalInterrupt(HalpProcessorIdentity[NTProcessorNumber].LapicId, (StartupLoc.LowPart) >> 12,
132}
133
134/* HAL IPI FUNCTIONS **********************************************************/
135
142VOID
143NTAPI
146 _In_ BOOLEAN IncludeSelf)
147{
148 APIC_DSH DestinationShortHand = IncludeSelf ?
150
151 /* Request the interrupt targeted at all processors */
152 ApicRequestGlobalInterrupt(0, // Ignored
153 Vector,
156 DestinationShortHand);
157}
158
167VOID
168NTAPI
170 _In_ KAFFINITY TargetSet,
172{
173 KAFFINITY ActiveProcessors = HalpActiveProcessors;
174 KAFFINITY RemainingSet, SetMember;
175 ULONG ProcessorIndex;
176 ULONG LApicId;
177
178 /* Sanitize the target set */
179 TargetSet &= ActiveProcessors;
180
181 /* Check if all processors are requested */
182 if (TargetSet == ActiveProcessors)
183 {
184 /* Send an IPI to all processors, including this processor */
186 return;
187 }
188
189 /* Check if all processors except the current one are requested */
190 if (TargetSet == (ActiveProcessors & ~KeGetCurrentPrcb()->SetMember))
191 {
192 /* Send an IPI to all processors, excluding this processor */
194 return;
195 }
196
197 /* Loop while we have more processors */
198 RemainingSet = TargetSet;
199 while (RemainingSet != 0)
200 {
201 NT_VERIFY(BitScanForwardAffinity(&ProcessorIndex, RemainingSet) != 0);
202 ASSERT(ProcessorIndex < KeNumberProcessors);
203 SetMember = AFFINITY_MASK(ProcessorIndex);
204 RemainingSet &= ~SetMember;
205
206 /* Send the interrupt to the target processor */
207 LApicId = HalpProcessorIdentity[ProcessorIndex].LapicId;
209 Vector,
213 }
214}
215
221VOID
222NTAPI
224 _In_ KAFFINITY TargetSet)
225{
226 /* Request the IPI vector */
228}
229
230#ifdef _M_AMD64
231
238VOID
239NTAPI
240HalpSendSoftwareInterrupt(
241 _In_ KAFFINITY TargetSet,
243{
245
246 /* Get the vector for the requested IRQL */
247 if (Irql == APC_LEVEL)
248 {
250 }
251 else if (Irql == DISPATCH_LEVEL)
252 {
254 }
255 else
256 {
257 ASSERT(FALSE);
258 return;
259 }
260
261 /* Request the IPI with the specified vector */
263}
264
270VOID
271NTAPI
272HalpSendNMI(
273 _In_ KAFFINITY TargetSet)
274{
275 KAFFINITY RemainingSet, SetMember;
276 ULONG ProcessorIndex;
277 ULONG LApicId;
278
279 /* Make sure we do not send an NMI to ourselves */
280 ASSERT((TargetSet & KeGetCurrentPrcb()->SetMember) == 0);
281
282 /* Loop while we have more processors */
283 RemainingSet = TargetSet;
284 while (RemainingSet != 0)
285 {
286 NT_VERIFY(BitScanForwardAffinity(&ProcessorIndex, RemainingSet) != 0);
287 ASSERT(ProcessorIndex < KeNumberProcessors);
288 SetMember = AFFINITY_MASK(ProcessorIndex);
289 RemainingSet &= ~SetMember;
290
291 /* Send and NMI to the target processor */
292 LApicId = HalpProcessorIdentity[ProcessorIndex].LapicId;
294 0,
298 }
299}
300
301#endif // _M_AMD64
unsigned char BOOLEAN
@ APIC_DM_Physical
Definition: apicp.h:145
#define APC_VECTOR
Definition: apicp.h:41
@ APIC_DSH_AllIncludingSelf
Definition: apicp.h:154
@ APIC_DSH_Destination
Definition: apicp.h:152
@ APIC_DSH_AllExcludingSelf
Definition: apicp.h:155
@ APIC_MT_INIT
Definition: apicp.h:130
@ APIC_MT_Fixed
Definition: apicp.h:125
@ APIC_MT_NMI
Definition: apicp.h:129
@ APIC_MT_Startup
Definition: apicp.h:131
#define APIC_IPI_VECTOR
Definition: apicp.h:47
enum _APIC_MT APIC_MT
#define DISPATCH_VECTOR
Definition: apicp.h:42
FORCEINLINE ULONG ApicRead(APIC_REGISTER Register)
Definition: apicp.h:316
FORCEINLINE VOID ApicWrite(APIC_REGISTER Register, ULONG Value)
Definition: apicp.h:323
enum _APIC_TGM APIC_TGM
@ APIC_ICR0
Definition: apicp.h:94
@ APIC_ICR1
Definition: apicp.h:95
enum _APIC_DSH APIC_DSH
@ APIC_TGM_Level
Definition: apicp.h:139
@ APIC_TGM_Edge
Definition: apicp.h:138
FORCEINLINE VOID ApicRequestGlobalInterrupt(_In_ UCHAR DestinationProcessor, _In_ UCHAR Vector, _In_ APIC_MT MessageType, _In_ APIC_TGM TriggerMode, _In_ APIC_DSH DestinationShortHand)
Definition: apicsmp.c:63
VOID ApicStartApplicationProcessor(_In_ ULONG NTProcessorNumber, _In_ PHYSICAL_ADDRESS StartupLoc)
Definition: apicsmp.c:110
VOID NTAPI HalpRequestIpi(_In_ KAFFINITY TargetSet)
Requests an IPI interrupt on the specified processors.
Definition: apicsmp.c:223
VOID NTAPI HalRequestIpiSpecifyVector(_In_ KAFFINITY TargetSet, _In_ UCHAR Vector)
Requests an IPI with a specified vector on the specified processors.
Definition: apicsmp.c:169
VOID NTAPI HalpBroadcastIpiSpecifyVector(_In_ UCHAR Vector, _In_ BOOLEAN IncludeSelf)
Broadcasts an IPI with a specified vector to all processors.
Definition: apicsmp.c:144
PPROCESSOR_IDENTITY HalpProcessorIdentity
Definition: madt.c:21
VOID NTAPI KeStallExecutionProcessor(IN ULONG MicroSeconds)
Definition: ntoskrnl.c:81
_Out_ PKIRQL Irql
Definition: csq.h:179
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
ULONG_PTR KAFFINITY
Definition: compat.h:85
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define APC_LEVEL
Definition: env_spec_w32.h:695
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
KAFFINITY HalpActiveProcessors
Definition: processor.c:17
void __cdecl _disable(void)
Definition: intrin_arm.h:365
void __cdecl _enable(void)
Definition: intrin_arm.h:373
__INTRIN_INLINE uintptr_t __readeflags(void)
Definition: intrin_x86.h:1674
CCHAR KeNumberProcessors
Definition: krnlinit.c:35
#define ASSERT(a)
Definition: mode.c:44
#define _In_
Definition: ms_sal.h:308
#define EFLAGS_INTERRUPT_MASK
Definition: ketypes.h:187
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1148
FORCEINLINE KAFFINITY AFFINITY_MASK(ULONG Index)
Definition: kefuncs.h:39
FORCEINLINE BOOLEAN BitScanForwardAffinity(PULONG Index, KAFFINITY Mask)
Definition: kefuncs.h:45
UCHAR LapicId
Definition: smp.h:14
#define NTAPI
Definition: typedefs.h:36
uint32_t ULONG
Definition: typedefs.h:59
#define FORCEINLINE
Definition: wdftypes.h:67
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
#define NT_VERIFY(exp)
Definition: rtlfuncs.h:3287
unsigned char UCHAR
Definition: xmlstorage.h:181