Leaked source code of windows server 2003
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.

6534 lines
180 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. dumpctl.c
  5. Abstract:
  6. This module contains the code to dump memory to disk after a crash.
  7. Author:
  8. Darryl E. Havens (darrylh) 17-dec-1993
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #include "iomgr.h"
  14. #include "dumpctl.h"
  15. #include "ntddft.h"
  16. #include <inbv.h>
  17. #include <windef.h>
  18. #define NOEXTAPI
  19. #include <wdbgexts.h>
  20. extern KDDEBUGGER_DATA64 KdDebuggerDataBlock;
  21. typedef struct _TRIAGE_PTR_DATA_BLOCK {
  22. PUCHAR MinAddress;
  23. PUCHAR MaxAddress;
  24. } TRIAGE_PTR_DATA_BLOCK, *PTRIAGE_PTR_DATA_BLOCK;
  25. // A triage dump is sixteen pages long. Some of that is
  26. // header information and at least a few other pages will
  27. // be used for basic dump information so limit the number
  28. // of extra data blocks to something less than sixteen
  29. // to save array space.
  30. #define IO_MAX_TRIAGE_DUMP_DATA_BLOCKS 8
  31. //
  32. // Global variables
  33. //
  34. extern PVOID MmPfnDatabase;
  35. extern PFN_NUMBER MmHighestPossiblePhysicalPage;
  36. #if defined (_IA64_)
  37. extern PFN_NUMBER MmSystemParentTablePage;
  38. #endif
  39. ULONG IopAutoReboot;
  40. NTSTATUS IopFinalCrashDumpStatus = -1;
  41. ERESOURCE IopCrashDumpLock;
  42. ULONG IopNumTriageDumpDataBlocks;
  43. TRIAGE_PTR_DATA_BLOCK IopTriageDumpDataBlocks[IO_MAX_TRIAGE_DUMP_DATA_BLOCKS];
  44. //
  45. // If space is available in a triage dump it's possible
  46. // to add "interesting" data pages referenced by runtime
  47. // information such as context registers. The following
  48. // lists are offsets into the CONTEXT structure of pointers
  49. // which usually point to interesting data. They are
  50. // in priority order.
  51. //
  52. #define IOP_LAST_CONTEXT_OFFSET 0xffff
  53. #if defined(_X86_)
  54. USHORT IopRunTimeContextOffsets[] = {
  55. FIELD_OFFSET(CONTEXT, Ebx),
  56. FIELD_OFFSET(CONTEXT, Esi),
  57. FIELD_OFFSET(CONTEXT, Edi),
  58. FIELD_OFFSET(CONTEXT, Ecx),
  59. FIELD_OFFSET(CONTEXT, Edx),
  60. FIELD_OFFSET(CONTEXT, Eax),
  61. FIELD_OFFSET(CONTEXT, Eip),
  62. IOP_LAST_CONTEXT_OFFSET
  63. };
  64. #elif defined(_IA64_)
  65. USHORT IopRunTimeContextOffsets[] = {
  66. FIELD_OFFSET(CONTEXT, IntS0),
  67. FIELD_OFFSET(CONTEXT, IntS1),
  68. FIELD_OFFSET(CONTEXT, IntS2),
  69. FIELD_OFFSET(CONTEXT, IntS3),
  70. FIELD_OFFSET(CONTEXT, StIIP),
  71. IOP_LAST_CONTEXT_OFFSET
  72. };
  73. #elif defined(_AMD64_)
  74. USHORT IopRunTimeContextOffsets[] = {
  75. FIELD_OFFSET(CONTEXT, Rbx),
  76. FIELD_OFFSET(CONTEXT, Rsi),
  77. FIELD_OFFSET(CONTEXT, Rdi),
  78. FIELD_OFFSET(CONTEXT, Rcx),
  79. FIELD_OFFSET(CONTEXT, Rdx),
  80. FIELD_OFFSET(CONTEXT, Rax),
  81. FIELD_OFFSET(CONTEXT, Rip),
  82. IOP_LAST_CONTEXT_OFFSET
  83. };
  84. #else
  85. USHORT IopRunTimeContextOffsets[] = {
  86. IOP_LAST_CONTEXT_OFFSET
  87. };
  88. #endif
  89. //
  90. // Set IopIgnoreDumpCheck to TRUE when debugging dumps to prevent
  91. // the checksum from interfering with debugging.
  92. //
  93. LOGICAL IopIgnoreDumpCheck = FALSE;
  94. //
  95. // Max dump transfer sizes
  96. //
  97. #define IO_DUMP_MAXIMUM_TRANSFER_SIZE ( 1024 * 64 )
  98. #define IO_DUMP_MINIMUM_TRANSFER_SIZE ( 1024 * 32 )
  99. #define IO_DUMP_MINIMUM_FILE_SIZE ( PAGE_SIZE * 256 )
  100. #define MAX_UNICODE_LENGTH ( 512 )
  101. #define DEFAULT_DRIVER_PATH ( L"\\SystemRoot\\System32\\Drivers\\" )
  102. #define DEFAULT_DUMP_DRIVER ( L"\\SystemRoot\\System32\\Drivers\\diskdump.sys" )
  103. #define SCSIPORT_DRIVER_NAME ( L"scsiport.sys" )
  104. #define STORPORT_DRIVER_NAME ( L"storport.sys" )
  105. #ifdef _WIN64
  106. #define MAX_TRIAGE_STACK_SIZE ( 32 * 1024 )
  107. #else
  108. #define MAX_TRIAGE_STACK_SIZE ( 16 * 1024 )
  109. #endif
  110. #define DEFAULT_TRIAGE_DUMP_FLAGS ( 0xFFFFFFFF )
  111. //
  112. // for memory allocations
  113. //
  114. #define DUMP_TAG ('pmuD')
  115. #undef ExAllocatePool
  116. #define ExAllocatePool(Pool,Size) ExAllocatePoolWithTag(Pool,Size,DUMP_TAG)
  117. //
  118. // Function prototypes
  119. //
  120. NTSTATUS
  121. IoConfigureCrashDump(
  122. CRASHDUMP_CONFIGURATION Configuration
  123. );
  124. BOOLEAN
  125. IoInitializeCrashDump(
  126. IN HANDLE hPageFile
  127. );
  128. NTSTATUS
  129. IopWriteTriageDump(
  130. IN ULONG FieldsToWrite,
  131. IN PDUMP_DRIVER_WRITE WriteRoutine,
  132. IN OUT PLARGE_INTEGER * Mcb,
  133. IN OUT PMDL Mdl,
  134. IN ULONG DiverTransferSize,
  135. IN PCONTEXT Context,
  136. IN PKTHREAD Thread,
  137. IN LPBYTE Buffer,
  138. IN ULONG BufferSize,
  139. IN ULONG ServicePackBuild,
  140. IN ULONG TriageOptions
  141. );
  142. NTSTATUS
  143. IopWriteSummaryDump(
  144. IN PRTL_BITMAP PageMap,
  145. IN PDUMP_DRIVER_WRITE WriteRoutine,
  146. IN PANSI_STRING ProgressMessage,
  147. IN PUCHAR MessageBuffer,
  148. IN OUT PLARGE_INTEGER * Mcb,
  149. IN ULONG DiverTransferSize
  150. );
  151. NTSTATUS
  152. IopWriteToDisk(
  153. IN PVOID Buffer,
  154. IN ULONG WriteLength,
  155. IN PDUMP_DRIVER_WRITE DriverWriteRoutine,
  156. IN OUT PLARGE_INTEGER * Mcb,
  157. IN OUT PMDL Mdl,
  158. IN ULONG DriverTransferSize,
  159. IN KBUGCHECK_DUMP_IO_TYPE DataType
  160. );
  161. VOID
  162. IopMapPhysicalMemory(
  163. IN OUT PMDL Mdl,
  164. IN ULONG64 MemoryAddress,
  165. IN ULONG Length
  166. );
  167. NTSTATUS
  168. IopLoadDumpDriver (
  169. IN OUT PDUMP_STACK_CONTEXT DumpStack,
  170. IN PWCHAR DriverNameString,
  171. IN PWCHAR NewBaseNameString
  172. );
  173. NTSTATUS
  174. IopInitializeSummaryDump(
  175. IN OUT PMEMORY_DUMP MemoryDump,
  176. IN PDUMP_CONTROL_BLOCK DumpControlBlock
  177. );
  178. NTSTATUS
  179. IopWriteSummaryHeader(
  180. IN PSUMMARY_DUMP SummaryHeader,
  181. IN PDUMP_DRIVER_WRITE Write,
  182. IN OUT PLARGE_INTEGER * Mcb,
  183. IN OUT PMDL Mdl,
  184. IN ULONG WriteSize,
  185. IN ULONG Length
  186. );
  187. VOID
  188. IopMapVirtualToPhysicalMdl(
  189. IN OUT PMDL pMdl,
  190. IN ULONG_PTR dwMemoryAddress,
  191. IN ULONG dwLength
  192. );
  193. ULONG
  194. IopCreateSummaryDump (
  195. IN PMEMORY_DUMP MemoryDump
  196. );
  197. NTSTATUS
  198. IopInvokeSecondaryDumpDataCallbacks(
  199. IN PDUMP_DRIVER_WRITE DriverWriteRoutine,
  200. IN OUT PLARGE_INTEGER * Mcb,
  201. IN OUT PMDL Mdl,
  202. IN ULONG DriverTransferSize,
  203. IN BYTE* Buffer,
  204. IN ULONG BufferSize,
  205. IN ULONG MaxTotal,
  206. IN ULONG MaxPerCallback,
  207. OUT OPTIONAL PULONG SpaceNeeded
  208. );
  209. NTSTATUS
  210. IopInvokeDumpIoCallbacks(
  211. IN PVOID Buffer,
  212. IN ULONG BufferSize,
  213. IN KBUGCHECK_DUMP_IO_TYPE Type
  214. );
  215. NTSTATUS
  216. IopGetDumpStack (
  217. IN PWCHAR ModulePrefix,
  218. OUT PDUMP_STACK_CONTEXT *pDumpStack,
  219. IN PUNICODE_STRING pUniDeviceName,
  220. IN PWSTR pDumpDriverName,
  221. IN DEVICE_USAGE_NOTIFICATION_TYPE UsageType,
  222. IN ULONG IgnoreDeviceUsageFailure
  223. );
  224. BOOLEAN
  225. IopInitializeDCB(
  226. );
  227. LARGE_INTEGER
  228. IopCalculateRequiredDumpSpace(
  229. IN ULONG dwDmpFlags,
  230. IN ULONG dwHeaderSize,
  231. IN PFN_NUMBER dwMaxPages,
  232. IN PFN_NUMBER dwMaxSummaryPages,
  233. IN BOOLEAN LargestPossibleSize
  234. );
  235. NTSTATUS
  236. IopCompleteDumpInitialization(
  237. IN HANDLE FileHandle
  238. );
  239. #ifdef ALLOC_PRAGMA
  240. VOID
  241. IopReadDumpRegistry(
  242. OUT PULONG dumpControl,
  243. OUT PULONG numberOfHeaderPages,
  244. OUT PULONG autoReboot,
  245. OUT PULONG dumpFileSize
  246. );
  247. VOID
  248. IopFreeDCB(
  249. BOOLEAN FreeDCB
  250. );
  251. #pragma alloc_text(PAGE,IoGetDumpStack)
  252. #pragma alloc_text(PAGE,IopGetDumpStack)
  253. #pragma alloc_text(PAGE,IopLoadDumpDriver)
  254. #pragma alloc_text(PAGE,IoFreeDumpStack)
  255. #pragma alloc_text(PAGE,IopCompleteDumpInitialization)
  256. #pragma alloc_text(PAGE,IopFreeDCB)
  257. #pragma alloc_text(PAGE,IopReadDumpRegistry)
  258. #pragma alloc_text(PAGE,IopInitializeDCB)
  259. #pragma alloc_text(PAGE,IopConfigureCrashDump)
  260. #pragma alloc_text(PAGE,IoInitializeCrashDump)
  261. #pragma alloc_text(PAGE,IoConfigureCrashDump)
  262. #endif
  263. #if defined (i386)
  264. //
  265. // Functions
  266. //
  267. BOOLEAN
  268. X86PaeEnabled(
  269. )
  270. /*++
  271. Routine Description:
  272. Is PAE currently enabled?
  273. Return Values:
  274. Return TRUE if PAE is enabled in the CR4 register, FALSE otherwise.
  275. --*/
  276. {
  277. ULONG Reg_Cr4;
  278. _asm {
  279. _emit 0Fh
  280. _emit 20h
  281. _emit 0E0h ;; mov eax, cr4
  282. mov Reg_Cr4, eax
  283. }
  284. return (Reg_Cr4 & CR4_PAE ? TRUE : FALSE);
  285. }
  286. #endif
  287. BOOLEAN
  288. IopIsAddressRangeValid(
  289. IN PVOID VirtualAddress,
  290. IN SIZE_T Length
  291. )
  292. /*++
  293. Routine Description:
  294. Validate a range of addresses.
  295. Arguments:
  296. Virtual Address - Beginning of of memory block to validate.
  297. Length - Length of memory block to validate.
  298. Return Value:
  299. TRUE - Address range is valid.
  300. FALSE - Address range is not valid.
  301. --*/
  302. {
  303. UINT_PTR Va;
  304. ULONG Pages;
  305. Va = (UINT_PTR) PAGE_ALIGN (VirtualAddress);
  306. Pages = ADDRESS_AND_SIZE_TO_SPAN_PAGES (VirtualAddress, Length);
  307. while (Pages) {
  308. if ((Va < 0x10000) ||
  309. (!MmIsAddressValid ( (LPVOID) Va))) {
  310. return FALSE;
  311. }
  312. Va += PAGE_SIZE;
  313. Pages--;
  314. }
  315. return TRUE;
  316. }
  317. BOOLEAN
  318. IoAddTriageDumpDataBlock(
  319. IN PVOID Address,
  320. IN ULONG Length
  321. )
  322. /*++
  323. Routine Description:
  324. Add an entry to the list of data blocks that should
  325. be saved in any triage dump generated. The entire
  326. block must be valid for any of it to be saved.
  327. Arguments:
  328. Address - Beginning of data block.
  329. Length - Length of data block. This must be less than
  330. the triage dump size.
  331. Return Value:
  332. TRUE - Block was added.
  333. FALSE - Block was not added.
  334. --*/
  335. {
  336. ULONG i;
  337. PTRIAGE_PTR_DATA_BLOCK Block;
  338. PUCHAR MinAddress, MaxAddress;
  339. if (Length >= TRIAGE_DUMP_SIZE ||
  340. !IopIsAddressRangeValid(Address, Length)) {
  341. return FALSE;
  342. }
  343. MinAddress = (PUCHAR)Address;
  344. MaxAddress = MinAddress + Length;
  345. //
  346. // Minimize overlap between the new block and existing blocks.
  347. // Blocks cannot simply be merged as blocks are inserted in
  348. // priority order for storage in the dump. Combining a low-priority
  349. // block with a high-priority block could lead to a medium-
  350. // priority block being bumped improperly from the dump.
  351. //
  352. Block = IopTriageDumpDataBlocks;
  353. for (i = 0; i < IopNumTriageDumpDataBlocks; i++, Block++) {
  354. if (MinAddress >= Block->MaxAddress ||
  355. MaxAddress <= Block->MinAddress) {
  356. // No overlap.
  357. continue;
  358. }
  359. //
  360. // Trim overlap out of the new block. If this
  361. // would split the new block into pieces don't
  362. // trim to keep things simple. Content may then
  363. // be duplicated in the dump.
  364. //
  365. if (MinAddress >= Block->MinAddress) {
  366. if (MaxAddress <= Block->MaxAddress) {
  367. // New block is completely contained.
  368. return TRUE;
  369. }
  370. // New block extends above the current block
  371. // so trim off the low-range overlap.
  372. MinAddress = Block->MaxAddress;
  373. } else if (MaxAddress <= Block->MaxAddress) {
  374. // New block extends below the current block
  375. // so trim off the high-range overlap.
  376. MaxAddress = Block->MinAddress;
  377. }
  378. }
  379. if (IopNumTriageDumpDataBlocks >= IO_MAX_TRIAGE_DUMP_DATA_BLOCKS) {
  380. return FALSE;
  381. }
  382. Block = IopTriageDumpDataBlocks + IopNumTriageDumpDataBlocks++;
  383. Block->MinAddress = MinAddress;
  384. Block->MaxAddress = MaxAddress;
  385. return TRUE;
  386. }
  387. VOID
  388. IopAddRunTimeTriageDataBlocks(
  389. IN PCONTEXT Context,
  390. IN PVOID* StackMin,
  391. IN PVOID* StackMax,
  392. IN PVOID* StoreMin,
  393. IN PVOID* StoreMax
  394. )
  395. /*++
  396. Routine Description:
  397. Add data blocks referenced by the context or
  398. other runtime state.
  399. Arguments:
  400. Context - Context record at the time the dump is being generated for.
  401. StackMin, StackMax - Stack memory boundaries. Stack memory is
  402. stored elsewhere in the dump.
  403. StoreMin, StoreMax - Backing store memory boundaries. Store memory
  404. is stored elsewhere in the dump.
  405. Return Value:
  406. None.
  407. --*/
  408. {
  409. PUSHORT ContextOffset;
  410. ContextOffset = IopRunTimeContextOffsets;
  411. while (*ContextOffset < IOP_LAST_CONTEXT_OFFSET) {
  412. PVOID* Ptr;
  413. //
  414. // Retrieve possible pointers from the context
  415. // registers.
  416. //
  417. Ptr = *(PVOID**)((PUCHAR)Context + *ContextOffset);
  418. // Stack and backing store memory is already saved
  419. // so ignore any pointers that fall into those ranges.
  420. if ((Ptr < StackMin || Ptr >= StackMax) &&
  421. (Ptr < StoreMin || Ptr >= StoreMax)) {
  422. IoAddTriageDumpDataBlock(PAGE_ALIGN(Ptr), PAGE_SIZE);
  423. }
  424. ContextOffset++;
  425. }
  426. }
  427. NTSTATUS
  428. IoGetDumpStack (
  429. IN PWCHAR ModulePrefix,
  430. OUT PDUMP_STACK_CONTEXT * pDumpStack,
  431. IN DEVICE_USAGE_NOTIFICATION_TYPE UsageType,
  432. IN ULONG IgnoreDeviceUsageFailure
  433. )
  434. /*++
  435. Routine Description:
  436. This routine loads a dump stack instance and returns an allocated
  437. context structure to track the loaded dumps stack.
  438. Arguments:
  439. ModePrefix - The prefix to prepent to BaseName during the load
  440. operation. This allows loading the same drivers
  441. multiple times with different virtual names and
  442. linkages.
  443. pDumpStack - The returned dump stack context structure
  444. UsageType - The Device Notification Usage Type for this file, that
  445. this routine will send as to the device object once the
  446. file has been successfully created and initialized.
  447. IgnoreDeviceUsageFailure - If the Device Usage Notification Irp fails, allow
  448. this to succeed anyway.
  449. Return Value:
  450. Status
  451. --*/
  452. {
  453. PAGED_CODE();
  454. return IopGetDumpStack(ModulePrefix,
  455. pDumpStack,
  456. &IoArcBootDeviceName,
  457. DEFAULT_DUMP_DRIVER,
  458. UsageType,
  459. IgnoreDeviceUsageFailure
  460. );
  461. }
  462. BOOLEAN
  463. IoIsTriageDumpEnabled(
  464. VOID
  465. )
  466. {
  467. if (IopDumpControlBlock &&
  468. (IopDumpControlBlock->Flags & DCB_TRIAGE_DUMP_ENABLED)) {
  469. return TRUE;
  470. }
  471. return FALSE;
  472. }
  473. VOID
  474. IopDisplayString(
  475. IN PCCHAR FormatString,
  476. ...
  477. )
  478. /*++
  479. Routine Description:
  480. Display a string to the boot video console. This will also print the
  481. string to the debugger, if the proper flags have been enabled.
  482. Arguments:
  483. String - String to display.
  484. Return Value:
  485. None.
  486. --*/
  487. {
  488. va_list ap;
  489. CHAR buffer [ 128 ];
  490. va_start( ap, FormatString );
  491. _vsnprintf( buffer,
  492. sizeof ( buffer ),
  493. FormatString,
  494. ap );
  495. buffer[sizeof(buffer) - 1] = 0;
  496. //
  497. // Display the string to the boot video monitor.
  498. //
  499. InbvDisplayString ( (PUCHAR) buffer );
  500. //
  501. // And, optionally, to the debugger.
  502. //
  503. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  504. CRASHDUMP_TRACE,
  505. "CRASHDUMP [DISP]: %s\r",
  506. buffer ));
  507. va_end(ap);
  508. }
  509. typedef struct _INTERNAL_GEOMETRY {
  510. DISK_GEOMETRY Geometry;
  511. LARGE_INTEGER DiskSize;
  512. DISK_PARTITION_INFO PartitionInfo;
  513. } INTERNAL_GEOMETRY, *PINTERNAL_GEOMETRY;
  514. C_ASSERT ( FIELD_OFFSET (INTERNAL_GEOMETRY, PartitionInfo) == FIELD_OFFSET (DISK_GEOMETRY_EX, Data) );
  515. NTSTATUS
  516. IopGetDumpStack (
  517. IN PWCHAR ModulePrefix,
  518. OUT PDUMP_STACK_CONTEXT * DumpStackBuffer,
  519. IN PUNICODE_STRING UniDeviceName,
  520. IN PWCHAR DumpDriverName,
  521. IN DEVICE_USAGE_NOTIFICATION_TYPE UsageType,
  522. IN ULONG IgnoreDeviceUsageFailure
  523. )
  524. /*++
  525. Routine Description:
  526. This routine loads a dump stack instance and returns an allocated
  527. context structure to track the loaded dumps stack.
  528. Arguments:
  529. ModePrefix - The prefix to prepent to BaseName during the load
  530. operation. This allows loading the same drivers
  531. multiple times with different virtual names and
  532. linkages.
  533. DumpStackBuffer - The returned dump stack context structure
  534. DeviceName - The name of the target dump device
  535. DumpDriverName - The name of the target dump driver
  536. UsageType - The Device Notification Usage Type for this file, that
  537. this routine will send as to the device object once the
  538. file has been successfully created and initialized.
  539. IgnoreDeviceUsageFailure - If the Device Usage Notification Irp fails, allow
  540. this to succeed anyway.
  541. Return Value:
  542. Status
  543. --*/
  544. {
  545. PDUMP_STACK_CONTEXT DumpStack;
  546. PCHAR Buffer;
  547. ANSI_STRING AnsiString;
  548. UNICODE_STRING TempName;
  549. OBJECT_ATTRIBUTES ObjectAttributes;
  550. NTSTATUS Status;
  551. HANDLE DeviceHandle;
  552. SCSI_ADDRESS ScsiAddress;
  553. BOOLEAN ScsiDump;
  554. PARTITION_INFORMATION_EX PartitionInfo;
  555. PFILE_OBJECT FileObject;
  556. PDEVICE_OBJECT DeviceObject;
  557. PDUMP_POINTERS DumpPointers;
  558. UNICODE_STRING DriverName;
  559. PDRIVER_OBJECT DriverObject;
  560. PIRP Irp;
  561. PIO_STACK_LOCATION IrpSp;
  562. IO_STATUS_BLOCK IoStatus;
  563. PWCHAR DumpName;
  564. PWCHAR NameOffset;
  565. KEVENT Event;
  566. PVOID p1;
  567. PHYSICAL_ADDRESS pa;
  568. ULONG i;
  569. IO_STACK_LOCATION irpSp;
  570. PINTERNAL_GEOMETRY Geometry;
  571. PDUMP_INITIALIZATION_CONTEXT DumpInit;
  572. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  573. CRASHDUMP_TRACE,
  574. "CRASHDUMP: Prefix:%ws stk: %x device:%ws driver:%ws\n",
  575. ModulePrefix,
  576. DumpStackBuffer,
  577. UniDeviceName->Buffer,
  578. DumpDriverName
  579. ));
  580. ASSERT (DeviceUsageTypeUndefined != UsageType);
  581. DumpStack = ExAllocatePool (
  582. NonPagedPool,
  583. sizeof (DUMP_STACK_CONTEXT) + sizeof (DUMP_POINTERS)
  584. );
  585. if (!DumpStack) {
  586. return STATUS_INSUFFICIENT_RESOURCES;
  587. }
  588. RtlZeroMemory(DumpStack, sizeof(DUMP_STACK_CONTEXT)+sizeof(DUMP_POINTERS));
  589. DumpInit = &DumpStack->Init;
  590. DumpPointers = (PDUMP_POINTERS) (DumpStack + 1);
  591. DumpStack->DumpPointers = DumpPointers;
  592. InitializeListHead (&DumpStack->DriverList);
  593. DumpName = NULL;
  594. //
  595. // Allocate scratch buffer
  596. //
  597. Buffer = ExAllocatePool (PagedPool, PAGE_SIZE);
  598. if (!Buffer) {
  599. ExFreePool (DumpStack);
  600. return STATUS_INSUFFICIENT_RESOURCES;
  601. }
  602. if (!KeGetBugMessageText(BUGCODE_PSS_CRASH_INIT, &DumpStack->InitMsg) ||
  603. !KeGetBugMessageText(BUGCODE_PSS_CRASH_PROGRESS, &DumpStack->ProgMsg) ||
  604. !KeGetBugMessageText(BUGCODE_PSS_CRASH_DONE, &DumpStack->DoneMsg)) {
  605. Status = STATUS_UNSUCCESSFUL;
  606. goto Done;
  607. }
  608. InitializeObjectAttributes(
  609. &ObjectAttributes,
  610. UniDeviceName,
  611. OBJ_KERNEL_HANDLE,
  612. NULL,
  613. NULL
  614. );
  615. Status = ZwOpenFile(
  616. &DeviceHandle,
  617. FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
  618. &ObjectAttributes,
  619. &IoStatus,
  620. FILE_SHARE_READ | FILE_SHARE_WRITE,
  621. FILE_NON_DIRECTORY_FILE
  622. );
  623. if (!NT_SUCCESS(Status)) {
  624. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  625. CRASHDUMP_ERROR,
  626. "CRASHDUMP: Could not open boot device partition, %s\n",
  627. Buffer
  628. ));
  629. goto Done;
  630. }
  631. //
  632. // Check to see whether or not the system was booted from a SCSI device.
  633. //
  634. Status = ZwDeviceIoControlFile (
  635. DeviceHandle,
  636. NULL,
  637. NULL,
  638. NULL,
  639. &IoStatus,
  640. IOCTL_SCSI_GET_ADDRESS,
  641. NULL,
  642. 0,
  643. &ScsiAddress,
  644. sizeof( SCSI_ADDRESS )
  645. );
  646. if (Status == STATUS_PENDING) {
  647. ZwWaitForSingleObject (
  648. DeviceHandle,
  649. FALSE,
  650. NULL
  651. );
  652. Status = IoStatus.Status;
  653. }
  654. ScsiDump = (BOOLEAN) (NT_SUCCESS(Status));
  655. //
  656. // If SCSI then allocate storage to contain the target address information.
  657. //
  658. DumpInit->TargetAddress = NULL;
  659. if (ScsiDump) {
  660. DumpInit->TargetAddress = ExAllocatePool(
  661. NonPagedPool,
  662. sizeof (SCSI_ADDRESS)
  663. );
  664. //
  665. // Formerly, this allocation was allowed to fail and the dump port
  666. // driver would search for a disk with a matching signature. No
  667. // longer. If we can't allocate a SCSI address, just fail.
  668. // Note, if we always pass in a valid SCSI target address, then the
  669. // disk signature isn't really necessary, but leave it in for now.
  670. //
  671. if (DumpInit->TargetAddress == NULL) {
  672. Status = STATUS_NO_MEMORY;
  673. goto Done;
  674. }
  675. RtlCopyMemory(
  676. DumpInit->TargetAddress,
  677. &ScsiAddress,
  678. sizeof(SCSI_ADDRESS)
  679. );
  680. }
  681. //
  682. // Determine the disk signature for the device from which the system was
  683. // booted and get the partition offset.
  684. //
  685. Status = ZwDeviceIoControlFile(
  686. DeviceHandle,
  687. NULL,
  688. NULL,
  689. NULL,
  690. &IoStatus,
  691. IOCTL_DISK_GET_PARTITION_INFO_EX,
  692. NULL,
  693. 0,
  694. &PartitionInfo,
  695. sizeof( PartitionInfo )
  696. );
  697. if (Status == STATUS_PENDING) {
  698. ZwWaitForSingleObject (
  699. DeviceHandle,
  700. FALSE,
  701. NULL
  702. );
  703. Status = IoStatus.Status;
  704. }
  705. //
  706. // Use the scratch buffer for the geometry.
  707. //
  708. Geometry = (PINTERNAL_GEOMETRY) Buffer;
  709. Status = ZwDeviceIoControlFile(
  710. DeviceHandle,
  711. NULL,
  712. NULL,
  713. NULL,
  714. &IoStatus,
  715. IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
  716. NULL,
  717. 0,
  718. Geometry,
  719. sizeof (*Geometry)
  720. );
  721. if (Status == STATUS_PENDING) {
  722. ZwWaitForSingleObject (
  723. DeviceHandle,
  724. FALSE,
  725. NULL
  726. );
  727. Status = IoStatus.Status;
  728. }
  729. //
  730. // Copy the signature, either MBR or GPT.
  731. //
  732. DumpInit->PartitionStyle = Geometry->PartitionInfo.PartitionStyle;
  733. if ( DumpInit->PartitionStyle == PARTITION_STYLE_MBR ) {
  734. DumpInit->DiskInfo.Mbr.Signature = Geometry->PartitionInfo.Mbr.Signature;
  735. DumpInit->DiskInfo.Mbr.CheckSum = Geometry->PartitionInfo.Mbr.CheckSum;
  736. } else {
  737. DumpInit->DiskInfo.Gpt.DiskId = Geometry->PartitionInfo.Gpt.DiskId;
  738. }
  739. //
  740. // The scratch buffer is now free to use.
  741. //
  742. Geometry = NULL;
  743. //
  744. // Get the adapter object and base mapping registers for the disk from
  745. // the disk driver. These will be used to call the HAL once the system
  746. // system has crashed, since it is not possible at that point to recreate
  747. // them from scratch.
  748. //
  749. ObReferenceObjectByHandle (
  750. DeviceHandle,
  751. 0,
  752. IoFileObjectType,
  753. KernelMode,
  754. (PVOID *) &FileObject,
  755. NULL
  756. );
  757. DeviceObject = IoGetRelatedDeviceObject (FileObject);
  758. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  759. Irp = IoBuildDeviceIoControlRequest(
  760. IOCTL_SCSI_GET_DUMP_POINTERS,
  761. DeviceObject,
  762. DumpPointers,
  763. sizeof (DUMP_POINTERS),
  764. DumpPointers,
  765. sizeof (DUMP_POINTERS),
  766. FALSE,
  767. &Event,
  768. &IoStatus
  769. );
  770. if (!Irp) {
  771. ObDereferenceObject (FileObject);
  772. ZwClose (DeviceHandle);
  773. Status = STATUS_INSUFFICIENT_RESOURCES;
  774. goto Done;
  775. }
  776. IrpSp = IoGetNextIrpStackLocation (Irp);
  777. IrpSp->FileObject = FileObject;
  778. Status = IoCallDriver( DeviceObject, Irp );
  779. if (Status == STATUS_PENDING) {
  780. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  781. Status = IoStatus.Status;
  782. }
  783. if (!NT_SUCCESS(Status) ||
  784. IoStatus.Information < FIELD_OFFSET(DUMP_POINTERS, DeviceObject)) {
  785. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  786. CRASHDUMP_ERROR,
  787. "CRASHDUMP: Could not get dump pointers; error = %x, length %x\n",
  788. Status,
  789. IoStatus.Information
  790. ));
  791. ObDereferenceObject (FileObject);
  792. ZwClose (DeviceHandle);
  793. goto Done;
  794. }
  795. DumpStack->PointersLength = (ULONG) IoStatus.Information;
  796. //
  797. // If the driver returned a pointer to a device object, that is the
  798. // object for the dump driver (non-scsi case)
  799. //
  800. DeviceObject = (PDEVICE_OBJECT) DumpPointers->DeviceObject;
  801. if (DeviceObject) {
  802. DriverObject = DeviceObject->DriverObject;
  803. //
  804. // Loop through the name of the driver looking for the end of the name,
  805. // which is the name of the dump image.
  806. //
  807. DumpName = DriverObject->DriverName.Buffer;
  808. while ( NameOffset = wcsstr( DumpName, L"\\" )) {
  809. DumpName = ++NameOffset;
  810. }
  811. ScsiDump = FALSE;
  812. }
  813. //
  814. // Release the handle, but keep the reference to the file object as it
  815. // will be needed at free dump dump driver time
  816. //
  817. DumpStack->FileObject = FileObject;
  818. ZwClose (DeviceHandle);
  819. //
  820. // Fill in some DumpInit results
  821. //
  822. DumpInit->Length = sizeof (DUMP_INITIALIZATION_CONTEXT);
  823. DumpInit->Reserved = 0;
  824. DumpInit->StallRoutine = &KeStallExecutionProcessor;
  825. DumpInit->AdapterObject = DumpPointers->AdapterObject;
  826. DumpInit->MappedRegisterBase = DumpPointers->MappedRegisterBase;
  827. DumpInit->PortConfiguration = DumpPointers->DumpData;
  828. DumpStack->ModulePrefix = ModulePrefix;
  829. DumpStack->PartitionOffset = PartitionInfo.StartingOffset;
  830. DumpStack->UsageType = DeviceUsageTypeUndefined;
  831. //
  832. // The minimum common buffer size is IO_DUMP_COMMON_BUFFER_SIZE (compatability)
  833. // This is used by the dump driver for SRB extension, CachedExtension, and sense buffer
  834. //
  835. if (DumpPointers->CommonBufferSize < IO_DUMP_COMMON_BUFFER_SIZE) {
  836. DumpPointers->CommonBufferSize = IO_DUMP_COMMON_BUFFER_SIZE;
  837. }
  838. DumpInit->CommonBufferSize = DumpPointers->CommonBufferSize;
  839. //
  840. // Allocate the required common buffers
  841. //
  842. if (DumpPointers->AllocateCommonBuffers) {
  843. for (i=0; i < 2; i++) {
  844. //
  845. // Don't use the adapter's DmaOperations to allocate the CommonBuffer.
  846. // Some adapters support 64-bit DMA, but then fail crashdump if the CommonBuffer
  847. // is above 4GB in physical RAM, making this unreliable.
  848. // (We no longer support legacy ISA adapters that require he DMA buffer
  849. // to be in the low 16MB).
  850. //
  851. pa.QuadPart = 0x0ffffffffL;
  852. p1 = MmAllocateContiguousMemory(DumpPointers->CommonBufferSize, pa);
  853. if (!p1) {
  854. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  855. CRASHDUMP_ERROR,
  856. "CRASHDUMP: Could not allocate common buffers for dump\n"
  857. ));
  858. Status = STATUS_INSUFFICIENT_RESOURCES;
  859. goto Done;
  860. }
  861. pa = MmGetPhysicalAddress(p1);
  862. DumpInit->CommonBuffer[i] = p1;
  863. DumpInit->PhysicalAddress[i] = pa;
  864. }
  865. }
  866. //
  867. // Determine whether or not the system booted from SCSI.
  868. //
  869. ASSERT (DumpPointers->UseDiskDump == TRUE ||
  870. DumpPointers->UseDiskDump == FALSE);
  871. if (DumpPointers->UseDiskDump || ScsiDump) {
  872. //
  873. // Load the boot disk and port driver to be used by the various
  874. // miniports for writing memory to the disk.
  875. //
  876. //
  877. // NB: Using the UseDiskDump flag to determine whether this is
  878. // a SCSIPORT miniport or a STORPORT miniport is gross. Fix this
  879. // when we fix crashdump.
  880. //
  881. Status = IopLoadDumpDriver (
  882. DumpStack,
  883. DumpDriverName,
  884. ScsiDump ? SCSIPORT_DRIVER_NAME : STORPORT_DRIVER_NAME
  885. );
  886. if (!NT_SUCCESS(Status)) {
  887. IopLogErrorEvent(0,9,STATUS_SUCCESS,IO_DUMP_DRIVER_LOAD_FAILURE,0,NULL,0,NULL);
  888. goto Done;
  889. }
  890. }
  891. if (ScsiDump) {
  892. //
  893. // The disk and port dump driver has been loaded. Load the appropriate
  894. // miniport driver as well so that the boot device can be accessed.
  895. //
  896. DriverName.Length = 0;
  897. DriverName.Buffer = (PVOID) Buffer;
  898. DriverName.MaximumLength = PAGE_SIZE;
  899. //
  900. // The system was booted from SCSI. Get the name of the appropriate
  901. // miniport driver and load it.
  902. //
  903. sprintf(Buffer, "\\Device\\ScsiPort%d", ScsiAddress.PortNumber );
  904. RtlInitAnsiString( &AnsiString, Buffer );
  905. Status = RtlAnsiStringToUnicodeString( &TempName, &AnsiString, TRUE );
  906. if (NT_SUCCESS(Status)){
  907. InitializeObjectAttributes(
  908. &ObjectAttributes,
  909. &TempName,
  910. 0,
  911. NULL,
  912. NULL
  913. );
  914. Status = ZwOpenFile(
  915. &DeviceHandle,
  916. FILE_READ_ATTRIBUTES,
  917. &ObjectAttributes,
  918. &IoStatus,
  919. FILE_SHARE_READ | FILE_SHARE_WRITE,
  920. FILE_NON_DIRECTORY_FILE
  921. );
  922. RtlFreeUnicodeString( &TempName );
  923. }
  924. if (!NT_SUCCESS( Status )) {
  925. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  926. CRASHDUMP_ERROR,
  927. "CRASHDUMP: Could not open SCSI port %d, error = %x\n",
  928. ScsiAddress.PortNumber,
  929. Status
  930. ));
  931. goto Done;
  932. }
  933. //
  934. // Convert the file handle into a pointer to the device object, and
  935. // get the name of the driver from its driver object.
  936. //
  937. ObReferenceObjectByHandle(
  938. DeviceHandle,
  939. 0,
  940. IoFileObjectType,
  941. KernelMode,
  942. (PVOID *) &FileObject,
  943. NULL
  944. );
  945. DriverObject = FileObject->DeviceObject->DriverObject;
  946. ObDereferenceObject( FileObject );
  947. ZwClose( DeviceHandle );
  948. //
  949. // Loop through the name of the driver looking for the end of the name,
  950. // which is the name of the miniport image.
  951. //
  952. DumpName = DriverObject->DriverName.Buffer;
  953. while ( NameOffset = wcsstr( DumpName, L"\\" )) {
  954. DumpName = ++NameOffset;
  955. }
  956. }
  957. //
  958. // Load the dump driver
  959. //
  960. if (!DumpName) {
  961. Status = STATUS_NOT_SUPPORTED;
  962. goto Done;
  963. }
  964. swprintf ((PWCHAR) Buffer, L"\\SystemRoot\\System32\\Drivers\\%s.sys", DumpName);
  965. Status = IopLoadDumpDriver (
  966. DumpStack,
  967. (PWCHAR) Buffer,
  968. NULL
  969. );
  970. if (!NT_SUCCESS(Status)) {
  971. IopLogErrorEvent(0,10,STATUS_SUCCESS,IO_DUMP_DRIVER_LOAD_FAILURE,0,NULL,0,NULL);
  972. goto Done;
  973. }
  974. //
  975. // Claim the file as part of specific device usage path.
  976. //
  977. FileObject = DumpStack->FileObject;
  978. DeviceObject = IoGetRelatedDeviceObject (FileObject);
  979. RtlZeroMemory (&irpSp, sizeof (IO_STACK_LOCATION));
  980. irpSp.MajorFunction = IRP_MJ_PNP;
  981. irpSp.MinorFunction = IRP_MN_DEVICE_USAGE_NOTIFICATION;
  982. irpSp.Parameters.UsageNotification.Type = UsageType;
  983. irpSp.Parameters.UsageNotification.InPath = TRUE;
  984. irpSp.FileObject = FileObject;
  985. Status = IopSynchronousCall (DeviceObject, &irpSp, NULL);
  986. if (!NT_SUCCESS(Status) && IgnoreDeviceUsageFailure) {
  987. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  988. CRASHDUMP_WARNING,
  989. "CRASHDUMP: IopGetDumpStack: DEVICE_USAGE_NOTIFICATION "
  990. "Error ignored (%x)\n",
  991. Status
  992. ));
  993. Status = STATUS_SUCCESS;
  994. }
  995. if (NT_SUCCESS(Status)) {
  996. DumpStack->UsageType = UsageType;
  997. }
  998. Done:
  999. if (NT_SUCCESS(Status)) {
  1000. *DumpStackBuffer = DumpStack;
  1001. } else {
  1002. IoFreeDumpStack (DumpStack);
  1003. }
  1004. ExFreePool (Buffer);
  1005. return Status;
  1006. }
  1007. NTSTATUS
  1008. IopLoadDumpDriver (
  1009. IN OUT PDUMP_STACK_CONTEXT DumpStack,
  1010. IN PWCHAR DriverNameString,
  1011. IN PWCHAR NewBaseNameString OPTIONAL
  1012. )
  1013. /*++
  1014. Routine Description:
  1015. Worker function for IoGetDumpStack to load a particular driver into
  1016. the current DumpStack being created
  1017. Arguments:
  1018. DumpStack - Dump driver stack being built
  1019. DriverNameString - The string name of the driver to load
  1020. NewBaseNameString - The modified basename of the driver once loaded
  1021. Return Value:
  1022. Status
  1023. --*/
  1024. {
  1025. NTSTATUS Status;
  1026. PDUMP_STACK_IMAGE DumpImage;
  1027. UNICODE_STRING DriverName;
  1028. UNICODE_STRING BaseName;
  1029. UNICODE_STRING Prefix;
  1030. PUNICODE_STRING LoadBaseName;
  1031. //
  1032. // Allocate space to track this dump driver
  1033. //
  1034. DumpImage = ExAllocatePool(
  1035. NonPagedPool,
  1036. sizeof (DUMP_STACK_IMAGE)
  1037. );
  1038. if (!DumpImage) {
  1039. return STATUS_INSUFFICIENT_RESOURCES;
  1040. }
  1041. //
  1042. // Load the system image
  1043. //
  1044. RtlInitUnicodeString (&DriverName, DriverNameString);
  1045. RtlInitUnicodeString (&Prefix, DumpStack->ModulePrefix);
  1046. LoadBaseName = NULL;
  1047. if (NewBaseNameString) {
  1048. LoadBaseName = &BaseName;
  1049. RtlInitUnicodeString (&BaseName, NewBaseNameString);
  1050. BaseName.MaximumLength = Prefix.Length + BaseName.Length;
  1051. BaseName.Buffer = ExAllocatePool (
  1052. NonPagedPool,
  1053. BaseName.MaximumLength
  1054. );
  1055. if (!BaseName.Buffer) {
  1056. ExFreePool (DumpImage);
  1057. return STATUS_INSUFFICIENT_RESOURCES;
  1058. }
  1059. BaseName.Length = 0;
  1060. RtlAppendUnicodeStringToString (&BaseName, &Prefix);
  1061. RtlAppendUnicodeToString (&BaseName, NewBaseNameString);
  1062. }
  1063. else {
  1064. BaseName.Buffer = NULL;
  1065. }
  1066. Status = MmLoadSystemImage(
  1067. &DriverName,
  1068. &Prefix,
  1069. LoadBaseName,
  1070. MM_LOAD_IMAGE_AND_LOCKDOWN,
  1071. &DumpImage->Image,
  1072. &DumpImage->ImageBase
  1073. );
  1074. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1075. CRASHDUMP_TRACE,
  1076. "CRASHDUMP: MmLoadAndLockSystemImage\n"
  1077. " DumpImage %p Image %p Base %p\n",
  1078. DumpImage,
  1079. DumpImage->Image,
  1080. DumpImage->ImageBase
  1081. ));
  1082. if (BaseName.Buffer) {
  1083. ExFreePool (BaseName.Buffer);
  1084. }
  1085. if (!NT_SUCCESS (Status)) {
  1086. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1087. CRASHDUMP_ERROR,
  1088. "CRASHDUMP: Could not load %wZ; error = %x\n",
  1089. &DriverName,
  1090. Status
  1091. ));
  1092. ExFreePool (DumpImage);
  1093. return Status;
  1094. }
  1095. //
  1096. // Put this driver on the list of drivers to be processed at crash time
  1097. //
  1098. DumpImage->SizeOfImage = DumpImage->Image->SizeOfImage;
  1099. InsertTailList (&DumpStack->DriverList, &DumpImage->Link);
  1100. return STATUS_SUCCESS;
  1101. }
  1102. ULONG
  1103. IopGetDumpControlBlockCheck (
  1104. IN PDUMP_CONTROL_BLOCK Dcb
  1105. )
  1106. /*++
  1107. Routine Description:
  1108. Return the current checksum total for the Dcb
  1109. Arguments:
  1110. DumpStack - Dump driver stack to checksum
  1111. Return Value:
  1112. Checksum value
  1113. --*/
  1114. {
  1115. ULONG Check;
  1116. PLIST_ENTRY Link;
  1117. PDUMP_STACK_IMAGE DumpImage;
  1118. PMAPPED_ADDRESS MappedAddress;
  1119. PDUMP_STACK_CONTEXT DumpStack;
  1120. //
  1121. // Check the DCB, memory descriptor array, and the FileDescriptorArray
  1122. //
  1123. Check = PoSimpleCheck(0, Dcb, sizeof(DUMP_CONTROL_BLOCK));
  1124. Check = PoSimpleCheck(Check, Dcb->FileDescriptorArray, Dcb->FileDescriptorSize);
  1125. DumpStack = Dcb->DumpStack;
  1126. if (DumpStack) {
  1127. //
  1128. // Include the dump stack context structure, and dump driver images
  1129. //
  1130. Check = PoSimpleCheck(Check, DumpStack, sizeof(DUMP_STACK_CONTEXT));
  1131. Check = PoSimpleCheck(Check, DumpStack->DumpPointers, DumpStack->PointersLength);
  1132. for (Link = DumpStack->DriverList.Flink;
  1133. Link != &DumpStack->DriverList;
  1134. Link = Link->Flink) {
  1135. DumpImage = CONTAINING_RECORD(Link, DUMP_STACK_IMAGE, Link);
  1136. Check = PoSimpleCheck(Check, DumpImage, sizeof(DUMP_STACK_IMAGE));
  1137. #if !defined (_IA64_)
  1138. //
  1139. // ISSUE - 2000/02/14 - math: Add image check image for IA64.
  1140. //
  1141. // Disable the image checksum on IA64 because it's broken.
  1142. Check = PoSimpleCheck(Check, DumpImage->ImageBase, DumpImage->SizeOfImage);
  1143. #endif
  1144. }
  1145. //
  1146. // Include the mapped addresses
  1147. //
  1148. // If this is non-null it is treated as a PMAPPED_ADDRESS * (see scsiport and atdisk)
  1149. //
  1150. if (DumpStack->Init.MappedRegisterBase != NULL) {
  1151. MappedAddress = *(PMAPPED_ADDRESS *)DumpStack->Init.MappedRegisterBase;
  1152. } else {
  1153. MappedAddress = NULL;
  1154. }
  1155. while (MappedAddress) {
  1156. Check = PoSimpleCheck (Check, MappedAddress, sizeof(MAPPED_ADDRESS));
  1157. MappedAddress = MappedAddress->NextMappedAddress;
  1158. }
  1159. }
  1160. return Check;
  1161. }
  1162. NTSTATUS
  1163. IoInitializeDumpStack (
  1164. IN PDUMP_STACK_CONTEXT DumpStack,
  1165. IN PUCHAR MessageBuffer OPTIONAL
  1166. )
  1167. /*++
  1168. Routine Description:
  1169. Initialize the dump driver stack referenced by DumpStack to perform IO.
  1170. Arguments:
  1171. DumpStack - Dump driver stack being initialized
  1172. Return Value:
  1173. Status
  1174. --*/
  1175. {
  1176. PDUMP_INITIALIZATION_CONTEXT DumpInit;
  1177. PLIST_ENTRY Link;
  1178. NTSTATUS Status;
  1179. PDRIVER_INITIALIZE DriverInit;
  1180. PDUMP_STACK_IMAGE DumpImage;
  1181. DumpInit = &DumpStack->Init;
  1182. //
  1183. // ISSUE - 2000/02/07 - math: Verify checksum on DumpStack structure
  1184. //
  1185. //
  1186. // Initializes the dump drivers
  1187. //
  1188. for (Link = DumpStack->DriverList.Flink;
  1189. Link != &DumpStack->DriverList;
  1190. Link = Link->Flink) {
  1191. DumpImage = CONTAINING_RECORD(Link, DUMP_STACK_IMAGE, Link);
  1192. //
  1193. // Call this driver's driver init. Only the first driver gets the
  1194. // dump initialization context
  1195. //
  1196. DriverInit = (PDRIVER_INITIALIZE) (ULONG_PTR) DumpImage->Image->EntryPoint;
  1197. Status = DriverInit (NULL, (PUNICODE_STRING) DumpInit);
  1198. DumpInit = NULL;
  1199. if (!NT_SUCCESS(Status)) {
  1200. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1201. CRASHDUMP_ERROR,
  1202. "CRASHDUMP: Unable to initialize driver; error = %x\n",
  1203. Status
  1204. ));
  1205. return Status;
  1206. }
  1207. }
  1208. DumpInit = &DumpStack->Init;
  1209. //
  1210. // Display string we are starting
  1211. //
  1212. if (MessageBuffer) {
  1213. IopDisplayString ( (PCCHAR) MessageBuffer );
  1214. }
  1215. //
  1216. // Open the partition from which the system was booted.
  1217. // This returns TRUE if the disk w/the appropriate signature was found,
  1218. // otherwise a NULL, in which case there is no way to continue.
  1219. //
  1220. if (!DumpInit->OpenRoutine (DumpStack->PartitionOffset)) {
  1221. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1222. CRASHDUMP_ERROR,
  1223. "CRASHDUMP: Could not find/open partition offset\n"
  1224. ));
  1225. return STATUS_UNSUCCESSFUL;
  1226. }
  1227. return STATUS_SUCCESS;
  1228. }
  1229. VOID
  1230. IoGetDumpHiberRanges (
  1231. IN PVOID HiberContext,
  1232. IN PDUMP_STACK_CONTEXT DumpStack
  1233. )
  1234. /*++
  1235. Routine Description:
  1236. Adds the dump driver stack storage to the hibernate range list,
  1237. to inform the hibernate procedure which pages need cloned,
  1238. discarded or not checksumed as they are in use by the dump
  1239. stack.
  1240. Arguments:
  1241. HiberContext - Pointer to the hiber context structure
  1242. DumpStack - Dump driver stack being initialized
  1243. Return Value:
  1244. None
  1245. --*/
  1246. {
  1247. PDUMP_POINTERS DumpPointers;
  1248. PDUMP_STACK_IMAGE DumpImage;
  1249. PLIST_ENTRY Link;
  1250. DumpPointers = DumpStack->DumpPointers;
  1251. //
  1252. // Report the common buffer
  1253. //
  1254. if (DumpPointers->CommonBufferVa) {
  1255. PoSetHiberRange (
  1256. HiberContext,
  1257. PO_MEM_CL_OR_NCHK,
  1258. DumpPointers->CommonBufferVa,
  1259. DumpPointers->CommonBufferSize,
  1260. 'fubc'
  1261. );
  1262. }
  1263. //
  1264. // Dump the entire image of the dump drivers
  1265. //
  1266. for (Link = DumpStack->DriverList.Flink;
  1267. Link != &DumpStack->DriverList;
  1268. Link = Link->Flink) {
  1269. DumpImage = CONTAINING_RECORD(Link, DUMP_STACK_IMAGE, Link);
  1270. PoSetHiberRange (
  1271. HiberContext,
  1272. PO_MEM_CL_OR_NCHK,
  1273. DumpImage->ImageBase,
  1274. DumpImage->SizeOfImage,
  1275. 'gmID'
  1276. );
  1277. }
  1278. }
  1279. VOID
  1280. IoFreeDumpStack (
  1281. IN PDUMP_STACK_CONTEXT DumpStack
  1282. )
  1283. /*++
  1284. Routine Description:
  1285. Free the dump driver stack referenced by DumpStack
  1286. Arguments:
  1287. DumpStack - Dump driver stack being initialized
  1288. Return Value:
  1289. None
  1290. --*/
  1291. {
  1292. PDUMP_INITIALIZATION_CONTEXT DumpInit;
  1293. PDUMP_STACK_IMAGE DumpImage;
  1294. PDEVICE_OBJECT DeviceObject;
  1295. IO_STATUS_BLOCK IoStatus;
  1296. PIRP Irp;
  1297. KEVENT Event;
  1298. NTSTATUS Status;
  1299. ULONG i;
  1300. PFILE_OBJECT FileObject;
  1301. IO_STACK_LOCATION irpSp;
  1302. PAGED_CODE();
  1303. DumpInit = &DumpStack->Init;
  1304. //
  1305. // Release the claim to this file as a specific device usage path.
  1306. //
  1307. FileObject = DumpStack->FileObject;
  1308. if (FileObject) {
  1309. DeviceObject = IoGetRelatedDeviceObject (FileObject);
  1310. RtlZeroMemory (&irpSp, sizeof (IO_STACK_LOCATION));
  1311. irpSp.MajorFunction = IRP_MJ_PNP;
  1312. irpSp.MinorFunction = IRP_MN_DEVICE_USAGE_NOTIFICATION;
  1313. irpSp.Parameters.UsageNotification.Type = DumpStack->UsageType;
  1314. irpSp.Parameters.UsageNotification.InPath = FALSE;
  1315. irpSp.FileObject = FileObject;
  1316. if (DeviceUsageTypeUndefined != DumpStack->UsageType) {
  1317. Status = IopSynchronousCall (DeviceObject, &irpSp, NULL);
  1318. } else {
  1319. Status = STATUS_SUCCESS;
  1320. }
  1321. }
  1322. //
  1323. // Free any common buffers which where allocated
  1324. //
  1325. for (i=0; i < 2; i++) {
  1326. if (DumpInit->CommonBuffer[i]) {
  1327. MmFreeContiguousMemory (DumpInit->CommonBuffer[i]);
  1328. DumpInit->CommonBuffer[i] = NULL;
  1329. }
  1330. }
  1331. //
  1332. // Unload the dump drivers
  1333. //
  1334. while (!IsListEmpty(&DumpStack->DriverList)) {
  1335. DumpImage = CONTAINING_RECORD(DumpStack->DriverList.Blink, DUMP_STACK_IMAGE, Link);
  1336. RemoveEntryList (&DumpImage->Link);
  1337. MmUnloadSystemImage (DumpImage->Image);
  1338. ExFreePool (DumpImage);
  1339. }
  1340. //
  1341. // Inform the driver stack that the dump registartion is over
  1342. //
  1343. if (DumpStack->FileObject) {
  1344. DeviceObject = IoGetRelatedDeviceObject ((PFILE_OBJECT) DumpStack->FileObject);
  1345. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  1346. Irp = IoBuildDeviceIoControlRequest(
  1347. IOCTL_SCSI_FREE_DUMP_POINTERS,
  1348. DeviceObject,
  1349. DumpStack->DumpPointers,
  1350. sizeof (DUMP_POINTERS),
  1351. NULL,
  1352. 0,
  1353. FALSE,
  1354. &Event,
  1355. &IoStatus
  1356. );
  1357. if (Irp){
  1358. PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(Irp);
  1359. nextSp->FileObject = DumpStack->FileObject;
  1360. Status = IoCallDriver( DeviceObject, Irp );
  1361. if (Status == STATUS_PENDING) {
  1362. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  1363. Status = IoStatus.Status;
  1364. }
  1365. }
  1366. ObDereferenceObject( DumpStack->FileObject );
  1367. }
  1368. //
  1369. // Free the target address if it exists
  1370. //
  1371. if (DumpStack->Init.TargetAddress) {
  1372. ExFreePool( DumpStack->Init.TargetAddress);
  1373. }
  1374. //
  1375. // Free the dump stack context
  1376. //
  1377. ExFreePool (DumpStack);
  1378. }
  1379. VOID
  1380. IopGetSecondaryDumpDataLimits(
  1381. ULONG Flags,
  1382. OUT PULONG MaxData,
  1383. OUT PULONG MaxPerCallback
  1384. )
  1385. {
  1386. // When the selected dump type is small also
  1387. // limit the amount of secondary dump data.
  1388. // This prevents overzealous secondary dumpers from
  1389. // creating multi-megabyte secondary dumps when triage
  1390. // dumps are selected.
  1391. if (!(Flags & DCB_DUMP_ENABLED) ||
  1392. (Flags & DCB_DUMP_HEADER_ENABLED)) {
  1393. *MaxData = 0;
  1394. *MaxPerCallback = 0;
  1395. } else if (Flags & DCB_TRIAGE_DUMP_ENABLED) {
  1396. *MaxData = 16 * PAGE_SIZE;
  1397. *MaxPerCallback = 2 * PAGE_SIZE;
  1398. } else {
  1399. // Arbitrarily limit maximum data amount to 256MB.
  1400. // There shouldn't be any reason that callers should
  1401. // have anywhere near that much data that wouldn't
  1402. // get picked up by a full dump.
  1403. *MaxData = 256 * 1024 * 1024;
  1404. *MaxPerCallback = *MaxData / 4;
  1405. }
  1406. }
  1407. NTSTATUS
  1408. IopGetSecondaryDumpDataSpace(
  1409. IN PDUMP_CONTROL_BLOCK dcb,
  1410. OUT PULONG Space
  1411. )
  1412. {
  1413. ULONG MaxDumpData;
  1414. ULONG MaxPerCallbackDumpData;
  1415. NTSTATUS NtStatus;
  1416. IopGetSecondaryDumpDataLimits(dcb->Flags,
  1417. &MaxDumpData, &MaxPerCallbackDumpData);
  1418. NtStatus = IopInvokeSecondaryDumpDataCallbacks(NULL, NULL, NULL, 0,
  1419. (PBYTE)dcb->HeaderPage,
  1420. PAGE_SIZE,
  1421. MaxDumpData,
  1422. MaxPerCallbackDumpData,
  1423. Space);
  1424. if (!NT_SUCCESS(NtStatus)) {
  1425. *Space = 0;
  1426. }
  1427. return NtStatus;
  1428. }
  1429. NTSTATUS
  1430. IopInitializeDumpSpaceAndType(
  1431. IN PDUMP_CONTROL_BLOCK dcb,
  1432. IN OUT PMEMORY_DUMP MemoryDump,
  1433. IN ULONG SecondarySpace
  1434. )
  1435. {
  1436. LARGE_INTEGER Space;
  1437. Space.QuadPart = 0;
  1438. if (dcb->Flags & DCB_TRIAGE_DUMP_ENABLED) {
  1439. //
  1440. // Fixed size dump for triage-dumps.
  1441. //
  1442. MemoryDump->Header.DumpType = DUMP_TYPE_TRIAGE;
  1443. MemoryDump->Header.MiniDumpFields = dcb->TriageDumpFlags;
  1444. Space.QuadPart = TRIAGE_DUMP_SIZE;
  1445. } else if (dcb->Flags & DCB_SUMMARY_DUMP_ENABLED) {
  1446. MemoryDump->Header.DumpType = DUMP_TYPE_SUMMARY;
  1447. Space = IopCalculateRequiredDumpSpace(
  1448. dcb->Flags,
  1449. dcb->HeaderSize,
  1450. MmPhysicalMemoryBlock->NumberOfPages,
  1451. MemoryDump->Summary.Pages,
  1452. FALSE
  1453. );
  1454. } else {
  1455. if (dcb->Flags & DCB_DUMP_HEADER_ENABLED) {
  1456. MemoryDump->Header.DumpType = DUMP_TYPE_HEADER;
  1457. }
  1458. Space = IopCalculateRequiredDumpSpace(
  1459. dcb->Flags,
  1460. dcb->HeaderSize,
  1461. MmPhysicalMemoryBlock->NumberOfPages,
  1462. MmPhysicalMemoryBlock->NumberOfPages,
  1463. FALSE
  1464. );
  1465. }
  1466. //
  1467. // Add in any secondary space.
  1468. //
  1469. Space.QuadPart += SecondarySpace;
  1470. //
  1471. // If the calculated size is larger than the pagefile, truncate it to
  1472. // the pagefile size.
  1473. //
  1474. if (Space.QuadPart > dcb->DumpFileSize.QuadPart) {
  1475. Space.QuadPart = dcb->DumpFileSize.QuadPart;
  1476. }
  1477. MemoryDump->Header.RequiredDumpSpace = Space;
  1478. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1479. CRASHDUMP_TRACE,
  1480. "CRASHDUMP: Dump File Size set to %I64x\n",
  1481. Space.QuadPart
  1482. ));
  1483. return STATUS_SUCCESS;
  1484. }
  1485. BOOLEAN
  1486. IoWriteCrashDump(
  1487. IN ULONG BugCheckCode,
  1488. IN ULONG_PTR BugCheckParameter1,
  1489. IN ULONG_PTR BugCheckParameter2,
  1490. IN ULONG_PTR BugCheckParameter3,
  1491. IN ULONG_PTR BugCheckParameter4,
  1492. IN PVOID ContextSave,
  1493. IN PKTHREAD Thread,
  1494. OUT PBOOLEAN Reboot
  1495. )
  1496. /*++
  1497. Routine Description:
  1498. This routine checks to see whether or not crash dumps are enabled and, if
  1499. so, writes all of physical memory to the system disk's paging file.
  1500. Arguments:
  1501. BugCheckCode/ParameterN - Code and parameters w/which BugCheck was called.
  1502. Return Value:
  1503. None.
  1504. --*/
  1505. {
  1506. NTSTATUS status;
  1507. PDUMP_CONTROL_BLOCK dcb;
  1508. PDUMP_STACK_CONTEXT dumpStack;
  1509. PDUMP_DRIVER_WRITE write;
  1510. PDUMP_DRIVER_FINISH finishUp;
  1511. PDUMP_HEADER header;
  1512. PCONTEXT context = ContextSave;
  1513. PMEMORY_DUMP MemoryDump;
  1514. LARGE_INTEGER diskByteOffset;
  1515. PFN_NUMBER localMdl[(sizeof( MDL )/sizeof(PFN_NUMBER)) + 17];
  1516. PMDL mdl;
  1517. PLARGE_INTEGER mcb;
  1518. ULONG64 memoryAddress;
  1519. ULONG byteOffset;
  1520. ULONG byteCount;
  1521. PFN_NUMBER ActualPages;
  1522. ULONG dwTransferSize;
  1523. PFN_NUMBER NumberOfPages;
  1524. #if defined (_X86_)
  1525. ULONG_PTR DirBasePage;
  1526. #endif
  1527. ULONG MaxDumpData;
  1528. ULONG MaxPerCallbackDumpData;
  1529. NTSTATUS SecondaryStatus;
  1530. ULONG SecondarySpace;
  1531. PPHYSICAL_MEMORY_RUN CurRun;
  1532. ULONG64 LastRunAddr;
  1533. KdCheckForDebugBreak();
  1534. ASSERT (Reboot != NULL);
  1535. //
  1536. // Initialization
  1537. //
  1538. MemoryDump = NULL;
  1539. //
  1540. // Immediately fill out the reboot parameter as auto-reboot
  1541. // may be enabled even with no other post-mortem features.
  1542. //
  1543. if (IopAutoReboot) {
  1544. *Reboot = TRUE;
  1545. } else {
  1546. *Reboot = FALSE;
  1547. }
  1548. //
  1549. // Begin by determining whether or not crash dumps are enabled. If not,
  1550. // return immediately since there is nothing to do.
  1551. //
  1552. dcb = IopDumpControlBlock;
  1553. if (!dcb) {
  1554. return FALSE;
  1555. }
  1556. if (dcb->Flags & DCB_DUMP_ENABLED || dcb->Flags & DCB_SUMMARY_ENABLED) {
  1557. IopFinalCrashDumpStatus = STATUS_PENDING;
  1558. //
  1559. // A dump is to be written to the paging file. Ensure that all of the
  1560. // descriptor data for what needs to be done is valid, otherwise it
  1561. // could be that part of the reason for the bugcheck is that this data
  1562. // was corrupted. Or, it could be that no paging file was found yet,
  1563. // or any number of other situations.
  1564. //
  1565. //
  1566. // We do not check the checksum if IopIgnoreDumpCheck is TRUE. Use
  1567. // this to make debugging easier.
  1568. //
  1569. if (!IopIgnoreDumpCheck &&
  1570. IopGetDumpControlBlockCheck(dcb) != IopDumpControlBlockChecksum) {
  1571. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1572. CRASHDUMP_ERROR,
  1573. "CRASHDUMP: Disk dump routine returning due to DCB integrity error\n"
  1574. " Computed Checksum: %d != Saved Checksum %d\n"
  1575. " No dump will be created\n",
  1576. IopGetDumpControlBlockCheck (dcb),
  1577. IopDumpControlBlockChecksum
  1578. ));
  1579. IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL;
  1580. return FALSE;
  1581. }
  1582. //
  1583. // Message that we are starting the crashdump
  1584. //
  1585. dumpStack = dcb->DumpStack;
  1586. // sprintf( messageBuffer, "%Z\n", &dumpStack->InitMsg );
  1587. //
  1588. // Disable HAL Verifier during a crash dump.
  1589. //
  1590. VfDisableHalVerifier();
  1591. //
  1592. // Initialize the dump stack
  1593. //
  1594. status = IoInitializeDumpStack (dumpStack, NULL);
  1595. KdCheckForDebugBreak();
  1596. if (!NT_SUCCESS( status )) {
  1597. IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL;
  1598. return FALSE;
  1599. }
  1600. //
  1601. // If we successfully initialized the dump stack, print out the PSS
  1602. // message.
  1603. //
  1604. IopDisplayString ("%Z\r\n", &dumpStack->InitMsg);
  1605. //
  1606. // Record the dump driver's entry points.
  1607. //
  1608. write = dumpStack->Init.WriteRoutine;
  1609. finishUp = dumpStack->Init.FinishRoutine;
  1610. dwTransferSize = dumpStack->Init.MaximumTransferSize;
  1611. if ( ( !dwTransferSize ) || ( dwTransferSize > IO_DUMP_MAXIMUM_TRANSFER_SIZE ) ) {
  1612. dwTransferSize = IO_DUMP_MINIMUM_TRANSFER_SIZE;
  1613. }
  1614. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1615. CRASHDUMP_TRACE,
  1616. "CRASHDUMP: Maximum Transfer Size = %x\n",dwTransferSize
  1617. ));
  1618. //
  1619. // The boot partition was found, so put together a dump file header
  1620. // and write it to the disk.
  1621. //
  1622. // Get the amount of secondary dump data while the
  1623. // header page can still be used as scratch space.
  1624. SecondaryStatus = IopGetSecondaryDumpDataSpace(dcb, &SecondarySpace);
  1625. MemoryDump = (PMEMORY_DUMP) dcb->HeaderPage;
  1626. header = &MemoryDump->Header;
  1627. RtlFillMemoryUlong( header, sizeof(*header), DUMP_SIGNATURE );
  1628. header->ValidDump = DUMP_VALID_DUMP;
  1629. header->BugCheckCode = BugCheckCode;
  1630. header->BugCheckParameter1 = BugCheckParameter1;
  1631. header->BugCheckParameter2 = BugCheckParameter2;
  1632. header->BugCheckParameter3 = BugCheckParameter3;
  1633. header->BugCheckParameter4 = BugCheckParameter4;
  1634. header->SecondaryDataState = (ULONG)SecondaryStatus;
  1635. #if defined (_X86_)
  1636. //
  1637. // Add the current page directory table page - don't use the directory
  1638. // table base for the crashing process as we have switched cr3 on
  1639. // stack overflow crashes, etc.
  1640. //
  1641. _asm {
  1642. mov eax, cr3
  1643. mov DirBasePage, eax
  1644. }
  1645. header->DirectoryTableBase = DirBasePage;
  1646. #elif defined (_IA64_)
  1647. ASSERT (((MmSystemParentTablePage << PAGE_SHIFT) >> PAGE_SHIFT) ==
  1648. MmSystemParentTablePage);
  1649. header->DirectoryTableBase = MmSystemParentTablePage << PAGE_SHIFT;
  1650. #else
  1651. header->DirectoryTableBase = KeGetCurrentThread()->ApcState.Process->DirectoryTableBase[0];
  1652. #endif
  1653. header->PfnDataBase = (ULONG_PTR)MmPfnDatabase;
  1654. header->PsLoadedModuleList = (ULONG_PTR) &PsLoadedModuleList;
  1655. header->PsActiveProcessHead = (ULONG_PTR) &PsActiveProcessHead;
  1656. header->NumberProcessors = dcb->NumberProcessors;
  1657. header->MajorVersion = dcb->MajorVersion;
  1658. header->MinorVersion = dcb->MinorVersion;
  1659. #if defined (i386)
  1660. header->PaeEnabled = X86PaeEnabled ();
  1661. #endif
  1662. header->KdDebuggerDataBlock = KdGetDataBlock();
  1663. header->MachineImageType = CURRENT_IMAGE_TYPE ();
  1664. if (!(dcb->Flags & DCB_DUMP_ENABLED)) {
  1665. NumberOfPages = 1;
  1666. } else {
  1667. NumberOfPages = MmPhysicalMemoryBlock->NumberOfPages;
  1668. }
  1669. strcpy( header->VersionUser, dcb->VersionUser );
  1670. //
  1671. // Copy the physical memory descriptor.
  1672. //
  1673. RtlCopyMemory (&MemoryDump->Header.PhysicalMemoryBlock,
  1674. MmPhysicalMemoryBlock,
  1675. sizeof( PHYSICAL_MEMORY_DESCRIPTOR ) +
  1676. ((MmPhysicalMemoryBlock->NumberOfRuns - 1) *
  1677. sizeof( PHYSICAL_MEMORY_RUN )) );
  1678. RtlCopyMemory( MemoryDump->Header.ContextRecord,
  1679. context,
  1680. sizeof( CONTEXT ) );
  1681. MemoryDump->Header.Exception.ExceptionCode = STATUS_BREAKPOINT;
  1682. MemoryDump->Header.Exception.ExceptionRecord = 0;
  1683. MemoryDump->Header.Exception.NumberParameters = 0;
  1684. MemoryDump->Header.Exception.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
  1685. MemoryDump->Header.Exception.ExceptionAddress = PROGRAM_COUNTER (context);
  1686. //
  1687. // Init dump type to FULL
  1688. //
  1689. MemoryDump->Header.DumpType = DUMP_TYPE_FULL;
  1690. //
  1691. // Save the System time and uptime (This is always available)
  1692. // It's a KSYSTEM_TIME structure, but we only store the low and
  1693. // high 1 part
  1694. //
  1695. MemoryDump->Header.SystemTime.LowPart = SharedUserData->SystemTime.LowPart;
  1696. MemoryDump->Header.SystemTime.HighPart = SharedUserData->SystemTime.High1Time;
  1697. MemoryDump->Header.SystemUpTime.LowPart = SharedUserData->InterruptTime.LowPart;
  1698. MemoryDump->Header.SystemUpTime.HighPart = SharedUserData->InterruptTime.High1Time;
  1699. // Save product type and suite.
  1700. MemoryDump->Header.ProductType = SharedUserData->NtProductType;
  1701. MemoryDump->Header.SuiteMask = SharedUserData->SuiteMask;
  1702. //
  1703. // Set the Required dump size in the dump header. In the case of
  1704. // a summary dump the file allocation size can be significantly larger
  1705. // then the amount of used space.
  1706. //
  1707. MemoryDump->Header.RequiredDumpSpace.QuadPart = 0;
  1708. IopGetSecondaryDumpDataLimits(dcb->Flags,
  1709. &MaxDumpData, &MaxPerCallbackDumpData);
  1710. if (MaxDumpData > SecondarySpace) {
  1711. MaxDumpData = SecondarySpace;
  1712. if (MaxPerCallbackDumpData > MaxDumpData) {
  1713. MaxPerCallbackDumpData = MaxDumpData;
  1714. }
  1715. }
  1716. if (dcb->Flags & DCB_DUMP_ENABLED) {
  1717. //
  1718. // If summary dump try to create the dump header
  1719. //
  1720. if ( (dcb->Flags & DCB_SUMMARY_DUMP_ENABLED) ) {
  1721. //
  1722. // Initialize the summary dump
  1723. //
  1724. status = IopInitializeSummaryDump( MemoryDump, dcb );
  1725. if ( !NT_SUCCESS (status) ) {
  1726. //
  1727. // No summary dump header so return.
  1728. //
  1729. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1730. CRASHDUMP_WARNING,
  1731. "CRASHDUMP: NULL summary dump header\n"
  1732. ));
  1733. IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL;
  1734. return FALSE;
  1735. }
  1736. }
  1737. IopInitializeDumpSpaceAndType ( dcb, MemoryDump, SecondarySpace );
  1738. }
  1739. //
  1740. // All of the pieces of the header file have been generated. Before
  1741. // mapping or writing anything to the disk, the I- & D-stream caches
  1742. // must be flushed so that page color coherency is kept. Sweep both
  1743. // caches now.
  1744. //
  1745. KeSweepCurrentDcache();
  1746. KeSweepCurrentIcache();
  1747. //
  1748. // Create MDL for dump.
  1749. //
  1750. mdl = (PMDL) &localMdl[0];
  1751. MmCreateMdl( mdl, NULL, sizeof(*header) );
  1752. mdl->MdlFlags |= MDL_PAGES_LOCKED;
  1753. mcb = dcb->FileDescriptorArray;
  1754. //
  1755. // All of the pieces of the header file have been generated. Write
  1756. // the header page to the paging file, using the appropriate drivers,
  1757. // etc.
  1758. //
  1759. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1760. CRASHDUMP_TRACE,
  1761. "CRASHDUMP: Writing dump header to disk\n"
  1762. ));
  1763. status = IopWriteToDisk(dcb->HeaderPage, sizeof(*header),
  1764. write, &mcb, mdl, dwTransferSize,
  1765. KbDumpIoHeader);
  1766. if (!NT_SUCCESS(status)) {
  1767. IopFinalCrashDumpStatus = status;
  1768. return FALSE;
  1769. }
  1770. //
  1771. // If only requesting a header dump, we are now done.
  1772. //
  1773. if (dcb->Flags & DCB_DUMP_HEADER_ENABLED) {
  1774. goto FinishDump;
  1775. }
  1776. //
  1777. // The header page has been written. If this is a triage-dump, write
  1778. // the dump information and bail. Otherwise, fall through and do the
  1779. // full or summary dump.
  1780. //
  1781. if (dcb->Flags & DCB_TRIAGE_DUMP_ENABLED) {
  1782. status = IopWriteTriageDump (dcb->TriageDumpFlags,
  1783. write,
  1784. &mcb,
  1785. mdl,
  1786. dwTransferSize,
  1787. context,
  1788. Thread,
  1789. dcb->TriageDumpBuffer,
  1790. dcb->TriageDumpBufferSize - sizeof(DUMP_HEADER),
  1791. dcb->BuildNumber,
  1792. (UCHAR)dcb->Flags
  1793. );
  1794. if (!NT_SUCCESS (status)) {
  1795. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1796. CRASHDUMP_WARNING,
  1797. "CRASHDUMP: Failed to write triage-dump\n"
  1798. ));
  1799. IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL;
  1800. return FALSE;
  1801. }
  1802. goto FinishDump;
  1803. }
  1804. //
  1805. // The header page has been written to the paging file. If a full dump
  1806. // of all of physical memory is to be written, write it now.
  1807. //
  1808. if (dcb->Flags & DCB_DUMP_ENABLED) {
  1809. ULONG64 bytesDoneSoFar = 0;
  1810. ULONG currentPercentage = 0;
  1811. ULONG maximumPercentage = 0;
  1812. //
  1813. // Actual Pages is the number of pages to dump.
  1814. //
  1815. ActualPages = NumberOfPages;
  1816. if (dcb->Flags & DCB_SUMMARY_DUMP_ENABLED) {
  1817. //
  1818. // At this point the dump header header has been sucessfully
  1819. // written. Write the summary dump header.
  1820. //
  1821. status = IopWriteSummaryHeader(
  1822. &MemoryDump->Summary,
  1823. write,
  1824. &mcb,
  1825. mdl,
  1826. dwTransferSize,
  1827. (dcb->HeaderSize - sizeof(DUMP_HEADER))
  1828. );
  1829. if ( !NT_SUCCESS (status) ) {
  1830. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1831. CRASHDUMP_WARNING,
  1832. "CRASHDUMP: Error writing summary dump header %08x\n",
  1833. status
  1834. ));
  1835. IopFinalCrashDumpStatus = status;
  1836. return FALSE;
  1837. }
  1838. ActualPages = MemoryDump->Summary.Pages;
  1839. }
  1840. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1841. CRASHDUMP_TRACE,
  1842. "CRASHDUMP: Writing Memory Dump\n"
  1843. ));
  1844. if ( dcb->Flags & DCB_SUMMARY_DUMP_ENABLED ) {
  1845. status = IopWriteSummaryDump (
  1846. (PRTL_BITMAP) &MemoryDump->Summary.Bitmap,
  1847. write,
  1848. &dumpStack->ProgMsg,
  1849. NULL,
  1850. &mcb,
  1851. dwTransferSize
  1852. );
  1853. if (!NT_SUCCESS (status)) {
  1854. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1855. CRASHDUMP_WARNING,
  1856. "CRASHDUMP: Failed to write kernel memory dump\n"
  1857. ));
  1858. IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL;
  1859. return FALSE;
  1860. }
  1861. goto FinishDump;
  1862. }
  1863. //
  1864. // Set the virtual file offset and initialize loop variables and
  1865. // constants then loop, writing all of physical memory
  1866. // to the paging file.
  1867. //
  1868. // Force a new run to be selected immediately.
  1869. CurRun = MmPhysicalMemoryBlock->Run;
  1870. memoryAddress = 0;
  1871. LastRunAddr = 0;
  1872. while (mcb[0].QuadPart) {
  1873. ASSERT(memoryAddress <= LastRunAddr);
  1874. if (memoryAddress >= LastRunAddr) {
  1875. ASSERT(CurRun >= MmPhysicalMemoryBlock->Run &&
  1876. CurRun <= MmPhysicalMemoryBlock->Run +
  1877. (MmPhysicalMemoryBlock->NumberOfRuns - 1));
  1878. memoryAddress = (ULONG64)CurRun->BasePage * PAGE_SIZE;
  1879. LastRunAddr = memoryAddress +
  1880. (ULONG64)CurRun->PageCount * PAGE_SIZE;
  1881. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1882. CRASHDUMP_TRACE,
  1883. "CRASHDUMP: Run %d: %I64x - %I64x\n",
  1884. (ULONG)(CurRun - MmPhysicalMemoryBlock->Run),
  1885. memoryAddress, LastRunAddr));
  1886. CurRun++;
  1887. }
  1888. diskByteOffset = mcb[1];
  1889. //
  1890. // Calculate byte offset;
  1891. //
  1892. byteOffset = (ULONG)(memoryAddress & (PAGE_SIZE - 1));
  1893. byteCount = dwTransferSize - byteOffset;
  1894. if (byteCount > mcb[0].QuadPart) {
  1895. byteCount = mcb[0].LowPart;
  1896. }
  1897. if (LastRunAddr - memoryAddress < byteCount) {
  1898. byteCount = (ULONG)(LastRunAddr - memoryAddress);
  1899. }
  1900. bytesDoneSoFar += byteCount;
  1901. currentPercentage = (ULONG)
  1902. (((bytesDoneSoFar / PAGE_SIZE) * 100) / ActualPages);
  1903. if (currentPercentage > maximumPercentage) {
  1904. maximumPercentage = currentPercentage;
  1905. //
  1906. // Update message on screen.
  1907. //
  1908. IopDisplayString ( "%Z: %3d\r",
  1909. &dumpStack->ProgMsg,
  1910. maximumPercentage
  1911. );
  1912. }
  1913. //
  1914. // Map the physical memory and write it to the
  1915. // current segment of the file.
  1916. //
  1917. IopMapPhysicalMemory( mdl,
  1918. memoryAddress,
  1919. byteCount
  1920. );
  1921. //
  1922. // Write the next segment.
  1923. //
  1924. KdCheckForDebugBreak();
  1925. IopInvokeDumpIoCallbacks((PUCHAR)mdl->MappedSystemVa +
  1926. mdl->ByteOffset, byteCount,
  1927. KbDumpIoBody);
  1928. if (!NT_SUCCESS( write( &diskByteOffset, mdl ) )) {
  1929. IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL;
  1930. return FALSE;
  1931. }
  1932. //
  1933. // Adjust pointers for next part.
  1934. //
  1935. memoryAddress += byteCount;
  1936. mcb[0].QuadPart = mcb[0].QuadPart - byteCount;
  1937. mcb[1].QuadPart = mcb[1].QuadPart + byteCount;
  1938. if (!mcb[0].QuadPart) {
  1939. mcb += 2;
  1940. }
  1941. if ((bytesDoneSoFar / PAGE_SIZE) >= ActualPages) {
  1942. break;
  1943. }
  1944. }
  1945. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1946. CRASHDUMP_TRACE,
  1947. "CRASHDUMP: memory dump written\n"
  1948. ));
  1949. }
  1950. FinishDump:
  1951. IopDisplayString ( "\n\r%Z", &dumpStack->DoneMsg );
  1952. IopInvokeSecondaryDumpDataCallbacks(write,
  1953. &mcb,
  1954. mdl,
  1955. dwTransferSize,
  1956. (PBYTE)dcb->HeaderPage,
  1957. PAGE_SIZE,
  1958. MaxDumpData,
  1959. MaxPerCallbackDumpData,
  1960. NULL);
  1961. // Final I/O complete notification.
  1962. IopInvokeDumpIoCallbacks(NULL, 0, KbDumpIoComplete);
  1963. //
  1964. // Sweep the cache so the debugger will work.
  1965. //
  1966. KeSweepCurrentDcache();
  1967. KeSweepCurrentIcache();
  1968. //
  1969. // Have the dump flush the adapter and disk caches.
  1970. //
  1971. finishUp();
  1972. //
  1973. // Indicate to the debugger that the dump has been successfully
  1974. // written.
  1975. //
  1976. IopFinalCrashDumpStatus = STATUS_SUCCESS;
  1977. }
  1978. KdCheckForDebugBreak();
  1979. return TRUE;
  1980. }
  1981. VOID
  1982. IopMapPhysicalMemory(
  1983. IN OUT PMDL Mdl,
  1984. IN ULONG64 MemoryAddress,
  1985. IN ULONG Length
  1986. )
  1987. /*++
  1988. Routine Description:
  1989. This routine is invoked to fill in the specified MDL (Memory Descriptor
  1990. List) w/the appropriate information to map the specified memory address
  1991. range.
  1992. Arguments:
  1993. Mdl - Address of the MDL to be filled in.
  1994. MemoryAddress - Physical address being mapped.
  1995. Length - Length of transfer to be mapped.
  1996. Return Value:
  1997. None.
  1998. --*/
  1999. {
  2000. PPFN_NUMBER page;
  2001. PFN_NUMBER pages;
  2002. PFN_NUMBER base;
  2003. //
  2004. // Begin by determining the base physical page of the start of the address
  2005. // range and filling in the MDL appropriately.
  2006. //
  2007. Mdl->StartVa = PAGE_ALIGN( (PVOID)(ULONG_PTR)MemoryAddress );
  2008. Mdl->ByteOffset = (ULONG)(MemoryAddress & (PAGE_SIZE - 1));
  2009. Mdl->ByteCount = Length;
  2010. //
  2011. // Get the page frame index for the base address.
  2012. //
  2013. base = (PFN_NUMBER) (MemoryAddress >> PAGE_SHIFT);
  2014. pages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MemoryAddress, Length);
  2015. page = MmGetMdlPfnArray(Mdl);
  2016. //
  2017. // Map all of the pages for this transfer until there are no more remaining
  2018. // to be mapped.
  2019. //
  2020. while (pages) {
  2021. *page++ = base++;
  2022. pages--;
  2023. }
  2024. //
  2025. // All of the PFNs for the address range have been filled in so map the
  2026. // physical memory into virtual address space.
  2027. //
  2028. MmMapMemoryDumpMdl( Mdl );
  2029. }
  2030. BOOLEAN
  2031. IopAddPageToPageMap(
  2032. IN ULONG MaxPage,
  2033. IN PRTL_BITMAP BitMap,
  2034. IN ULONG PageFrameIndex,
  2035. IN ULONG NumberOfPages
  2036. )
  2037. {
  2038. //
  2039. // Sometimes we get PFNs that are out of range. Just ignore them.
  2040. //
  2041. if (PageFrameIndex >= MaxPage) {
  2042. return FALSE;
  2043. }
  2044. RtlSetBits (BitMap, PageFrameIndex, NumberOfPages);
  2045. return TRUE;
  2046. }
  2047. BOOLEAN
  2048. IopRemovePageFromPageMap(
  2049. IN ULONG MaxPage,
  2050. IN PRTL_BITMAP BitMap,
  2051. IN ULONG PageFrameIndex,
  2052. IN ULONG NumberOfPages
  2053. )
  2054. {
  2055. //
  2056. // Sometimes we get PFNs that are out of range. Just ignore them.
  2057. //
  2058. if (PageFrameIndex >= MaxPage) {
  2059. return FALSE;
  2060. }
  2061. RtlClearBits (BitMap, PageFrameIndex, NumberOfPages);
  2062. return TRUE;
  2063. }
  2064. NTSTATUS
  2065. IoSetDumpRange(
  2066. IN PMM_KERNEL_DUMP_CONTEXT Context,
  2067. IN PVOID StartVa,
  2068. IN ULONG_PTR Pages,
  2069. IN ULONG AddressFlags
  2070. )
  2071. /*++
  2072. Routine Description:
  2073. This routine includes this range of memory in the dump
  2074. Arguments:
  2075. Context - Dump context.
  2076. StartVa - Starting virtual address.
  2077. Pages - The number of pages to include
  2078. AddressFlags - 0 if the address is virtually mapped.
  2079. 1 if the address is super/large page mapped. This implies
  2080. the entire page range is physically contiguous.
  2081. 2 if the address really represents a physical page frame
  2082. number. This also implies the entire page range is
  2083. physically contiguous.
  2084. Return Value:
  2085. STATUS_SUCCESS - On success.
  2086. NTSTATUS - Error.
  2087. --*/
  2088. {
  2089. PCHAR Va;
  2090. PRTL_BITMAP BitMap;
  2091. PHYSICAL_ADDRESS PhyAddr;
  2092. PSUMMARY_DUMP Summary;
  2093. BOOLEAN AllPagesSet;
  2094. ULONG_PTR PageFrameIndex;
  2095. //
  2096. // Validation
  2097. //
  2098. ASSERT (Context != NULL &&
  2099. Context->Context != NULL);
  2100. //
  2101. // Initialization
  2102. //
  2103. Summary = (PSUMMARY_DUMP) Context->Context;
  2104. BitMap = (PRTL_BITMAP) &Summary->Bitmap;
  2105. Va = StartVa;
  2106. AllPagesSet = TRUE;
  2107. //
  2108. // Win64 can have really large page addresses. This dump code does
  2109. // not handle that yet. Note that before this assert is removed
  2110. // the casts of Pages to ULONG must be removed.
  2111. //
  2112. ASSERT(Pages <= MAXULONG);
  2113. if (AddressFlags == 1) {
  2114. PhyAddr = MmGetPhysicalAddress (Va);
  2115. AllPagesSet =
  2116. IopAddPageToPageMap ( Summary->BitmapSize,
  2117. BitMap,
  2118. (ULONG) (PhyAddr.QuadPart >> PAGE_SHIFT),
  2119. (ULONG) Pages
  2120. );
  2121. } else if (AddressFlags == 2) {
  2122. PageFrameIndex = (ULONG_PTR) Va;
  2123. AllPagesSet =
  2124. IopAddPageToPageMap ( Summary->BitmapSize,
  2125. BitMap,
  2126. (ULONG) PageFrameIndex,
  2127. (ULONG) Pages
  2128. );
  2129. } else {
  2130. //
  2131. // Not physically contiguous.
  2132. //
  2133. while (Pages) {
  2134. //
  2135. // Only do a translation for valid pages.
  2136. //
  2137. if ( MmIsAddressValid(Va) ) {
  2138. //
  2139. // Get the physical mapping. Note: this does not require a lock
  2140. //
  2141. PhyAddr = MmGetPhysicalAddress (Va);
  2142. if (!IopAddPageToPageMap ( Summary->BitmapSize,
  2143. BitMap,
  2144. (ULONG)( PhyAddr.QuadPart >> PAGE_SHIFT),
  2145. 1)) {
  2146. AllPagesSet = FALSE;
  2147. }
  2148. }
  2149. Va += PAGE_SIZE;
  2150. Pages--;
  2151. }
  2152. }
  2153. if (AllPagesSet) {
  2154. return STATUS_SUCCESS;
  2155. }
  2156. return STATUS_INVALID_ADDRESS;
  2157. }
  2158. NTSTATUS
  2159. IoFreeDumpRange(
  2160. IN PMM_KERNEL_DUMP_CONTEXT Context,
  2161. IN PVOID StartVa,
  2162. IN ULONG_PTR Pages,
  2163. IN ULONG AddressFlags
  2164. )
  2165. /*++
  2166. Routine Description:
  2167. This routine excludes this range of memory in the dump.
  2168. Arguments:
  2169. DumpContext - dump context
  2170. StartVa - Starting VA
  2171. Pages - The number of pages to include
  2172. AddressFlags - 0 if the address is virtually mapped.
  2173. 1 if the address is super/large page mapped. This implies
  2174. the entire page range is physically contiguous.
  2175. 2 if the address really represents a physical page frame
  2176. number. This also implies the entire page range is
  2177. physically contiguous.
  2178. Return Value:
  2179. STATUS_SUCCESS - On success.
  2180. NTSTATUS - Error.
  2181. --*/
  2182. {
  2183. PCHAR Va;
  2184. PRTL_BITMAP BitMap;
  2185. PHYSICAL_ADDRESS PhyAddr;
  2186. PSUMMARY_DUMP Summary;
  2187. ULONG_PTR PageFrameIndex;
  2188. ASSERT (Context != NULL &&
  2189. Context->Context != NULL);
  2190. //
  2191. // Round to page size.
  2192. //
  2193. Summary = (PSUMMARY_DUMP)Context->Context;
  2194. BitMap = (PRTL_BITMAP) &Summary->Bitmap;
  2195. Va = StartVa;
  2196. //
  2197. // Win64 can have really large page addresses. This dump code does
  2198. // not handle that yet. Note that before this assert is removed
  2199. // the casts of Pages to ULONG must be removed.
  2200. //
  2201. ASSERT (Pages <= MAXULONG);
  2202. if (AddressFlags == 1) {
  2203. PhyAddr = MmGetPhysicalAddress(Va);
  2204. IopRemovePageFromPageMap (Summary->BitmapSize,
  2205. BitMap,
  2206. (ULONG)(PhyAddr.QuadPart >> PAGE_SHIFT),
  2207. (ULONG) Pages
  2208. );
  2209. } else if (AddressFlags == 2) {
  2210. PageFrameIndex = (ULONG_PTR) Va;
  2211. IopRemovePageFromPageMap (Summary->BitmapSize,
  2212. BitMap,
  2213. (ULONG) PageFrameIndex,
  2214. (ULONG) Pages
  2215. );
  2216. } else {
  2217. while (Pages) {
  2218. //
  2219. // Only do a translation for valid pages.
  2220. //
  2221. if ( MmIsAddressValid (Va) ) {
  2222. PhyAddr = MmGetPhysicalAddress (Va);
  2223. IopRemovePageFromPageMap (Summary->BitmapSize,
  2224. BitMap,
  2225. (ULONG)(PhyAddr.QuadPart >> PAGE_SHIFT),
  2226. 1);
  2227. }
  2228. Va += PAGE_SIZE;
  2229. Pages--;
  2230. }
  2231. }
  2232. return STATUS_SUCCESS;
  2233. }
  2234. LARGE_INTEGER
  2235. IopCalculateRequiredDumpSpace(
  2236. IN ULONG dwDmpFlags,
  2237. IN ULONG dwHeaderSize,
  2238. IN PFN_NUMBER dwMaxPages,
  2239. IN PFN_NUMBER dwMaxSummaryPages,
  2240. IN BOOLEAN LargestPossibleSize
  2241. )
  2242. /*++
  2243. Routine Description:
  2244. This routine is used to calcuate required dump space
  2245. 1. Crash dump summary must be at least 1 page in length.
  2246. 2. Summary dump must be large enough for kernel memory plus header,
  2247. plus summary header.
  2248. 3. Full dump must be large enough for header plus all physical memory.
  2249. Arguments:
  2250. dwDmpFlags - Dump Control Block (DCB) flags.
  2251. dwHeaderSize - The size of the dump header.
  2252. dwMaxPages - All physical memory.
  2253. dwMaxSummaryPages - Maximum pages in summary dump.
  2254. LargestPossibleSize - If TRUE return the largest size a dump
  2255. could be, otherwise return the size of a dump
  2256. of the current state. The largest possible
  2257. size of a dump may be larger than the current
  2258. size because memory may be added dynamically.
  2259. Return Value:
  2260. Size of the dump file
  2261. --*/
  2262. {
  2263. LARGE_INTEGER maxMemorySize;
  2264. //
  2265. // Dump header or dump summary.
  2266. //
  2267. if ( (dwDmpFlags & DCB_DUMP_HEADER_ENABLED) ||
  2268. ( !( dwDmpFlags & DCB_DUMP_ENABLED ) &&
  2269. ( dwDmpFlags & DCB_SUMMARY_ENABLED ) ) ) {
  2270. maxMemorySize.QuadPart = IO_DUMP_MINIMUM_FILE_SIZE;
  2271. return maxMemorySize;
  2272. }
  2273. if (dwDmpFlags & DCB_TRIAGE_DUMP_ENABLED) {
  2274. maxMemorySize.QuadPart = TRIAGE_DUMP_SIZE;
  2275. return maxMemorySize;
  2276. }
  2277. if (dwDmpFlags & DCB_SUMMARY_DUMP_ENABLED) {
  2278. #ifndef _WIN64
  2279. ULONG dwGB;
  2280. #endif
  2281. if (LargestPossibleSize) {
  2282. dwMaxSummaryPages = 0xffffffff;
  2283. }
  2284. #ifndef _WIN64
  2285. maxMemorySize.QuadPart = (ULONG64)dwMaxSummaryPages * PAGE_SIZE;
  2286. //
  2287. // 32-bit systems can't have more than 3GB of kernel
  2288. // memory so don't ask for more space than that.
  2289. //
  2290. dwGB = 1024 * 1024 * 1024;
  2291. if (maxMemorySize.QuadPart > (3 * dwGB) ) {
  2292. maxMemorySize.QuadPart = (3 * dwGB);
  2293. }
  2294. #else
  2295. maxMemorySize.QuadPart = (ULONG64)dwMaxSummaryPages * PAGE_SIZE;
  2296. #endif
  2297. //
  2298. // Control block header size for summary dump
  2299. // includes space for the base header, the summary
  2300. // header and the page bitmap.
  2301. //
  2302. maxMemorySize.QuadPart += dwHeaderSize;
  2303. return maxMemorySize;
  2304. }
  2305. //
  2306. // Full memory dump is #pages * pagesize plus 1 page for the dump header.
  2307. //
  2308. if (LargestPossibleSize) {
  2309. maxMemorySize.QuadPart = 0x1000000000000000 + dwHeaderSize;
  2310. } else {
  2311. maxMemorySize.QuadPart =
  2312. ((ULONG64)dwMaxPages * PAGE_SIZE) + dwHeaderSize;
  2313. }
  2314. return maxMemorySize;
  2315. }
  2316. //
  2317. // Triage-dump support routines.
  2318. //
  2319. NTSTATUS
  2320. IopGetLoadedDriverInfo(
  2321. OUT ULONG * lpDriverCount,
  2322. OUT ULONG * lpSizeOfStringData
  2323. )
  2324. /*++
  2325. Routine Description:
  2326. Get information about all loaded drivers.
  2327. Arguments:
  2328. lpDriverCount - Buffer to return the count of all the drivers that are
  2329. currently loaded in the system.
  2330. lpSizeOfStringData - Buffer to return the sum of the sizes of all driver
  2331. name strings (FullDllName). This does not include the size
  2332. of the UNICODE_STRING structure or a trailing NULL byte.
  2333. Return Values:
  2334. NTSTATUS
  2335. --*/
  2336. {
  2337. ULONG DriverCount = 0;
  2338. ULONG SizeOfStringData = 0;
  2339. PLIST_ENTRY NextEntry;
  2340. PKLDR_DATA_TABLE_ENTRY DriverEntry;
  2341. NextEntry = PsLoadedModuleList.Flink;
  2342. while (NextEntry != &PsLoadedModuleList) {
  2343. DriverEntry = CONTAINING_RECORD (NextEntry,
  2344. KLDR_DATA_TABLE_ENTRY,
  2345. InLoadOrderLinks
  2346. );
  2347. if (!IopIsAddressRangeValid (DriverEntry, sizeof (*DriverEntry)) ||
  2348. !IopIsAddressRangeValid (DriverEntry->BaseDllName.Buffer,
  2349. DriverEntry->BaseDllName.Length)) {
  2350. return STATUS_UNSUCCESSFUL;
  2351. }
  2352. DriverCount++;
  2353. //
  2354. // The extra two bytes is for the NULL termination. The extra 7 is
  2355. // because we force 8-byte alignment of all strings.
  2356. //
  2357. SizeOfStringData += DriverEntry->BaseDllName.Length + 2 + 7;
  2358. NextEntry = NextEntry->Flink;
  2359. }
  2360. *lpDriverCount = DriverCount;
  2361. *lpSizeOfStringData = SizeOfStringData;
  2362. return STATUS_SUCCESS;
  2363. }
  2364. #define DmpPoolStringSize(DumpString)\
  2365. (sizeof (DUMP_STRING) + sizeof (WCHAR) * ( DumpString->Length + 1 ))
  2366. #define DmpNextPoolString(DumpString) \
  2367. (PDUMP_STRING) ( \
  2368. ALIGN_UP_POINTER( \
  2369. ((LPBYTE) DumpString) + DmpPoolStringSize (DumpString), \
  2370. ULONGLONG \
  2371. ) \
  2372. )
  2373. #define ALIGN_8(_x) ALIGN_UP(_x, DWORDLONG)
  2374. #define ASSERT_ALIGNMENT(Pointer, Alignment)\
  2375. ASSERT ((((ULONG_PTR)Pointer) & ((Alignment) - 1)) == 0)
  2376. #ifndef IndexByByte
  2377. #define IndexByByte(Pointer, Index) (&(((BYTE*) (Pointer)) [Index]))
  2378. #endif
  2379. NTSTATUS
  2380. IopWriteDriverList(
  2381. IN ULONG_PTR BufferAddress,
  2382. IN ULONG BufferSize,
  2383. IN ULONG DriverListOffset,
  2384. IN ULONG StringPoolOffset
  2385. )
  2386. /*++
  2387. Routine Description:
  2388. Write the triage dump driver list to the buffer.
  2389. Arguments:
  2390. BufferAddress - The address of the buffer.
  2391. BufferSize - The size of the buffer.
  2392. DriverListOffset - The offset within the buffer where the driver list
  2393. should be written.
  2394. StringPoolOffset - The offset within the buffer where the driver list's
  2395. string pool should start. If there are no other strings for the triage
  2396. dump other than driver name strings, this will be the string pool
  2397. offset.
  2398. Return Value:
  2399. NTSTATUS
  2400. --*/
  2401. {
  2402. ULONG i = 0;
  2403. PLIST_ENTRY NextEntry;
  2404. PKLDR_DATA_TABLE_ENTRY DriverEntry;
  2405. PDUMP_DRIVER_ENTRY DumpImageArray;
  2406. PDUMP_STRING DumpStringName = NULL;
  2407. PIMAGE_NT_HEADERS NtHeaders;
  2408. ASSERT (DriverListOffset != 0);
  2409. ASSERT (StringPoolOffset != 0);
  2410. UNREFERENCED_PARAMETER (BufferSize);
  2411. DumpImageArray = (PDUMP_DRIVER_ENTRY) (BufferAddress + DriverListOffset);
  2412. DumpStringName = (PDUMP_STRING) (BufferAddress + StringPoolOffset);
  2413. NextEntry = PsLoadedModuleList.Flink;
  2414. while (NextEntry != &PsLoadedModuleList) {
  2415. DriverEntry = CONTAINING_RECORD (NextEntry,
  2416. KLDR_DATA_TABLE_ENTRY,
  2417. InLoadOrderLinks);
  2418. //
  2419. // Verify the memory is valid before reading anything from it.
  2420. //
  2421. if (!IopIsAddressRangeValid (DriverEntry, sizeof (*DriverEntry)) ||
  2422. !IopIsAddressRangeValid (DriverEntry->BaseDllName.Buffer,
  2423. DriverEntry->BaseDllName.Length)) {
  2424. return STATUS_UNSUCCESSFUL;
  2425. }
  2426. //
  2427. // Build the entry in the string pool. We guarantee all strings are
  2428. // NULL terminated as well as length prefixed.
  2429. //
  2430. DumpStringName->Length = DriverEntry->BaseDllName.Length / 2;
  2431. RtlCopyMemory (DumpStringName->Buffer,
  2432. DriverEntry->BaseDllName.Buffer,
  2433. DumpStringName->Length * sizeof (WCHAR)
  2434. );
  2435. DumpStringName->Buffer[ DumpStringName->Length ] = '\000';
  2436. RtlCopyMemory (&DumpImageArray [i].LdrEntry,
  2437. DriverEntry,
  2438. sizeof (DumpImageArray [i].LdrEntry)
  2439. );
  2440. //
  2441. // Add the time/date stamp.
  2442. //
  2443. DumpImageArray[i].LdrEntry.TimeDateStamp = 0;
  2444. DumpImageArray[i].LdrEntry.SizeOfImage = 0;
  2445. if ( MmIsAddressValid (DriverEntry->DllBase ) &&
  2446. (NtHeaders = RtlImageNtHeader(DriverEntry->DllBase)) ) {
  2447. DumpImageArray[i].LdrEntry.TimeDateStamp =
  2448. NtHeaders->FileHeader.TimeDateStamp;
  2449. DumpImageArray[i].LdrEntry.SizeOfImage =
  2450. NtHeaders->OptionalHeader.SizeOfImage;
  2451. } else if (DriverEntry->Flags & LDRP_NON_PAGED_DEBUG_INFO) {
  2452. DumpImageArray[i].LdrEntry.TimeDateStamp =
  2453. DriverEntry->NonPagedDebugInfo->TimeDateStamp;
  2454. DumpImageArray[i].LdrEntry.SizeOfImage =
  2455. DriverEntry->NonPagedDebugInfo->SizeOfImage;
  2456. }
  2457. DumpImageArray [i].DriverNameOffset =
  2458. (ULONG)((ULONG_PTR) DumpStringName - BufferAddress);
  2459. i++;
  2460. DumpStringName = DmpNextPoolString (DumpStringName);
  2461. NextEntry = NextEntry->Flink;
  2462. }
  2463. return STATUS_SUCCESS;
  2464. }
  2465. ULONG
  2466. IopSizeTriageDumpDataBlocks(
  2467. PTRIAGE_DUMP TriageDump,
  2468. ULONG Offset,
  2469. ULONG BufferSize
  2470. )
  2471. /*++
  2472. Routine Description:
  2473. Determine all triage dump data blocks that fit and
  2474. update dump header to match.
  2475. Arguments:
  2476. TriageDump - Dump header.
  2477. Offset - Current offset in dump buffer.
  2478. BufferSize - Dump buffer size.
  2479. Return Values:
  2480. Updated offset.
  2481. --*/
  2482. {
  2483. ULONG i;
  2484. ULONG Size;
  2485. PTRIAGE_PTR_DATA_BLOCK Block;
  2486. TriageDump->DataBlocksCount = 0;
  2487. Block = IopTriageDumpDataBlocks;
  2488. for (i = 0; i < IopNumTriageDumpDataBlocks; i++, Block++) {
  2489. Size = ALIGN_8(sizeof(TRIAGE_DATA_BLOCK)) +
  2490. ALIGN_8((ULONG)(Block->MaxAddress - Block->MinAddress));
  2491. if (Offset + Size >= BufferSize) {
  2492. TriageDump->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  2493. break;
  2494. }
  2495. if (i == 0) {
  2496. TriageDump->DataBlocksOffset = Offset;
  2497. }
  2498. Offset += Size;
  2499. TriageDump->DataBlocksCount++;
  2500. }
  2501. return Offset;
  2502. }
  2503. VOID
  2504. IopWriteTriageDumpDataBlocks(
  2505. PTRIAGE_DUMP TriageDump,
  2506. PUCHAR BufferAddress
  2507. )
  2508. /*++
  2509. Routine Description:
  2510. Write triage dump data blocks given in header.
  2511. Arguments:
  2512. TriageDump - Dump header.
  2513. BufferAddress - Address of dump data buffer.
  2514. Return Values:
  2515. None.
  2516. --*/
  2517. {
  2518. ULONG i;
  2519. PTRIAGE_PTR_DATA_BLOCK Block;
  2520. PUCHAR DataBuffer;
  2521. PTRIAGE_DATA_BLOCK DumpBlock;
  2522. DumpBlock = (PTRIAGE_DATA_BLOCK)
  2523. (BufferAddress + TriageDump->DataBlocksOffset);
  2524. DataBuffer = (PUCHAR)(DumpBlock + TriageDump->DataBlocksCount);
  2525. Block = IopTriageDumpDataBlocks;
  2526. for (i = 0; i < TriageDump->DataBlocksCount; i++, Block++) {
  2527. DumpBlock->Address = (ULONG64)(LONG_PTR)Block->MinAddress;
  2528. DumpBlock->Offset = (ULONG)(DataBuffer - BufferAddress);
  2529. DumpBlock->Size = (ULONG)(Block->MaxAddress - Block->MinAddress);
  2530. RtlCopyMemory(DataBuffer, Block->MinAddress, DumpBlock->Size);
  2531. DataBuffer += DumpBlock->Size;
  2532. DumpBlock++;
  2533. }
  2534. }
  2535. NTSTATUS
  2536. IopWriteTriageDump(
  2537. IN ULONG Fields,
  2538. IN PDUMP_DRIVER_WRITE DriverWriteRoutine,
  2539. IN OUT PLARGE_INTEGER * Mcb,
  2540. IN OUT PMDL Mdl,
  2541. IN ULONG DriverTransferSize,
  2542. IN PCONTEXT Context,
  2543. IN PKTHREAD Thread,
  2544. IN BYTE* Buffer,
  2545. IN ULONG BufferSize,
  2546. IN ULONG ServicePackBuild,
  2547. IN ULONG TriageOptions
  2548. )
  2549. /*++
  2550. Routine Description:
  2551. Write the Triage-Dump to the MCB.
  2552. Arguments:
  2553. Fields - The set of fields that should be written.
  2554. DriverWriteRoutine - The write routine for the driver.
  2555. Mcb - Message Control Block where the data is to be written.
  2556. Mdl - A MDL descrbing the data to be written (??).
  2557. DriverTransferSize - The maximum transfer size for the driver.
  2558. Context - The context.
  2559. Buffer - The buffer to use as a scratch buffer.
  2560. BufferSize - The size of the buffer.
  2561. ServicePackBuild - Service Pack BuildNumber.
  2562. TriageOptions - Triage Options.
  2563. Return Values:
  2564. STATUS_SUCCESS - On success.
  2565. NTSTATUS - Otherwise.
  2566. Comments:
  2567. This function assumes that exactly one header page was written.
  2568. --*/
  2569. {
  2570. ULONG SizeOfSection;
  2571. ULONG SizeOfStringData;
  2572. ULONG DriverCount = 0;
  2573. LPVOID Address = NULL;
  2574. ULONG BytesToWrite = 0;
  2575. ULONG_PTR BufferAddress = 0;
  2576. NTSTATUS Status;
  2577. ULONG Offset;
  2578. PTRIAGE_DUMP TriageDump = NULL;
  2579. //
  2580. // Setup the triage-dump header.
  2581. //
  2582. if (BufferSize < sizeof (TRIAGE_DUMP) + sizeof (DWORD)) {
  2583. return STATUS_NO_MEMORY;
  2584. }
  2585. TriageDump = (PTRIAGE_DUMP) Buffer;
  2586. RtlZeroMemory (TriageDump, sizeof (*TriageDump));
  2587. //
  2588. // The normal dump header is a DUMP_HEADER.
  2589. //
  2590. TriageDump->SizeOfDump = BufferSize + sizeof(DUMP_HEADER);
  2591. //
  2592. // Adjust the BufferSize so we can write the final status DWORD at the
  2593. // end.
  2594. //
  2595. BufferSize -= sizeof (DWORD);
  2596. RtlZeroMemory (IndexByByte (Buffer, BufferSize), sizeof (DWORD));
  2597. TriageDump->ValidOffset = ( TriageDump->SizeOfDump - sizeof (ULONG) );
  2598. TriageDump->ContextOffset = FIELD_OFFSET (DUMP_HEADER, ContextRecord);
  2599. TriageDump->ExceptionOffset = FIELD_OFFSET (DUMP_HEADER, Exception);
  2600. TriageDump->BrokenDriverOffset = 0;
  2601. TriageDump->ServicePackBuild = ServicePackBuild;
  2602. TriageDump->TriageOptions = TriageOptions;
  2603. Offset = ALIGN_8 (sizeof(DUMP_HEADER) + sizeof (TRIAGE_DUMP));
  2604. ASSERT_ALIGNMENT (Offset, 8);
  2605. //
  2606. // Set the Mm Offset, if necessary.
  2607. //
  2608. SizeOfSection = ALIGN_8 (MmSizeOfTriageInformation());
  2609. if (Offset + SizeOfSection < BufferSize) {
  2610. TriageDump->MmOffset = Offset;
  2611. Offset += SizeOfSection;
  2612. } else {
  2613. TriageDump->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  2614. }
  2615. ASSERT_ALIGNMENT (Offset, 8);
  2616. //
  2617. // Set the Unloaded Drivers Offset, if necessary.
  2618. //
  2619. SizeOfSection = ALIGN_8 (MmSizeOfUnloadedDriverInformation());
  2620. if (Offset + SizeOfSection < BufferSize) {
  2621. TriageDump->UnloadedDriversOffset = Offset;
  2622. Offset += SizeOfSection;
  2623. } else {
  2624. TriageDump->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  2625. }
  2626. ASSERT_ALIGNMENT (Offset, 8);
  2627. //
  2628. // Set the Prcb Offset, if necessary.
  2629. //
  2630. if (Fields & TRIAGE_DUMP_PRCB) {
  2631. SizeOfSection = ALIGN_8 (sizeof (KPRCB));
  2632. if (Offset + SizeOfSection < BufferSize) {
  2633. TriageDump->PrcbOffset = Offset;
  2634. Offset += SizeOfSection;
  2635. } else {
  2636. TriageDump->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  2637. }
  2638. }
  2639. ASSERT_ALIGNMENT (Offset, 8);
  2640. //
  2641. // Set the Process Offset, if necessary.
  2642. //
  2643. if (Fields & TRIAGE_DUMP_PROCESS) {
  2644. SizeOfSection = ALIGN_8 (sizeof (EPROCESS));
  2645. if (Offset + SizeOfSection < BufferSize) {
  2646. TriageDump->ProcessOffset = Offset;
  2647. Offset += SizeOfSection;
  2648. } else {
  2649. TriageDump->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  2650. }
  2651. }
  2652. ASSERT_ALIGNMENT (Offset, 8);
  2653. //
  2654. // Set the Thread Offset, if necessary.
  2655. //
  2656. if (Fields & TRIAGE_DUMP_THREAD) {
  2657. SizeOfSection = ALIGN_8 (sizeof (ETHREAD));
  2658. if (Offset + SizeOfSection < BufferSize) {
  2659. TriageDump->ThreadOffset = Offset;
  2660. Offset += SizeOfSection;
  2661. } else {
  2662. TriageDump->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  2663. }
  2664. }
  2665. ASSERT_ALIGNMENT (Offset, 8);
  2666. //
  2667. // Set the CallStack Offset, if necessary.
  2668. //
  2669. if (Fields & TRIAGE_DUMP_STACK) {
  2670. //
  2671. // If there is a stack, calculate its size.
  2672. //
  2673. //
  2674. // Remember: the callstack grows downward in memory, therefore,
  2675. // Base >= Current = SP = Top > Limit.
  2676. //
  2677. if (Thread->KernelStackResident) {
  2678. ULONG_PTR StackBase;
  2679. ULONG_PTR StackLimit;
  2680. ULONG_PTR StackTop;
  2681. StackBase = (ULONG_PTR) Thread->StackBase;
  2682. StackLimit = (ULONG_PTR) Thread->StackLimit;
  2683. //
  2684. // Don't necessarily trust that SP is valid. If it's
  2685. // outside the reasonable range, just copy from the limit.
  2686. //
  2687. if (StackLimit < STACK_POINTER (Context) &&
  2688. STACK_POINTER (Context) <= StackBase) {
  2689. StackTop = STACK_POINTER (Context);
  2690. } else {
  2691. StackTop = (ULONG_PTR) Thread->StackLimit;
  2692. }
  2693. ASSERT (StackLimit <= StackTop && StackTop < StackBase);
  2694. //
  2695. // There is a valid stack. Note that we limit the size of
  2696. // the triage dump stack to MAX_TRIAGE_STACK_SIZE (currently
  2697. // 16 KB).
  2698. //
  2699. SizeOfSection = (ULONG) min (StackBase - StackTop,
  2700. MAX_TRIAGE_STACK_SIZE - 1);
  2701. if (SizeOfSection) {
  2702. if (Offset + SizeOfSection < BufferSize) {
  2703. TriageDump->CallStackOffset = Offset;
  2704. TriageDump->SizeOfCallStack = SizeOfSection;
  2705. TriageDump->TopOfStack = StackTop;
  2706. Offset += SizeOfSection;
  2707. Offset = ALIGN_8 (Offset);
  2708. } else {
  2709. TriageDump->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  2710. }
  2711. }
  2712. } else {
  2713. //
  2714. // There is not a valid stack.
  2715. //
  2716. }
  2717. }
  2718. ASSERT_ALIGNMENT (Offset, 8);
  2719. #if defined (_IA64_)
  2720. //
  2721. // The IA64 contains two callstacks. The first is the normal
  2722. // callstack, and the second is a scratch region where
  2723. // the processor can spill registers. It is this latter stack,
  2724. // the backing-store, that we now save.
  2725. //
  2726. if ( Fields & TRIAGE_DUMP_STACK ) {
  2727. ULONG_PTR BStoreBase;
  2728. ULONG_PTR BStoreLimit;
  2729. BStoreBase = (ULONG_PTR) Thread->InitialBStore;
  2730. BStoreLimit = (ULONG_PTR) Thread->BStoreLimit;
  2731. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  2732. CRASHDUMP_TRACE,
  2733. "CRASHDUMP: IA64 BStore: base %p limit %p\n",
  2734. BStoreBase,
  2735. BStoreLimit));
  2736. SizeOfSection = (ULONG) (BStoreLimit - BStoreBase);
  2737. //
  2738. // The calculated size had better be less than the maximum size
  2739. // for a BSTORE region.
  2740. //
  2741. ASSERT ( SizeOfSection < KERNEL_LARGE_BSTORE_SIZE );
  2742. if (SizeOfSection) {
  2743. if (Offset + SizeOfSection < BufferSize) {
  2744. TriageDump->ArchitectureSpecific.Ia64.BStoreOffset = Offset;
  2745. TriageDump->ArchitectureSpecific.Ia64.SizeOfBStore = SizeOfSection;
  2746. TriageDump->ArchitectureSpecific.Ia64.LimitOfBStore= BStoreLimit;
  2747. Offset += SizeOfSection;
  2748. Offset = ALIGN_8 (Offset);
  2749. } else {
  2750. TriageDump->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  2751. }
  2752. }
  2753. }
  2754. #endif
  2755. ASSERT_ALIGNMENT (Offset, 8);
  2756. if (Fields & TRIAGE_DUMP_DEBUGGER_DATA) {
  2757. if (Offset + ALIGN_8(sizeof(KdDebuggerDataBlock)) < BufferSize) {
  2758. TriageDump->DebuggerDataOffset = Offset;
  2759. TriageDump->DebuggerDataSize = sizeof(KdDebuggerDataBlock);
  2760. Offset += ALIGN_8(sizeof(KdDebuggerDataBlock));
  2761. Offset = ALIGN_8 (Offset);
  2762. } else {
  2763. TriageDump->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  2764. }
  2765. }
  2766. ASSERT_ALIGNMENT (Offset, 8);
  2767. //
  2768. // Set the Driver List Offset, if necessary.
  2769. //
  2770. Status = IopGetLoadedDriverInfo (&DriverCount, &SizeOfStringData);
  2771. if (NT_SUCCESS (Status) && (Fields & TRIAGE_DUMP_DRIVER_LIST)) {
  2772. SizeOfSection = ALIGN_8 (DriverCount * sizeof (DUMP_DRIVER_ENTRY));
  2773. if (SizeOfSection) {
  2774. if (Offset + SizeOfSection < BufferSize) {
  2775. TriageDump->DriverListOffset = Offset;
  2776. TriageDump->DriverCount = DriverCount;
  2777. Offset += SizeOfSection;
  2778. } else {
  2779. TriageDump->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  2780. }
  2781. }
  2782. } else {
  2783. SizeOfSection = 0;
  2784. SizeOfStringData = 0;
  2785. }
  2786. //
  2787. // Set the String Pool offset.
  2788. //
  2789. SizeOfSection = ALIGN_8 (SizeOfStringData +
  2790. DriverCount * (sizeof (WCHAR) + sizeof (DUMP_STRING)));
  2791. if (SizeOfSection) {
  2792. if (Offset + SizeOfSection < BufferSize) {
  2793. TriageDump->StringPoolOffset = (ULONG)Offset;
  2794. TriageDump->StringPoolSize = SizeOfSection;
  2795. Offset += SizeOfSection;
  2796. Offset = ALIGN_8 (Offset);
  2797. } else {
  2798. TriageDump->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  2799. }
  2800. }
  2801. ASSERT_ALIGNMENT (Offset, 8);
  2802. if (Fields & TRIAGE_DUMP_DATA_BLOCKS) {
  2803. #ifdef _IA64_
  2804. volatile KPCR* const Pcr = KeGetPcr();
  2805. //
  2806. // In certain failures there is a switch from
  2807. // the current thread's stack and store to
  2808. // a special stack and store. The PCR contains
  2809. // stack and store pointers which will be different
  2810. // from the current thread's stack and store pointers
  2811. // so save the extra stack and store if they are.
  2812. //
  2813. if ((PVOID)Pcr->InitialBStore != Thread->InitialBStore ||
  2814. (PVOID)Pcr->BStoreLimit != Thread->BStoreLimit) {
  2815. ULONG64 StoreTop, StoreBase;
  2816. ULONG FrameSize;
  2817. ULONG StoreSize;
  2818. StoreTop = Context->RsBSP;
  2819. StoreBase = Pcr->InitialBStore;
  2820. FrameSize = (ULONG)(Context->StIFS & PFS_SIZE_MASK);
  2821. // Add in a ULONG64 for every register in the
  2822. // current frame. While doing so, check for
  2823. // spill entries.
  2824. while (FrameSize-- > 0) {
  2825. StoreTop += sizeof(ULONG64);
  2826. if ((StoreTop & 0x1f8) == 0x1f8) {
  2827. // Spill will be placed at this address so
  2828. // account for it.
  2829. StoreTop += sizeof(ULONG64);
  2830. }
  2831. }
  2832. if (StoreTop < Pcr->InitialBStore ||
  2833. StoreTop >= Pcr->BStoreLimit) {
  2834. // BSP isn't in the PCR store range so
  2835. // just save the whole thing.
  2836. StoreTop = Pcr->BStoreLimit;
  2837. }
  2838. StoreSize = (ULONG)(StoreTop - Pcr->InitialBStore);
  2839. if (StoreSize > MAX_TRIAGE_STACK_SIZE) {
  2840. StoreSize = MAX_TRIAGE_STACK_SIZE;
  2841. StoreBase = StoreTop - StoreSize;
  2842. }
  2843. IoAddTriageDumpDataBlock((PVOID)StoreBase, StoreSize);
  2844. }
  2845. if ((PVOID)Pcr->InitialStack != Thread->InitialStack ||
  2846. (PVOID)Pcr->StackLimit != Thread->StackLimit) {
  2847. ULONG64 StackTop;
  2848. ULONG StackSize;
  2849. StackTop = STACK_POINTER(Context);
  2850. if (StackTop < Pcr->StackLimit ||
  2851. StackTop >= Pcr->InitialStack) {
  2852. // SP isn't in the PCR stack range so
  2853. // just save the whole thing.
  2854. StackTop = Pcr->StackLimit;
  2855. }
  2856. StackSize = (ULONG)(Pcr->InitialStack - StackTop);
  2857. if (StackSize > MAX_TRIAGE_STACK_SIZE) {
  2858. StackSize = MAX_TRIAGE_STACK_SIZE;
  2859. }
  2860. IoAddTriageDumpDataBlock((PVOID)StackTop, StackSize);
  2861. }
  2862. #endif
  2863. // Add data blocks which might be referred to by
  2864. // the context or other runtime state.
  2865. IopAddRunTimeTriageDataBlocks(Context,
  2866. (PVOID*)TriageDump->TopOfStack,
  2867. (PVOID*)((PUCHAR)TriageDump->TopOfStack +
  2868. TriageDump->SizeOfCallStack),
  2869. #ifdef _IA64_
  2870. (PVOID*)Thread->InitialBStore,
  2871. (PVOID*)((PUCHAR)Thread->InitialBStore +
  2872. TriageDump->ArchitectureSpecific.Ia64.SizeOfBStore)
  2873. #else
  2874. NULL, NULL
  2875. #endif
  2876. );
  2877. // Check which data blocks fit.
  2878. Offset = IopSizeTriageDumpDataBlocks(TriageDump, Offset, BufferSize);
  2879. Offset = ALIGN_8 (Offset);
  2880. }
  2881. ASSERT_ALIGNMENT (Offset, 8);
  2882. BytesToWrite = (ULONG)Offset;
  2883. BufferAddress = ((ULONG_PTR) Buffer) - sizeof(DUMP_HEADER);
  2884. //
  2885. // Write the Mm information.
  2886. //
  2887. if (TriageDump->MmOffset) {
  2888. Address = (LPVOID) (BufferAddress + TriageDump->MmOffset);
  2889. MmWriteTriageInformation (Address);
  2890. }
  2891. if (TriageDump->UnloadedDriversOffset) {
  2892. Address = (LPVOID) (BufferAddress + TriageDump->UnloadedDriversOffset);
  2893. MmWriteUnloadedDriverInformation (Address);
  2894. }
  2895. //
  2896. // Write the PRCB.
  2897. //
  2898. if (TriageDump->PrcbOffset) {
  2899. Address = (LPVOID) (BufferAddress + TriageDump->PrcbOffset);
  2900. RtlCopyMemory (Address,
  2901. KeGetCurrentPrcb (),
  2902. sizeof (KPRCB)
  2903. );
  2904. }
  2905. //
  2906. // Write the EPROCESS.
  2907. //
  2908. if (TriageDump->ProcessOffset) {
  2909. Address = (LPVOID) (BufferAddress + TriageDump->ProcessOffset);
  2910. RtlCopyMemory (Address,
  2911. Thread->ApcState.Process,
  2912. sizeof (EPROCESS)
  2913. );
  2914. }
  2915. //
  2916. // Write the ETHREAD.
  2917. //
  2918. if (TriageDump->ThreadOffset) {
  2919. Address = (LPVOID) (BufferAddress + TriageDump->ThreadOffset);
  2920. RtlCopyMemory (Address,
  2921. Thread,
  2922. sizeof (ETHREAD));
  2923. }
  2924. //
  2925. // Write the Call Stack.
  2926. //
  2927. if (TriageDump->CallStackOffset) {
  2928. PVOID StackTop;
  2929. ASSERT (TriageDump->SizeOfCallStack != 0);
  2930. StackTop = (PVOID)TriageDump->TopOfStack;
  2931. ASSERT (IopIsAddressRangeValid (StackTop, TriageDump->SizeOfCallStack));
  2932. Address = (LPVOID) (BufferAddress + TriageDump->CallStackOffset);
  2933. RtlCopyMemory (Address,
  2934. StackTop,
  2935. TriageDump->SizeOfCallStack
  2936. );
  2937. }
  2938. #if defined (_IA64_)
  2939. //
  2940. // Write the IA64 BStore.
  2941. //
  2942. if ( TriageDump->ArchitectureSpecific.Ia64.BStoreOffset ) {
  2943. ASSERT (IopIsAddressRangeValid (Thread->InitialBStore,
  2944. TriageDump->ArchitectureSpecific.Ia64.SizeOfBStore));
  2945. Address = (PVOID) (BufferAddress + TriageDump->ArchitectureSpecific.Ia64.BStoreOffset);
  2946. RtlCopyMemory (Address,
  2947. Thread->InitialBStore,
  2948. TriageDump->ArchitectureSpecific.Ia64.SizeOfBStore
  2949. );
  2950. }
  2951. #endif // IA64
  2952. //
  2953. // Write the debugger data block.
  2954. //
  2955. if (TriageDump->DebuggerDataOffset) {
  2956. Address = (LPVOID) (BufferAddress + TriageDump->DebuggerDataOffset);
  2957. RtlCopyMemory (Address,
  2958. &KdDebuggerDataBlock,
  2959. sizeof(KdDebuggerDataBlock)
  2960. );
  2961. }
  2962. //
  2963. // Write the Driver List.
  2964. //
  2965. if (TriageDump->DriverListOffset &&
  2966. TriageDump->StringPoolOffset) {
  2967. Status = IopWriteDriverList (BufferAddress,
  2968. BufferSize,
  2969. TriageDump->DriverListOffset,
  2970. TriageDump->StringPoolOffset
  2971. );
  2972. if (!NT_SUCCESS (Status)) {
  2973. TriageDump->DriverListOffset = 0;
  2974. }
  2975. }
  2976. //
  2977. // Write the data blocks.
  2978. //
  2979. IopWriteTriageDumpDataBlocks(TriageDump, (PUCHAR)BufferAddress);
  2980. ASSERT (BytesToWrite < BufferSize);
  2981. ASSERT (ALIGN_UP (BytesToWrite, PAGE_SIZE) < BufferSize);
  2982. //
  2983. // Write the valid status to the end of the dump.
  2984. //
  2985. *((ULONG *)IndexByByte (Buffer, BufferSize)) = TRIAGE_DUMP_VALID ;
  2986. //
  2987. // Re-adjust the buffer size.
  2988. //
  2989. BufferSize += sizeof (DWORD);
  2990. //
  2991. // NOTE: This routine writes the entire buffer, even if it is not
  2992. // all required.
  2993. //
  2994. Status = IopWriteToDisk (Buffer,
  2995. BufferSize,
  2996. DriverWriteRoutine,
  2997. Mcb,
  2998. Mdl,
  2999. DriverTransferSize,
  3000. KbDumpIoBody
  3001. );
  3002. return Status;
  3003. }
  3004. NTSTATUS
  3005. IopWritePageToDisk(
  3006. IN PDUMP_DRIVER_WRITE DriverWrite,
  3007. IN OUT PLARGE_INTEGER * McbBuffer,
  3008. IN OUT ULONG DriverTransferSize,
  3009. IN PFN_NUMBER PageFrameIndex
  3010. )
  3011. /*++
  3012. Routine Description:
  3013. Write the page described by PageFrameIndex to the disk/file (DriverWrite,
  3014. McbBuffer) and update the MCB buffer to reflect the new position in the
  3015. file.
  3016. Arguments:
  3017. DriverWrite - The driver write routine.
  3018. McbBuffer - A pointer to the MCB array. This array is terminated by
  3019. a zero-length MCB entry. On success, this pointer is updated
  3020. to reflect the new position in the MCB array.
  3021. NB: MCB[0] is the size and MCB[1] is the offset.
  3022. DriverTransferSize - The maximum transfer size for this driver.
  3023. PageFrameIndex - The page to be written.
  3024. Return Values:
  3025. NTSTATUS code.
  3026. --*/
  3027. {
  3028. NTSTATUS Status = STATUS_SUCCESS;
  3029. PFN_NUMBER MdlHack [ (sizeof (MDL) / sizeof (PFN_NUMBER)) + 1];
  3030. PPFN_NUMBER PfnArray;
  3031. PLARGE_INTEGER Mcb;
  3032. ULONG ByteCount;
  3033. ULONG ByteOffset;
  3034. ULONG BytesToWrite;
  3035. PMDL TempMdl;
  3036. ASSERT ( DriverWrite );
  3037. ASSERT ( McbBuffer );
  3038. ASSERT ( DriverTransferSize && DriverTransferSize >= PAGE_SIZE );
  3039. KdCheckForDebugBreak();
  3040. //
  3041. // Initialization
  3042. //
  3043. TempMdl = (PMDL) &MdlHack[0];
  3044. Mcb = *McbBuffer;
  3045. BytesToWrite = PAGE_SIZE;
  3046. //
  3047. // Initialze the MDL to point to this page.
  3048. //
  3049. MmInitializeMdl (TempMdl, NULL, PAGE_SIZE);
  3050. // TempMdl->StartVa = (PVOID) (PageFrameIndex << PAGE_SHIFT);
  3051. PfnArray = MmGetMdlPfnArray ( TempMdl );
  3052. PfnArray[0] = PageFrameIndex;
  3053. //
  3054. // We loop for the cases when the space remaining in this block (Mcb [0])
  3055. // is less than one page. Generally the Mcb will be large enough to hold
  3056. // the entire page and this loop will only be executed once. When Mcb[0]
  3057. // is less than a page, we will write the first part of the page to this
  3058. // Mcb then increment the Mcb and write the remaining part to the next
  3059. // page.
  3060. //
  3061. ByteOffset = 0;
  3062. while ( BytesToWrite ) {
  3063. ASSERT ( Mcb[0].QuadPart != 0 );
  3064. ByteCount = (ULONG) min3 ((LONGLONG) BytesToWrite,
  3065. (LONGLONG) DriverTransferSize,
  3066. Mcb[0].QuadPart
  3067. );
  3068. ASSERT ( ByteCount != 0 );
  3069. //
  3070. // Update the MDL byte count and byte offset.
  3071. //
  3072. TempMdl->ByteCount = ByteCount;
  3073. TempMdl->ByteOffset = ByteOffset;
  3074. //
  3075. // Map the MDL. The flags are updated to show that MappedSystemVa
  3076. // is valid (which should probably be done in MmMapMemoryDumpMdl).
  3077. //
  3078. MmMapMemoryDumpMdl ( TempMdl );
  3079. TempMdl->MdlFlags |= ( MDL_PAGES_LOCKED | MDL_MAPPED_TO_SYSTEM_VA );
  3080. TempMdl->StartVa = PAGE_ALIGN (TempMdl->MappedSystemVa);
  3081. IopInvokeDumpIoCallbacks((PUCHAR)TempMdl->StartVa + ByteOffset,
  3082. ByteCount, KbDumpIoBody);
  3083. //
  3084. // Write the bufffer.
  3085. //
  3086. Status = DriverWrite ( &Mcb[1], TempMdl );
  3087. if (!NT_SUCCESS (Status)) {
  3088. return Status;
  3089. }
  3090. BytesToWrite -= ByteCount;
  3091. ByteOffset += ByteCount;
  3092. Mcb[0].QuadPart -= ByteCount;
  3093. Mcb[1].QuadPart += ByteCount;
  3094. //
  3095. // If there is no more room for this MCB, go to the next one.
  3096. //
  3097. if ( Mcb[0].QuadPart == 0 ) {
  3098. Mcb += 2;
  3099. //
  3100. // We have filled up all the space in the paging file.
  3101. //
  3102. if ( Mcb[0].QuadPart == 0) {
  3103. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  3104. CRASHDUMP_ERROR,
  3105. "CRASHDUMP: Pagefile is full.\n"));
  3106. return STATUS_END_OF_FILE;
  3107. }
  3108. }
  3109. }
  3110. *McbBuffer = Mcb;
  3111. return Status;
  3112. }
  3113. NTSTATUS
  3114. IopWriteSummaryDump(
  3115. IN PRTL_BITMAP PageMap,
  3116. IN PDUMP_DRIVER_WRITE DriverWriteRoutine,
  3117. IN PANSI_STRING ProgressMessage,
  3118. IN PUCHAR MessageBuffer,
  3119. IN OUT PLARGE_INTEGER * Mcb,
  3120. IN OUT ULONG DriverTransferSize
  3121. )
  3122. /*++
  3123. Routine Description:
  3124. Write a summary dump to the disk.
  3125. Arguments:
  3126. PageMap - A bitmap of the pages that need to be written.
  3127. DriverWriteRoutine - The driver's write routine.
  3128. ProgressMessage - The "Percent Complete" message.
  3129. MessageBuffer - Not used. Must be NULL.
  3130. Mcb - Message Control Block where the data is to be written.
  3131. DriverTransferSize - The maximum transfer size for the driver.
  3132. Return Values:
  3133. NTSTATUS code.
  3134. --*/
  3135. {
  3136. PFN_NUMBER PageFrameIndex;
  3137. NTSTATUS Status;
  3138. ULONG WriteCount;
  3139. ULONG MaxWriteCount;
  3140. ULONG Step;
  3141. #if !DBG
  3142. UNREFERENCED_PARAMETER (MessageBuffer);
  3143. #endif
  3144. ASSERT ( DriverWriteRoutine != NULL );
  3145. ASSERT ( Mcb != NULL );
  3146. ASSERT ( DriverTransferSize != 0 );
  3147. ASSERT ( MessageBuffer == NULL );
  3148. MaxWriteCount = RtlNumberOfSetBits ( PageMap );
  3149. ASSERT (MaxWriteCount != 0);
  3150. Step = MaxWriteCount / 100;
  3151. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  3152. CRASHDUMP_TRACE,
  3153. "CRASHDUMP: Summary Dump\n"
  3154. " Writing %x pages to disk from a total of %x\n",
  3155. MaxWriteCount,
  3156. PageMap->SizeOfBitMap
  3157. ));
  3158. //
  3159. // Loop over all pages in the system and write those that are set
  3160. // in the bitmap.
  3161. //
  3162. WriteCount = 0;
  3163. for ( PageFrameIndex = 0;
  3164. PageFrameIndex < PageMap->SizeOfBitMap;
  3165. PageFrameIndex++) {
  3166. //
  3167. // If this page needs to be included in the dump file.
  3168. //
  3169. if ( RtlCheckBit (PageMap, PageFrameIndex) ) {
  3170. if (++WriteCount % Step == 0) {
  3171. //
  3172. // Update the progress percentage.
  3173. //
  3174. IopDisplayString ("%Z: %3d\r",
  3175. ProgressMessage,
  3176. (WriteCount * 100) / MaxWriteCount
  3177. );
  3178. }
  3179. ASSERT ( WriteCount <= MaxWriteCount );
  3180. //
  3181. // Write the page to disk.
  3182. //
  3183. KdCheckForDebugBreak();
  3184. Status = IopWritePageToDisk (
  3185. DriverWriteRoutine,
  3186. Mcb,
  3187. DriverTransferSize,
  3188. PageFrameIndex
  3189. );
  3190. if (!NT_SUCCESS (Status)) {
  3191. return STATUS_UNSUCCESSFUL;
  3192. }
  3193. }
  3194. }
  3195. return STATUS_SUCCESS;
  3196. }
  3197. NTSTATUS
  3198. IopInitializeSummaryDump(
  3199. IN OUT PMEMORY_DUMP MemoryDump,
  3200. IN PDUMP_CONTROL_BLOCK DumpControlBlock
  3201. )
  3202. /*++
  3203. Routine Description:
  3204. This routine creates a summary dump header. In particular it initializes
  3205. a bitmap that contains a map of kernel memory.
  3206. Arguments:
  3207. MemoryDump - The memory dump.
  3208. DumpControlBlock - A pointer to the dump control block.
  3209. Return Value:
  3210. Non-NULL - A pointer to the summary dump header
  3211. NULL - Error
  3212. --*/
  3213. {
  3214. ULONG ActualPages;
  3215. ASSERT ( MemoryDump != NULL );
  3216. ASSERT ( DumpControlBlock != NULL );
  3217. //
  3218. // Fill the header with signatures.
  3219. //
  3220. RtlFillMemoryUlong( &MemoryDump->Summary,
  3221. sizeof (SUMMARY_DUMP),
  3222. DUMP_SUMMARY_SIGNATURE);
  3223. //
  3224. // Set the size and valid signature.
  3225. //
  3226. //
  3227. // ISSUE - 2000/02/07 - math: Review for Win64
  3228. //
  3229. // Computing the bitmap size is probably wrong for 64 bit.
  3230. //
  3231. MemoryDump->Summary.BitmapSize =
  3232. (ULONG)( MmPhysicalMemoryBlock->Run[MmPhysicalMemoryBlock->NumberOfRuns-1].BasePage +
  3233. MmPhysicalMemoryBlock->Run[MmPhysicalMemoryBlock->NumberOfRuns-1].PageCount );
  3234. MemoryDump->Summary.ValidDump = DUMP_SUMMARY_VALID;
  3235. //
  3236. // Construct the kernel memory bitmap.
  3237. //
  3238. //
  3239. // ISSUE - 2000/02/07 - math: Review for Win64
  3240. //
  3241. // Actual will probably need to be a 64-bit value for Win64.
  3242. //
  3243. ActualPages = IopCreateSummaryDump (MemoryDump);
  3244. KdPrintEx ((DPFLTR_CRASHDUMP_ID, CRASHDUMP_TRACE,
  3245. "CRASHDUMP: Kernel Pages = %x\n",
  3246. ActualPages ));
  3247. if (ActualPages == 0) {
  3248. return STATUS_UNSUCCESSFUL;
  3249. }
  3250. //
  3251. // Set the actual number of physical pages in the summary dump
  3252. //
  3253. MemoryDump->Summary.Pages = ActualPages;
  3254. MemoryDump->Summary.HeaderSize = DumpControlBlock->HeaderSize;
  3255. return STATUS_SUCCESS;
  3256. }
  3257. NTSTATUS
  3258. IopWriteSummaryHeader(
  3259. IN PSUMMARY_DUMP SummaryHeader,
  3260. IN PDUMP_DRIVER_WRITE WriteRoutine,
  3261. IN OUT PLARGE_INTEGER * McbBuffer,
  3262. IN OUT PMDL Mdl,
  3263. IN ULONG WriteSize,
  3264. IN ULONG Length
  3265. )
  3266. /*++
  3267. Routine Description:
  3268. Write the summary dump header to the dump file.
  3269. Arguments:
  3270. SummaryHeader - pointer to the summary dump bitmap
  3271. WriteRoutine - dump driver write function
  3272. McbBuffer - Pointer to the dump file MCB array.
  3273. Mdl - Pointer to an MDL
  3274. WriteSize - the max transfer size for the dump driver
  3275. Length - the length of this transfer
  3276. Return Value:
  3277. NTSTATUS code.
  3278. --*/
  3279. {
  3280. NTSTATUS Status;
  3281. ULONG BytesRemaining;
  3282. ULONG_PTR MemoryAddress;
  3283. ULONG ByteOffset;
  3284. ULONG ByteCount;
  3285. PLARGE_INTEGER Mcb;
  3286. Mcb = *McbBuffer;
  3287. BytesRemaining = Length;
  3288. MemoryAddress = (ULONG_PTR) SummaryHeader;
  3289. IopInvokeDumpIoCallbacks(SummaryHeader, Length, KbDumpIoBody);
  3290. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  3291. CRASHDUMP_TRACE,
  3292. "CRASHDUMP: Writing SUMMARY dump header to disk\n" ));
  3293. while ( BytesRemaining ) {
  3294. ByteOffset = BYTE_OFFSET ( MemoryAddress );
  3295. //
  3296. // See if the number of bytes to write is greator than the crash
  3297. // drives max transfer.
  3298. //
  3299. if ( BytesRemaining <= WriteSize) {
  3300. ByteCount = BytesRemaining;
  3301. } else {
  3302. ByteCount = WriteSize;
  3303. }
  3304. //
  3305. // If the byteCount is greater than the remaining mcb then correct it.
  3306. //
  3307. if ( ByteCount > Mcb[0].QuadPart) {
  3308. ByteCount = Mcb[0].LowPart;
  3309. }
  3310. Mdl->ByteCount = ByteCount;
  3311. Mdl->ByteOffset = ByteOffset;
  3312. Mdl->MappedSystemVa = (PVOID) MemoryAddress;
  3313. //
  3314. // Get the actual physical frame and create an mdl.
  3315. //
  3316. IopMapVirtualToPhysicalMdl ( Mdl, MemoryAddress, ByteCount );
  3317. //
  3318. // Write to disk.
  3319. //
  3320. Status = WriteRoutine ( &Mcb[1], Mdl );
  3321. if ( !NT_SUCCESS (Status)) {
  3322. return Status;
  3323. }
  3324. //
  3325. // Adjust bytes remaining.
  3326. //
  3327. BytesRemaining -= ByteCount;
  3328. MemoryAddress += ByteCount;
  3329. Mcb[0].QuadPart = Mcb[0].QuadPart - ByteCount;
  3330. Mcb[1].QuadPart = Mcb[1].QuadPart + ByteCount;
  3331. if (Mcb[0].QuadPart == 0) {
  3332. Mcb += 2;
  3333. }
  3334. if (Mcb[0].QuadPart == 0) {
  3335. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  3336. CRASHDUMP_ERROR,
  3337. "CRASHDUMP: Pagefile is full.\n"));
  3338. return STATUS_END_OF_FILE;
  3339. }
  3340. }
  3341. *McbBuffer = Mcb;
  3342. return STATUS_SUCCESS;
  3343. }
  3344. NTSTATUS
  3345. IopWriteToDisk(
  3346. IN PVOID Buffer,
  3347. IN ULONG WriteLength,
  3348. IN PDUMP_DRIVER_WRITE DriverWriteRoutine,
  3349. IN OUT PLARGE_INTEGER * McbBuffer,
  3350. IN OUT PMDL Mdl,
  3351. IN ULONG DriverTransferSize,
  3352. IN KBUGCHECK_DUMP_IO_TYPE DataType
  3353. )
  3354. /*++
  3355. Routine Description:
  3356. Write the summary dump header to the dump file.
  3357. Arguments:
  3358. Buffer - Pointer to the buffer to write.
  3359. WriteLength - The length of this transfer.
  3360. DriverWriteRoutine - Dump driver write function.
  3361. McbBuffer - Pointer to the dump file Mapped Control Block.
  3362. Mdl - Pointer to an MDL.
  3363. DriverTransferSize - The max transfer size for the dump driver.
  3364. DataType - Type of data being written, for I/O callbacks.
  3365. Return Value:
  3366. --*/
  3367. {
  3368. ULONG BytesRemaining;
  3369. ULONG_PTR MemoryAddress;
  3370. ULONG ByteOffset;
  3371. ULONG ByteCount;
  3372. PLARGE_INTEGER Mcb;
  3373. ASSERT (Buffer);
  3374. ASSERT (WriteLength);
  3375. ASSERT (DriverWriteRoutine);
  3376. ASSERT (McbBuffer && *McbBuffer);
  3377. ASSERT (Mdl);
  3378. ASSERT (DriverTransferSize >= IO_DUMP_MINIMUM_TRANSFER_SIZE &&
  3379. DriverTransferSize <= IO_DUMP_MAXIMUM_TRANSFER_SIZE);
  3380. IopInvokeDumpIoCallbacks(Buffer, WriteLength, DataType);
  3381. Mcb = *McbBuffer;
  3382. BytesRemaining = WriteLength;
  3383. MemoryAddress = (ULONG_PTR) Buffer;
  3384. while ( BytesRemaining ) {
  3385. ASSERT (IopDumpControlBlock->FileDescriptorArray <= Mcb &&
  3386. (LPBYTE) Mcb < (LPBYTE) IopDumpControlBlock->FileDescriptorArray +
  3387. IopDumpControlBlock->FileDescriptorSize
  3388. );
  3389. if (Mcb[0].QuadPart == 0) {
  3390. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  3391. CRASHDUMP_ERROR,
  3392. "CRASHDUMP: Pagefile is full.\n"));
  3393. return STATUS_END_OF_FILE;
  3394. }
  3395. ByteOffset = BYTE_OFFSET ( MemoryAddress );
  3396. //
  3397. // See if the number of bytes to write is greator than the crash
  3398. // drives max transfer.
  3399. //
  3400. ByteCount = min ( BytesRemaining, DriverTransferSize );
  3401. //
  3402. // If the byteCount is greater than the remaining mcb then correct it.
  3403. //
  3404. if (ByteCount > Mcb[0].QuadPart) {
  3405. ByteCount = Mcb[0].LowPart;
  3406. }
  3407. Mdl->ByteCount = ByteCount;
  3408. Mdl->ByteOffset = ByteOffset;
  3409. Mdl->MappedSystemVa = (PVOID) MemoryAddress;
  3410. //
  3411. // Get the actual physical frame and create an mdl.
  3412. //
  3413. IopMapVirtualToPhysicalMdl(Mdl, MemoryAddress, ByteCount);
  3414. KdCheckForDebugBreak();
  3415. if (!NT_SUCCESS( DriverWriteRoutine ( &Mcb[1], Mdl ) )) {
  3416. //
  3417. // We are in deep trouble if we failed the write.
  3418. //
  3419. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  3420. CRASHDUMP_ERROR,
  3421. "CRASHDUMP: Failed to write Mcb = %p, Mdl = %p to disk\n",
  3422. &Mcb[1],
  3423. Mdl
  3424. ));
  3425. return STATUS_UNSUCCESSFUL;
  3426. }
  3427. //
  3428. // Adjust bytes remaining.
  3429. //
  3430. ASSERT ( BytesRemaining >= ByteCount );
  3431. ASSERT ( ByteCount != 0 );
  3432. BytesRemaining -= ByteCount;
  3433. MemoryAddress += ByteCount;
  3434. Mcb[0].QuadPart -= ByteCount;
  3435. Mcb[1].QuadPart += ByteCount;
  3436. if (Mcb[0].QuadPart == 0) {
  3437. Mcb += 2;
  3438. }
  3439. }
  3440. *McbBuffer = Mcb;
  3441. return STATUS_SUCCESS;
  3442. }
  3443. VOID
  3444. IopMapVirtualToPhysicalMdl(
  3445. IN OUT PMDL Mdl,
  3446. IN ULONG_PTR MemoryAddress,
  3447. IN ULONG Length
  3448. )
  3449. {
  3450. ULONG Pages;
  3451. PPFN_NUMBER Pfn;
  3452. PCHAR BaseVa;
  3453. PHYSICAL_ADDRESS PhysicalAddress;
  3454. //
  3455. // ISSUE - 2000/02/07 - math: Review for Win64
  3456. //
  3457. // This whole function needs to be revisited for Win64.
  3458. // There are a ton of tacit assumptions here about the
  3459. // size of a PFN.
  3460. //
  3461. //
  3462. // Begin by determining the base physical page of the start of the address
  3463. // range and filling in the MDL appropriately.
  3464. //
  3465. Mdl->StartVa = PAGE_ALIGN ( MemoryAddress );
  3466. Mdl->ByteOffset = BYTE_OFFSET ( MemoryAddress );
  3467. Mdl->ByteCount = Length;
  3468. Mdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA;
  3469. //
  3470. // Compute the number of pages spanned
  3471. //
  3472. Pages = ADDRESS_AND_SIZE_TO_SPAN_PAGES( MemoryAddress, Length );
  3473. Pfn = MmGetMdlPfnArray ( Mdl );
  3474. //
  3475. // Map all of the pages for this transfer until there are no more remaining
  3476. // to be mapped.
  3477. //
  3478. BaseVa = PAGE_ALIGN ( MemoryAddress );
  3479. while ( Pages ) {
  3480. PhysicalAddress = MmGetPhysicalAddress ( BaseVa );
  3481. *Pfn++ = (PFN_NUMBER)(PhysicalAddress.QuadPart >> PAGE_SHIFT);
  3482. BaseVa += PAGE_SIZE;
  3483. Pages--;
  3484. }
  3485. //
  3486. // All of the PFNs for the address range have been filled in so map the
  3487. // physical memory into virtual address space using crash dump PTE.
  3488. //
  3489. // MmMapMemoryDumpMdl( pMdl );
  3490. }
  3491. ULONG
  3492. IopCreateSummaryDump (
  3493. IN PMEMORY_DUMP MemoryDump
  3494. )
  3495. /*++
  3496. Routine Description:
  3497. This routine determines the kernel memory and data structures to include
  3498. in the summary memory dump.
  3499. NOTE: This function uses MmGetPhysicalAddress. MmGetPhysicalAddress does
  3500. not acquire any locks. It uses a set of macros for translation.
  3501. Arguments:
  3502. MemoryDump - The memory dump.
  3503. Return Value:
  3504. Status
  3505. --*/
  3506. {
  3507. PRTL_BITMAP BitMap;
  3508. LARGE_INTEGER DumpFileSize;
  3509. ULONG PagesUsed;
  3510. PSUMMARY_DUMP Summary;
  3511. MM_KERNEL_DUMP_CONTEXT Context;
  3512. //
  3513. // Validation
  3514. //
  3515. ASSERT (MemoryDump != NULL);
  3516. //
  3517. // Initialize Bit Map, set the size and buffer address.
  3518. //
  3519. Summary = &MemoryDump->Summary;
  3520. BitMap = (PRTL_BITMAP) &Summary->Bitmap;
  3521. BitMap->SizeOfBitMap = Summary->BitmapSize; // Why??
  3522. BitMap->Buffer = Summary->Bitmap.Buffer;
  3523. //
  3524. // Clear all bits
  3525. //
  3526. RtlClearAllBits (BitMap);
  3527. //
  3528. // Have MM initialize the kernel memory to dump
  3529. //
  3530. Context.Context = Summary;
  3531. Context.SetDumpRange = IoSetDumpRange;
  3532. Context.FreeDumpRange = IoFreeDumpRange;
  3533. MmGetKernelDumpRange (&Context);
  3534. PagesUsed = RtlNumberOfSetBits ( BitMap );
  3535. //
  3536. // See If we have room to Include user va for the current process
  3537. //
  3538. DumpFileSize = MemoryDump->Header.RequiredDumpSpace;
  3539. DumpFileSize.QuadPart -= IopDumpControlBlock->HeaderSize;
  3540. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  3541. CRASHDUMP_TRACE,
  3542. "CRASHDUMP: Kernel Dump, Header = %p\n",
  3543. Summary
  3544. ));
  3545. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  3546. CRASHDUMP_TRACE,
  3547. " BitMapSize: %x\n"
  3548. " Pages: %x\n"
  3549. " BitMapBuffer: %p\n",
  3550. Summary->BitmapSize,
  3551. PagesUsed,
  3552. BitMap->Buffer
  3553. ));
  3554. return PagesUsed;
  3555. }
  3556. NTSTATUS
  3557. IopInvokeSecondaryDumpDataCallbacks(
  3558. IN PDUMP_DRIVER_WRITE DriverWriteRoutine,
  3559. IN OUT PLARGE_INTEGER * Mcb,
  3560. IN OUT PMDL Mdl,
  3561. IN ULONG DriverTransferSize,
  3562. IN BYTE* Buffer,
  3563. IN ULONG BufferSize,
  3564. IN ULONG MaxTotal,
  3565. IN ULONG MaxPerCallback,
  3566. OUT OPTIONAL PULONG SpaceNeeded
  3567. )
  3568. /*++
  3569. Routine Description:
  3570. Walk the list of dump data callbacks, invoking them
  3571. and writing their data out.
  3572. Arguments:
  3573. DriverWriteRoutine - The write routine for the driver.
  3574. Mcb - Message Control Block where the data is to be written.
  3575. Mdl - Address of the MDL to be filled in.
  3576. DriverTransferSize - The maximum transfer size for the driver.
  3577. Buffer - The buffer to use as a scratch buffer.
  3578. BufferSize - Size of Buffer.
  3579. MaxTotal - Maximum amount of data allowed overall.
  3580. MaxPerCallback - Maximum amount of data allowed per callback.
  3581. SpaceNeeded - Amount of data used by all callbacks. If this
  3582. argument is present then no I/O is done, just
  3583. accumulation of data sizes.
  3584. Return Values:
  3585. STATUS_SUCCESS - On success.
  3586. NTSTATUS - Otherwise.
  3587. --*/
  3588. {
  3589. PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord;
  3590. ULONG_PTR Checksum;
  3591. ULONG Index;
  3592. PLIST_ENTRY LastEntry;
  3593. PLIST_ENTRY ListHead;
  3594. PLIST_ENTRY NextEntry;
  3595. PUCHAR Source;
  3596. PDUMP_BLOB_FILE_HEADER BlobFileHdr;
  3597. PDUMP_BLOB_HEADER BlobHdr;
  3598. // Assert that basic structures preserve 8-byte alignment.
  3599. C_ASSERT((sizeof(DUMP_BLOB_FILE_HEADER) & 7) == 0);
  3600. C_ASSERT((sizeof(DUMP_BLOB_HEADER) & 7) == 0);
  3601. if (ARGUMENT_PRESENT(SpaceNeeded)) {
  3602. *SpaceNeeded = 0;
  3603. }
  3604. //
  3605. // If the caller isn't allowing a reasonable amount of
  3606. // data don't even bother to look.
  3607. //
  3608. if (MaxPerCallback < PAGE_SIZE || MaxTotal < MaxPerCallback) {
  3609. return STATUS_SUCCESS;
  3610. }
  3611. //
  3612. // If the bug check callback listhead is not initialized, then the
  3613. // bug check has occured before the system has gotten far enough
  3614. // in the initialization code to enable anyone to register a callback.
  3615. //
  3616. ListHead = &KeBugCheckReasonCallbackListHead;
  3617. if (ListHead->Flink == NULL || ListHead->Blink == NULL) {
  3618. return STATUS_SUCCESS;
  3619. }
  3620. //
  3621. // The current dump I/O routines only handle
  3622. // page-granular I/O so everything must be
  3623. // packed into a page for a single write.
  3624. //
  3625. // Start out with an overall file header followed
  3626. // by a blob header. After the first blob is written
  3627. // the blob header will be moved down to the head
  3628. // of the buffer.
  3629. //
  3630. BlobFileHdr = (PDUMP_BLOB_FILE_HEADER)Buffer;
  3631. BlobHdr = (PDUMP_BLOB_HEADER)(BlobFileHdr + 1);
  3632. //
  3633. // Scan the bug check callback list.
  3634. //
  3635. LastEntry = ListHead;
  3636. NextEntry = ListHead->Flink;
  3637. while (NextEntry != ListHead) {
  3638. //
  3639. // If no more dump data is allowed we're done.
  3640. //
  3641. if (!MaxTotal) {
  3642. break;
  3643. }
  3644. //
  3645. // The next entry address must be aligned properly, the
  3646. // callback record must be readable, and the callback record
  3647. // must have back link to the last entry.
  3648. //
  3649. if (((ULONG_PTR)NextEntry & (sizeof(ULONG_PTR) - 1)) != 0) {
  3650. return STATUS_DATATYPE_MISALIGNMENT;
  3651. }
  3652. CallbackRecord = CONTAINING_RECORD(NextEntry,
  3653. KBUGCHECK_REASON_CALLBACK_RECORD,
  3654. Entry);
  3655. Source = (PUCHAR)CallbackRecord;
  3656. for (Index = 0; Index < sizeof(*CallbackRecord); Index += 1) {
  3657. if (MmIsAddressValid((PVOID)Source) == FALSE) {
  3658. return STATUS_PARTIAL_COPY;
  3659. }
  3660. Source += 1;
  3661. }
  3662. if (CallbackRecord->Entry.Blink != LastEntry) {
  3663. return STATUS_INVALID_PARAMETER;
  3664. }
  3665. LastEntry = NextEntry;
  3666. NextEntry = NextEntry->Flink;
  3667. //
  3668. // If the callback record has a state of inserted and the
  3669. // computed checksum matches the callback record checksum,
  3670. // then call the specified bug check callback routine.
  3671. //
  3672. Checksum = (ULONG_PTR)CallbackRecord->CallbackRoutine;
  3673. Checksum += (ULONG_PTR)CallbackRecord->Reason;
  3674. Checksum += (ULONG_PTR)CallbackRecord->Component;
  3675. if ((CallbackRecord->State != BufferInserted) ||
  3676. (CallbackRecord->Checksum != Checksum) ||
  3677. (CallbackRecord->Reason != KbCallbackSecondaryDumpData) ||
  3678. MmIsAddressValid((PVOID)(ULONG_PTR)CallbackRecord->
  3679. CallbackRoutine) == FALSE) {
  3680. continue;
  3681. }
  3682. //
  3683. // Call the specified bug check callback routine and
  3684. // handle any exceptions that occur.
  3685. //
  3686. if (!ARGUMENT_PRESENT(SpaceNeeded)) {
  3687. CallbackRecord->State = BufferStarted;
  3688. }
  3689. try {
  3690. KBUGCHECK_SECONDARY_DUMP_DATA CbArgument;
  3691. NTSTATUS Status;
  3692. ULONG BufferAvail;
  3693. // Clean the buffer before letting
  3694. // the callback have it.
  3695. RtlZeroMemory(Buffer, BufferSize);
  3696. // Start the callback's buffer after the blob header.
  3697. CbArgument.InBuffer = (PVOID)(BlobHdr + 1);
  3698. BufferAvail = BufferSize - (ULONG)
  3699. ((ULONG_PTR)CbArgument.InBuffer - (ULONG_PTR)Buffer);
  3700. CbArgument.InBufferLength = BufferAvail;
  3701. CbArgument.MaximumAllowed = MaxPerCallback;
  3702. RtlZeroMemory(&CbArgument.Guid, sizeof(CbArgument.Guid));
  3703. CbArgument.OutBuffer = ARGUMENT_PRESENT(SpaceNeeded) ?
  3704. NULL : CbArgument.InBuffer;
  3705. CbArgument.OutBufferLength = 0;
  3706. (CallbackRecord->CallbackRoutine)(KbCallbackSecondaryDumpData,
  3707. CallbackRecord,
  3708. &CbArgument,
  3709. sizeof(CbArgument));
  3710. //
  3711. // If no data was used there's nothing to write.
  3712. //
  3713. if (!CbArgument.OutBuffer || !CbArgument.OutBufferLength) {
  3714. // Set this state even when sizing as
  3715. // there's no need to call again.
  3716. CallbackRecord->State = BufferFinished;
  3717. __leave;
  3718. }
  3719. //
  3720. // The callback may have used the buffer given or
  3721. // it may have returned its own buffer. If it
  3722. // used the buffer given it must be page aligned.
  3723. //
  3724. if ((PBYTE)CbArgument.OutBuffer >= Buffer &&
  3725. (PBYTE)CbArgument.OutBuffer < Buffer + BufferSize) {
  3726. if (CbArgument.OutBuffer != (PVOID)(BlobHdr + 1) ||
  3727. CbArgument.OutBufferLength > BufferAvail) {
  3728. // If too much or the wrong data was used memory has
  3729. // been trashed. Exit and hope the system still runs.
  3730. return STATUS_INVALID_PARAMETER;
  3731. }
  3732. // The header buffer was used so we can write
  3733. // the data along with the header.
  3734. BlobHdr->PrePad = 0;
  3735. BlobHdr->PostPad = BufferAvail - CbArgument.OutBufferLength;
  3736. } else {
  3737. if (CbArgument.OutBufferLength > MaxPerCallback ||
  3738. BYTE_OFFSET(CbArgument.OutBuffer) ||
  3739. !IopIsAddressRangeValid(CbArgument.OutBuffer,
  3740. CbArgument.OutBufferLength)) {
  3741. return STATUS_INVALID_PARAMETER;
  3742. }
  3743. // The header buffer is separate from the data
  3744. // buffer so prepad and postpad to a page boundary.
  3745. BlobHdr->PrePad = BufferAvail;
  3746. BlobHdr->PostPad =
  3747. (ULONG)(ROUND_TO_PAGES(CbArgument.OutBufferLength) -
  3748. CbArgument.OutBufferLength);
  3749. }
  3750. //
  3751. // Write the page containing the headers.
  3752. //
  3753. if ((PBYTE)BlobHdr > Buffer) {
  3754. BlobFileHdr->Signature1 = DUMP_BLOB_SIGNATURE1;
  3755. BlobFileHdr->Signature2 = DUMP_BLOB_SIGNATURE2;
  3756. BlobFileHdr->HeaderSize = sizeof(*BlobFileHdr);
  3757. BlobFileHdr->BuildNumber = NtBuildNumber;
  3758. }
  3759. BlobHdr->HeaderSize = sizeof(*BlobHdr);
  3760. BlobHdr->Tag = CbArgument.Guid;
  3761. BlobHdr->DataSize = CbArgument.OutBufferLength;
  3762. if (ARGUMENT_PRESENT(SpaceNeeded)) {
  3763. (*SpaceNeeded) += BufferSize;
  3764. } else {
  3765. Status = IopWriteToDisk(Buffer, BufferSize,
  3766. DriverWriteRoutine,
  3767. Mcb, Mdl, DriverTransferSize,
  3768. KbDumpIoSecondaryData);
  3769. if (!NT_SUCCESS(Status)) {
  3770. return Status;
  3771. }
  3772. }
  3773. //
  3774. // Write any extra data buffer pages.
  3775. //
  3776. if (CbArgument.OutBuffer != (PVOID)(BlobHdr + 1)) {
  3777. if (ARGUMENT_PRESENT(SpaceNeeded)) {
  3778. (*SpaceNeeded) += (ULONG)
  3779. ROUND_TO_PAGES(CbArgument.OutBufferLength);
  3780. } else {
  3781. Status = IopWriteToDisk(CbArgument.OutBuffer,
  3782. (ULONG)ROUND_TO_PAGES(CbArgument.OutBufferLength),
  3783. DriverWriteRoutine,
  3784. Mcb, Mdl, DriverTransferSize,
  3785. KbDumpIoSecondaryData);
  3786. if (!NT_SUCCESS(Status)) {
  3787. return Status;
  3788. }
  3789. }
  3790. }
  3791. MaxTotal -= (ULONG)ROUND_TO_PAGES(CbArgument.OutBufferLength);
  3792. // We've written at least one blob so we don't
  3793. // need the file header any more.
  3794. BlobHdr = (PDUMP_BLOB_HEADER)Buffer;
  3795. if (!ARGUMENT_PRESENT(SpaceNeeded)) {
  3796. CallbackRecord->State = BufferFinished;
  3797. }
  3798. } except(EXCEPTION_EXECUTE_HANDLER) {
  3799. // Set this state even when sizing as
  3800. // we don't want to call a bad callback again.
  3801. CallbackRecord->State = BufferIncomplete;
  3802. }
  3803. }
  3804. return STATUS_SUCCESS;
  3805. }
  3806. NTSTATUS
  3807. IopInvokeDumpIoCallbacks(
  3808. IN PVOID Buffer,
  3809. IN ULONG BufferLength,
  3810. IN KBUGCHECK_DUMP_IO_TYPE Type
  3811. )
  3812. /*++
  3813. Routine Description:
  3814. Walk the list of dump I/O callbacks and invoke them.
  3815. Arguments:
  3816. Buffer - The buffer of data being written.
  3817. BufferLength - Size of Buffer.
  3818. Type - Type of data being written.
  3819. Return Values:
  3820. STATUS_SUCCESS - On success.
  3821. NTSTATUS - Otherwise.
  3822. --*/
  3823. {
  3824. PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord;
  3825. ULONG_PTR Checksum;
  3826. ULONG Index;
  3827. PLIST_ENTRY LastEntry;
  3828. PLIST_ENTRY ListHead;
  3829. PLIST_ENTRY NextEntry;
  3830. PUCHAR Source;
  3831. //
  3832. // If the bug check callback listhead is not initialized, then the
  3833. // bug check has occured before the system has gotten far enough
  3834. // in the initialization code to enable anyone to register a callback.
  3835. //
  3836. ListHead = &KeBugCheckReasonCallbackListHead;
  3837. if (ListHead->Flink == NULL || ListHead->Blink == NULL) {
  3838. return STATUS_SUCCESS;
  3839. }
  3840. //
  3841. // Scan the bug check callback list.
  3842. //
  3843. LastEntry = ListHead;
  3844. NextEntry = ListHead->Flink;
  3845. while (NextEntry != ListHead) {
  3846. //
  3847. // The next entry address must be aligned properly, the
  3848. // callback record must be readable, and the callback record
  3849. // must have back link to the last entry.
  3850. //
  3851. if (((ULONG_PTR)NextEntry & (sizeof(ULONG_PTR) - 1)) != 0) {
  3852. return STATUS_DATATYPE_MISALIGNMENT;
  3853. }
  3854. CallbackRecord = CONTAINING_RECORD(NextEntry,
  3855. KBUGCHECK_REASON_CALLBACK_RECORD,
  3856. Entry);
  3857. Source = (PUCHAR)CallbackRecord;
  3858. for (Index = 0; Index < sizeof(*CallbackRecord); Index += 1) {
  3859. if (MmIsAddressValid((PVOID)Source) == FALSE) {
  3860. return STATUS_PARTIAL_COPY;
  3861. }
  3862. Source += 1;
  3863. }
  3864. if (CallbackRecord->Entry.Blink != LastEntry) {
  3865. return STATUS_INVALID_PARAMETER;
  3866. }
  3867. LastEntry = NextEntry;
  3868. NextEntry = NextEntry->Flink;
  3869. //
  3870. // If the callback record has a state of inserted and the
  3871. // computed checksum matches the callback record checksum,
  3872. // then call the specified bug check callback routine.
  3873. //
  3874. Checksum = (ULONG_PTR)CallbackRecord->CallbackRoutine;
  3875. Checksum += (ULONG_PTR)CallbackRecord->Reason;
  3876. Checksum += (ULONG_PTR)CallbackRecord->Component;
  3877. if ((CallbackRecord->State != BufferInserted) ||
  3878. (CallbackRecord->Checksum != Checksum) ||
  3879. (CallbackRecord->Reason != KbCallbackDumpIo) ||
  3880. MmIsAddressValid((PVOID)(ULONG_PTR)CallbackRecord->
  3881. CallbackRoutine) == FALSE) {
  3882. continue;
  3883. }
  3884. //
  3885. // Call the specified bug check callback routine and
  3886. // handle any exceptions that occur.
  3887. //
  3888. try {
  3889. KBUGCHECK_DUMP_IO CbArgument;
  3890. // Currently we aren't allowing arbitrary I/O
  3891. // so always use the special sequential I/O offset.
  3892. CbArgument.Offset = (ULONG64)-1;
  3893. CbArgument.Buffer = Buffer;
  3894. CbArgument.BufferLength = BufferLength;
  3895. CbArgument.Type = Type;
  3896. (CallbackRecord->CallbackRoutine)(KbCallbackDumpIo,
  3897. CallbackRecord,
  3898. &CbArgument,
  3899. sizeof(CbArgument));
  3900. if (Type == KbDumpIoComplete) {
  3901. CallbackRecord->State = BufferFinished;
  3902. }
  3903. } except(EXCEPTION_EXECUTE_HANDLER) {
  3904. CallbackRecord->State = BufferIncomplete;
  3905. }
  3906. }
  3907. return STATUS_SUCCESS;
  3908. }
  3909. NTSTATUS
  3910. IopCompleteDumpInitialization(
  3911. IN HANDLE FileHandle
  3912. )
  3913. /*++
  3914. Routine Description:
  3915. This routine is invoked after the dump file is created.
  3916. The purpose is to obtain the retrieval pointers so that they can then be
  3917. used later to write the dump. The last step is to checksum the
  3918. IopDumpControlBlock.
  3919. Fields in the IopDumpControlBlock are updated if necessary and the
  3920. IopDumpControlBlockChecksum is initialized.
  3921. This is the final step in dump initialization.
  3922. Arguments:
  3923. FileHandle - Handle to the dump file just created.
  3924. Return Value:
  3925. STATUS_SUCCESS - Indicates success.
  3926. Other NTSTATUS - Failure.
  3927. --*/
  3928. {
  3929. NTSTATUS Status;
  3930. NTSTATUS ErrorToLog;
  3931. ULONG i;
  3932. LARGE_INTEGER RequestedFileSize;
  3933. PLARGE_INTEGER mcb;
  3934. PFILE_OBJECT FileObject;
  3935. PDEVICE_OBJECT DeviceObject;
  3936. IO_STATUS_BLOCK IoStatusBlock;
  3937. FILE_STANDARD_INFORMATION StandardFileInfo;
  3938. ULONG MaxSecondaryData;
  3939. ULONG MaxSecondaryCbData;
  3940. Status = STATUS_UNSUCCESSFUL;
  3941. ErrorToLog = STATUS_SUCCESS; // No error
  3942. FileObject = NULL;
  3943. DeviceObject = NULL;
  3944. Status = ObReferenceObjectByHandle( FileHandle,
  3945. 0,
  3946. IoFileObjectType,
  3947. KernelMode,
  3948. (PVOID *) &FileObject,
  3949. NULL
  3950. );
  3951. if ( !NT_SUCCESS (Status) ) {
  3952. ASSERT (FALSE);
  3953. goto Cleanup;
  3954. }
  3955. DeviceObject = FileObject->DeviceObject;
  3956. //
  3957. // If this device object represents the boot partition then query
  3958. // the retrieval pointers for the file.
  3959. //
  3960. if ( !(DeviceObject->Flags & DO_SYSTEM_BOOT_PARTITION) ) {
  3961. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  3962. CRASHDUMP_ERROR,
  3963. "CRASHDUMP: Cannot dump to pagefile on non-system partition.\n"
  3964. " DO = %p\n",
  3965. DeviceObject));
  3966. goto Cleanup;
  3967. }
  3968. Status = ZwQueryInformationFile(
  3969. FileHandle,
  3970. &IoStatusBlock,
  3971. &StandardFileInfo,
  3972. sizeof (StandardFileInfo),
  3973. FileStandardInformation
  3974. );
  3975. if (Status == STATUS_PENDING) {
  3976. Status = KeWaitForSingleObject( &FileObject->Event,
  3977. Executive,
  3978. KernelMode,
  3979. FALSE,
  3980. NULL
  3981. );
  3982. Status = IoStatusBlock.Status;
  3983. }
  3984. if ( !NT_SUCCESS (Status) ) {
  3985. goto Cleanup;
  3986. }
  3987. //
  3988. // Ask for as much space as needed for the basic dump
  3989. // plus extra space for secondary dump data.
  3990. //
  3991. RequestedFileSize = IopDumpControlBlock->DumpFileSize;
  3992. IopGetSecondaryDumpDataLimits(IopDumpControlBlock->Flags,
  3993. &MaxSecondaryData, &MaxSecondaryCbData);
  3994. if ((ULONG64)-1 - RequestedFileSize.QuadPart < MaxSecondaryData) {
  3995. RequestedFileSize.QuadPart = (ULONG64)-1;
  3996. } else {
  3997. RequestedFileSize.QuadPart += MaxSecondaryData;
  3998. }
  3999. //
  4000. // Do not ask for more space than is in the pagefile.
  4001. //
  4002. if (RequestedFileSize.QuadPart > StandardFileInfo.EndOfFile.QuadPart) {
  4003. RequestedFileSize = StandardFileInfo.EndOfFile;
  4004. }
  4005. Status = ZwFsControlFile(
  4006. FileHandle,
  4007. NULL,
  4008. NULL,
  4009. NULL,
  4010. &IoStatusBlock,
  4011. FSCTL_QUERY_RETRIEVAL_POINTERS,
  4012. &RequestedFileSize,
  4013. sizeof( LARGE_INTEGER ),
  4014. &mcb,
  4015. sizeof( PVOID )
  4016. );
  4017. if (Status == STATUS_PENDING) {
  4018. Status = KeWaitForSingleObject( &FileObject->Event,
  4019. Executive,
  4020. KernelMode,
  4021. FALSE,
  4022. NULL );
  4023. Status = IoStatusBlock.Status;
  4024. }
  4025. //
  4026. // NOTE: If you fail here, put a BP on ntfs!NtfsQueryRetrievalPointers
  4027. // or FatQueryRetrievalPointers and see why you failed.
  4028. //
  4029. if ( !NT_SUCCESS (Status) ) {
  4030. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  4031. CRASHDUMP_ERROR,
  4032. "CRASHDUMP: ZwFsControlFile returnd %d\n"
  4033. " File = %p\n",
  4034. FileObject,
  4035. Status
  4036. ));
  4037. ErrorToLog = IO_DUMP_POINTER_FAILURE;
  4038. goto Cleanup;
  4039. }
  4040. //
  4041. // This paging file is on the system boot partition, and
  4042. // the retrieval pointers for the file were just successfully
  4043. // queried. Walk the MCB to size it, and then checksum it.
  4044. //
  4045. for (i = 0; mcb [i].QuadPart; i++) {
  4046. NOTHING;
  4047. }
  4048. //
  4049. // Write back fields of the IopDumpControlBlock.
  4050. //
  4051. IopDumpControlBlock->FileDescriptorArray = mcb;
  4052. IopDumpControlBlock->FileDescriptorSize = (i + 1) * sizeof (LARGE_INTEGER);
  4053. IopDumpControlBlock->DumpFileSize = RequestedFileSize;
  4054. IopDumpControlBlockChecksum = IopGetDumpControlBlockCheck ( IopDumpControlBlock );
  4055. Status = STATUS_SUCCESS;
  4056. Cleanup:
  4057. if (Status != STATUS_SUCCESS &&
  4058. ErrorToLog != STATUS_SUCCESS ) {
  4059. IopLogErrorEvent (0,
  4060. 4,
  4061. STATUS_SUCCESS,
  4062. ErrorToLog,
  4063. 0,
  4064. NULL,
  4065. 0,
  4066. NULL
  4067. );
  4068. }
  4069. DeviceObject = NULL;
  4070. if ( FileObject ) {
  4071. ObDereferenceObject( FileObject );
  4072. FileObject = NULL;
  4073. }
  4074. return Status;
  4075. }
  4076. VOID
  4077. IopFreeDCB(
  4078. BOOLEAN FreeDCB
  4079. )
  4080. /*++
  4081. Routine Description:
  4082. Free dump control block storage.
  4083. Arguments:
  4084. FreeDCB - Implictly free storage for the dump control block.
  4085. Return Value:
  4086. None
  4087. --*/
  4088. {
  4089. PDUMP_CONTROL_BLOCK dcb;
  4090. dcb = IopDumpControlBlock;
  4091. if (dcb) {
  4092. if (dcb->HeaderPage) {
  4093. ExFreePool (dcb->HeaderPage);
  4094. dcb->HeaderPage = NULL;
  4095. }
  4096. if (dcb->FileDescriptorArray) {
  4097. ExFreePool (dcb->FileDescriptorArray);
  4098. dcb->FileDescriptorArray = NULL;
  4099. }
  4100. if (dcb->DumpStack) {
  4101. IoFreeDumpStack (dcb->DumpStack);
  4102. dcb->DumpStack = NULL;
  4103. }
  4104. if (dcb->TriageDumpBuffer) {
  4105. ExFreePool (dcb->TriageDumpBuffer);
  4106. dcb->TriageDumpBuffer = NULL;
  4107. dcb->TriageDumpBufferSize = 0;
  4108. }
  4109. //
  4110. // Disable all options that require dump file access
  4111. //
  4112. dcb->Flags = 0;
  4113. if (FreeDCB) {
  4114. IopDumpControlBlock = NULL;
  4115. ExFreePool( dcb );
  4116. }
  4117. }
  4118. }
  4119. NTSTATUS
  4120. IoConfigureCrashDump(
  4121. CRASHDUMP_CONFIGURATION Configuration
  4122. )
  4123. /*++
  4124. Routine Description:
  4125. Change the configuration of the crashdump for this machine.
  4126. Arguments:
  4127. Configuration - What to change the configuration to.
  4128. CrashDumpDisable - Disable crashdumps for this machine.
  4129. CrashDumpReconfigure - Reread crashdump settings from the
  4130. registry and apply them.
  4131. Return Value:
  4132. NTSTATUS code.
  4133. --*/
  4134. {
  4135. NTSTATUS Status;
  4136. HANDLE FileHandle;
  4137. PKTHREAD CurrentThread;
  4138. CurrentThread = KeGetCurrentThread ();
  4139. KeEnterCriticalRegionThread(CurrentThread);
  4140. switch (Configuration) {
  4141. case CrashDumpDisable:
  4142. if (ExAcquireResourceExclusiveLite(&IopCrashDumpLock, FALSE)) {
  4143. IopFreeDCB (FALSE);
  4144. ExReleaseResourceLite(&IopCrashDumpLock);
  4145. }
  4146. Status = STATUS_SUCCESS;
  4147. break;
  4148. case CrashDumpReconfigure:
  4149. FileHandle = MmGetSystemPageFile();
  4150. if (FileHandle == NULL) {
  4151. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  4152. } else {
  4153. ExAcquireResourceExclusiveLite(&IopCrashDumpLock,TRUE);
  4154. if (IoInitializeCrashDump(FileHandle)) {
  4155. Status = STATUS_SUCCESS;
  4156. } else {
  4157. Status = STATUS_UNSUCCESSFUL;
  4158. }
  4159. ExReleaseResourceLite(&IopCrashDumpLock);
  4160. }
  4161. break;
  4162. default:
  4163. Status = STATUS_INVALID_DEVICE_REQUEST;
  4164. }
  4165. KeLeaveCriticalRegionThread(CurrentThread);
  4166. return Status;
  4167. }
  4168. VOID
  4169. IopReadDumpRegistry(
  4170. OUT PULONG dumpControl,
  4171. OUT PULONG numberOfHeaderPages,
  4172. OUT PULONG autoReboot,
  4173. OUT PULONG dumpFileSize
  4174. )
  4175. /*++
  4176. Routine Description:
  4177. This routine reads the dump parameters from the registry.
  4178. Arguments:
  4179. dumpControl - Supplies a pointer to the dumpControl flags to set.
  4180. Return Value:
  4181. None.
  4182. --*/
  4183. {
  4184. HANDLE keyHandle;
  4185. HANDLE crashHandle;
  4186. LOGICAL crashHandleOpened;
  4187. UNICODE_STRING keyName;
  4188. NTSTATUS status;
  4189. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  4190. ULONG handleValue;
  4191. *dumpControl = 0;
  4192. *autoReboot = 0;
  4193. *dumpFileSize = 0;
  4194. *numberOfHeaderPages = BYTES_TO_PAGES(sizeof(DUMP_HEADER));
  4195. //
  4196. // Begin by opening the path to the control for dumping memory. Note
  4197. // that if it does not exist, then no dumps will occur.
  4198. //
  4199. crashHandleOpened = FALSE;
  4200. RtlInitUnicodeString( &keyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control" );
  4201. status = IopOpenRegistryKey( &keyHandle,
  4202. (HANDLE) NULL,
  4203. &keyName,
  4204. KEY_READ,
  4205. FALSE );
  4206. if (!NT_SUCCESS( status )) {
  4207. return;
  4208. }
  4209. RtlInitUnicodeString( &keyName, L"CrashControl" );
  4210. status = IopOpenRegistryKey( &crashHandle,
  4211. keyHandle,
  4212. &keyName,
  4213. KEY_READ,
  4214. FALSE );
  4215. ObCloseHandle( keyHandle , KernelMode);
  4216. if (!NT_SUCCESS( status )) {
  4217. return;
  4218. }
  4219. crashHandleOpened = TRUE;
  4220. //
  4221. // Now get the value of the crash control to determine whether or not
  4222. // dumping is enabled.
  4223. //
  4224. status = IopGetRegistryValue( crashHandle,
  4225. L"CrashDumpEnabled",
  4226. &keyValueInformation );
  4227. if (NT_SUCCESS (status)) {
  4228. if (keyValueInformation->DataLength) {
  4229. handleValue = * ((PULONG) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset));
  4230. ExFreePool( keyValueInformation );
  4231. if (handleValue) {
  4232. *dumpControl |= DCB_DUMP_ENABLED;
  4233. if ( handleValue == 3 ) {
  4234. *dumpControl |= DCB_TRIAGE_DUMP_ENABLED;
  4235. } else if ( handleValue == 4 ) {
  4236. *dumpControl |= ( DCB_TRIAGE_DUMP_ENABLED | DCB_TRIAGE_DUMP_ACT_UPON_ENABLED );
  4237. } else if ( handleValue == 2 ) {
  4238. PPHYSICAL_MEMORY_RUN LastRun;
  4239. *dumpControl |= DCB_SUMMARY_DUMP_ENABLED;
  4240. //
  4241. // Allocate enough storage for the dump header, summary
  4242. // dump header and bitmap.
  4243. //
  4244. LastRun = MmPhysicalMemoryBlock->Run +
  4245. (MmPhysicalMemoryBlock->NumberOfRuns - 1);
  4246. *numberOfHeaderPages = (ULONG) BYTES_TO_PAGES(
  4247. sizeof(DUMP_HEADER) +
  4248. ( LastRun->BasePage + LastRun->PageCount + 7) / 8 +
  4249. sizeof (SUMMARY_DUMP));
  4250. }
  4251. }
  4252. }
  4253. }
  4254. status = IopGetRegistryValue( crashHandle,
  4255. L"LogEvent",
  4256. &keyValueInformation );
  4257. if (NT_SUCCESS( status )) {
  4258. if (keyValueInformation->DataLength) {
  4259. handleValue = * ((PULONG) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset));
  4260. ExFreePool( keyValueInformation);
  4261. if (handleValue) {
  4262. *dumpControl |= DCB_SUMMARY_ENABLED;
  4263. }
  4264. }
  4265. }
  4266. status = IopGetRegistryValue( crashHandle,
  4267. L"SendAlert",
  4268. &keyValueInformation );
  4269. if (NT_SUCCESS( status )) {
  4270. if (keyValueInformation->DataLength) {
  4271. handleValue = * ((PULONG) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset));
  4272. ExFreePool( keyValueInformation);
  4273. if (handleValue) {
  4274. *dumpControl |= DCB_SUMMARY_ENABLED;
  4275. }
  4276. }
  4277. }
  4278. //
  4279. // Now determine whether or not automatic reboot is enabled.
  4280. //
  4281. status = IopGetRegistryValue( crashHandle,
  4282. L"AutoReboot",
  4283. &keyValueInformation );
  4284. if (NT_SUCCESS( status )) {
  4285. if (keyValueInformation->DataLength) {
  4286. *autoReboot = * ((PULONG) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset));
  4287. }
  4288. ExFreePool( keyValueInformation );
  4289. }
  4290. //
  4291. // If we aren't auto rebooting or crashing then return now.
  4292. //
  4293. if (*dumpControl == 0 && *autoReboot == 0) {
  4294. if (crashHandleOpened == TRUE) {
  4295. ObCloseHandle( crashHandle , KernelMode);
  4296. }
  4297. return;
  4298. }
  4299. status = IopGetRegistryValue( crashHandle,
  4300. L"DumpFileSize",
  4301. &keyValueInformation );
  4302. if (NT_SUCCESS( status )) {
  4303. if (keyValueInformation->DataLength) {
  4304. *dumpFileSize = * ((PULONG) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset));
  4305. }
  4306. ExFreePool( keyValueInformation );
  4307. }
  4308. ObCloseHandle(crashHandle, KernelMode);
  4309. return;
  4310. }
  4311. BOOLEAN
  4312. IopInitializeDCB(
  4313. )
  4314. /*++
  4315. Routine Description:
  4316. This routine initializes the Dump Control Block (DCB). It allocates the
  4317. DCB and reads the crashdump parameters from the registry.
  4318. Arguments:
  4319. Return Value:
  4320. The final function value is TRUE if everything worked, else FALSE.
  4321. --*/
  4322. {
  4323. PDUMP_CONTROL_BLOCK dcb;
  4324. ULONG dumpControl;
  4325. ULONG dcbSize;
  4326. LARGE_INTEGER page;
  4327. ULONG numberOfHeaderPages;
  4328. ULONG dumpFileSize;
  4329. //
  4330. // Read all the registry default values first.
  4331. //
  4332. IopReadDumpRegistry ( &dumpControl,
  4333. &numberOfHeaderPages,
  4334. &IopAutoReboot,
  4335. &dumpFileSize);
  4336. //
  4337. // If we aren't crashing or auto rebooting then return now.
  4338. //
  4339. if (dumpControl == 0 && IopAutoReboot == 0) {
  4340. //
  4341. // At some point, we will conditionally on system size, type, etc,
  4342. // set dump defaults like the below and skip over the return.
  4343. //
  4344. // *dumpControl = (DCB_DUMP_ENABLED | DCB_TRIAGE_DUMP_ENABLED);
  4345. // *IopAutoReboot = 1;
  4346. // *dumpFileSize = ?
  4347. //
  4348. return TRUE;
  4349. }
  4350. if (dumpControl & DCB_TRIAGE_DUMP_ENABLED) {
  4351. dumpControl &= ~DCB_SUMMARY_ENABLED;
  4352. dumpFileSize = TRIAGE_DUMP_SIZE;
  4353. }
  4354. //
  4355. // Allocate and initialize the structures necessary to describe and control
  4356. // the post-bugcheck code.
  4357. //
  4358. dcbSize = sizeof( DUMP_CONTROL_BLOCK ) + sizeof( MINIPORT_NODE );
  4359. dcb = ExAllocatePool( NonPagedPool, dcbSize );
  4360. if (!dcb) {
  4361. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  4362. CRASHDUMP_ERROR,
  4363. "CRASHDUMP: Not enough pool to allocate DCB %d\n",
  4364. __LINE__
  4365. ));
  4366. IopLogErrorEvent(0,1,STATUS_SUCCESS,IO_DUMP_INITIALIZATION_FAILURE,0,NULL,0,NULL);
  4367. return FALSE;
  4368. }
  4369. RtlZeroMemory( dcb, dcbSize );
  4370. dcb->Type = IO_TYPE_DCB;
  4371. dcb->Size = (USHORT) dcbSize;
  4372. dcb->Flags = (UCHAR) dumpControl;
  4373. dcb->NumberProcessors = KeNumberProcessors;
  4374. dcb->ProcessorArchitecture = KeProcessorArchitecture;
  4375. dcb->MinorVersion = (USHORT) NtBuildNumber;
  4376. dcb->MajorVersion = (USHORT) ((NtBuildNumber >> 28) & 0xfffffff);
  4377. dcb->BuildNumber = CmNtCSDVersion;
  4378. dcb->TriageDumpFlags = TRIAGE_DUMP_BASIC_INFO | TRIAGE_DUMP_MMINFO |
  4379. TRIAGE_DUMP_DEBUGGER_DATA | TRIAGE_DUMP_DATA_BLOCKS;
  4380. dcb->DumpFileSize.QuadPart = dumpFileSize;
  4381. //
  4382. // Allocate header page.
  4383. //
  4384. dcb->HeaderSize = numberOfHeaderPages * PAGE_SIZE;
  4385. dcb->HeaderPage = ExAllocatePool( NonPagedPool, dcb->HeaderSize );
  4386. if (!dcb->HeaderPage) {
  4387. ExFreePool (dcb);
  4388. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  4389. CRASHDUMP_ERROR,
  4390. "CRASHDUMP: Not enough pool to allocate DCB %d\n",
  4391. __LINE__
  4392. ));
  4393. IopLogErrorEvent(0,1,STATUS_SUCCESS,IO_DUMP_INITIALIZATION_FAILURE,0,NULL,0,NULL);
  4394. return FALSE;
  4395. }
  4396. page = MmGetPhysicalAddress( dcb->HeaderPage );
  4397. dcb->HeaderPfn = (ULONG)(page.QuadPart >> PAGE_SHIFT);
  4398. //
  4399. // Allocate the triage-dump buffer.
  4400. //
  4401. if (dumpControl & DCB_TRIAGE_DUMP_ENABLED) {
  4402. dcb->TriageDumpBuffer = ExAllocatePool (
  4403. NonPagedPool,
  4404. dumpFileSize
  4405. );
  4406. if (!dcb->TriageDumpBuffer) {
  4407. ExFreePool (dcb->HeaderPage);
  4408. ExFreePool (dcb);
  4409. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  4410. CRASHDUMP_ERROR,
  4411. "CRASHDUMP: Not enough pool to allocate DCB %d\n",
  4412. __LINE__
  4413. ));
  4414. IopLogErrorEvent(0,1,STATUS_SUCCESS,IO_DUMP_INITIALIZATION_FAILURE,0,NULL,0,NULL);
  4415. return FALSE;
  4416. }
  4417. dcb->TriageDumpBufferSize = dumpFileSize;
  4418. }
  4419. IopDumpControlBlock = dcb;
  4420. return TRUE;
  4421. }
  4422. BOOLEAN
  4423. IoInitializeCrashDump(
  4424. IN HANDLE hPageFile
  4425. )
  4426. /*++
  4427. Routine Description:
  4428. This routine configures the system for crash dump. The following things
  4429. are done:
  4430. 1. Initialize the dump control block and init registry crashdump
  4431. parameters.
  4432. 2. Configure either page or fast dump.
  4433. 3. Complete dump file initialization.
  4434. This routine is called as each page file is created. A return value of
  4435. TRUE tells the caller (i.e., NtCreatePagingFiles, IoPageFileCreated)
  4436. that crash dump has been configured.
  4437. Arguments:
  4438. hPageFile - Handle to the paging file
  4439. Return Value:
  4440. TRUE - Configuration complete (or crash dump not enabled).
  4441. FALSE - Error, retry PageFile is not on boot partition.
  4442. --*/
  4443. {
  4444. NTSTATUS dwStatus;
  4445. PFILE_OBJECT fileObject;
  4446. PDEVICE_OBJECT deviceObject;
  4447. //
  4448. // If crashdump is already enabled, free it and reinitialize with the
  4449. // current settings.
  4450. //
  4451. IopFreeDCB (TRUE);
  4452. if (!IopInitializeDCB()) {
  4453. return TRUE;
  4454. }
  4455. //
  4456. // Return crash dump not enabled
  4457. //
  4458. if (!IopDumpControlBlock) {
  4459. return TRUE;
  4460. }
  4461. //
  4462. // No dump enabled?
  4463. //
  4464. if ( !( IopDumpControlBlock->Flags & (DCB_DUMP_ENABLED | DCB_SUMMARY_ENABLED) ) ) {
  4465. return TRUE;
  4466. }
  4467. //
  4468. // Configure the paging file for crash dump.
  4469. //
  4470. dwStatus = ObReferenceObjectByHandle(
  4471. hPageFile,
  4472. 0,
  4473. IoFileObjectType,
  4474. KernelMode,
  4475. (PVOID *) &fileObject,
  4476. NULL
  4477. );
  4478. if (!NT_SUCCESS( dwStatus )) {
  4479. goto error_return;
  4480. }
  4481. //
  4482. // Get a pointer to the device object for this file. Note that it
  4483. // cannot go away, since there is an open handle to it, so it is
  4484. // OK to dereference it and then use it.
  4485. //
  4486. deviceObject = fileObject->DeviceObject;
  4487. ObDereferenceObject( fileObject );
  4488. //
  4489. // This should never be called on devices that are not the boot partition
  4490. //
  4491. ASSERT(deviceObject->Flags & DO_SYSTEM_BOOT_PARTITION);
  4492. //
  4493. // Load paging file dump stack
  4494. //
  4495. dwStatus = IoGetDumpStack (L"dump_",
  4496. &IopDumpControlBlock->DumpStack,
  4497. DeviceUsageTypeDumpFile,
  4498. FALSE);
  4499. if (!NT_SUCCESS(dwStatus)) {
  4500. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  4501. CRASHDUMP_ERROR,
  4502. "CRASHDUMP: Could not load dump stack status = %x\n",
  4503. dwStatus
  4504. ));
  4505. goto error_return;
  4506. }
  4507. IopDumpControlBlock->DumpStack->Init.CrashDump = TRUE;
  4508. IopDumpControlBlock->DumpStack->Init.MemoryBlock = ExAllocatePool (
  4509. NonPagedPool,
  4510. IO_DUMP_MEMORY_BLOCK_PAGES * PAGE_SIZE
  4511. );
  4512. if (!IopDumpControlBlock->DumpStack->Init.MemoryBlock) {
  4513. dwStatus = STATUS_NO_MEMORY;
  4514. goto error_return;
  4515. }
  4516. //
  4517. // Calculate the amount of space required for the dump
  4518. //
  4519. IopDumpControlBlock->DumpFileSize =
  4520. IopCalculateRequiredDumpSpace(
  4521. IopDumpControlBlock->Flags,
  4522. IopDumpControlBlock->HeaderSize,
  4523. MmPhysicalMemoryBlock->NumberOfPages,
  4524. MmPhysicalMemoryBlock->NumberOfPages,
  4525. TRUE
  4526. );
  4527. //
  4528. // Complete dump initialization
  4529. //
  4530. dwStatus = IopCompleteDumpInitialization(hPageFile);
  4531. error_return:
  4532. //
  4533. // The BOOT partition paging file could not be configured.
  4534. // 1. Log an error message
  4535. // 2. Return TRUE so that MM does not try again
  4536. //
  4537. if (!NT_SUCCESS(dwStatus)) {
  4538. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  4539. CRASHDUMP_ERROR,
  4540. "CRASHDUMP: Page File dump init FAILED status = %x\n",
  4541. dwStatus
  4542. ));
  4543. IopLogErrorEvent(0, 3, STATUS_SUCCESS, IO_DUMP_PAGE_CONFIG_FAILED, 0, NULL, 0, NULL);
  4544. //
  4545. // ISSUE - 2000/02/07 - math: IopFreeDCB probably wrong.
  4546. //
  4547. // Is the call to IopFreeDCB() correct here? Doesn't this prevent
  4548. // other dump types from working properly? Review this.
  4549. //
  4550. IopFreeDCB(FALSE);
  4551. }
  4552. return TRUE;
  4553. }
  4554. #define TRIAGE_DUMP_DATA_SIZE (TRIAGE_DUMP_SIZE - sizeof(ULONG))
  4555. static
  4556. BOOLEAN
  4557. IopValidateSectionSize(
  4558. ULONG Offset,
  4559. ULONG* pSectionSize
  4560. )
  4561. /*++
  4562. Routine Description:
  4563. Checks whether specified section size will overflow the dump buffer
  4564. (used just for creation of live minidumps)
  4565. Arguments:
  4566. Offset - Section offset
  4567. pSectionSize - Section size (will be changed to fit the dump)
  4568. pbOverflow - used to return the overflow status
  4569. Return Value:
  4570. TRUE - if the section fits the dump, otherwise section size will decreased
  4571. and FALSE will be returned
  4572. --*/
  4573. {
  4574. if ((Offset + *pSectionSize) < TRIAGE_DUMP_DATA_SIZE) return TRUE;
  4575. *pSectionSize = (Offset < TRIAGE_DUMP_DATA_SIZE) ?
  4576. (TRIAGE_DUMP_DATA_SIZE - Offset) : 0;
  4577. return FALSE;
  4578. }
  4579. static
  4580. ULONG
  4581. IopGetMaxValidSectionSize(
  4582. ULONG_PTR Base,
  4583. ULONG MaxSize
  4584. )
  4585. /*++
  4586. Routine Description:
  4587. Gets maximum valid memory section size less than SectionMaxSize
  4588. Arguments:
  4589. Base - beginning of the section
  4590. MaxSize - Maximum size of the section
  4591. Return Value:
  4592. Size of the continuously valid memory starting from SectionBase up to
  4593. SectionMaxSize
  4594. --*/
  4595. {
  4596. ULONG Size = 0;
  4597. // XXX olegk - optimize it later to iterate by page size
  4598. while ((Size < MaxSize) && (MmIsAddressValid((PVOID)(Base + Size))))
  4599. ++Size;
  4600. return Size;
  4601. }
  4602. static
  4603. ULONG
  4604. IopGetMaxValidSectionSizeDown(
  4605. ULONG_PTR Base,
  4606. ULONG MaxSize
  4607. )
  4608. /*++
  4609. Routine Description:
  4610. Gets maximum valid memory section size less than SectionMaxSize
  4611. Arguments:
  4612. Base - End of the section
  4613. MaxSize - Maximum size of the section
  4614. Return Value:
  4615. Size of the continuously valid memory ending at SectionBase downto to
  4616. SectionMaxSize
  4617. --*/
  4618. {
  4619. ULONG Size = 0;
  4620. if ((ULONG_PTR)Base < (ULONG_PTR)MaxSize) MaxSize = (ULONG)Base;
  4621. // XXX olegk - optimize it later to iterate by page size
  4622. while ((Size < MaxSize) && (MmIsAddressValid((PVOID)(Base - Size))))
  4623. ++Size;
  4624. return Size;
  4625. }
  4626. ULONG
  4627. KeCapturePersistentThreadState(
  4628. PCONTEXT pContext,
  4629. PETHREAD pThread,
  4630. ULONG ulBugCheckCode,
  4631. ULONG_PTR ulpBugCheckParam1,
  4632. ULONG_PTR ulpBugCheckParam2,
  4633. ULONG_PTR ulpBugCheckParam3,
  4634. ULONG_PTR ulpBugCheckParam4,
  4635. PVOID pvDump
  4636. )
  4637. /*++
  4638. Routine Description:
  4639. Creates main portion of the minidump in the specified buffer
  4640. This function can be used to crate live minidump (originaly designed to
  4641. work with EA recovery for video drivers)
  4642. Arguments:
  4643. pContext - context of failed thread
  4644. pThread - failed thread object (NULL means current thread)
  4645. ulBugCheckCode,
  4646. ulpBugCheckParam1,
  4647. ulpBugCheckParam2,
  4648. ulpBugCheckParam3,
  4649. ulpBugCheckParam4 - Bugcheck info
  4650. pModules - List of te loaded modules
  4651. pDump - Memory buffer to write dump context (Size of the buffer should
  4652. be at least TRIAGE_DUMP_SIZE
  4653. Return Value:
  4654. Actual size of the dump file to save on disk (always at least TRIAGE_DUMP_SIZE)
  4655. --*/
  4656. {
  4657. PMEMORY_DUMP pDump = (PMEMORY_DUMP)pvDump;
  4658. PDUMP_HEADER pdh = &(pDump->Header);
  4659. PTRIAGE_DUMP ptdh = &(pDump->Triage);
  4660. ULONG Offset = 0, SectionSize = 0;
  4661. PKDDEBUGGER_DATA64 pKdDebuggerDataBlock = (PKDDEBUGGER_DATA64)KdGetDataBlock();
  4662. PEPROCESS pProcess;
  4663. if (!pvDump) return 0;
  4664. if (!pThread) pThread = PsGetCurrentThread();
  4665. pProcess = (PEPROCESS)pThread->Tcb.ApcState.Process;
  4666. RtlZeroMemory(pDump, TRIAGE_DUMP_SIZE);
  4667. //
  4668. // Fill the dump header with signature
  4669. //
  4670. RtlFillMemoryUlong(pdh, sizeof(*pdh), DUMP_SIGNATURE);
  4671. pdh->Signature = DUMP_SIGNATURE;
  4672. pdh->ValidDump = DUMP_VALID_DUMP;
  4673. pdh->MinorVersion = (USHORT) NtBuildNumber;
  4674. pdh->MajorVersion = (USHORT) ((NtBuildNumber >> 28) & 0xfffffff);
  4675. #if defined (_IA64_)
  4676. pdh->DirectoryTableBase = MmSystemParentTablePage << PAGE_SHIFT;
  4677. #else
  4678. pdh->DirectoryTableBase = pThread->Tcb.ApcState.Process->DirectoryTableBase[0];
  4679. #endif
  4680. pdh->PfnDataBase = (ULONG_PTR)MmPfnDatabase;
  4681. pdh->PsLoadedModuleList = (ULONG_PTR)&PsLoadedModuleList;
  4682. pdh->PsActiveProcessHead = (ULONG_PTR)&PsActiveProcessHead;
  4683. pdh->MachineImageType = CURRENT_IMAGE_TYPE();
  4684. pdh->NumberProcessors = KeNumberProcessors;
  4685. pdh->BugCheckCode = ulBugCheckCode;
  4686. pdh->BugCheckParameter1 = ulpBugCheckParam1;
  4687. pdh->BugCheckParameter2 = ulpBugCheckParam2;
  4688. pdh->BugCheckParameter3 = ulpBugCheckParam3;
  4689. pdh->BugCheckParameter4 = ulpBugCheckParam4;
  4690. #if defined (_X86_)
  4691. pdh->PaeEnabled = X86PaeEnabled ();
  4692. #endif
  4693. pdh->Exception.ExceptionCode = STATUS_BREAKPOINT; // XXX olegk - ???
  4694. pdh->Exception.ExceptionRecord = 0;
  4695. pdh->Exception.NumberParameters = 0;
  4696. pdh->Exception.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
  4697. pdh->Exception.ExceptionAddress = PROGRAM_COUNTER (pContext);
  4698. pdh->RequiredDumpSpace.QuadPart = TRIAGE_DUMP_SIZE;
  4699. pdh->SystemTime.LowPart = SharedUserData->SystemTime.LowPart;
  4700. pdh->SystemTime.HighPart = SharedUserData->SystemTime.High1Time;
  4701. pdh->SystemUpTime.LowPart = SharedUserData->InterruptTime.LowPart;
  4702. pdh->SystemUpTime.HighPart = SharedUserData->InterruptTime.High1Time;
  4703. pdh->DumpType = DUMP_TYPE_TRIAGE;
  4704. pdh->MiniDumpFields = TRIAGE_DUMP_EXCEPTION |
  4705. TRIAGE_DUMP_BROKEN_DRIVER; // XXX olegk - debugger need it for memory mapping
  4706. pdh->ProductType = SharedUserData->NtProductType;
  4707. pdh->SuiteMask = SharedUserData->SuiteMask;
  4708. //
  4709. // TRIAGE header
  4710. //
  4711. ptdh->TriageOptions = 0;
  4712. ptdh->ServicePackBuild = CmNtCSDVersion;
  4713. ptdh->SizeOfDump = TRIAGE_DUMP_SIZE;
  4714. ptdh->ExceptionOffset = FIELD_OFFSET(DUMP_HEADER, Exception);
  4715. ptdh->BrokenDriverOffset = 0;
  4716. Offset = sizeof(DUMP_HEADER) + sizeof(TRIAGE_DUMP);
  4717. //
  4718. // Context
  4719. //
  4720. pdh->MiniDumpFields |= TRIAGE_DUMP_CONTEXT;
  4721. ptdh->ContextOffset = FIELD_OFFSET (DUMP_HEADER, ContextRecord);
  4722. RtlCopyMemory(pdh->ContextRecord, pContext, sizeof(CONTEXT));
  4723. //
  4724. // Save debugger data block
  4725. //
  4726. SectionSize = sizeof(KDDEBUGGER_DATA64);
  4727. if (IopValidateSectionSize(ALIGN_8(Offset), &SectionSize)) {
  4728. Offset = ALIGN_8(Offset);
  4729. pdh->MiniDumpFields |= TRIAGE_DUMP_DEBUGGER_DATA;
  4730. pdh->KdDebuggerDataBlock = (LONG_PTR)pKdDebuggerDataBlock;
  4731. ptdh->DebuggerDataOffset = Offset;
  4732. ptdh->DebuggerDataSize = sizeof(KDDEBUGGER_DATA64);
  4733. RtlCopyMemory((char*)pDump + Offset,
  4734. pKdDebuggerDataBlock,
  4735. SectionSize);
  4736. Offset += SectionSize;
  4737. }
  4738. //
  4739. // Write the PRCB.
  4740. //
  4741. SectionSize = sizeof(KPRCB);
  4742. if (IopValidateSectionSize(ALIGN_8(Offset), &SectionSize)) {
  4743. Offset = ALIGN_8(Offset);
  4744. pdh->MiniDumpFields |= TRIAGE_DUMP_PRCB;
  4745. ptdh->PrcbOffset = Offset;
  4746. RtlCopyMemory((char*)pDump + Offset,
  4747. KeGetCurrentPrcb(),
  4748. SectionSize);
  4749. Offset += SectionSize;
  4750. }
  4751. //
  4752. // Write the EPROCESS
  4753. //
  4754. SectionSize = sizeof(EPROCESS);
  4755. if (IopValidateSectionSize(ALIGN_8(Offset), &SectionSize)) {
  4756. Offset = ALIGN_8(Offset);
  4757. pdh->MiniDumpFields |= TRIAGE_DUMP_PROCESS;
  4758. ptdh->ProcessOffset = Offset;
  4759. RtlCopyMemory((char*)pDump + Offset,
  4760. pThread->Tcb.ApcState.Process,
  4761. SectionSize);
  4762. Offset += SectionSize;
  4763. }
  4764. //
  4765. // Write the ETHREAD
  4766. //
  4767. SectionSize = sizeof(ETHREAD);
  4768. if (IopValidateSectionSize(ALIGN_8(Offset), &SectionSize)) {
  4769. Offset = ALIGN_8(Offset);
  4770. pdh->MiniDumpFields |= TRIAGE_DUMP_THREAD;
  4771. ptdh->ThreadOffset = Offset;
  4772. RtlCopyMemory((PUCHAR)pDump + Offset,
  4773. pThread,
  4774. SectionSize);
  4775. Offset += SectionSize;
  4776. }
  4777. //
  4778. // Call Stack (and backing store on ia64)
  4779. //
  4780. if (pThread->Tcb.KernelStackResident) {
  4781. ULONG_PTR StackBase = (ULONG_PTR)pThread->Tcb.StackBase;
  4782. ULONG_PTR StackLimit = (ULONG_PTR)pThread->Tcb.StackLimit;
  4783. ULONG_PTR StackTop = STACK_POINTER(pContext);
  4784. if ((StackLimit > StackTop) || (StackTop >= StackBase))
  4785. StackTop = (ULONG_PTR)pThread->Tcb.StackLimit;
  4786. SectionSize = (StackBase > StackTop) ? (ULONG)(StackBase - StackTop) : 0;
  4787. SectionSize = min(SectionSize, MAX_TRIAGE_STACK_SIZE - 1);
  4788. SectionSize = IopGetMaxValidSectionSize(StackTop, SectionSize);
  4789. if (SectionSize) {
  4790. if (!IopValidateSectionSize(Offset, &SectionSize))
  4791. ptdh->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  4792. pdh->MiniDumpFields |= TRIAGE_DUMP_STACK;
  4793. ptdh->CallStackOffset = Offset;
  4794. ptdh->SizeOfCallStack = SectionSize;
  4795. ptdh->TopOfStack = (LONG_PTR)StackTop;
  4796. RtlCopyMemory((char*)pDump + Offset,
  4797. (char*)StackTop,
  4798. SectionSize);
  4799. Offset += SectionSize;
  4800. }
  4801. #if defined(_IA64_)
  4802. {
  4803. ULONG_PTR BStoreTop = pContext->RsBSP;
  4804. ULONG_PTR BStoreBase = (ULONG_PTR)pThread->Tcb.InitialBStore;
  4805. ULONG_PTR BStoreLimit = (ULONG_PTR)pThread->Tcb.BStoreLimit;
  4806. if ((BStoreBase >= BStoreTop) || (BStoreTop > BStoreLimit))
  4807. BStoreTop = (ULONG_PTR)pThread->Tcb.BStoreLimit;
  4808. SectionSize = (BStoreTop > BStoreBase) ? (ULONG)(BStoreTop - BStoreBase) : 0;
  4809. SectionSize = min(SectionSize, MAX_TRIAGE_STACK_SIZE - 1);
  4810. SectionSize = IopGetMaxValidSectionSizeDown(BStoreTop, SectionSize);
  4811. if (SectionSize) {
  4812. if (!IopValidateSectionSize(Offset, &SectionSize))
  4813. ptdh->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  4814. ptdh->ArchitectureSpecific.Ia64.BStoreOffset = Offset;
  4815. ptdh->ArchitectureSpecific.Ia64.SizeOfBStore = SectionSize;
  4816. ptdh->ArchitectureSpecific.Ia64.LimitOfBStore = (LONG_PTR)BStoreTop;
  4817. RtlCopyMemory((char*)pDump + Offset,
  4818. (char*)BStoreTop - SectionSize + 1,
  4819. SectionSize);
  4820. Offset += SectionSize;
  4821. }
  4822. }
  4823. #endif // defined(_IA64_)
  4824. }
  4825. //
  4826. // Loaded modules list
  4827. //
  4828. {
  4829. ULONG DrvOffset = ALIGN_8(Offset);
  4830. ULONG DrvCount, StrDataSize;
  4831. KIRQL OldIrql;
  4832. OldIrql = KeGetCurrentIrql();
  4833. if (OldIrql < DISPATCH_LEVEL) {
  4834. KeRaiseIrqlToDpcLevel();
  4835. }
  4836. ExAcquireSpinLockAtDpcLevel(&PsLoadedModuleSpinLock);
  4837. if (NT_SUCCESS(IopGetLoadedDriverInfo(&DrvCount, &StrDataSize))) {
  4838. SectionSize = ALIGN_8(DrvCount * sizeof(DUMP_DRIVER_ENTRY));
  4839. if (SectionSize &&
  4840. IopValidateSectionSize(DrvOffset, &SectionSize))
  4841. {
  4842. ULONG StrOffset = DrvOffset + SectionSize;
  4843. SectionSize = ALIGN_8(StrDataSize +
  4844. DrvCount * (sizeof(WCHAR) +
  4845. sizeof(DUMP_STRING)));
  4846. if (SectionSize &&
  4847. IopValidateSectionSize(StrOffset, &SectionSize))
  4848. {
  4849. if (NT_SUCCESS(IopWriteDriverList((ULONG_PTR)pDump,
  4850. TRIAGE_DUMP_DATA_SIZE,
  4851. DrvOffset,
  4852. StrOffset)))
  4853. {
  4854. pdh->MiniDumpFields |= TRIAGE_DUMP_DRIVER_LIST;
  4855. ptdh->DriverListOffset = DrvOffset;
  4856. ptdh->DriverCount = DrvCount;
  4857. ptdh->StringPoolOffset = (ULONG)StrOffset;
  4858. ptdh->StringPoolSize = SectionSize;
  4859. Offset = StrOffset + SectionSize;
  4860. }
  4861. } else {
  4862. ptdh->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  4863. }
  4864. } else {
  4865. ptdh->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  4866. }
  4867. }
  4868. ExReleaseSpinLock(&PsLoadedModuleSpinLock, OldIrql);
  4869. } // Loaded modules list
  4870. //
  4871. // Save some current code
  4872. //
  4873. SectionSize = PAGE_SIZE + sizeof(TRIAGE_DATA_BLOCK);
  4874. IopValidateSectionSize(ALIGN_8(Offset), &SectionSize);
  4875. if (SectionSize > sizeof(TRIAGE_DATA_BLOCK)) {
  4876. ULONG DataSize = SectionSize - sizeof(TRIAGE_DATA_BLOCK);
  4877. ULONG PreIpSize = IopGetMaxValidSectionSizeDown(PROGRAM_COUNTER(pContext),
  4878. DataSize / 2);
  4879. if (PreIpSize) {
  4880. ULONG_PTR CodeStartOffset = PROGRAM_COUNTER(pContext) - PreIpSize + 1;
  4881. DataSize = IopGetMaxValidSectionSize(CodeStartOffset,
  4882. DataSize);
  4883. if (DataSize) {
  4884. PTRIAGE_DATA_BLOCK pDataBlock;
  4885. Offset = ALIGN_8(Offset);
  4886. pdh->MiniDumpFields |= TRIAGE_DUMP_DATA_BLOCKS;
  4887. ptdh->DataBlocksOffset = Offset;
  4888. ptdh->DataBlocksCount = 1;
  4889. pDataBlock = (PTRIAGE_DATA_BLOCK)((char*)pDump + Offset);
  4890. Offset += sizeof(*pDataBlock);
  4891. Offset = ALIGN_8(Offset);
  4892. pDataBlock->Address = (LONG_PTR)CodeStartOffset;
  4893. pDataBlock->Size = DataSize;
  4894. pDataBlock->Offset = Offset;
  4895. RtlCopyMemory((char*)pDump + Offset,
  4896. (char*)CodeStartOffset,
  4897. DataSize);
  4898. Offset += DataSize;
  4899. }
  4900. }
  4901. }
  4902. //
  4903. // End of dump validation
  4904. //
  4905. ptdh->ValidOffset = TRIAGE_DUMP_SIZE - sizeof(ULONG);
  4906. *(PULONG)((char*)pDump + ptdh->ValidOffset) = TRIAGE_DUMP_VALID;
  4907. Offset = TRIAGE_DUMP_SIZE;
  4908. return Offset;
  4909. }