ReactOS 0.4.16-dev-716-g2b2bdab
freeze.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: Processor freeze support for x64
5 * COPYRIGHT: Copyright 2023-2024 Timo Kreuzer <timo.kreuzer@reactos.org>
6 */
7
8/*
9
10 IpiFrozen state graph (based on Windows behavior):
11
12 +-----------------+ Freeze request +-----------------+
13 | RUNNING |------------------------>| TARGET_FREEZE |
14 +-----------------+<--------- +-----------------+
15 |^ | Resume |
16 Freeze || Thaw +-----------+ Thaw request | Freeze IPI
17 v| | THAW |<-----------\ v
18 +-----------------+ +-----------+ +-----------------+
19 | OWNER + ACTIVE | ^ | FROZEN |
20 +-----------------+ | +-----------------+
21 ^ | ^
22 | Kd proc switch | | Kd proc switch
23 v | v
24 +-----------------+ | +-----------------+
25 | OWNER |---------+ | FROZEN + ACTIVE |
26 +-----------------+ Thaw request +-----------------+
27
28 */
29
30/* INCLUDES *******************************************************************/
31
32#include <ntoskrnl.h>
33#define NDEBUG
34#include <debug.h>
35
36/* NOT INCLUDES ANYMORE ******************************************************/
37
39
40/* FUNCTIONS *****************************************************************/
41
44 _In_ PKTRAP_FRAME TrapFrame,
45 _In_ PKEXCEPTION_FRAME ExceptionFrame)
46{
47 PKPRCB CurrentPrcb = KeGetCurrentPrcb();
48
49 /* Make sure this is a freeze request */
50 if (CurrentPrcb->IpiFrozen != IPI_FROZEN_STATE_TARGET_FREEZE)
51 {
52 /* Not a freeze request, return FALSE to signal it is unhandled */
53 return FALSE;
54 }
55
56 /* We are frozen now */
58
59 /* Save the processor state */
60 KiSaveProcessorState(TrapFrame, ExceptionFrame);
61
62 /* Wait for the freeze owner to release us */
63 while (CurrentPrcb->IpiFrozen != IPI_FROZEN_STATE_THAW)
64 {
65 /* Check for Kd processor switch */
66 if (CurrentPrcb->IpiFrozen & IPI_FROZEN_FLAG_ACTIVE)
67 {
68 KCONTINUE_STATUS ContinueStatus;
69
70 /* Enter the debugger */
71 ContinueStatus = KdReportProcessorChange();
72
73 /* Set the state back to frozen */
75
76 /* If the status is ContinueSuccess, we need to release the freeze owner */
77 if (ContinueStatus == ContinueSuccess)
78 {
79 /* Release the freeze owner */
81 }
82 }
83
86 }
87
88 /* Restore the processor state */
89 KiRestoreProcessorState(TrapFrame, ExceptionFrame);
90
91 /* We are running again now */
93
94 /* Return TRUE to signal that we handled the freeze */
95 return TRUE;
96}
97
98VOID
101 VOID)
102{
103 PKPRCB CurrentPrcb = KeGetCurrentPrcb();
104
105 /* Avoid blocking on recursive debug action */
106 if (KiFreezeOwner == CurrentPrcb)
107 {
108 return;
109 }
110
111 /* Try to acquire the freeze owner */
113 {
114 /* Someone else was faster. We expect an NMI to freeze any time.
115 Spin here until the freeze owner is available. */
116 while (KiFreezeOwner != NULL)
117 {
120 }
121 }
122
123 /* We are the owner now and active */
125
126 /* Loop all processors */
127 for (ULONG i = 0; i < KeNumberProcessors; i++)
128 {
129 PKPRCB TargetPrcb = KiProcessorBlock[i];
130 if (TargetPrcb != CurrentPrcb)
131 {
132 /* Only the active processor is allowed to change IpiFrozen */
134
135 /* Request target to freeze */
137 }
138 }
139
140 /* Send the freeze IPI */
142
143 /* Wait for all targets to be frozen */
144 for (ULONG i = 0; i < KeNumberProcessors; i++)
145 {
146 PKPRCB TargetPrcb = KiProcessorBlock[i];
147 if (TargetPrcb != CurrentPrcb)
148 {
149 /* Wait for the target to be frozen */
150 while (TargetPrcb->IpiFrozen != IPI_FROZEN_STATE_FROZEN)
151 {
154 }
155 }
156 }
157
158 /* All targets are frozen, we can continue */
159}
160
161VOID
162NTAPI
164 VOID)
165{
166 PKPRCB CurrentPrcb = KeGetCurrentPrcb();
168
169 /* Loop all processors */
170 for (ULONG i = 0; i < KeNumberProcessors; i++)
171 {
172 PKPRCB TargetPrcb = KiProcessorBlock[i];
173 if (TargetPrcb != CurrentPrcb)
174 {
175 /* Make sure they are still frozen */
177
178 /* Request target to thaw */
179 TargetPrcb->IpiFrozen = IPI_FROZEN_STATE_THAW;
180 }
181 }
182
183 /* Wait for all targets to be running */
184 for (ULONG i = 0; i < KeNumberProcessors; i++)
185 {
186 PKPRCB TargetPrcb = KiProcessorBlock[i];
187 if (TargetPrcb != CurrentPrcb)
188 {
189 /* Wait for the target to be running again */
190 while (TargetPrcb->IpiFrozen != IPI_FROZEN_STATE_RUNNING)
191 {
194 }
195 }
196 }
197
198 /* We are running again now */
199 CurrentPrcb->IpiFrozen = IPI_FROZEN_STATE_RUNNING;
200
201 /* Release the freeze owner */
203}
204
206NTAPI
208 _In_ ULONG ProcessorIndex)
209{
210 PKPRCB CurrentPrcb = KeGetCurrentPrcb();
211 PKPRCB TargetPrcb;
212
213 /* Make sure that the processor index is valid */
214 ASSERT(ProcessorIndex < KeNumberProcessors);
215
216 /* We are no longer active */
218 CurrentPrcb->IpiFrozen &= ~IPI_FROZEN_FLAG_ACTIVE;
219
220 /* Inform the target processor that it's his turn now */
221 TargetPrcb = KiProcessorBlock[ProcessorIndex];
222 TargetPrcb->IpiFrozen |= IPI_FROZEN_FLAG_ACTIVE;
223
224 /* If we are not the freeze owner, we return back to the freeze loop */
225 if (KiFreezeOwner != CurrentPrcb)
226 {
228 }
229
230 /* Loop until it's our turn again */
231 while (CurrentPrcb->IpiFrozen == IPI_FROZEN_STATE_OWNER)
232 {
235 }
236
237 /* Check if we have been thawed */
238 if (CurrentPrcb->IpiFrozen == IPI_FROZEN_STATE_THAW)
239 {
240 /* Another CPU has completed, we can leave the debugger now */
241 KdpDprintf("[%u] KxSwitchKdProcessor: ContinueSuccess\n", KeGetCurrentProcessorNumber());
243 return ContinueSuccess;
244 }
245
246 /* We have been reselected, return to Kd to continue in the debugger */
248
250}
unsigned char BOOLEAN
PKPRCB KiFreezeOwner
Definition: freeze.c:38
VOID NTAPI KxThawExecution(VOID)
Definition: freeze.c:163
KCONTINUE_STATUS NTAPI KxSwitchKdProcessor(_In_ ULONG ProcessorIndex)
Definition: freeze.c:207
BOOLEAN KiProcessorFreezeHandler(_In_ PKTRAP_FRAME TrapFrame, _In_ PKEXCEPTION_FRAME ExceptionFrame)
Definition: freeze.c:43
VOID NTAPI KxFreezeExecution(VOID)
Definition: freeze.c:100
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define InterlockedExchangePointer(Target, Value)
Definition: dshow.h:45
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define InterlockedCompareExchangePointer
Definition: interlocked.h:129
KCONTINUE_STATUS NTAPI KdReportProcessorChange(VOID)
Definition: kdapi.c:1806
#define KdpDprintf(...)
Definition: mmdbg.c:19
#define ASSERT(a)
Definition: mode.c:44
#define IPI_FROZEN_STATE_TARGET_FREEZE
Definition: ketypes.h:319
#define IPI_FROZEN_FLAG_ACTIVE
Definition: ketypes.h:320
#define IPI_FROZEN_STATE_RUNNING
Definition: ketypes.h:315
#define IPI_FREEZE
Definition: ketypes.h:303
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1182
#define IPI_FROZEN_STATE_OWNER
Definition: ketypes.h:318
#define IPI_FROZEN_STATE_THAW
Definition: ketypes.h:317
#define IPI_FROZEN_STATE_FROZEN
Definition: ketypes.h:316
enum _KCONTINUE_STATUS KCONTINUE_STATUS
@ ContinueNextProcessor
Definition: ketypes.h:452
@ ContinueProcessorReselected
Definition: ketypes.h:451
@ ContinueSuccess
Definition: ketypes.h:450
#define _In_
Definition: no_sal2.h:158
PKPRCB KiProcessorBlock[]
Definition: krnlinit.c:31
KAFFINITY KeActiveProcessors
Definition: processor.c:17
VOID FASTCALL KiIpiSend(KAFFINITY TargetSet, ULONG IpiRequest)
VOID NTAPI KiSaveProcessorState(_In_ PKTRAP_FRAME TrapFrame, _In_ PKEXCEPTION_FRAME ExceptionFrame)
Definition: cpu.c:618
VOID NTAPI KiRestoreProcessorState(_Out_ PKTRAP_FRAME TrapFrame, _Out_ PKEXCEPTION_FRAME ExceptionFrame)
Definition: cpu.c:634
CCHAR KeNumberProcessors
Definition: processor.c:16
#define YieldProcessor
Definition: ke.h:48
FORCEINLINE ULONG KeGetCurrentProcessorNumber(VOID)
Definition: ke.h:341
FORCEINLINE VOID KeMemoryBarrier(VOID)
Definition: ke.h:58
ULONG IpiFrozen
Definition: ketypes.h:764
UINT64 SetMember
Definition: ketypes.h:671
#define NTAPI
Definition: typedefs.h:36
uint32_t ULONG
Definition: typedefs.h:59