Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

546 lines
11 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. stubs.c
  5. Abstract:
  6. This module implements kernel debugger synchronization routines.
  7. Author:
  8. Ken Reneris (kenr) 30-Aug-1990
  9. Environment:
  10. Kernel mode only.
  11. Revision History:
  12. --*/
  13. #include "ki.h"
  14. #define IDBG 1
  15. #define FrozenState(a) (a & 0xF)
  16. // state
  17. #define RUNNING 0x00
  18. #define TARGET_FROZEN 0x02
  19. #define TARGET_THAW 0x03
  20. #define FREEZE_OWNER 0x04
  21. // flags (bits)
  22. #define FREEZE_ACTIVE 0x20
  23. //
  24. // Define local storage to save the old IRQL.
  25. //
  26. KIRQL KiOldIrql;
  27. #ifndef NT_UP
  28. PKPRCB KiFreezeOwner;
  29. #endif
  30. BOOLEAN
  31. KeFreezeExecution (
  32. IN PKTRAP_FRAME TrapFrame,
  33. IN PKEXCEPTION_FRAME ExceptionFrame
  34. )
  35. /*++
  36. Routine Description:
  37. This function freezes the execution of all other processors in the host
  38. configuration and then returns to the caller.
  39. Arguments:
  40. TrapFrame - Supplies a pointer to a trap frame that describes the
  41. trap.
  42. ExceptionFrame - Supplies a pointer to an exception frame that
  43. describes the trap.
  44. Return Value:
  45. Previous interrupt enable.
  46. --*/
  47. {
  48. BOOLEAN Enable;
  49. #if !defined(NT_UP)
  50. BOOLEAN Flag;
  51. PKPRCB Prcb;
  52. KAFFINITY TargetSet;
  53. ULONG BitNumber;
  54. KIRQL OldIrql;
  55. #if IDBG
  56. ULONG Count = 30000;
  57. #endif
  58. #endif
  59. //
  60. // Disable interrupts.
  61. //
  62. Enable = KeDisableInterrupts();
  63. KiFreezeFlag = FREEZE_FROZEN;
  64. #if !defined(NT_UP)
  65. //
  66. // Raise IRQL to HIGH_LEVEL.
  67. //
  68. KeRaiseIrql(HIGH_LEVEL, &OldIrql);
  69. if (FrozenState(KeGetCurrentPrcb()->IpiFrozen) == FREEZE_OWNER) {
  70. //
  71. // This processor already owns the freeze lock.
  72. // Return without trying to re-acquire lock or without
  73. // trying to IPI the other processors again
  74. //
  75. return Enable;
  76. }
  77. //
  78. // Try to acquire the KiFreezeExecutionLock before sending the request.
  79. // To prevent deadlock from occurring, we need to accept and process
  80. // incoming FreexeExecution requests while we are waiting to acquire
  81. // the FreezeExecutionFlag.
  82. //
  83. while (KeTryToAcquireSpinLockAtDpcLevel(&KiFreezeExecutionLock) == FALSE) {
  84. //
  85. // FreezeExecutionLock is busy. Another processor may be trying
  86. // to IPI us - go service any IPI.
  87. //
  88. KeEnableInterrupts(Enable);
  89. Flag = KiIpiServiceRoutine((PVOID)TrapFrame, (PVOID)ExceptionFrame);
  90. KeDisableInterrupts();
  91. #if IDBG
  92. if (Flag != FALSE) {
  93. Count = 30000;
  94. continue;
  95. }
  96. KeStallExecutionProcessor (100);
  97. if (!Count--) {
  98. Count = 30000;
  99. if (KeTryToAcquireSpinLockAtDpcLevel(&KiFreezeLockBackup) == TRUE) {
  100. KiFreezeFlag |= FREEZE_BACKUP;
  101. break;
  102. }
  103. }
  104. #endif
  105. }
  106. //
  107. // After acquiring the lock flag, we send Freeze request to each processor
  108. // in the system (other than us) and wait for it to become frozen.
  109. //
  110. Prcb = KeGetCurrentPrcb(); // Do this after spinlock is acquired.
  111. TargetSet = KeActiveProcessors & ~(AFFINITY_MASK(Prcb->Number));
  112. if (TargetSet) {
  113. #if IDBG
  114. Count = 400;
  115. #endif
  116. KiFreezeOwner = Prcb;
  117. Prcb->IpiFrozen = FREEZE_OWNER | FREEZE_ACTIVE;
  118. Prcb->SkipTick = TRUE;
  119. KiIpiSend((KAFFINITY) TargetSet, IPI_FREEZE);
  120. while (TargetSet != 0) {
  121. KeFindFirstSetLeftAffinity(TargetSet, &BitNumber);
  122. ClearMember(BitNumber, TargetSet);
  123. Prcb = KiProcessorBlock[BitNumber];
  124. #if IDBG
  125. while (Prcb->IpiFrozen != TARGET_FROZEN) {
  126. if (Count == 0) {
  127. KiFreezeFlag |= FREEZE_SKIPPED_PROCESSOR;
  128. break;
  129. }
  130. KeStallExecutionProcessor (10000);
  131. Count--;
  132. }
  133. #else
  134. while (Prcb->IpiFrozen != TARGET_FROZEN) {
  135. KeYieldProcessor();
  136. }
  137. #endif
  138. }
  139. }
  140. //
  141. // Save the old IRQL and return whether interrupts were previous enabled.
  142. //
  143. KiOldIrql = OldIrql;
  144. #endif // !defined(NT_UP)
  145. return Enable;
  146. }
  147. VOID
  148. KiFreezeTargetExecution (
  149. IN PKTRAP_FRAME TrapFrame,
  150. IN PKEXCEPTION_FRAME ExceptionFrame
  151. )
  152. /*++
  153. Routine Description:
  154. This function freezes the execution of the current running processor.
  155. If a trapframe is supplied to current state is saved into the prcb
  156. for the debugger.
  157. Arguments:
  158. TrapFrame - Supplies a pointer to the trap frame that describes the
  159. trap.
  160. ExceptionFrame - Supplies a pointer to the exception frame that
  161. describes the trap.
  162. Return Value:
  163. None.
  164. --*/
  165. {
  166. #if !defined(NT_UP)
  167. KIRQL OldIrql;
  168. PKPRCB Prcb;
  169. BOOLEAN Enable;
  170. KCONTINUE_STATUS Status;
  171. EXCEPTION_RECORD ExceptionRecord;
  172. Enable = KeDisableInterrupts();
  173. KeRaiseIrql(HIGH_LEVEL, &OldIrql);
  174. Prcb = KeGetCurrentPrcb();
  175. Prcb->IpiFrozen = TARGET_FROZEN;
  176. Prcb->SkipTick = TRUE;
  177. if (TrapFrame != NULL) {
  178. KiSaveProcessorState(TrapFrame, ExceptionFrame);
  179. }
  180. //
  181. // Sweep the data cache in case this is a system crash and the bug
  182. // check code is attempting to write a crash dump file.
  183. //
  184. KeSweepCurrentDcache();
  185. //
  186. // Wait for person requesting us to freeze to
  187. // clear our frozen flag
  188. //
  189. while (FrozenState(Prcb->IpiFrozen) == TARGET_FROZEN) {
  190. if (Prcb->IpiFrozen & FREEZE_ACTIVE) {
  191. //
  192. // This processor has been made the active processor
  193. //
  194. if (TrapFrame) {
  195. RtlZeroMemory (&ExceptionRecord, sizeof ExceptionRecord);
  196. ExceptionRecord.ExceptionCode = STATUS_WAKE_SYSTEM_DEBUGGER;
  197. ExceptionRecord.ExceptionRecord = &ExceptionRecord;
  198. ExceptionRecord.ExceptionAddress =
  199. (PVOID)CONTEXT_TO_PROGRAM_COUNTER (&Prcb->ProcessorState.ContextFrame);
  200. Status = (KiDebugSwitchRoutine) (
  201. &ExceptionRecord,
  202. &Prcb->ProcessorState.ContextFrame,
  203. FALSE
  204. );
  205. } else {
  206. Status = ContinueError;
  207. }
  208. //
  209. // If status is anything other then, continue with next
  210. // processor then reselect master
  211. //
  212. if (Status != ContinueNextProcessor) {
  213. Prcb->IpiFrozen &= ~FREEZE_ACTIVE;
  214. KiFreezeOwner->IpiFrozen |= FREEZE_ACTIVE;
  215. }
  216. }
  217. KeYieldProcessor();
  218. }
  219. if (TrapFrame != NULL) {
  220. KiRestoreProcessorState(TrapFrame, ExceptionFrame);
  221. }
  222. Prcb->IpiFrozen = RUNNING;
  223. KeFlushCurrentTb();
  224. KeSweepCurrentIcache();
  225. KeLowerIrql(OldIrql);
  226. KeEnableInterrupts(Enable);
  227. #endif // !define(NT_UP)
  228. return;
  229. }
  230. KCONTINUE_STATUS
  231. KeSwitchFrozenProcessor (
  232. IN ULONG ProcessorNumber
  233. )
  234. {
  235. #if !defined(NT_UP)
  236. PKPRCB TargetPrcb, CurrentPrcb;
  237. //
  238. // If Processor number is out of range, reselect current processor
  239. //
  240. if (ProcessorNumber >= (ULONG) KeNumberProcessors) {
  241. return ContinueProcessorReselected;
  242. }
  243. TargetPrcb = KiProcessorBlock[ProcessorNumber];
  244. CurrentPrcb = KeGetCurrentPrcb();
  245. //
  246. // Move active flag to correct processor.
  247. //
  248. CurrentPrcb->IpiFrozen &= ~FREEZE_ACTIVE;
  249. TargetPrcb->IpiFrozen |= FREEZE_ACTIVE;
  250. //
  251. // If this processor is frozen in KiFreezeTargetExecution, return to it
  252. //
  253. if (FrozenState(CurrentPrcb->IpiFrozen) == TARGET_FROZEN) {
  254. return ContinueNextProcessor;
  255. }
  256. //
  257. // This processor must be FREEZE_OWNER, wait to be reselected as the
  258. // active processor
  259. //
  260. if (FrozenState(CurrentPrcb->IpiFrozen) != FREEZE_OWNER) {
  261. return ContinueError;
  262. }
  263. while (!(CurrentPrcb->IpiFrozen & FREEZE_ACTIVE)) {
  264. KeYieldProcessor();
  265. }
  266. #endif // !defined(NT_UP)
  267. //
  268. // Reselect this processor
  269. //
  270. return ContinueProcessorReselected;
  271. }
  272. VOID
  273. KeThawExecution (
  274. IN BOOLEAN Enable
  275. )
  276. /*++
  277. Routine Description:
  278. This function thaws the execution of all other processors in the host
  279. configuration and then returns to the caller. It is intended for use by
  280. the kernel debugger.
  281. Arguments:
  282. Enable - Supplies the previous interrupt enable that is to be restored
  283. after having thawed the execution of all other processors.
  284. Return Value:
  285. None.
  286. --*/
  287. {
  288. #if !defined(NT_UP)
  289. KIRQL OldIrql;
  290. KAFFINITY TargetSet;
  291. ULONG BitNumber;
  292. ULONG Flag;
  293. PKPRCB Prcb;
  294. //
  295. // Before releasing FreezeExecutionLock clear any all targets IpiFrozen
  296. // flag.
  297. //
  298. KeGetCurrentPrcb()->IpiFrozen = RUNNING;
  299. TargetSet = KeActiveProcessors & ~(AFFINITY_MASK(KeGetCurrentPrcb()->Number));
  300. while (TargetSet != 0) {
  301. KeFindFirstSetLeftAffinity(TargetSet, &BitNumber);
  302. ClearMember(BitNumber, TargetSet);
  303. Prcb = KiProcessorBlock[BitNumber];
  304. #if IDBG
  305. //
  306. // If the target processor was not forzen, then don't wait
  307. // for target to unfreeze.
  308. //
  309. if (FrozenState(Prcb->IpiFrozen) != TARGET_FROZEN) {
  310. Prcb->IpiFrozen = RUNNING;
  311. continue;
  312. }
  313. #endif
  314. Prcb->IpiFrozen = TARGET_THAW;
  315. while (Prcb->IpiFrozen == TARGET_THAW) {
  316. KeYieldProcessor();
  317. }
  318. }
  319. //
  320. // Capture the previous IRQL before releasing the freeze lock.
  321. //
  322. OldIrql = KiOldIrql;
  323. #if IDBG
  324. Flag = KiFreezeFlag;
  325. KiFreezeFlag = 0;
  326. if ((Flag & FREEZE_BACKUP) != 0) {
  327. KiReleaseSpinLock(&KiFreezeLockBackup);
  328. } else {
  329. KiReleaseSpinLock(&KiFreezeExecutionLock);
  330. }
  331. #else
  332. KiFreezeFlag = 0;
  333. KiReleaseSpinLock(&KiFreezeExecutionLock);
  334. #endif
  335. #endif // !defined (NT_UP)
  336. //
  337. // Flush the current TB, instruction cache, and data cache.
  338. //
  339. KeFlushCurrentTb();
  340. KeSweepCurrentIcache();
  341. KeSweepCurrentDcache();
  342. //
  343. // Lower IRQL and restore interrupt enable
  344. //
  345. #if !defined(NT_UP)
  346. KeLowerIrql(OldIrql);
  347. #endif
  348. KeEnableInterrupts(Enable);
  349. return;
  350. }
  351. VOID
  352. KiPollFreezeExecution(
  353. VOID
  354. )
  355. /*++
  356. Routine Description:
  357. This routine is called from code that is spinning with interrupts
  358. disabled, waiting for something to happen, when there is some
  359. (possibly extremely small) chance that that thing will not happen
  360. because a system freeze has been initiated.
  361. N.B. Interrupts are disabled.
  362. Arguments:
  363. None.
  364. Return Value:
  365. None.
  366. --*/
  367. {
  368. //
  369. // Check to see if a freeze is pending for this processor.
  370. //
  371. PKPRCB Prcb = KeGetCurrentPrcb();
  372. if ((Prcb->RequestSummary & IPI_FREEZE) != 0) {
  373. //
  374. // Clear the freeze request and freeze this processor.
  375. //
  376. InterlockedExchangeAdd((PLONG)&Prcb->RequestSummary, -(IPI_FREEZE));
  377. KiFreezeTargetExecution(NULL, NULL);
  378. } else {
  379. //
  380. // No freeze pending, assume this processor is spinning.
  381. //
  382. KeYieldProcessor();
  383. }
  384. }