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.

1909 lines
52 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. stubs.c
  5. Abstract:
  6. This module implements bug check and system shutdown code.
  7. Author:
  8. Mark Lucovsky (markl) 30-Aug-1990
  9. Environment:
  10. Kernel mode only.
  11. Revision History:
  12. --*/
  13. #include "ki.h"
  14. #define NOEXTAPI
  15. #include "wdbgexts.h"
  16. #include <inbv.h>
  17. #include <hdlsblk.h>
  18. #include <hdlsterm.h>
  19. //
  20. //
  21. //
  22. extern KDDEBUGGER_DATA64 KdDebuggerDataBlock;
  23. extern PVOID ExPoolCodeStart;
  24. extern PVOID ExPoolCodeEnd;
  25. extern PVOID MmPoolCodeStart;
  26. extern PVOID MmPoolCodeEnd;
  27. extern PVOID MmPteCodeStart;
  28. extern PVOID MmPteCodeEnd;
  29. #if defined(_AMD64_)
  30. #define PROGRAM_COUNTER(_trapframe) ((_trapframe)->Rip)
  31. #elif defined(_X86_)
  32. #define PROGRAM_COUNTER(_trapframe) ((_trapframe)->Eip)
  33. #elif defined(_IA64_)
  34. #define PROGRAM_COUNTER(_trapframe) ((_trapframe)->StIIP)
  35. #else
  36. #error "no target architecture"
  37. #endif
  38. //
  39. // Define forward referenced prototypes.
  40. //
  41. VOID
  42. KiScanBugCheckCallbackList (
  43. VOID
  44. );
  45. VOID
  46. KiInvokeBugCheckEntryCallbacks (
  47. VOID
  48. );
  49. //
  50. // Define bug count recursion counter and a context buffer.
  51. //
  52. ULONG KeBugCheckCount = 1;
  53. VOID
  54. KeBugCheck (
  55. IN ULONG BugCheckCode
  56. )
  57. {
  58. KeBugCheck2(BugCheckCode,0,0,0,0,NULL);
  59. }
  60. VOID
  61. KeBugCheckEx (
  62. IN ULONG BugCheckCode,
  63. IN ULONG_PTR P1,
  64. IN ULONG_PTR P2,
  65. IN ULONG_PTR P3,
  66. IN ULONG_PTR P4
  67. )
  68. {
  69. KeBugCheck2(BugCheckCode,P1,P2,P3,P4,NULL);
  70. }
  71. ULONG_PTR KiBugCheckData[5];
  72. PUNICODE_STRING KiBugCheckDriver;
  73. BOOLEAN
  74. KeGetBugMessageText(
  75. IN ULONG MessageId,
  76. IN PANSI_STRING ReturnedString OPTIONAL
  77. )
  78. {
  79. ULONG i;
  80. PUCHAR s;
  81. PMESSAGE_RESOURCE_BLOCK MessageBlock;
  82. PUCHAR Buffer;
  83. BOOLEAN Result;
  84. Result = FALSE;
  85. try {
  86. if (KiBugCodeMessages != NULL) {
  87. MmMakeKernelResourceSectionWritable ();
  88. MessageBlock = &KiBugCodeMessages->Blocks[0];
  89. for (i = KiBugCodeMessages->NumberOfBlocks; i; i -= 1) {
  90. if (MessageId >= MessageBlock->LowId &&
  91. MessageId <= MessageBlock->HighId) {
  92. s = (PCHAR)KiBugCodeMessages + MessageBlock->OffsetToEntries;
  93. for (i = MessageId - MessageBlock->LowId; i; i -= 1) {
  94. s += ((PMESSAGE_RESOURCE_ENTRY)s)->Length;
  95. }
  96. Buffer = ((PMESSAGE_RESOURCE_ENTRY)s)->Text;
  97. i = strlen(Buffer) - 1;
  98. while (i > 0 && (Buffer[i] == '\n' ||
  99. Buffer[i] == '\r' ||
  100. Buffer[i] == 0
  101. )
  102. ) {
  103. if (!ARGUMENT_PRESENT( ReturnedString )) {
  104. Buffer[i] = 0;
  105. }
  106. i -= 1;
  107. }
  108. if (!ARGUMENT_PRESENT( ReturnedString )) {
  109. InbvDisplayString(Buffer);
  110. }
  111. else {
  112. ReturnedString->Buffer = Buffer;
  113. ReturnedString->Length = (USHORT)(i+1);
  114. ReturnedString->MaximumLength = (USHORT)(i+1);
  115. }
  116. Result = TRUE;
  117. break;
  118. }
  119. MessageBlock += 1;
  120. }
  121. }
  122. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  123. ;
  124. }
  125. return Result;
  126. }
  127. PCHAR
  128. KeBugCheckUnicodeToAnsi(
  129. IN PUNICODE_STRING UnicodeString,
  130. OUT PCHAR AnsiBuffer,
  131. IN ULONG MaxAnsiLength
  132. )
  133. {
  134. PCHAR Dst;
  135. PWSTR Src;
  136. ULONG Length;
  137. Length = UnicodeString->Length / sizeof( WCHAR );
  138. if (Length >= MaxAnsiLength) {
  139. Length = MaxAnsiLength - 1;
  140. }
  141. Src = UnicodeString->Buffer;
  142. Dst = AnsiBuffer;
  143. while (Length--) {
  144. *Dst++ = (UCHAR)*Src++;
  145. }
  146. *Dst = '\0';
  147. return AnsiBuffer;
  148. }
  149. VOID
  150. KiBugCheckDebugBreak (
  151. IN ULONG BreakStatus
  152. )
  153. {
  154. do {
  155. try {
  156. //
  157. // Issue a breakpoint
  158. //
  159. DbgBreakPointWithStatus (BreakStatus);
  160. } except(EXCEPTION_EXECUTE_HANDLER) {
  161. HEADLESS_RSP_QUERY_INFO Response;
  162. NTSTATUS Status;
  163. SIZE_T Length;
  164. //
  165. // Failed to issue the breakpoint, must be no debugger. Now, give
  166. // the headless terminal a chance to reboot the system, if there is one.
  167. //
  168. Length = sizeof(HEADLESS_RSP_QUERY_INFO);
  169. Status = HeadlessDispatch(HeadlessCmdQueryInformation,
  170. NULL,
  171. 0,
  172. &Response,
  173. &Length
  174. );
  175. if (NT_SUCCESS(Status) &&
  176. (Response.PortType == HeadlessSerialPort) &&
  177. Response.Serial.TerminalAttached) {
  178. HeadlessDispatch(HeadlessCmdPutString,
  179. "\r\n",
  180. sizeof("\r\n"),
  181. NULL,
  182. NULL
  183. );
  184. for (;;) {
  185. HeadlessDispatch(HeadlessCmdDoBugCheckProcessing, NULL, 0, NULL, NULL);
  186. }
  187. }
  188. //
  189. // No terminal, or it failed, halt the system
  190. //
  191. try {
  192. HalHaltSystem();
  193. } except(EXCEPTION_EXECUTE_HANDLER) {
  194. for (;;) {
  195. }
  196. }
  197. }
  198. } while (BreakStatus != DBG_STATUS_BUGCHECK_FIRST);
  199. }
  200. PVOID
  201. KiPcToFileHeader(
  202. IN PVOID PcValue,
  203. OUT PLDR_DATA_TABLE_ENTRY *DataTableEntry,
  204. IN LOGICAL DriversOnly,
  205. OUT PBOOLEAN InKernelOrHal
  206. )
  207. /*++
  208. Routine Description:
  209. This function returns the base of an image that contains the
  210. specified PcValue. An image contains the PcValue if the PcValue
  211. is within the ImageBase, and the ImageBase plus the size of the
  212. virtual image.
  213. Arguments:
  214. PcValue - Supplies a PcValue.
  215. DataTableEntry - Supplies a pointer to a variable that receives the
  216. address of the data table entry that describes the image.
  217. DriversOnly - Supplies TRUE if the kernel and HAL should be skipped.
  218. InKernelOrHal - Set to TRUE if the PcValue is in the kernel or the HAL.
  219. This only has meaning if DriversOnly is FALSE.
  220. Return Value:
  221. NULL - No image was found that contains the PcValue.
  222. NON-NULL - Returns the base address of the image that contains the
  223. PcValue.
  224. --*/
  225. {
  226. ULONG i;
  227. PLIST_ENTRY ModuleListHead;
  228. PLDR_DATA_TABLE_ENTRY Entry;
  229. PLIST_ENTRY Next;
  230. ULONG_PTR Bounds;
  231. PVOID ReturnBase, Base;
  232. //
  233. // If the module list has been initialized, then scan the list to
  234. // locate the appropriate entry.
  235. //
  236. if (KeLoaderBlock != NULL) {
  237. ModuleListHead = &KeLoaderBlock->LoadOrderListHead;
  238. } else {
  239. ModuleListHead = &PsLoadedModuleList;
  240. }
  241. *InKernelOrHal = FALSE;
  242. ReturnBase = NULL;
  243. Next = ModuleListHead->Flink;
  244. if (Next != NULL) {
  245. i = 0;
  246. while (Next != ModuleListHead) {
  247. if (MmIsAddressValid(Next) == FALSE) {
  248. return NULL;
  249. }
  250. i += 1;
  251. if ((i <= 2) && (DriversOnly == TRUE)) {
  252. Next = Next->Flink;
  253. continue;
  254. }
  255. Entry = CONTAINING_RECORD(Next,
  256. LDR_DATA_TABLE_ENTRY,
  257. InLoadOrderLinks);
  258. Next = Next->Flink;
  259. Base = Entry->DllBase;
  260. Bounds = (ULONG_PTR)Base + Entry->SizeOfImage;
  261. if ((ULONG_PTR)PcValue >= (ULONG_PTR)Base && (ULONG_PTR)PcValue < Bounds) {
  262. *DataTableEntry = Entry;
  263. ReturnBase = Base;
  264. if (i <= 2) {
  265. *InKernelOrHal = TRUE;
  266. }
  267. break;
  268. }
  269. }
  270. }
  271. return ReturnBase;
  272. }
  273. VOID
  274. KiDumpParameterImages(
  275. IN PCHAR Buffer,
  276. IN PULONG_PTR BugCheckParameters,
  277. IN ULONG NumberOfParameters,
  278. IN PKE_BUGCHECK_UNICODE_TO_ANSI UnicodeToAnsiRoutine
  279. )
  280. /*++
  281. Routine Description:
  282. This function formats and displays the image names of boogcheck parameters
  283. that happen to match an address in an image.
  284. Arguments:
  285. Buffer - Supplies a pointer to a buffer to be used to output machine
  286. state information.
  287. BugCheckParameters - Supplies additional bugcheck information.
  288. NumberOfParameters - sizeof BugCheckParameters array.
  289. if just 1 parameter is passed in, just save the string.
  290. UnicodeToAnsiRoutine - Supplies a pointer to a routine to convert Unicode
  291. strings to Ansi strings without touching paged translation tables.
  292. Return Value:
  293. None.
  294. --*/
  295. {
  296. PUNICODE_STRING BugCheckDriver;
  297. ULONG i;
  298. PLDR_DATA_TABLE_ENTRY DataTableEntry;
  299. PVOID ImageBase;
  300. UCHAR AnsiBuffer[ 32 ];
  301. ULONG DateStamp;
  302. PIMAGE_NT_HEADERS NtHeaders;
  303. BOOLEAN FirstPrint = TRUE;
  304. BOOLEAN InKernelOrHal;
  305. PUNICODE_STRING DriverName;
  306. //
  307. // At this point the context record contains the machine state at the
  308. // call to bug check.
  309. //
  310. // Put out the system version and the title line with the PSR and FSR.
  311. //
  312. //
  313. // Check to see if any BugCheckParameters are valid code addresses.
  314. // If so, print them for the user.
  315. //
  316. DriverName = NULL;
  317. for (i = 0; i < NumberOfParameters; i += 1)
  318. {
  319. DateStamp = 0;
  320. ImageBase = KiPcToFileHeader((PVOID) BugCheckParameters[i],
  321. &DataTableEntry,
  322. TRUE,
  323. &InKernelOrHal);
  324. if (ImageBase == NULL)
  325. {
  326. BugCheckDriver = MmLocateUnloadedDriver ((PVOID)BugCheckParameters[i]);
  327. if (BugCheckDriver == NULL)
  328. {
  329. continue;
  330. }
  331. DriverName = BugCheckDriver;
  332. ImageBase = (PVOID)BugCheckParameters[i];
  333. (*UnicodeToAnsiRoutine) (BugCheckDriver,
  334. AnsiBuffer,
  335. sizeof (AnsiBuffer));
  336. }
  337. else
  338. {
  339. if (MmIsAddressValid(DataTableEntry->DllBase) == TRUE)
  340. {
  341. NtHeaders = RtlImageNtHeader(DataTableEntry->DllBase);
  342. if (NtHeaders)
  343. {
  344. DateStamp = NtHeaders->FileHeader.TimeDateStamp;
  345. }
  346. }
  347. DriverName = &DataTableEntry->BaseDllName;
  348. (*UnicodeToAnsiRoutine)( DriverName,
  349. AnsiBuffer,
  350. sizeof( AnsiBuffer ));
  351. }
  352. sprintf(Buffer, "%s** %12s - Address %p base at %p, DateStamp %08lx\n",
  353. FirstPrint ? "\n*":"*",
  354. AnsiBuffer,
  355. (PVOID)BugCheckParameters[i],
  356. ImageBase,
  357. DateStamp);
  358. //
  359. // Only print the string if we are called to print multiple.
  360. //
  361. if (NumberOfParameters > 1)
  362. {
  363. InbvDisplayString(Buffer);
  364. }
  365. else
  366. {
  367. KiBugCheckDriver = DriverName;
  368. }
  369. FirstPrint = FALSE;
  370. }
  371. return;
  372. }
  373. #ifdef _X86_
  374. #pragma optimize("y", off) // RtlCaptureContext needs EBP to be correct
  375. #endif
  376. VOID
  377. KeBugCheck2 (
  378. IN ULONG BugCheckCode,
  379. IN ULONG_PTR BugCheckParameter1,
  380. IN ULONG_PTR BugCheckParameter2,
  381. IN ULONG_PTR BugCheckParameter3,
  382. IN ULONG_PTR BugCheckParameter4,
  383. IN PVOID SaveDataPage
  384. )
  385. /*++
  386. Routine Description:
  387. This function crashes the system in a controlled manner.
  388. Arguments:
  389. BugCheckCode - Supplies the reason for the bug check.
  390. BugCheckParameter1-4 - Supplies additional bug check information
  391. Return Value:
  392. None.
  393. --*/
  394. {
  395. UCHAR Buffer[103];
  396. CONTEXT ContextSave;
  397. ULONG PssMessage;
  398. PCHAR HardErrorCaption = NULL;
  399. PCHAR HardErrorMessage = NULL;
  400. KIRQL OldIrql;
  401. PKTRAP_FRAME TrapInformation;
  402. PVOID ExecutionAddress = NULL;
  403. PVOID ImageBase;
  404. PVOID VirtualAddress;
  405. PLDR_DATA_TABLE_ENTRY DataTableEntry;
  406. CHAR AnsiBuffer[100];
  407. PKTHREAD Thread = KeGetCurrentThread();
  408. BOOLEAN InKernelOrHal;
  409. BOOLEAN Reboot;
  410. #if !defined(NT_UP)
  411. KAFFINITY TargetSet;
  412. #endif
  413. BOOLEAN hardErrorCalled = FALSE;
  414. //
  415. // Initialization
  416. //
  417. Reboot = FALSE;
  418. KiBugCheckDriver = NULL;
  419. //
  420. // Try to simulate a power failure for Cluster testing
  421. //
  422. if (BugCheckCode == POWER_FAILURE_SIMULATE) {
  423. KiScanBugCheckCallbackList();
  424. HalReturnToFirmware(HalRebootRoutine);
  425. }
  426. //
  427. // Capture the callers context as closely as possible into the debugger's
  428. // processor state area of the Prcb.
  429. //
  430. // N.B. There may be some prologue code that shuffles registers such that
  431. // they get destroyed.
  432. //
  433. #if defined(_X86_)
  434. KiSetHardwareTrigger();
  435. #else
  436. InterlockedIncrement64((LONGLONG volatile *)&KiHardwareTrigger);
  437. #endif
  438. RtlCaptureContext(&KeGetCurrentPrcb()->ProcessorState.ContextFrame);
  439. KiSaveProcessorControlState(&KeGetCurrentPrcb()->ProcessorState);
  440. //
  441. // This is necessary on machines where the virtual unwind that happens
  442. // during KeDumpMachineState() destroys the context record.
  443. //
  444. ContextSave = KeGetCurrentPrcb()->ProcessorState.ContextFrame;
  445. //
  446. // Get the correct string for bugchecks
  447. //
  448. switch (BugCheckCode) {
  449. case SYSTEM_THREAD_EXCEPTION_NOT_HANDLED:
  450. case KERNEL_MODE_EXCEPTION_NOT_HANDLED:
  451. case KMODE_EXCEPTION_NOT_HANDLED:
  452. PssMessage = KMODE_EXCEPTION_NOT_HANDLED;
  453. break;
  454. case DATA_BUS_ERROR:
  455. case NO_MORE_SYSTEM_PTES:
  456. case INACCESSIBLE_BOOT_DEVICE:
  457. case UNEXPECTED_KERNEL_MODE_TRAP:
  458. case ACPI_BIOS_ERROR:
  459. case ACPI_BIOS_FATAL_ERROR:
  460. case FAT_FILE_SYSTEM:
  461. case DRIVER_CORRUPTED_EXPOOL:
  462. case THREAD_STUCK_IN_DEVICE_DRIVER:
  463. PssMessage = BugCheckCode;
  464. break;
  465. case DRIVER_CORRUPTED_MMPOOL:
  466. PssMessage = DRIVER_CORRUPTED_EXPOOL;
  467. break;
  468. case NTFS_FILE_SYSTEM:
  469. PssMessage = FAT_FILE_SYSTEM;
  470. break;
  471. case STATUS_SYSTEM_IMAGE_BAD_SIGNATURE:
  472. PssMessage = BUGCODE_PSS_MESSAGE_SIGNATURE;
  473. break;
  474. default:
  475. PssMessage = BUGCODE_PSS_MESSAGE;
  476. break;
  477. }
  478. //
  479. // Do further processing on bugcheck codes
  480. //
  481. KiBugCheckData[0] = BugCheckCode;
  482. KiBugCheckData[1] = BugCheckParameter1;
  483. KiBugCheckData[2] = BugCheckParameter2;
  484. KiBugCheckData[3] = BugCheckParameter3;
  485. KiBugCheckData[4] = BugCheckParameter4;
  486. switch (BugCheckCode) {
  487. case FATAL_UNHANDLED_HARD_ERROR:
  488. //
  489. // If we are called by hard error then we don't want to dump the
  490. // processor state on the machine.
  491. //
  492. // We know that we are called by hard error because the bug check
  493. // code will be FATAL_UNHANDLED_HARD_ERROR. If this is so then the
  494. // error status passed to harderr is the first parameter, and a pointer
  495. // to the parameter array from hard error is passed as the second
  496. // argument.
  497. //
  498. // The third argument is the OemCaption to be printed.
  499. // The last argument is the OemMessage to be printed.
  500. //
  501. {
  502. PULONG_PTR parameterArray;
  503. hardErrorCalled = TRUE;
  504. HardErrorCaption = (PCHAR)BugCheckParameter3;
  505. HardErrorMessage = (PCHAR)BugCheckParameter4;
  506. parameterArray = (PULONG_PTR)BugCheckParameter2;
  507. KiBugCheckData[0] = (ULONG)BugCheckParameter1;
  508. KiBugCheckData[1] = parameterArray[0];
  509. KiBugCheckData[2] = parameterArray[1];
  510. KiBugCheckData[3] = parameterArray[2];
  511. KiBugCheckData[4] = parameterArray[3];
  512. }
  513. break;
  514. case IRQL_NOT_LESS_OR_EQUAL:
  515. ExecutionAddress = (PVOID)BugCheckParameter4;
  516. if (ExecutionAddress >= ExPoolCodeStart && ExecutionAddress < ExPoolCodeEnd) {
  517. KiBugCheckData[0] = DRIVER_CORRUPTED_EXPOOL;
  518. }
  519. else if (ExecutionAddress >= MmPoolCodeStart && ExecutionAddress < MmPoolCodeEnd) {
  520. KiBugCheckData[0] = DRIVER_CORRUPTED_MMPOOL;
  521. }
  522. else if (ExecutionAddress >= MmPteCodeStart && ExecutionAddress < MmPteCodeEnd) {
  523. KiBugCheckData[0] = DRIVER_CORRUPTED_SYSPTES;
  524. }
  525. else {
  526. ImageBase = KiPcToFileHeader (ExecutionAddress,
  527. &DataTableEntry,
  528. FALSE,
  529. &InKernelOrHal);
  530. if (InKernelOrHal == TRUE) {
  531. //
  532. // The kernel faulted at raised IRQL. Quite often this
  533. // is a driver that has unloaded without deleting its
  534. // lookaside lists or other resources. Or its resources
  535. // are marked pagable and shouldn't be. Detect both
  536. // cases here and identify the offending driver
  537. // whenever possible.
  538. //
  539. VirtualAddress = (PVOID)BugCheckParameter1;
  540. ImageBase = KiPcToFileHeader (VirtualAddress,
  541. &DataTableEntry,
  542. TRUE,
  543. &InKernelOrHal);
  544. if (ImageBase != NULL) {
  545. KiBugCheckDriver = &DataTableEntry->BaseDllName;
  546. KiBugCheckData[0] = DRIVER_PORTION_MUST_BE_NONPAGED;
  547. }
  548. else {
  549. KiBugCheckDriver = MmLocateUnloadedDriver (VirtualAddress);
  550. if (KiBugCheckDriver != NULL) {
  551. KiBugCheckData[0] = SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD;
  552. }
  553. }
  554. }
  555. else {
  556. KiBugCheckData[0] = DRIVER_IRQL_NOT_LESS_OR_EQUAL;
  557. }
  558. }
  559. ExecutionAddress = NULL;
  560. break;
  561. case ATTEMPTED_WRITE_TO_READONLY_MEMORY:
  562. TrapInformation = (PKTRAP_FRAME)BugCheckParameter3;
  563. //
  564. // Extract the execution address from the trap frame to
  565. // identify the component.
  566. //
  567. if (TrapInformation != NULL) {
  568. ExecutionAddress = (PVOID) PROGRAM_COUNTER (TrapInformation);
  569. }
  570. break;
  571. case DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS:
  572. ExecutionAddress = (PVOID)BugCheckParameter1;
  573. break;
  574. case DRIVER_USED_EXCESSIVE_PTES:
  575. DataTableEntry = (PLDR_DATA_TABLE_ENTRY)BugCheckParameter1;
  576. KiBugCheckDriver = &DataTableEntry->BaseDllName;
  577. break;
  578. case PAGE_FAULT_IN_NONPAGED_AREA:
  579. ImageBase = NULL;
  580. //
  581. // Extract the execution address from the trap frame to
  582. // identify the component.
  583. //
  584. if (BugCheckParameter3) {
  585. ExecutionAddress = (PVOID)PROGRAM_COUNTER
  586. ((PKTRAP_FRAME)BugCheckParameter3);
  587. KiBugCheckData[3] = (ULONG_PTR)ExecutionAddress;
  588. ImageBase = KiPcToFileHeader (ExecutionAddress,
  589. &DataTableEntry,
  590. FALSE,
  591. &InKernelOrHal);
  592. }
  593. else {
  594. //
  595. // No trap frame, so no execution address either.
  596. //
  597. InKernelOrHal = TRUE;
  598. }
  599. VirtualAddress = (PVOID)BugCheckParameter1;
  600. if (MmIsSpecialPoolAddress (VirtualAddress) == TRUE) {
  601. //
  602. // Update the bugcheck number so the administrator gets
  603. // useful feedback that enabling special pool has enabled
  604. // the system to locate the corruptor.
  605. //
  606. if (MmIsSpecialPoolAddressFree (VirtualAddress) == TRUE) {
  607. if (InKernelOrHal == TRUE) {
  608. KiBugCheckData[0] = PAGE_FAULT_IN_FREED_SPECIAL_POOL;
  609. }
  610. else {
  611. KiBugCheckData[0] = DRIVER_PAGE_FAULT_IN_FREED_SPECIAL_POOL;
  612. }
  613. }
  614. else {
  615. if (InKernelOrHal == TRUE) {
  616. KiBugCheckData[0] = PAGE_FAULT_BEYOND_END_OF_ALLOCATION;
  617. }
  618. else {
  619. KiBugCheckData[0] = DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION;
  620. }
  621. }
  622. }
  623. else if ((ExecutionAddress == VirtualAddress) &&
  624. (MmIsSessionAddress (VirtualAddress) == TRUE) &&
  625. ((Thread->Teb == NULL) || (IS_SYSTEM_ADDRESS(Thread->Teb)))) {
  626. //
  627. // This is a driver reference to session space from a
  628. // worker thread. Since the system process has no session
  629. // space this is illegal and the driver must be fixed.
  630. //
  631. KiBugCheckData[0] = TERMINAL_SERVER_DRIVER_MADE_INCORRECT_MEMORY_REFERENCE;
  632. }
  633. else if (ImageBase == NULL) {
  634. KiBugCheckDriver = MmLocateUnloadedDriver (VirtualAddress);
  635. if (KiBugCheckDriver != NULL) {
  636. KiBugCheckData[0] = DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS;
  637. }
  638. }
  639. break;
  640. case THREAD_STUCK_IN_DEVICE_DRIVER:
  641. KiBugCheckDriver = (PUNICODE_STRING) BugCheckParameter3;
  642. break;
  643. default:
  644. break;
  645. }
  646. if (KiBugCheckDriver)
  647. {
  648. KeBugCheckUnicodeToAnsi(KiBugCheckDriver,
  649. AnsiBuffer,
  650. sizeof(AnsiBuffer));
  651. }
  652. else
  653. {
  654. //
  655. // This will set KiBugCheckDriver to 1 if successful.
  656. //
  657. if (ExecutionAddress)
  658. {
  659. KiDumpParameterImages(AnsiBuffer,
  660. (PULONG_PTR)&ExecutionAddress,
  661. 1,
  662. KeBugCheckUnicodeToAnsi);
  663. }
  664. }
  665. if (KdPitchDebugger == FALSE ) {
  666. KdDebuggerDataBlock.SavedContext = (ULONG_PTR) &ContextSave;
  667. }
  668. //
  669. // If the user manually crashed the machine, skips the DbgPrints and
  670. // go to the crashdump.
  671. // Trying to do DbgPrint causes us to reeeter the debugger which causes
  672. // some problems.
  673. //
  674. // Otherwise, if the debugger is enabled, print out the information and
  675. // stop.
  676. //
  677. if ((BugCheckCode != MANUALLY_INITIATED_CRASH) &&
  678. (KdDebuggerEnabled)) {
  679. DbgPrint("\n*** Fatal System Error: 0x%08lx\n"
  680. " (0x%p,0x%p,0x%p,0x%p)\n\n",
  681. (ULONG)KiBugCheckData[0],
  682. KiBugCheckData[1],
  683. KiBugCheckData[2],
  684. KiBugCheckData[3],
  685. KiBugCheckData[4]);
  686. //
  687. // If the debugger is not actually connected, or the user manually
  688. // crashed the machine by typing .crash in the debugger, proceed to
  689. // "blue screen" the system.
  690. //
  691. // The call to DbgPrint above will have set the state of
  692. // KdDebuggerNotPresent if the debugger has become disconnected
  693. // since the system was booted.
  694. //
  695. if (KdDebuggerNotPresent == FALSE) {
  696. if (KiBugCheckDriver != NULL) {
  697. DbgPrint("Driver at fault: %s.\n", AnsiBuffer);
  698. }
  699. if (hardErrorCalled != FALSE) {
  700. if (HardErrorCaption) {
  701. DbgPrint(HardErrorCaption);
  702. }
  703. if (HardErrorMessage) {
  704. DbgPrint(HardErrorMessage);
  705. }
  706. }
  707. KiBugCheckDebugBreak (DBG_STATUS_BUGCHECK_FIRST);
  708. }
  709. }
  710. //
  711. // Freeze execution of the system by disabling interrupts and looping.
  712. //
  713. KeDisableInterrupts();
  714. KeRaiseIrql(HIGH_LEVEL, &OldIrql);
  715. //
  716. // Don't attempt to display message more than once.
  717. //
  718. if (InterlockedDecrement (&KeBugCheckCount) == 0) {
  719. #if !defined(NT_UP)
  720. //
  721. // Attempt to get the other processors frozen now, but don't wait
  722. // for them to freeze (in case someone is stuck).
  723. //
  724. TargetSet = KeActiveProcessors & ~KeGetCurrentPrcb()->SetMember;
  725. if (TargetSet != 0) {
  726. KiIpiSend((KAFFINITY) TargetSet, IPI_FREEZE);
  727. //
  728. // Give the other processors one second to flush their data caches.
  729. //
  730. // N.B. This cannot be synchronized since the reason for the bug
  731. // may be one of the other processors failed.
  732. //
  733. KeStallExecutionProcessor(1000 * 1000);
  734. }
  735. #endif
  736. //
  737. // Enable terminal output and turn on bugcheck processing.
  738. //
  739. {
  740. HEADLESS_CMD_ENABLE_TERMINAL HeadlessCmd;
  741. HEADLESS_CMD_SEND_BLUE_SCREEN_DATA HeadlessCmdBlueScreen;
  742. HeadlessCmdBlueScreen.BugcheckCode = (ULONG)KiBugCheckData[0];
  743. HeadlessCmd.Enable = TRUE;
  744. HeadlessDispatch(HeadlessCmdStartBugCheck, NULL, 0, NULL, NULL);
  745. HeadlessDispatch(HeadlessCmdEnableTerminal,
  746. &HeadlessCmd,
  747. sizeof(HEADLESS_CMD_ENABLE_TERMINAL),
  748. NULL,
  749. NULL
  750. );
  751. HeadlessDispatch(HeadlessCmdSendBlueScreenData,
  752. &HeadlessCmdBlueScreen,
  753. sizeof(HEADLESS_CMD_SEND_BLUE_SCREEN_DATA),
  754. NULL,
  755. NULL
  756. );
  757. }
  758. //
  759. // Enable InbvDisplayString calls to make it through to bootvid driver.
  760. //
  761. if (InbvIsBootDriverInstalled()) {
  762. InbvAcquireDisplayOwnership();
  763. InbvResetDisplay();
  764. InbvSolidColorFill(0,0,639,479,4); // make the screen blue
  765. InbvSetTextColor(15);
  766. InbvInstallDisplayStringFilter((INBV_DISPLAY_STRING_FILTER)NULL);
  767. InbvEnableDisplayString(TRUE); // enable display string
  768. InbvSetScrollRegion(0,0,639,475); // set to use entire screen
  769. }
  770. if (!hardErrorCalled)
  771. {
  772. InbvDisplayString("\n");
  773. KeGetBugMessageText(BUGCHECK_MESSAGE_INTRO, NULL);
  774. InbvDisplayString("\n\n");
  775. if (KiBugCheckDriver) {
  776. //
  777. // Output the driver name.
  778. //
  779. KeGetBugMessageText(BUGCODE_ID_DRIVER, NULL);
  780. KeBugCheckUnicodeToAnsi (KiBugCheckDriver, Buffer, sizeof (Buffer));
  781. InbvDisplayString(" ");
  782. InbvDisplayString (Buffer);
  783. InbvDisplayString("\n\n");
  784. }
  785. //
  786. // Display the PSS message.
  787. // If we have no special text, get the text for the bugcode
  788. // which will be the bugcode name.
  789. //
  790. if (PssMessage == BUGCODE_PSS_MESSAGE)
  791. {
  792. KeGetBugMessageText((ULONG)KiBugCheckData[0], NULL);
  793. InbvDisplayString("\n\n");
  794. }
  795. KeGetBugMessageText(PSS_MESSAGE_INTRO, NULL);
  796. InbvDisplayString("\n\n");
  797. KeGetBugMessageText(PssMessage, NULL);
  798. InbvDisplayString("\n\n");
  799. KeGetBugMessageText(BUGCHECK_TECH_INFO, NULL);
  800. sprintf((char *)Buffer,
  801. "\n\n*** STOP: 0x%08lX (0x%p,0x%p,0x%p,0x%p)\n\n",
  802. (ULONG)KiBugCheckData[0],
  803. (PVOID)KiBugCheckData[1],
  804. (PVOID)KiBugCheckData[2],
  805. (PVOID)KiBugCheckData[3],
  806. (PVOID)KiBugCheckData[4]);
  807. InbvDisplayString((char *)Buffer);
  808. if (KiBugCheckDriver) {
  809. InbvDisplayString(AnsiBuffer);
  810. }
  811. if (!KiBugCheckDriver)
  812. {
  813. KiDumpParameterImages(AnsiBuffer,
  814. &(KiBugCheckData[1]),
  815. 4,
  816. KeBugCheckUnicodeToAnsi);
  817. }
  818. } else {
  819. if (HardErrorCaption) {
  820. InbvDisplayString(HardErrorCaption);
  821. }
  822. if (HardErrorMessage) {
  823. InbvDisplayString(HardErrorMessage);
  824. }
  825. }
  826. KiInvokeBugCheckEntryCallbacks();
  827. //
  828. // If the debugger is not enabled, attempt to enable it.
  829. //
  830. if (KdDebuggerEnabled == FALSE && KdPitchDebugger == FALSE ) {
  831. KdInitSystem(0, NULL);
  832. } else {
  833. InbvDisplayString("\n");
  834. }
  835. // Restore the original Context frame
  836. KeGetCurrentPrcb()->ProcessorState.ContextFrame = ContextSave;
  837. //
  838. // For some bugchecks we want to change the thread and context before
  839. // it is written to the dump file IFF it is a minidump.
  840. // Look at the original bugcheck data, not the processed data from
  841. // above
  842. //
  843. #define MINIDUMP_BUGCHECK 0x10000000
  844. if (IoIsTriageDumpEnabled())
  845. {
  846. switch (BugCheckCode) {
  847. //
  848. // System thread stores a context record as the 4th parameter.
  849. // use that.
  850. // Also save the context record in case someone needs to look
  851. // at it.
  852. //
  853. case SYSTEM_THREAD_EXCEPTION_NOT_HANDLED:
  854. if (BugCheckParameter4)
  855. {
  856. ContextSave = *((PCONTEXT)BugCheckParameter4);
  857. KiBugCheckData[0] |= MINIDUMP_BUGCHECK;
  858. }
  859. break;
  860. #if defined (_X86_)
  861. //
  862. // 3rd parameter is a trap frame.
  863. //
  864. // Build a context record out of that only if it's a kernel mode
  865. // failure because esp may be wrong in that case ???.
  866. //
  867. case ATTEMPTED_WRITE_TO_READONLY_MEMORY:
  868. case KERNEL_MODE_EXCEPTION_NOT_HANDLED:
  869. case PAGE_FAULT_IN_NONPAGED_AREA:
  870. if (BugCheckParameter3)
  871. {
  872. PKTRAP_FRAME Trap = (PKTRAP_FRAME) BugCheckParameter3;
  873. if ((Trap->SegCs & 1) ||
  874. (Trap->EFlags & EFLAGS_V86_MASK))
  875. {
  876. ContextSave.Esp = Trap->HardwareEsp;
  877. }
  878. else
  879. {
  880. ContextSave.Esp = (ULONG)Trap +
  881. FIELD_OFFSET(KTRAP_FRAME, HardwareEsp);
  882. }
  883. if (Trap->EFlags & EFLAGS_V86_MASK)
  884. {
  885. ContextSave.SegSs = Trap->HardwareSegSs & 0xffff;
  886. }
  887. else if (Trap->SegCs & 1)
  888. {
  889. //
  890. // It's user mode.
  891. // The HardwareSegSs contains R3 data selector.
  892. //
  893. ContextSave.SegSs =
  894. (Trap->HardwareSegSs | 3) & 0xffff;
  895. }
  896. else
  897. {
  898. ContextSave.SegSs = KGDT_R0_DATA;
  899. }
  900. ContextSave.SegGs = Trap->SegGs & 0xffff;
  901. ContextSave.SegFs = Trap->SegFs & 0xffff;
  902. ContextSave.SegEs = Trap->SegEs & 0xffff;
  903. ContextSave.SegDs = Trap->SegDs & 0xffff;
  904. ContextSave.SegCs = Trap->SegCs & 0xffff;
  905. ContextSave.Eip = Trap->Eip;
  906. ContextSave.Ebp = Trap->Ebp;
  907. ContextSave.Eax = Trap->Eax;
  908. ContextSave.Ebx = Trap->Ebx;
  909. ContextSave.Ecx = Trap->Ecx;
  910. ContextSave.Edx = Trap->Edx;
  911. ContextSave.Edi = Trap->Edi;
  912. ContextSave.Esi = Trap->Esi;
  913. ContextSave.EFlags = Trap->EFlags;
  914. KiBugCheckData[0] |= MINIDUMP_BUGCHECK;
  915. }
  916. break;
  917. case THREAD_STUCK_IN_DEVICE_DRIVER:
  918. // Extract the address of the spinning code from the thread
  919. // object, so the dump is based off this thread.
  920. Thread = (PKTHREAD) BugCheckParameter1;
  921. if (Thread->State == Running)
  922. {
  923. //
  924. // If the thread was running, the thread is now in a
  925. // frozen state and the registers are in the PRCB
  926. // context
  927. //
  928. ULONG Processor = Thread->NextProcessor;
  929. ASSERT(Processor < (ULONG) KeNumberProcessors);
  930. ContextSave =
  931. KiProcessorBlock[Processor]->ProcessorState.ContextFrame;
  932. }
  933. else
  934. {
  935. //
  936. // This should be a uniproc machine, and the thread
  937. // should be suspended. Just get the data off the
  938. // switch frame.
  939. //
  940. PKSWITCHFRAME SwitchFrame = (PKSWITCHFRAME)Thread->KernelStack;
  941. ASSERT(Thread->State == Ready);
  942. ContextSave.Esp = (ULONG)Thread->KernelStack + sizeof(KSWITCHFRAME);
  943. ContextSave.Ebp = *((PULONG)(ContextSave.Esp));
  944. ContextSave.Eip = SwitchFrame->RetAddr;
  945. }
  946. KiBugCheckData[0] |= MINIDUMP_BUGCHECK;
  947. break;
  948. case UNEXPECTED_KERNEL_MODE_TRAP:
  949. //
  950. // Double fault
  951. //
  952. if (BugCheckParameter1 == 0x8)
  953. {
  954. // The thread is correct in this case.
  955. // Second parameter is the TSS. If we have a TSS, convert
  956. // the context and mark the bugcheck as converted.
  957. PKTSS Tss = (PKTSS) BugCheckParameter2;
  958. if (Tss)
  959. {
  960. if (Tss->EFlags & EFLAGS_V86_MASK)
  961. {
  962. ContextSave.SegSs = Tss->Ss & 0xffff;
  963. }
  964. else if (Tss->Cs & 1)
  965. {
  966. //
  967. // It's user mode.
  968. // The HardwareSegSs contains R3 data selector.
  969. //
  970. ContextSave.SegSs = (Tss->Ss | 3) & 0xffff;
  971. }
  972. else
  973. {
  974. ContextSave.SegSs = KGDT_R0_DATA;
  975. }
  976. ContextSave.SegGs = Tss->Gs & 0xffff;
  977. ContextSave.SegFs = Tss->Fs & 0xffff;
  978. ContextSave.SegEs = Tss->Es & 0xffff;
  979. ContextSave.SegDs = Tss->Ds & 0xffff;
  980. ContextSave.SegCs = Tss->Cs & 0xffff;
  981. ContextSave.Esp = Tss->Esp;
  982. ContextSave.Eip = Tss->Eip;
  983. ContextSave.Ebp = Tss->Ebp;
  984. ContextSave.Eax = Tss->Eax;
  985. ContextSave.Ebx = Tss->Ebx;
  986. ContextSave.Ecx = Tss->Ecx;
  987. ContextSave.Edx = Tss->Edx;
  988. ContextSave.Edi = Tss->Edi;
  989. ContextSave.Esi = Tss->Esi;
  990. ContextSave.EFlags = Tss->EFlags;
  991. }
  992. KiBugCheckData[0] |= MINIDUMP_BUGCHECK;
  993. break;
  994. }
  995. #endif
  996. default:
  997. break;
  998. }
  999. //
  1000. // Write a crash dump and optionally reboot if the system has been
  1001. // so configured.
  1002. //
  1003. IoAddTriageDumpDataBlock(PAGE_ALIGN(KiBugCheckData[1]), PAGE_SIZE);
  1004. IoAddTriageDumpDataBlock(PAGE_ALIGN(KiBugCheckData[2]), PAGE_SIZE);
  1005. IoAddTriageDumpDataBlock(PAGE_ALIGN(KiBugCheckData[3]), PAGE_SIZE);
  1006. IoAddTriageDumpDataBlock(PAGE_ALIGN(KiBugCheckData[4]), PAGE_SIZE);
  1007. IoAddTriageDumpDataBlock(PAGE_ALIGN(SaveDataPage), PAGE_SIZE);
  1008. //
  1009. // If the DPC stack is active, save that data page as well.
  1010. //
  1011. #if defined (_X86_)
  1012. if (KeGetCurrentPrcb()->DpcRoutineActive)
  1013. {
  1014. IoAddTriageDumpDataBlock(PAGE_ALIGN(KeGetCurrentPrcb()->DpcRoutineActive), PAGE_SIZE);
  1015. }
  1016. #endif
  1017. }
  1018. IoWriteCrashDump((ULONG)KiBugCheckData[0],
  1019. KiBugCheckData[1],
  1020. KiBugCheckData[2],
  1021. KiBugCheckData[3],
  1022. KiBugCheckData[4],
  1023. &ContextSave,
  1024. Thread,
  1025. &Reboot);
  1026. }
  1027. //
  1028. // Invoke bugcheck callbacks after crashdump, so the callbacks will
  1029. // not prevent us from crashdumping.
  1030. //
  1031. KiScanBugCheckCallbackList();
  1032. //
  1033. // Reboot the machine if necessary.
  1034. //
  1035. if (Reboot) {
  1036. DbgUnLoadImageSymbols (NULL, (PVOID)-1, 0);
  1037. HalReturnToFirmware (HalRebootRoutine);
  1038. }
  1039. //
  1040. // Attempt to enter the kernel debugger.
  1041. //
  1042. KiBugCheckDebugBreak (DBG_STATUS_BUGCHECK_SECOND);
  1043. }
  1044. #ifdef _X86_
  1045. #pragma optimize("", on)
  1046. #endif
  1047. VOID
  1048. KeEnterKernelDebugger (
  1049. VOID
  1050. )
  1051. /*++
  1052. Routine Description:
  1053. This function crashes the system in a controlled manner attempting
  1054. to invoke the kernel debugger.
  1055. Arguments:
  1056. None.
  1057. Return Value:
  1058. None.
  1059. --*/
  1060. {
  1061. #if !defined(i386)
  1062. KIRQL OldIrql;
  1063. #endif
  1064. //
  1065. // Freeze execution of the system by disabling interrupts and looping.
  1066. //
  1067. KiHardwareTrigger = 1;
  1068. KeDisableInterrupts();
  1069. #if !defined(i386)
  1070. KeRaiseIrql(HIGH_LEVEL, &OldIrql);
  1071. #endif
  1072. if (InterlockedDecrement (&KeBugCheckCount) == 0) {
  1073. if (KdDebuggerEnabled == FALSE) {
  1074. if ( KdPitchDebugger == FALSE ) {
  1075. KdInitSystem(0, NULL);
  1076. }
  1077. }
  1078. }
  1079. KiBugCheckDebugBreak (DBG_STATUS_FATAL);
  1080. }
  1081. NTKERNELAPI
  1082. BOOLEAN
  1083. KeDeregisterBugCheckCallback (
  1084. IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord
  1085. )
  1086. /*++
  1087. Routine Description:
  1088. This function deregisters a bug check callback record.
  1089. Arguments:
  1090. CallbackRecord - Supplies a pointer to a bug check callback record.
  1091. Return Value:
  1092. If the specified bug check callback record is successfully deregistered,
  1093. then a value of TRUE is returned. Otherwise, a value of FALSE is returned.
  1094. --*/
  1095. {
  1096. BOOLEAN Deregister;
  1097. KIRQL OldIrql;
  1098. //
  1099. // Raise IRQL to HIGH_LEVEL and acquire the bug check callback list
  1100. // spinlock.
  1101. //
  1102. KeRaiseIrql(HIGH_LEVEL, &OldIrql);
  1103. KiAcquireSpinLock(&KeBugCheckCallbackLock);
  1104. //
  1105. // If the specified callback record is currently registered, then
  1106. // deregister the callback record.
  1107. //
  1108. Deregister = FALSE;
  1109. if (CallbackRecord->State == BufferInserted) {
  1110. CallbackRecord->State = BufferEmpty;
  1111. RemoveEntryList(&CallbackRecord->Entry);
  1112. Deregister = TRUE;
  1113. }
  1114. //
  1115. // Release the bug check callback spinlock, lower IRQL to its previous
  1116. // value, and return whether the callback record was successfully
  1117. // deregistered.
  1118. //
  1119. KiReleaseSpinLock(&KeBugCheckCallbackLock);
  1120. KeLowerIrql(OldIrql);
  1121. return Deregister;
  1122. }
  1123. NTKERNELAPI
  1124. BOOLEAN
  1125. KeRegisterBugCheckCallback (
  1126. IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord,
  1127. IN PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine,
  1128. IN PVOID Buffer,
  1129. IN ULONG Length,
  1130. IN PUCHAR Component
  1131. )
  1132. /*++
  1133. Routine Description:
  1134. This function registers a bug check callback record. If the system
  1135. crashes, then the specified function will be called during bug check
  1136. processing so it may dump additional state in the specified bug check
  1137. buffer.
  1138. N.B. Bug check callback routines are called in reverse order of
  1139. registration, i.e., in LIFO order.
  1140. Arguments:
  1141. CallbackRecord - Supplies a pointer to a callback record.
  1142. CallbackRoutine - Supplies a pointer to the callback routine.
  1143. Buffer - Supplies a pointer to the bug check buffer.
  1144. Length - Supplies the length of the bug check buffer in bytes.
  1145. Component - Supplies a pointer to a zero terminated component
  1146. identifier.
  1147. Return Value:
  1148. If the specified bug check callback record is successfully registered,
  1149. then a value of TRUE is returned. Otherwise, a value of FALSE is returned.
  1150. --*/
  1151. {
  1152. BOOLEAN Inserted;
  1153. KIRQL OldIrql;
  1154. //
  1155. // Raise IRQL to HIGH_LEVEL and acquire the bug check callback list
  1156. // spinlock.
  1157. //
  1158. KeRaiseIrql(HIGH_LEVEL, &OldIrql);
  1159. KiAcquireSpinLock(&KeBugCheckCallbackLock);
  1160. //
  1161. // If the specified callback record is currently not registered, then
  1162. // register the callback record.
  1163. //
  1164. Inserted = FALSE;
  1165. if (CallbackRecord->State == BufferEmpty) {
  1166. CallbackRecord->CallbackRoutine = CallbackRoutine;
  1167. CallbackRecord->Buffer = Buffer;
  1168. CallbackRecord->Length = Length;
  1169. CallbackRecord->Component = Component;
  1170. CallbackRecord->Checksum =
  1171. ((ULONG_PTR)CallbackRoutine + (ULONG_PTR)Buffer + Length + (ULONG_PTR)Component);
  1172. CallbackRecord->State = BufferInserted;
  1173. InsertHeadList(&KeBugCheckCallbackListHead, &CallbackRecord->Entry);
  1174. Inserted = TRUE;
  1175. }
  1176. //
  1177. // Release the bug check callback spinlock, lower IRQL to its previous
  1178. // value, and return whether the callback record was successfully
  1179. // registered.
  1180. //
  1181. KiReleaseSpinLock(&KeBugCheckCallbackLock);
  1182. KeLowerIrql(OldIrql);
  1183. return Inserted;
  1184. }
  1185. VOID
  1186. KiScanBugCheckCallbackList (
  1187. VOID
  1188. )
  1189. /*++
  1190. Routine Description:
  1191. This function scans the bug check callback list and calls each bug
  1192. check callback routine so it can dump component specific information
  1193. that may identify the cause of the bug check.
  1194. N.B. The scan of the bug check callback list is performed VERY
  1195. carefully. Bug check callback routines are called at HIGH_LEVEL
  1196. and may not acquire ANY resources.
  1197. Arguments:
  1198. None.
  1199. Return Value:
  1200. None.
  1201. --*/
  1202. {
  1203. PKBUGCHECK_CALLBACK_RECORD CallbackRecord;
  1204. ULONG_PTR Checksum;
  1205. ULONG Index;
  1206. PLIST_ENTRY LastEntry;
  1207. PLIST_ENTRY ListHead;
  1208. PLIST_ENTRY NextEntry;
  1209. PUCHAR Source;
  1210. //
  1211. // If the bug check callback listhead is not initialized, then the
  1212. // bug check has occured before the system has gotten far enough
  1213. // in the initialization code to enable anyone to register a callback.
  1214. //
  1215. ListHead = &KeBugCheckCallbackListHead;
  1216. if ((ListHead->Flink != NULL) && (ListHead->Blink != NULL)) {
  1217. //
  1218. // Scan the bug check callback list.
  1219. //
  1220. LastEntry = ListHead;
  1221. NextEntry = ListHead->Flink;
  1222. while (NextEntry != ListHead) {
  1223. //
  1224. // The next entry address must be aligned properly, the
  1225. // callback record must be readable, and the callback record
  1226. // must have back link to the last entry.
  1227. //
  1228. if (((ULONG_PTR)NextEntry & (sizeof(ULONG_PTR) - 1)) != 0) {
  1229. return;
  1230. } else {
  1231. CallbackRecord = CONTAINING_RECORD(NextEntry,
  1232. KBUGCHECK_CALLBACK_RECORD,
  1233. Entry);
  1234. Source = (PUCHAR)CallbackRecord;
  1235. for (Index = 0; Index < sizeof(KBUGCHECK_CALLBACK_RECORD); Index += 1) {
  1236. if (MmIsAddressValid((PVOID)Source) == FALSE) {
  1237. return;
  1238. }
  1239. Source += 1;
  1240. }
  1241. if (CallbackRecord->Entry.Blink != LastEntry) {
  1242. return;
  1243. }
  1244. //
  1245. // If the callback record has a state of inserted and the
  1246. // computed checksum matches the callback record checksum,
  1247. // then call the specified bug check callback routine.
  1248. //
  1249. Checksum = (ULONG_PTR)CallbackRecord->CallbackRoutine;
  1250. Checksum += (ULONG_PTR)CallbackRecord->Buffer;
  1251. Checksum += CallbackRecord->Length;
  1252. Checksum += (ULONG_PTR)CallbackRecord->Component;
  1253. if ((CallbackRecord->State == BufferInserted) &&
  1254. (CallbackRecord->Checksum == Checksum)) {
  1255. //
  1256. // Call the specified bug check callback routine and
  1257. // handle any exceptions that occur.
  1258. //
  1259. CallbackRecord->State = BufferStarted;
  1260. try {
  1261. (CallbackRecord->CallbackRoutine)(CallbackRecord->Buffer,
  1262. CallbackRecord->Length);
  1263. CallbackRecord->State = BufferFinished;
  1264. } except(EXCEPTION_EXECUTE_HANDLER) {
  1265. CallbackRecord->State = BufferIncomplete;
  1266. }
  1267. }
  1268. }
  1269. LastEntry = NextEntry;
  1270. NextEntry = NextEntry->Flink;
  1271. }
  1272. }
  1273. return;
  1274. }
  1275. NTKERNELAPI
  1276. BOOLEAN
  1277. KeDeregisterBugCheckReasonCallback (
  1278. IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord
  1279. )
  1280. /*++
  1281. Routine Description:
  1282. This function deregisters a bug check callback record.
  1283. Arguments:
  1284. CallbackRecord - Supplies a pointer to a bug check callback record.
  1285. Return Value:
  1286. If the specified bug check callback record is successfully deregistered,
  1287. then a value of TRUE is returned. Otherwise, a value of FALSE is returned.
  1288. --*/
  1289. {
  1290. BOOLEAN Deregister;
  1291. KIRQL OldIrql;
  1292. //
  1293. // Raise IRQL to HIGH_LEVEL and acquire the bug check callback list
  1294. // spinlock.
  1295. //
  1296. KeRaiseIrql(HIGH_LEVEL, &OldIrql);
  1297. KiAcquireSpinLock(&KeBugCheckCallbackLock);
  1298. //
  1299. // If the specified callback record is currently registered, then
  1300. // deregister the callback record.
  1301. //
  1302. Deregister = FALSE;
  1303. if (CallbackRecord->State == BufferInserted) {
  1304. CallbackRecord->State = BufferEmpty;
  1305. RemoveEntryList(&CallbackRecord->Entry);
  1306. Deregister = TRUE;
  1307. }
  1308. //
  1309. // Release the bug check callback spinlock, lower IRQL to its previous
  1310. // value, and return whether the callback record was successfully
  1311. // deregistered.
  1312. //
  1313. KiReleaseSpinLock(&KeBugCheckCallbackLock);
  1314. KeLowerIrql(OldIrql);
  1315. return Deregister;
  1316. }
  1317. NTKERNELAPI
  1318. BOOLEAN
  1319. KeRegisterBugCheckReasonCallback (
  1320. IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord,
  1321. IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine,
  1322. IN KBUGCHECK_CALLBACK_REASON Reason,
  1323. IN PUCHAR Component
  1324. )
  1325. /*++
  1326. Routine Description:
  1327. This function registers a bug check callback record. If the system
  1328. crashes, then the specified function will be called during bug check
  1329. processing.
  1330. N.B. Bug check callback routines are called in reverse order of
  1331. registration, i.e., in LIFO order.
  1332. Arguments:
  1333. CallbackRecord - Supplies a pointer to a callback record.
  1334. CallbackRoutine - Supplies a pointer to the callback routine.
  1335. Reason - Specifies the conditions under which the callback
  1336. should be called.
  1337. Component - Supplies a pointer to a zero terminated component
  1338. identifier.
  1339. Return Value:
  1340. If the specified bug check callback record is successfully registered,
  1341. then a value of TRUE is returned. Otherwise, a value of FALSE is returned.
  1342. --*/
  1343. {
  1344. BOOLEAN Inserted;
  1345. KIRQL OldIrql;
  1346. //
  1347. // Raise IRQL to HIGH_LEVEL and acquire the bug check callback list
  1348. // spinlock.
  1349. //
  1350. KeRaiseIrql(HIGH_LEVEL, &OldIrql);
  1351. KiAcquireSpinLock(&KeBugCheckCallbackLock);
  1352. //
  1353. // If the specified callback record is currently not registered, then
  1354. // register the callback record.
  1355. //
  1356. Inserted = FALSE;
  1357. if (CallbackRecord->State == BufferEmpty) {
  1358. CallbackRecord->CallbackRoutine = CallbackRoutine;
  1359. CallbackRecord->Reason = Reason;
  1360. CallbackRecord->Component = Component;
  1361. CallbackRecord->Checksum =
  1362. ((ULONG_PTR)CallbackRoutine + Reason + (ULONG_PTR)Component);
  1363. CallbackRecord->State = BufferInserted;
  1364. InsertHeadList(&KeBugCheckReasonCallbackListHead,
  1365. &CallbackRecord->Entry);
  1366. Inserted = TRUE;
  1367. }
  1368. //
  1369. // Release the bug check callback spinlock, lower IRQL to its previous
  1370. // value, and return whether the callback record was successfully
  1371. // registered.
  1372. //
  1373. KiReleaseSpinLock(&KeBugCheckCallbackLock);
  1374. KeLowerIrql(OldIrql);
  1375. return Inserted;
  1376. }
  1377. VOID
  1378. KiInvokeBugCheckEntryCallbacks (
  1379. VOID
  1380. )
  1381. /*++
  1382. Routine Description:
  1383. This function scans the bug check reason callback list and calls
  1384. each bug check entry callback routine.
  1385. This may seem like a duplication of KiScanBugCheckCallbackList
  1386. but the critical difference is that the bug check entry callbacks
  1387. are called immediately upon entry to KeBugCheck2 whereas
  1388. KSBCCL does not invoke its callbacks until after all bug check
  1389. processing has finished.
  1390. In order to avoid people from abusing this callback it's
  1391. semi-private and the reason -- KbCallbackReserved1 -- has
  1392. an obscure name.
  1393. N.B. The scan of the bug check callback list is performed VERY
  1394. carefully. Bug check callback routines may be called at HIGH_LEVEL
  1395. and may not acquire ANY resources.
  1396. Arguments:
  1397. None.
  1398. Return Value:
  1399. None.
  1400. --*/
  1401. {
  1402. PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord;
  1403. ULONG_PTR Checksum;
  1404. ULONG Index;
  1405. PLIST_ENTRY LastEntry;
  1406. PLIST_ENTRY ListHead;
  1407. PLIST_ENTRY NextEntry;
  1408. PUCHAR Source;
  1409. //
  1410. // If the bug check callback listhead is not initialized, then the
  1411. // bug check has occured before the system has gotten far enough
  1412. // in the initialization code to enable anyone to register a callback.
  1413. //
  1414. ListHead = &KeBugCheckReasonCallbackListHead;
  1415. if (ListHead->Flink == NULL || ListHead->Blink == NULL) {
  1416. return;
  1417. }
  1418. //
  1419. // Scan the bug check callback list.
  1420. //
  1421. LastEntry = ListHead;
  1422. NextEntry = ListHead->Flink;
  1423. while (NextEntry != ListHead) {
  1424. //
  1425. // The next entry address must be aligned properly, the
  1426. // callback record must be readable, and the callback record
  1427. // must have back link to the last entry.
  1428. //
  1429. if (((ULONG_PTR)NextEntry & (sizeof(ULONG_PTR) - 1)) != 0) {
  1430. return;
  1431. }
  1432. CallbackRecord = CONTAINING_RECORD(NextEntry,
  1433. KBUGCHECK_REASON_CALLBACK_RECORD,
  1434. Entry);
  1435. Source = (PUCHAR)CallbackRecord;
  1436. for (Index = 0; Index < sizeof(*CallbackRecord); Index += 1) {
  1437. if (MmIsAddressValid((PVOID)Source) == FALSE) {
  1438. return;
  1439. }
  1440. Source += 1;
  1441. }
  1442. if (CallbackRecord->Entry.Blink != LastEntry) {
  1443. return;
  1444. }
  1445. LastEntry = NextEntry;
  1446. NextEntry = NextEntry->Flink;
  1447. //
  1448. // If the callback record has a state of inserted and the
  1449. // computed checksum matches the callback record checksum,
  1450. // then call the specified bug check callback routine.
  1451. //
  1452. Checksum = (ULONG_PTR)CallbackRecord->CallbackRoutine;
  1453. Checksum += (ULONG_PTR)CallbackRecord->Reason;
  1454. Checksum += (ULONG_PTR)CallbackRecord->Component;
  1455. if ((CallbackRecord->State != BufferInserted) ||
  1456. (CallbackRecord->Checksum != Checksum) ||
  1457. (CallbackRecord->Reason != KbCallbackReserved1) ||
  1458. MmIsAddressValid((PVOID)(ULONG_PTR)CallbackRecord->
  1459. CallbackRoutine) == FALSE) {
  1460. continue;
  1461. }
  1462. //
  1463. // Call the specified bug check callback routine and
  1464. // handle any exceptions that occur.
  1465. //
  1466. try {
  1467. (CallbackRecord->CallbackRoutine)(KbCallbackReserved1,
  1468. CallbackRecord,
  1469. NULL, 0);
  1470. CallbackRecord->State = BufferFinished;
  1471. } except(EXCEPTION_EXECUTE_HANDLER) {
  1472. CallbackRecord->State = BufferIncomplete;
  1473. }
  1474. }
  1475. }