Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

dumpctl.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 dumpctl.c 00008 00009 Abstract: 00010 00011 This module contains the code to dump memory to disk after a crash. 00012 00013 Author: 00014 00015 Darryl E. Havens (darrylh) 17-dec-1993 00016 00017 Environment: 00018 00019 Kernel mode 00020 00021 Revision History: 00022 00023 00024 --*/ 00025 00026 #include "iop.h" 00027 #include "ntddft.h" 00028 #include <inbv.h> 00029 #include <windef.h> 00030 00031 // 00032 // Processor specific macros. 00033 // 00034 00035 #if defined (i386) 00036 00037 #define PROGRAM_COUNTER(_context) ((_context)->Eip) 00038 #define STACK_POINTER(_context) ((_context)->Esp) 00039 #define CURRENT_IMAGE_TYPE() IMAGE_FILE_MACHINE_I386 00040 #define PaeEnabled() X86PaeEnabled() 00041 00042 #elif defined (ALPHA) 00043 00044 #define PROGRAM_COUNTER(_context) ((_context)->Fir) 00045 #define STACK_POINTER(_context) ((_context)->IntSp) 00046 #define CURRENT_IMAGE_TYPE() IMAGE_FILE_MACHINE_ALPHA 00047 #define PaeEnabled() (FALSE) 00048 00049 #elif defined (_IA64_) 00050 00051 #define PROGRAM_COUNTER(_context) ((_context)->StIIP) 00052 #define STACK_POINTER(_context) ((_context)->IntSp) 00053 #define CURRENT_IMAGE_TYPE() IMAGE_FILE_MACHINE_IA64 00054 #define PaeEnabled() (FALSE) 00055 00056 #else 00057 00058 #error ("unknown processor type") 00059 00060 #endif 00061 00062 // 00063 // min3(_a,_b,_c) 00064 // 00065 // Same as min() but takes 3 parameters. 00066 // 00067 00068 #define min3(_a,_b,_c) ( min ( min ((_a), (_b)), min ((_a), (_c))) ) 00069 00070 00071 // 00072 // Global variables 00073 // 00074 00075 extern PVOID MmPfnDatabase; 00076 extern PFN_NUMBER MmHighestPossiblePhysicalPage; 00077 00078 NTSTATUS IopFinalCrashDumpStatus = -1; 00079 ULONG IopCrashDumpStateChange = 0; 00080 BOOLEAN IopDumpFileContainsNewDump = FALSE; 00081 00082 // 00083 // Max dump transfer sizes 00084 // 00085 00086 #define IO_DUMP_MAXIMUM_TRANSFER_SIZE ( 1024 * 64 ) 00087 #define IO_DUMP_MINIMUM_TRANSFER_SIZE ( 1024 * 32 ) 00088 #define IO_DUMP_MINIMUM_FILE_SIZE ( PAGE_SIZE * 256 ) 00089 #define MAX_UNICODE_LENGTH ( 512 ) 00090 00091 #define DEFAULT_DRIVER_PATH L"\\SystemRoot\\System32\\Drivers\\" 00092 #define DEFAULT_DUMP_DRIVER L"\\SystemRoot\\System32\\Drivers\\diskdump.sys" 00093 #define SCSIPORT_DRIVER_NAME L"scsiport.sys" 00094 #define MAX_TRIAGE_STACK_SIZE ( 16 * 1024 ) 00095 #define DEFAULT_TRIAGE_DUMP_FLAGS (0xFFFFFFFF) 00096 00097 00098 // 00099 // Function prototypes 00100 // 00101 00102 00103 NTSTATUS 00104 IopWriteTriageDump( 00105 IN ULONG FieldsToWrite, 00106 IN PDUMP_DRIVER_WRITE WriteRoutine, 00107 IN OUT PLARGE_INTEGER Mcb, 00108 IN OUT PMDL Mdl, 00109 IN ULONG DiverTransferSize, 00110 IN PCONTEXT Context, 00111 IN LPBYTE Buffer, 00112 IN ULONG BufferSize, 00113 IN ULONG ServicePackBuild, 00114 IN ULONG TriageOptions 00115 ); 00116 00117 NTSTATUS 00118 IopWriteSummaryDump( 00119 IN PRTL_BITMAP PageMap, 00120 IN PDUMP_DRIVER_WRITE WriteRoutine, 00121 IN PANSI_STRING ProgressMessage, 00122 IN PUCHAR MessageBuffer, 00123 IN OUT PLARGE_INTEGER Mcb, 00124 IN ULONG DiverTransferSize 00125 ); 00126 00127 NTSTATUS 00128 IopWriteToDisk( 00129 IN PVOID Buffer, 00130 IN ULONG WriteLength, 00131 IN PDUMP_DRIVER_WRITE DriverWriteRoutine, 00132 IN OUT PLARGE_INTEGER * Mcb, 00133 IN OUT PMDL Mdl, 00134 IN ULONG DriverTransferSize 00135 ); 00136 00137 VOID 00138 IopMapPhysicalMemory( 00139 IN OUT PMDL Mdl, 00140 IN ULONG_PTR MemoryAddress, 00141 IN PPHYSICAL_MEMORY_RUN PhysicalMemoryRun, 00142 IN ULONG Length 00143 ); 00144 00145 NTSTATUS 00146 IopLoadDumpDriver ( 00147 IN OUT PDUMP_STACK_CONTEXT DumpStack, 00148 IN PWCHAR DriverNameString, 00149 IN PWCHAR NewBaseNameString 00150 ); 00151 00152 NTSTATUS 00153 IoSetCrashDumpState( 00154 IN SYSTEM_CRASH_STATE_INFORMATION *pDumpState 00155 ); 00156 00157 PSUMMARY_DUMP_HEADER 00158 IopInitializeSummaryDump( 00159 IN PDUMP_CONTROL_BLOCK pDcb 00160 ); 00161 00162 NTSTATUS 00163 IopWriteSummaryHeader( 00164 IN PSUMMARY_DUMP_HEADER pSummaryHeader, 00165 IN PDUMP_DRIVER_WRITE pfWrite, 00166 IN OUT PLARGE_INTEGER * pMcbBuffer, 00167 IN OUT PMDL pMdl, 00168 IN ULONG dwWriteSize, 00169 IN ULONG dwLength 00170 ); 00171 00172 VOID 00173 IopMapVirtualToPhysicalMdl( 00174 IN OUT PMDL pMdl, 00175 IN ULONG_PTR dwMemoryAddress, 00176 IN ULONG dwLength 00177 ); 00178 00179 ULONG 00180 IopCreateSummaryDump ( 00181 IN PSUMMARY_DUMP_HEADER pHeader 00182 ); 00183 00184 VOID 00185 IopDeleteNonExistentMemory( 00186 PSUMMARY_DUMP_HEADER pHeader, 00187 PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock 00188 ); 00189 00190 00191 NTSTATUS 00192 IopGetDumpStack ( 00193 IN PWCHAR ModulePrefix, 00194 OUT PDUMP_STACK_CONTEXT *pDumpStack, 00195 IN PUNICODE_STRING pUniDeviceName, 00196 IN PWSTR pDumpDriverName, 00197 IN DEVICE_USAGE_NOTIFICATION_TYPE UsageType, 00198 IN ULONG IgnoreDeviceUsageFailure 00199 ); 00200 00201 BOOLEAN 00202 IopInitializeDCB( 00203 ); 00204 00205 LARGE_INTEGER 00206 IopCalculateRequiredDumpSpace( 00207 IN ULONG dwDmpFlags, 00208 IN ULONG dwHeaderSize, 00209 IN PFN_NUMBER dwMaxPages, 00210 IN PFN_NUMBER dwMaxSummaryPages 00211 ); 00212 00213 NTSTATUS 00214 IopCompleteDumpInitialization( 00215 IN HANDLE FileHandle 00216 ); 00217 00218 #if DBG 00219 00220 VOID 00221 IopDebugPrint( 00222 ULONG DebugPrintLevel, 00223 PCCHAR DebugMessage, 00224 ... 00225 ); 00226 00227 #define IoDebugPrint(X) IopDebugPrint X 00228 00229 #else 00230 00231 #define IoDebugPrint(X) 00232 00233 #endif //DBG 00234 00235 00236 #ifdef ALLOC_PRAGMA 00237 #pragma alloc_text(PAGE,IoGetDumpStack) 00238 #pragma alloc_text(PAGE,IopLoadDumpDriver) 00239 #pragma alloc_text(PAGE,IoFreeDumpStack) 00240 #pragma alloc_text(PAGE,IoGetCrashDumpInformation) 00241 #pragma alloc_text(PAGE,IoGetCrashDumpStateInformation) 00242 #pragma alloc_text(PAGE,IoSetCrashDumpState) 00243 #endif 00244 00245 00246 #if defined (i386) 00247 00248 // 00249 // Functions 00250 // 00251 00252 00253 BOOL 00254 X86PaeEnabled( 00255 ) 00256 00257 /*++ 00258 00259 Routine Description: 00260 00261 Is PAE currently enabled? 00262 00263 Return Values: 00264 00265 Return TRUE if PAE is enabled in the CR4 register, FALSE otherwise. 00266 00267 --*/ 00268 00269 { 00270 ULONG Reg_Cr4; 00271 00272 _asm { 00273 _emit 0Fh 00274 _emit 20h 00275 _emit 0E0h ;; mov eax, cr4 00276 mov Reg_Cr4, eax 00277 } 00278 00279 return (Reg_Cr4 & CR4_PAE ? TRUE : FALSE); 00280 } 00281 00282 #endif 00283 00284 00285 00286 BOOLEAN 00287 IopIsAddressRangeValid( 00288 IN PVOID VirtualAddress, 00289 IN SIZE_T Length 00290 ) 00291 00292 /*++ 00293 00294 Routine Description: 00295 00296 Validate a range of addresses. 00297 00298 Arguments: 00299 00300 Virtual Address - Beginning of of memory block to validate. 00301 00302 Length - Length of memory block to validate. 00303 00304 Return Value: 00305 00306 TRUE - Address range is valid. 00307 00308 FALSE - Address range is not valid. 00309 00310 --*/ 00311 00312 { 00313 UINT_PTR Va; 00314 ULONG Pages; 00315 00316 Va = (UINT_PTR) PAGE_ALIGN (VirtualAddress); 00317 Pages = COMPUTE_PAGES_SPANNED (VirtualAddress, Length); 00318 00319 while (Pages) { 00320 00321 if (!MmIsAddressValid ( (LPVOID) Va)) { 00322 return FALSE; 00323 } 00324 00325 Va += PAGE_SIZE; 00326 Pages--; 00327 } 00328 00329 return TRUE; 00330 } 00331 00332 00333 00334 NTSTATUS 00335 IoGetDumpStack ( 00336 IN PWCHAR ModulePrefix, 00337 OUT PDUMP_STACK_CONTEXT * pDumpStack, 00338 IN DEVICE_USAGE_NOTIFICATION_TYPE UsageType, 00339 IN ULONG IgnoreDeviceUsageFailure 00340 ) 00341 /*++ 00342 00343 Routine Description: 00344 00345 This routine loads a dump stack instance and returns an allocated 00346 context structure to track the loaded dumps stack. 00347 00348 Arguments: 00349 00350 ModePrefix - The prefix to prepent to BaseName during the load 00351 operation. This allows loading the same drivers 00352 multiple times with different virtual names and 00353 linkages. 00354 00355 pDumpStack - The returned dump stack context structure 00356 00357 UsageType - The Device Notification Usage Type for this file, that 00358 this routine will send as to the device object once the 00359 file has been successfully created and initialized. 00360 00361 IgnoreDeviceUsageFailure - If the Device Usage Notification Irp fails, allow 00362 this to succeed anyway. 00363 00364 Return Value: 00365 00366 Status 00367 00368 --*/ 00369 { 00370 00371 PAGED_CODE(); 00372 return IopGetDumpStack(ModulePrefix, 00373 pDumpStack, 00374 &IoArcBootDeviceName, 00375 DEFAULT_DUMP_DRIVER, 00376 UsageType, 00377 IgnoreDeviceUsageFailure 00378 ); 00379 } 00380 00381 00382 00383 NTSTATUS 00384 IopGetDumpStack ( 00385 IN PWCHAR ModulePrefix, 00386 OUT PDUMP_STACK_CONTEXT * pDumpStack, 00387 IN PUNICODE_STRING pUniDeviceName, 00388 IN PWCHAR pDumpDriverName, 00389 IN DEVICE_USAGE_NOTIFICATION_TYPE UsageType, 00390 IN ULONG IgnoreDeviceUsageFailure 00391 ) 00392 /*++ 00393 00394 Routine Description: 00395 00396 This routine loads a dump stack instance and returns an allocated 00397 context structure to track the loaded dumps stack. 00398 00399 Arguments: 00400 00401 ModePrefix - The prefix to prepent to BaseName during the load 00402 operation. This allows loading the same drivers 00403 multiple times with different virtual names and 00404 linkages. 00405 00406 pDumpStack - The returned dump stack context structure 00407 00408 pDeviceName - The name of the target dump device 00409 00410 pDumpDriverName - The name of the target dump driver 00411 00412 UsageType - The Device Notification Usage Type for this file, that 00413 this routine will send as to the device object once the 00414 file has been successfully created and initialized. 00415 00416 IgnoreDeviceUsageFailure - If the Device Usage Notification Irp fails, allow 00417 this to succeed anyway. 00418 00419 Return Value: 00420 00421 Status 00422 00423 --*/ 00424 { 00425 PDUMP_STACK_CONTEXT DumpStack; 00426 PUCHAR Buffer; 00427 PUCHAR PartitionName; 00428 ANSI_STRING AnsiString; 00429 UNICODE_STRING TempName; 00430 OBJECT_ATTRIBUTES ObjectAttributes; 00431 NTSTATUS Status; 00432 HANDLE DeviceHandle; 00433 SCSI_ADDRESS ScsiAddress; 00434 BOOLEAN ScsiDump; 00435 PARTITION_INFORMATION PartitionInfo; 00436 PFILE_OBJECT FileObject; 00437 PDEVICE_OBJECT DeviceObject; 00438 PINITIALIZATION_CONTEXT DumpInit; 00439 PDUMP_POINTERS DumpPointers; 00440 UNICODE_STRING DriverName; 00441 PDRIVER_OBJECT DriverObject; 00442 PIRP Irp; 00443 PIO_STACK_LOCATION IrpSp; 00444 IO_STATUS_BLOCK IoStatus; 00445 PWCHAR DumpName, NameOffset; 00446 KEVENT Event; 00447 PVOID p1; 00448 PHYSICAL_ADDRESS pa; 00449 ULONG i; 00450 IO_STACK_LOCATION irpSp; 00451 ULONG information; 00452 00453 IoDebugPrint((2,"IopGetDumpStack: Prefix:%ws stk: %x device:%ws driver:%ws\n", 00454 ModulePrefix, pDumpStack, pUniDeviceName->Buffer,pDumpDriverName)); 00455 00456 ASSERT (DeviceUsageTypeUndefined != UsageType); 00457 00458 DumpStack = ExAllocatePoolWithTag ( 00459 NonPagedPool, 00460 sizeof (DUMP_STACK_CONTEXT) + sizeof (DUMP_POINTERS), 00461 'pmuD' 00462 ); 00463 00464 if (!DumpStack) { 00465 return STATUS_INSUFFICIENT_RESOURCES; 00466 } 00467 00468 RtlZeroMemory(DumpStack, sizeof(DUMP_STACK_CONTEXT)+sizeof(DUMP_POINTERS)); 00469 DumpInit = &DumpStack->Init; 00470 DumpPointers = (PDUMP_POINTERS) (DumpStack + 1); 00471 DumpStack->DumpPointers = DumpPointers; 00472 InitializeListHead (&DumpStack->DriverList); 00473 DumpName = NULL; 00474 00475 // 00476 // Allocate scratch buffer 00477 // 00478 00479 Buffer = ExAllocatePoolWithTag (PagedPool, PAGE_SIZE, 'pmuD'); 00480 if (!Buffer) { 00481 ExFreePool (DumpStack); 00482 return STATUS_INSUFFICIENT_RESOURCES; 00483 } 00484 00485 if (!KeGetBugMessageText(BUGCODE_PSS_CRASH_INIT, &DumpStack->InitMsg) || 00486 !KeGetBugMessageText(BUGCODE_PSS_CRASH_PROGRESS, &DumpStack->ProgMsg) || 00487 !KeGetBugMessageText(BUGCODE_PSS_CRASH_DONE, &DumpStack->DoneMsg)) { 00488 Status = STATUS_UNSUCCESSFUL; 00489 goto Done; 00490 } 00491 00492 InitializeObjectAttributes( 00493 &ObjectAttributes, 00494 pUniDeviceName, 00495 0, 00496 NULL, 00497 NULL 00498 ); 00499 00500 Status = ZwOpenFile( 00501 &DeviceHandle, 00502 FILE_READ_DATA | SYNCHRONIZE, 00503 &ObjectAttributes, 00504 &IoStatus, 00505 FILE_SHARE_READ | FILE_SHARE_WRITE, 00506 FILE_NON_DIRECTORY_FILE 00507 ); 00508 00509 if (!NT_SUCCESS(Status)) { 00510 IoDebugPrint ((0, 00511 "IODUMP: Could not open boot device partition, %s\n", 00512 Buffer 00513 )); 00514 goto Done; 00515 } 00516 00517 // 00518 // Check to see whether or not the system was booted from a SCSI device. 00519 // 00520 00521 Status = ZwDeviceIoControlFile ( 00522 DeviceHandle, 00523 NULL, 00524 NULL, 00525 NULL, 00526 &IoStatus, 00527 IOCTL_SCSI_GET_ADDRESS, 00528 NULL, 00529 0, 00530 &ScsiAddress, 00531 sizeof( SCSI_ADDRESS ) 00532 ); 00533 00534 if (Status == STATUS_PENDING) { 00535 ZwWaitForSingleObject ( 00536 DeviceHandle, 00537 FALSE, 00538 NULL 00539 ); 00540 00541 Status = IoStatus.Status; 00542 } 00543 00544 ScsiDump = (BOOLEAN) (NT_SUCCESS(Status)); 00545 00546 // 00547 // If SCSI then allocate storage to contain the target address information. 00548 // 00549 00550 DumpInit->TargetAddress = NULL; 00551 00552 if (ScsiDump) { 00553 00554 DumpInit->TargetAddress = ExAllocatePoolWithTag ( 00555 NonPagedPool, 00556 sizeof (SCSI_ADDRESS), 00557 'pmuD' 00558 ); 00559 // 00560 // It is ok If the allocation fails. The scsi dump driver will scan 00561 // all devices if the targetaddress information does not exist 00562 // 00563 00564 if (DumpInit->TargetAddress) { 00565 RtlCopyMemory(DumpInit->TargetAddress,&ScsiAddress,sizeof(SCSI_ADDRESS)); 00566 } 00567 } 00568 00569 // 00570 // Determine the disk signature for the device from which the system was 00571 // booted and get the partition offset. 00572 // 00573 00574 Status = ZwDeviceIoControlFile( 00575 DeviceHandle, 00576 NULL, 00577 NULL, 00578 NULL, 00579 &IoStatus, 00580 IOCTL_DISK_GET_PARTITION_INFO, 00581 NULL, 00582 0, 00583 &PartitionInfo, 00584 sizeof( PARTITION_INFORMATION ) 00585 ); 00586 00587 if (Status == STATUS_PENDING) { 00588 ZwWaitForSingleObject ( 00589 DeviceHandle, 00590 FALSE, 00591 NULL 00592 ); 00593 00594 Status = IoStatus.Status; 00595 } 00596 00597 IoDebugPrint((2,"Partition Type = %x\n",PartitionInfo.PartitionType)); 00598 IoDebugPrint((2,"Boot Indicator = %x\n",PartitionInfo.BootIndicator)); 00599 00600 Status = ZwDeviceIoControlFile( 00601 DeviceHandle, 00602 NULL, 00603 NULL, 00604 NULL, 00605 &IoStatus, 00606 IOCTL_DISK_GET_DRIVE_LAYOUT, 00607 NULL, 00608 0, 00609 Buffer, 00610 PAGE_SIZE 00611 ); 00612 00613 if (Status == STATUS_PENDING) { 00614 ZwWaitForSingleObject ( 00615 DeviceHandle, 00616 FALSE, 00617 NULL 00618 ); 00619 00620 Status = IoStatus.Status; 00621 } 00622 00623 DumpInit->DiskSignature = ((PDRIVE_LAYOUT_INFORMATION) Buffer)->Signature; 00624 00625 // 00626 // Get the adapter object and base mapping registers for the disk from 00627 // the disk driver. These will be used to call the HAL once the system 00628 // system has crashed, since it is not possible at that point to recreate 00629 // them from scratch. 00630 // 00631 00632 ObReferenceObjectByHandle ( 00633 DeviceHandle, 00634 0, 00635 IoFileObjectType, 00636 KernelMode, 00637 (PVOID *) &FileObject, 00638 NULL 00639 ); 00640 00641 00642 DeviceObject = IoGetRelatedDeviceObject (FileObject); 00643 00644 KeInitializeEvent( &Event, NotificationEvent, FALSE ); 00645 00646 Irp = IoBuildDeviceIoControlRequest( 00647 IOCTL_SCSI_GET_DUMP_POINTERS, 00648 DeviceObject, 00649 NULL, 00650 0, 00651 DumpPointers, 00652 sizeof (DUMP_POINTERS), 00653 FALSE, 00654 &Event, 00655 &IoStatus 00656 ); 00657 00658 if (!Irp) { 00659 ObDereferenceObject (FileObject); 00660 ZwClose (DeviceHandle); 00661 Status = STATUS_INSUFFICIENT_RESOURCES; 00662 goto Done; 00663 } 00664 00665 IrpSp = IoGetNextIrpStackLocation (Irp); 00666 00667 IrpSp->FileObject = FileObject; 00668 00669 Status = IoCallDriver( DeviceObject, Irp ); 00670 00671 if (Status == STATUS_PENDING) { 00672 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 00673 Status = IoStatus.Status; 00674 } 00675 00676 if (!NT_SUCCESS(Status) || IoStatus.Information < FIELD_OFFSET(DUMP_POINTERS, DeviceObject)) { 00677 00678 IoDebugPrint ((0, 00679 "IODUMP: Could not get dump pointers; error = %x, length %x\n", 00680 Status, 00681 IoStatus.Information 00682 )); 00683 ObDereferenceObject (FileObject); 00684 // NtClose (DeviceHandle); 00685 ZwClose (DeviceHandle); 00686 goto Done; 00687 } 00688 DumpStack->PointersLength = (ULONG) IoStatus.Information; 00689 00690 // 00691 // If the driver returned a pointer to a device object, that is the 00692 // object for the dump driver (non-scsi case) 00693 // 00694 00695 DeviceObject = (PDEVICE_OBJECT) DumpPointers->DeviceObject; 00696 if (DeviceObject) { 00697 DriverObject = DeviceObject->DriverObject; 00698 00699 // 00700 // Loop through the name of the driver looking for the end of the name, 00701 // which is the name of the dump image. 00702 // 00703 00704 DumpName = DriverObject->DriverName.Buffer; 00705 while ( NameOffset = wcsstr( DumpName, L"\\" )) { 00706 DumpName = ++NameOffset; 00707 } 00708 00709 ScsiDump = FALSE; 00710 } 00711 00712 // 00713 // Release the handle, but keep the reference to the file object as it 00714 // will be needed at free dump dump driver time 00715 // 00716 00717 DumpStack->FileObject = FileObject; 00718 ZwClose (DeviceHandle); 00719 00720 // 00721 // Fill in some DumpInit results 00722 // 00723 00724 DumpInit->Length = sizeof (INITIALIZATION_CONTEXT); 00725 DumpInit->StallRoutine = &KeStallExecutionProcessor; 00726 DumpInit->AdapterObject = DumpPointers->AdapterObject; 00727 DumpInit->MappedRegisterBase = DumpPointers->MappedRegisterBase; 00728 DumpInit->PortConfiguration = DumpPointers->DumpData; 00729 00730 DumpStack->ModulePrefix = ModulePrefix; 00731 DumpStack->PartitionOffset = PartitionInfo.StartingOffset; 00732 DumpStack->UsageType = DeviceUsageTypeUndefined; 00733 00734 // 00735 // The minimum common buffer size is IO_DUMP_COMMON_BUFFER_SIZE (compatability) 00736 // This is used by the dump driver for SRB extension, CachedExtension, and sense buffer 00737 // 00738 if (DumpPointers->CommonBufferSize < IO_DUMP_COMMON_BUFFER_SIZE) { 00739 DumpPointers->CommonBufferSize = IO_DUMP_COMMON_BUFFER_SIZE; 00740 } 00741 DumpInit->CommonBufferSize = DumpPointers->CommonBufferSize; 00742 00743 // 00744 // Allocate the required common buffers 00745 // 00746 00747 if (DumpPointers->AllocateCommonBuffers) { 00748 pa.QuadPart = 0x1000000 - 1; 00749 for (i=0; i < 2; i++) { 00750 if (DumpInit->AdapterObject) { 00751 00752 #if !defined(NO_LEGACY_DRIVERS) 00753 p1 = HalAllocateCommonBuffer( 00754 DumpInit->AdapterObject, 00755 DumpPointers->CommonBufferSize, 00756 &pa, 00757 FALSE 00758 ); 00759 00760 #else 00761 p1 = (*((PDMA_ADAPTER)DumpInit->AdapterObject)->DmaOperations-> 00762 AllocateCommonBuffer)( 00763 (PDMA_ADAPTER)DumpInit->AdapterObject, 00764 DumpPointers->CommonBufferSize, 00765 &pa, 00766 FALSE 00767 ); 00768 00769 #endif // NO_LEGACY_DRIVERS 00770 00771 } else { 00772 p1 = MmAllocateContiguousMemory ( 00773 DumpPointers->CommonBufferSize, 00774 pa 00775 ); 00776 00777 if (!p1) { 00778 p1 = MmAllocateNonCachedMemory (DumpPointers->CommonBufferSize); 00779 } 00780 pa = MmGetPhysicalAddress(p1); 00781 } 00782 00783 if (!p1) { 00784 IoDebugPrint ((0, "IODUMP: Could not allocate common buffers for dump\n")); 00785 Status = STATUS_INSUFFICIENT_RESOURCES; 00786 goto Done; 00787 } 00788 00789 DumpInit->CommonBuffer[i] = p1; 00790 DumpInit->PhysicalAddress[i] = pa; 00791 } 00792 } 00793 00794 // 00795 // Determine whether or not the system booted from SCSI. 00796 // 00797 00798 if (ScsiDump) { 00799 00800 // 00801 // Load the boot disk and port driver to be used by the various 00802 // miniports for writing memory to the disk. 00803 // 00804 00805 Status = IopLoadDumpDriver ( 00806 DumpStack, 00807 pDumpDriverName, 00808 SCSIPORT_DRIVER_NAME 00809 ); 00810 00811 if (!NT_SUCCESS(Status)) { 00812 00813 IopLogErrorEvent(0,9,STATUS_SUCCESS,IO_DUMP_DRIVER_LOAD_FAILURE,0,NULL,0,NULL); 00814 goto Done; 00815 } 00816 00817 // 00818 // The disk and port dump driver has been loaded. Load the appropriate 00819 // miniport driver as well so that the boot device can be accessed. 00820 // 00821 00822 DriverName.Length = 0; 00823 DriverName.Buffer = (PVOID) Buffer; 00824 DriverName.MaximumLength = PAGE_SIZE; 00825 00826 00827 // 00828 // The system was booted from SCSI. Get the name of the appropriate 00829 // miniport driver and load it. 00830 // 00831 00832 sprintf(Buffer, "\\Device\\ScsiPort%d", ScsiAddress.PortNumber ); 00833 RtlInitAnsiString( &AnsiString, Buffer ); 00834 RtlAnsiStringToUnicodeString( &TempName, &AnsiString, TRUE ); 00835 InitializeObjectAttributes( 00836 &ObjectAttributes, 00837 &TempName, 00838 0, 00839 NULL, 00840 NULL 00841 ); 00842 00843 Status = ZwOpenFile( 00844 &DeviceHandle, 00845 FILE_READ_ATTRIBUTES, 00846 &ObjectAttributes, 00847 &IoStatus, 00848 FILE_SHARE_READ | FILE_SHARE_WRITE, 00849 FILE_NON_DIRECTORY_FILE 00850 ); 00851 00852 RtlFreeUnicodeString( &TempName ); 00853 if (!NT_SUCCESS( Status )) { 00854 IoDebugPrint ((0, 00855 "IODUMP: Could not open SCSI port %d, error = %x\n", 00856 ScsiAddress.PortNumber, 00857 Status 00858 )); 00859 goto Done; 00860 } 00861 00862 // 00863 // Convert the file handle into a pointer to the device object, and 00864 // get the name of the driver from its driver object. 00865 // 00866 00867 ObReferenceObjectByHandle( 00868 DeviceHandle, 00869 0, 00870 IoFileObjectType, 00871 KernelMode, 00872 (PVOID *) &FileObject, 00873 NULL 00874 ); 00875 00876 DriverObject = FileObject->DeviceObject->DriverObject; 00877 ObDereferenceObject( FileObject ); 00878 ZwClose( DeviceHandle ); 00879 // 00880 // Loop through the name of the driver looking for the end of the name, 00881 // which is the name of the miniport image. 00882 // 00883 00884 DumpName = DriverObject->DriverName.Buffer; 00885 while ( NameOffset = wcsstr( DumpName, L"\\" )) { 00886 DumpName = ++NameOffset; 00887 } 00888 } 00889 00890 // 00891 // Load the dump driver 00892 // 00893 00894 if (!DumpName) { 00895 Status = STATUS_NOT_SUPPORTED; 00896 goto Done; 00897 } 00898 00899 swprintf ((PWCHAR) Buffer, L"\\SystemRoot\\System32\\Drivers\\%s.sys", DumpName); 00900 Status = IopLoadDumpDriver ( 00901 DumpStack, 00902 (PWCHAR) Buffer, 00903 NULL 00904 ); 00905 if (!NT_SUCCESS(Status)) { 00906 00907 IopLogErrorEvent(0,10,STATUS_SUCCESS,IO_DUMP_DRIVER_LOAD_FAILURE,0,NULL,0,NULL); 00908 goto Done; 00909 } 00910 00911 // 00912 // Claim the file as part of specific device usage path. 00913 // 00914 00915 FileObject = DumpStack->FileObject; 00916 DeviceObject = IoGetRelatedDeviceObject (FileObject); 00917 00918 RtlZeroMemory (&irpSp, sizeof (IO_STACK_LOCATION)); 00919 00920 irpSp.MajorFunction = IRP_MJ_PNP; 00921 irpSp.MinorFunction = IRP_MN_DEVICE_USAGE_NOTIFICATION; 00922 irpSp.Parameters.UsageNotification.Type = UsageType; 00923 irpSp.Parameters.UsageNotification.InPath = TRUE; 00924 irpSp.FileObject = FileObject; 00925 00926 Status = IopSynchronousCall (DeviceObject, &irpSp, (VOID **) &information); 00927 ASSERT (0 == information); 00928 00929 if (!NT_SUCCESS(Status) && IgnoreDeviceUsageFailure) { 00930 IoDebugPrint ((0, 00931 "IopGetDumpStack: DEVICE_USAGE_NOTIFICATION " 00932 "Error ignored (%x)\n", 00933 Status)); 00934 Status = STATUS_SUCCESS; 00935 } 00936 00937 if (NT_SUCCESS(Status)) { 00938 DumpStack->UsageType = UsageType; 00939 } 00940 00941 Done: 00942 if (NT_SUCCESS(Status)) { 00943 *pDumpStack = DumpStack; 00944 } else { 00945 IoFreeDumpStack (DumpStack); 00946 } 00947 ExFreePool (Buffer); 00948 return Status; 00949 } 00950 00951 00952 00953 NTSTATUS 00954 IopLoadDumpDriver ( 00955 IN OUT PDUMP_STACK_CONTEXT DumpStack, 00956 IN PWCHAR DriverNameString, 00957 IN PWCHAR NewBaseNameString OPTIONAL 00958 ) 00959 /*++ 00960 00961 Routine Description: 00962 00963 Worker function for IoGetDumpStack to load a particular driver into 00964 the current DumpStack being created 00965 00966 Arguments: 00967 00968 DumpStack - Dump driver stack being built 00969 00970 DriverNameString - The string name of the driver to load 00971 00972 NewBaseNameString - The modified basename of the driver once loaded 00973 00974 Return Value: 00975 00976 Status 00977 00978 --*/ 00979 { 00980 NTSTATUS Status; 00981 PDUMP_STACK_IMAGE DumpImage; 00982 PLDR_DATA_TABLE_ENTRY ImageLdrInfo; 00983 UNICODE_STRING DriverName; 00984 UNICODE_STRING BaseName; 00985 UNICODE_STRING Prefix; 00986 PUNICODE_STRING LoadBaseName; 00987 00988 // 00989 // Allocate space to track this dump driver 00990 // 00991 00992 DumpImage = ExAllocatePoolWithTag ( 00993 NonPagedPool, 00994 sizeof (DUMP_STACK_IMAGE), 00995 'pmuD' 00996 ); 00997 00998 if (!DumpImage) { 00999 return STATUS_INSUFFICIENT_RESOURCES; 01000 } 01001 01002 // 01003 // Load the system image 01004 // 01005 01006 RtlInitUnicodeString (&DriverName, DriverNameString); 01007 RtlInitUnicodeString (&Prefix, DumpStack->ModulePrefix); 01008 LoadBaseName = NULL; 01009 if (NewBaseNameString) { 01010 LoadBaseName = &BaseName; 01011 RtlInitUnicodeString (&BaseName, NewBaseNameString); 01012 BaseName.MaximumLength = Prefix.Length + BaseName.Length; 01013 BaseName.Buffer = ExAllocatePoolWithTag ( 01014 NonPagedPool, 01015 BaseName.MaximumLength, 01016 'pmuD' 01017 ); 01018 01019 01020 if (!BaseName.Buffer) { 01021 ExFreePool (DumpImage); 01022 return STATUS_INSUFFICIENT_RESOURCES; 01023 } 01024 01025 BaseName.Length = 0; 01026 RtlAppendUnicodeStringToString (&BaseName, &Prefix); 01027 RtlAppendUnicodeToString (&BaseName, NewBaseNameString); 01028 } 01029 01030 Status = MmLoadAndLockSystemImage( 01031 &DriverName, 01032 &Prefix, 01033 LoadBaseName, 01034 &DumpImage->Image, 01035 &DumpImage->ImageBase 01036 ); 01037 01038 if (NewBaseNameString) { 01039 ExFreePool (BaseName.Buffer); 01040 } 01041 01042 if (!NT_SUCCESS (Status)) { 01043 IoDebugPrint ((0, 01044 "IODUMP: Could not load %wZ; error = %x\n", 01045 &DriverName, 01046 Status)); 01047 ExFreePool (DumpImage); 01048 return Status; 01049 } 01050 01051 // 01052 // Put this driver on the list of drivers to be processed at crash time 01053 // 01054 01055 DumpImage->SizeOfImage = DumpImage->Image->SizeOfImage; 01056 InsertTailList (&DumpStack->DriverList, &DumpImage->Link); 01057 return STATUS_SUCCESS; 01058 } 01059 01060 01061 ULONG 01062 IopGetDumpControlBlockCheck ( 01063 IN PDUMP_CONTROL_BLOCK Dcb 01064 ) 01065 /*++ 01066 01067 Routine Description: 01068 01069 Return the current checksum total for the Dcb 01070 01071 Arguments: 01072 01073 DumpStack - Dump driver stack to checksum 01074 01075 Return Value: 01076 01077 Checksum value 01078 01079 --*/ 01080 { 01081 ULONG Check; 01082 PLIST_ENTRY Link; 01083 PDUMP_STACK_IMAGE DumpImage; 01084 PMAPPED_ADDRESS MappedAddress; 01085 PDUMP_STACK_CONTEXT DumpStack; 01086 01087 01088 // 01089 // Check the DCB, memory descriptor array, and the FileDescriptorArray 01090 // 01091 01092 Check = PoSimpleCheck(0, Dcb, sizeof(DUMP_CONTROL_BLOCK)); 01093 Check = PoSimpleCheck( 01094 Check, 01095 Dcb->MemoryDescriptor, 01096 Dcb->MemoryDescriptorLength 01097 ); 01098 01099 Check = PoSimpleCheck(Check, Dcb->FileDescriptorArray, Dcb->FileDescriptorSize); 01100 01101 DumpStack = Dcb->DumpStack; 01102 if (DumpStack) { 01103 01104 // 01105 // Include the dump stack context structure, and dump driver images 01106 // 01107 01108 Check = PoSimpleCheck(Check, DumpStack, sizeof(DUMP_STACK_CONTEXT)); 01109 Check = PoSimpleCheck(Check, DumpStack->DumpPointers, DumpStack->PointersLength); 01110 01111 for (Link = DumpStack->DriverList.Flink; 01112 Link != &DumpStack->DriverList; 01113 Link = Link->Flink) { 01114 01115 DumpImage = CONTAINING_RECORD(Link, DUMP_STACK_IMAGE, Link); 01116 Check = PoSimpleCheck(Check, DumpImage, sizeof(DUMP_STACK_IMAGE)); 01117 Check = PoSimpleCheck(Check, DumpImage->ImageBase, DumpImage->SizeOfImage); 01118 } 01119 01120 // 01121 // Include the mapped addresses 01122 // 01123 // If this is non-null it is treated as a PMAPPED_ADDRESS * (see scsiport and atdisk) 01124 // 01125 if (DumpStack->Init.MappedRegisterBase != NULL) { 01126 MappedAddress = *(PMAPPED_ADDRESS *)DumpStack->Init.MappedRegisterBase; 01127 } else { 01128 MappedAddress = NULL; 01129 } 01130 01131 while (MappedAddress) { 01132 Check = PoSimpleCheck (Check, MappedAddress, sizeof(MAPPED_ADDRESS)); 01133 MappedAddress = MappedAddress->NextMappedAddress; 01134 } 01135 } 01136 01137 return Check; 01138 } 01139 01140 01141 NTSTATUS 01142 IoInitializeDumpStack ( 01143 IN PDUMP_STACK_CONTEXT DumpStack, 01144 IN PUCHAR MessageBuffer OPTIONAL 01145 ) 01146 /*++ 01147 01148 Routine Description: 01149 01150 Initialize the dump driver stack referenced by DumpStack to perform IO. 01151 01152 Arguments: 01153 01154 DumpStack - Dump driver stack being initialized 01155 01156 Return Value: 01157 01158 Status 01159 01160 --*/ 01161 { 01162 01163 PINITIALIZATION_CONTEXT DumpInit; 01164 PLIST_ENTRY Link; 01165 ULONG Check; 01166 NTSTATUS Status; 01167 PDRIVER_INITIALIZE DriverInit; 01168 PDUMP_STACK_IMAGE DumpImage; 01169 01170 01171 DumpInit = &DumpStack->Init; 01172 01173 // 01174 // Verify checksum on DumpStack structure 01175 // 01176 01177 // BUGBUG: later 01178 01179 // 01180 // Initializes the dump drivers 01181 // 01182 01183 for (Link = DumpStack->DriverList.Flink; 01184 Link != &DumpStack->DriverList; 01185 Link = Link->Flink) { 01186 01187 DumpImage = CONTAINING_RECORD(Link, DUMP_STACK_IMAGE, Link); 01188 01189 // 01190 // Call this driver's driver init. Only the first driver gets the 01191 // dump initialization context 01192 // 01193 01194 DriverInit = DumpImage->Image->EntryPoint; 01195 Status = DriverInit (NULL, (PUNICODE_STRING) DumpInit); 01196 DumpInit = NULL; 01197 01198 if (!NT_SUCCESS(Status)) { 01199 IoDebugPrint ((0, 01200 "IODUMP: Unable to initialize driver; error = %x\n", 01201 Status 01202 )); 01203 return Status; 01204 } 01205 } 01206 01207 DumpInit = &DumpStack->Init; 01208 01209 // 01210 // Display string we are starting 01211 // 01212 01213 if (MessageBuffer) { 01214 InbvDisplayString (MessageBuffer); 01215 } 01216 01217 // 01218 // Open the partition from which the system was booted. 01219 // This returns TRUE if the disk w/the appropriate signature was found, 01220 // otherwise a NULL, in which case there is no way to continue. 01221 // 01222 01223 if (!DumpInit->OpenRoutine (DumpStack->PartitionOffset)) { 01224 IoDebugPrint (( 0, "IODUMP: Could not find/open partition offset\n" )); 01225 return STATUS_UNSUCCESSFUL; 01226 } 01227 01228 return STATUS_SUCCESS; 01229 } 01230 01231 01232 VOID 01233 IoGetDumpHiberRanges ( 01234 IN PVOID HiberContext, 01235 IN PDUMP_STACK_CONTEXT DumpStack 01236 ) 01237 /*++ 01238 01239 Routine Description: 01240 01241 Adds the dump driver stack storage to the hibernate range list, 01242 to inform the hibernate procedure which pages need cloned, 01243 discarded or not checksumed as they are in use by the dump 01244 stack. 01245 01246 Arguments: 01247 01248 HiberContext - Pointer to the hiber context structure 01249 01250 DumpStack - Dump driver stack being initialized 01251 01252 Return Value: 01253 01254 None 01255 01256 --*/ 01257 { 01258 PDUMP_POINTERS DumpPointers; 01259 PDUMP_STACK_IMAGE DumpImage; 01260 PLIST_ENTRY Link; 01261 01262 DumpPointers = DumpStack->DumpPointers; 01263 01264 // 01265 // Report the common buffer 01266 // 01267 01268 if (DumpPointers->CommonBufferVa) { 01269 PoSetHiberRange ( 01270 HiberContext, 01271 PO_MEM_CL_OR_NCHK, 01272 DumpPointers->CommonBufferVa, 01273 DumpPointers->CommonBufferSize, 01274 'fubc' 01275 ); 01276 } 01277 01278 // 01279 // Dump the entire image of the dump drivers 01280 // 01281 01282 for (Link = DumpStack->DriverList.Flink; 01283 Link != &DumpStack->DriverList; 01284 Link = Link->Flink) { 01285 01286 DumpImage = CONTAINING_RECORD(Link, DUMP_STACK_IMAGE, Link); 01287 01288 PoSetHiberRange ( 01289 HiberContext, 01290 PO_MEM_CL_OR_NCHK, 01291 DumpImage->ImageBase, 01292 DumpImage->SizeOfImage, 01293 'gmID' 01294 ); 01295 } 01296 } 01297 01298 01299 VOID 01300 IoFreeDumpStack ( 01301 IN PDUMP_STACK_CONTEXT DumpStack 01302 ) 01303 /*++ 01304 01305 Routine Description: 01306 01307 Free the dump driver stack referenced by DumpStack 01308 01309 Arguments: 01310 01311 DumpStack - Dump driver stack being initialized 01312 01313 Return Value: 01314 01315 None 01316 01317 --*/ 01318 { 01319 PINITIALIZATION_CONTEXT DumpInit; 01320 PDUMP_STACK_IMAGE DumpImage; 01321 PDEVICE_OBJECT DeviceObject; 01322 PIO_STACK_LOCATION IrpSp; 01323 IO_STATUS_BLOCK IoStatus; 01324 PIRP Irp; 01325 KEVENT Event; 01326 NTSTATUS Status; 01327 ULONG i; 01328 PFILE_OBJECT FileObject; 01329 IO_STACK_LOCATION irpSp; 01330 ULONG information; 01331 01332 PAGED_CODE(); 01333 DumpInit = &DumpStack->Init; 01334 01335 // 01336 // Release the claim to this file as a specific device usage path. 01337 // 01338 01339 FileObject = DumpStack->FileObject; 01340 if (FileObject) { 01341 DeviceObject = IoGetRelatedDeviceObject (FileObject); 01342 01343 RtlZeroMemory (&irpSp, sizeof (IO_STACK_LOCATION)); 01344 01345 irpSp.MajorFunction = IRP_MJ_PNP; 01346 irpSp.MinorFunction = IRP_MN_DEVICE_USAGE_NOTIFICATION; 01347 irpSp.Parameters.UsageNotification.Type = DumpStack->UsageType; 01348 irpSp.Parameters.UsageNotification.InPath = FALSE; 01349 irpSp.FileObject = FileObject; 01350 01351 if (DeviceUsageTypeUndefined != DumpStack->UsageType) { 01352 Status = IopSynchronousCall (DeviceObject, &irpSp, (VOID **) &information); 01353 ASSERT (0 == information); 01354 } else { 01355 Status = STATUS_SUCCESS; 01356 } 01357 } 01358 01359 // 01360 // Free any common buffers which where allocated 01361 // 01362 01363 for (i=0; i < 2; i++) { 01364 if (DumpInit->CommonBuffer[i]) { 01365 if (DumpInit->AdapterObject) { 01366 01367 #if !defined(NO_LEGACY_DRIVERS) 01368 HalFreeCommonBuffer ( 01369 DumpInit->AdapterObject, 01370 ((PDUMP_POINTERS)DumpStack->DumpPointers)->CommonBufferSize, 01371 DumpInit->PhysicalAddress[i], 01372 DumpInit->CommonBuffer[i], 01373 FALSE 01374 ); 01375 #else 01376 (*((PDMA_ADAPTER)DumpInit->AdapterObject)->DmaOperations-> 01377 FreeCommonBuffer )( 01378 (PDMA_ADAPTER)DumpInit->AdapterObject, 01379 ((PDUMP_POINTERS)DumpStack->DumpPointers)->CommonBufferSize, 01380 DumpInit->PhysicalAddress[i], 01381 DumpInit->CommonBuffer[i], 01382 FALSE 01383 ); 01384 01385 #endif // NO_LEGACY_DRIVERS 01386 01387 01388 } else { 01389 MmFreeContiguousMemory (DumpInit->CommonBuffer[i]); 01390 } 01391 } 01392 DumpInit->CommonBuffer[i] = NULL; 01393 } 01394 01395 // 01396 // Unload the dump drivers 01397 // 01398 01399 while (!IsListEmpty(&DumpStack->DriverList)) { 01400 DumpImage = CONTAINING_RECORD(DumpStack->DriverList.Blink, DUMP_STACK_IMAGE, Link); 01401 RemoveEntryList (&DumpImage->Link); 01402 MmUnloadSystemImage (DumpImage->Image); 01403 ExFreePool (DumpImage); 01404 } 01405 01406 // 01407 // Inform the driver stack that the dump registartion is over 01408 // 01409 01410 if (DumpStack->FileObject) { 01411 DeviceObject = IoGetRelatedDeviceObject ((PFILE_OBJECT) DumpStack->FileObject); 01412 01413 KeInitializeEvent( &Event, NotificationEvent, FALSE ); 01414 Irp = IoBuildDeviceIoControlRequest( 01415 IOCTL_SCSI_FREE_DUMP_POINTERS, 01416 DeviceObject, 01417 DumpStack->DumpPointers, 01418 sizeof (DUMP_POINTERS), 01419 NULL, 01420 0, 01421 FALSE, 01422 &Event, 01423 &IoStatus 01424 ); 01425 01426 IrpSp = IoGetNextIrpStackLocation (Irp); 01427 IrpSp->FileObject = DumpStack->FileObject; 01428 01429 Status = IoCallDriver( DeviceObject, Irp ); 01430 01431 if (Status == STATUS_PENDING) { 01432 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 01433 Status = IoStatus.Status; 01434 } 01435 ObDereferenceObject( DumpStack->FileObject ); 01436 } 01437 // 01438 // Free the target address if it exists 01439 // 01440 if (DumpStack->Init.TargetAddress) { 01441 ExFreePool( DumpStack->Init.TargetAddress); 01442 } 01443 // 01444 // Free the dump stack context 01445 // 01446 01447 ExFreePool (DumpStack); 01448 } 01449 01450 01451 NTSTATUS 01452 IopInitializeDumpSpaceAndType( 01453 IN PDUMP_CONTROL_BLOCK dcb, 01454 IN OUT PULONG block, 01455 IN PSUMMARY_DUMP_HEADER pSummaryHeader 01456 ) 01457 { 01458 LARGE_INTEGER Space; 01459 01460 Space.QuadPart = 0; 01461 01462 if (dcb->Flags & DCB_TRIAGE_DUMP_ENABLED) { 01463 01464 // 01465 // Fixed size dump for triage-dumps. 01466 // 01467 01468 block [ DH_DUMP_TYPE ] = DUMP_TYPE_TRIAGE; 01469 Space.QuadPart = TRIAGE_DUMP_SIZE; 01470 01471 01472 } else if (dcb->Flags & DCB_SUMMARY_DUMP_ENABLED) { 01473 01474 block [ DH_DUMP_TYPE ] = DUMP_TYPE_SUMMARY; 01475 01476 Space = IopCalculateRequiredDumpSpace( 01477 dcb->Flags, 01478 dcb->HeaderSize, 01479 dcb->MemoryDescriptor->NumberOfPages, 01480 pSummaryHeader->Pages 01481 ); 01482 } else { 01483 01484 if (dcb->Flags & DCB_DUMP_HEADER_ENABLED) { 01485 block [ DH_DUMP_TYPE ] = DUMP_TYPE_HEADER; 01486 } 01487 01488 Space = IopCalculateRequiredDumpSpace( 01489 dcb->Flags, 01490 dcb->HeaderSize, 01491 dcb->MemoryDescriptor->NumberOfPages, 01492 dcb->MemoryDescriptor->NumberOfPages 01493 ); 01494 } 01495 01496 // 01497 // If the calculated size is larger than the pagefile, truncate it to 01498 // the pagefile size. 01499 // 01500 01501 if (Space.QuadPart > dcb->DumpFileSize.QuadPart) { 01502 Space.QuadPart = dcb->DumpFileSize.QuadPart; 01503 } 01504 01505 block [ DH_REQUIRED_DUMP_SPACE ] = Space.LowPart; 01506 block [ DH_REQUIRED_DUMP_SPACE + 1 ] = Space.HighPart; 01507 01508 IoDebugPrint((2,"IODUMP: dcb File Size %x Block Size %x\n", 01509 block [DH_REQUIRED_DUMP_SPACE], 01510 (ULONG)dcb->DumpFileSize.LowPart 01511 )); 01512 01513 return STATUS_SUCCESS; 01514 } 01515 01516 01517 01518 BOOLEAN 01519 IoWriteCrashDump( 01520 IN ULONG BugCheckCode, 01521 IN ULONG_PTR BugCheckParameter1, 01522 IN ULONG_PTR BugCheckParameter2, 01523 IN ULONG_PTR BugCheckParameter3, 01524 IN ULONG_PTR BugCheckParameter4, 01525 IN PVOID ContextSave 01526 ) 01527 01528 /*++ 01529 01530 Routine Description: 01531 01532 This routine checks to see whether or not crash dumps are enabled and, if 01533 so, writes all of physical memory to the system disk's paging file. 01534 01535 Arguments: 01536 01537 BugCheckCode/ParameterN - Code and parameters w/which BugCheck was called. 01538 01539 Return Value: 01540 01541 None. 01542 01543 --*/ 01544 01545 { 01546 PDUMP_CONTROL_BLOCK dcb; 01547 PDUMP_STACK_CONTEXT dumpStack; 01548 PDUMP_DRIVER_WRITE write; 01549 PDUMP_DRIVER_FINISH finishUp; 01550 PDUMP_HEADER header; 01551 EXCEPTION_RECORD exception; 01552 PCONTEXT context = ContextSave; 01553 PULONG block; 01554 LARGE_INTEGER diskByteOffset; 01555 PPFN_NUMBER page; 01556 PFN_NUMBER localMdl[(sizeof( MDL )/sizeof(PFN_NUMBER)) + 17]; 01557 PMDL mdl; 01558 PLARGE_INTEGER mcb; 01559 ULONG_PTR memoryAddress; 01560 ULONG byteOffset; 01561 ULONG byteCount; 01562 ULONG bytesRemaining; 01563 NTSTATUS status; 01564 UCHAR messageBuffer[128]; 01565 PFN_NUMBER ActualPages; 01566 PSUMMARY_DUMP_HEADER pSummaryHeader; 01567 ULONG dwTransferSize; 01568 LARGE_INTEGER requiredDumpSpace; 01569 ULONG_PTR DirBasePage; 01570 01571 // 01572 // Begin by determining whether or not crash dumps are enabled. If not, 01573 // check to see whether or not auto-rebooting is enabled. If not, return 01574 // immediately since there is nothing to do. 01575 // 01576 01577 dcb = IopDumpControlBlock; 01578 if (!dcb) { 01579 return FALSE; 01580 } 01581 01582 if (dcb->Flags & DCB_DUMP_ENABLED || dcb->Flags & DCB_SUMMARY_ENABLED) { 01583 01584 IopFinalCrashDumpStatus = STATUS_PENDING; 01585 01586 // 01587 // A dump is to be written to the paging file. Ensure that all of the 01588 // descriptor data for what needs to be done is valid, otherwise it 01589 // could be that part of the reason for the bugcheck is that this data 01590 // was corrupted. Or, it could be that no paging file was found yet, 01591 // or any number of other situations. 01592 // 01593 01594 if (IopGetDumpControlBlockCheck(dcb) != IopDumpControlBlockChecksum) { 01595 IoDebugPrint (( 0, 01596 "CRASHDUMP: Disk dump routine returning due to DCB integrity error\n" 01597 " No dump will be created\n" )); 01598 IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL; 01599 return FALSE; 01600 } 01601 01602 // 01603 // Message that we are starting the crashdump 01604 // 01605 01606 dumpStack = dcb->DumpStack; 01607 sprintf( messageBuffer, "%Z\n", &dumpStack->InitMsg ); 01608 01609 // 01610 // Initialize the dump stack 01611 // 01612 01613 status = IoInitializeDumpStack (dumpStack, messageBuffer); 01614 if (!NT_SUCCESS( status )) { 01615 IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL; 01616 return FALSE; 01617 } 01618 01619 // 01620 // Record the dump driver's entry points. 01621 // 01622 01623 write = dumpStack->Init.WriteRoutine; 01624 finishUp = dumpStack->Init.FinishRoutine; 01625 01626 01627 dwTransferSize = dumpStack->Init.MaximumTransferSize; 01628 01629 if ( ( !dwTransferSize ) || ( dwTransferSize > IO_DUMP_MAXIMUM_TRANSFER_SIZE ) ) { 01630 dwTransferSize = IO_DUMP_MINIMUM_TRANSFER_SIZE; 01631 } 01632 01633 IoDebugPrint((2,"CRASHDUMP: Maximum Transfer Size = %x\n",dwTransferSize)); 01634 01635 01636 // 01637 // The boot partition was found, so put together a dump file header 01638 // and write it to the disk. 01639 // 01640 01641 block = dcb->HeaderPage; 01642 header = (PDUMP_HEADER) block; 01643 01644 RtlFillMemoryUlong( header, PAGE_SIZE, 'EGAP' ); 01645 header->ValidDump = 'PMUD'; 01646 header->BugCheckCode = BugCheckCode; 01647 header->BugCheckParameter1 = BugCheckParameter1; 01648 header->BugCheckParameter2 = BugCheckParameter2; 01649 header->BugCheckParameter3 = BugCheckParameter3; 01650 header->BugCheckParameter4 = BugCheckParameter4; 01651 #if defined (i386) 01652 // 01653 // Add the current page directory table page - don't use the directory 01654 // table base for the crashing process as we have switched cr3 on 01655 // stack overflow crashes, etc. 01656 // 01657 01658 _asm { 01659 mov eax, cr3 01660 mov DirBasePage, eax 01661 } 01662 header->DirectoryTableBase = DirBasePage; 01663 #else 01664 header->DirectoryTableBase = KeGetCurrentThread()->ApcState.Process->DirectoryTableBase[0]; 01665 #endif 01666 header->PfnDataBase = MmPfnDatabase; 01667 header->PsLoadedModuleList = &PsLoadedModuleList; 01668 header->PsActiveProcessHead = &PsActiveProcessHead; 01669 header->NumberProcessors = dcb->NumberProcessors; 01670 header->MajorVersion = dcb->MajorVersion; 01671 header->MinorVersion = dcb->MinorVersion; 01672 header->KdDebuggerDataBlock = KdGetDataBlock(); 01673 header->PaeEnabled = PaeEnabled (); 01674 01675 header->MachineImageType = CURRENT_IMAGE_TYPE (); 01676 01677 if (!(dcb->Flags & DCB_DUMP_ENABLED)) { 01678 dcb->MemoryDescriptor->NumberOfPages = 1; 01679 } 01680 01681 strcpy( header->VersionUser, dcb->VersionUser ); 01682 01683 RtlCopyMemory( &block[DH_PHYSICAL_MEMORY_BLOCK], 01684 dcb->MemoryDescriptor, 01685 sizeof( PHYSICAL_MEMORY_DESCRIPTOR ) + 01686 ((dcb->MemoryDescriptor->NumberOfRuns - 1) * 01687 sizeof( PHYSICAL_MEMORY_RUN )) ); 01688 01689 RtlCopyMemory( &block[DH_CONTEXT_RECORD], 01690 context, 01691 sizeof( CONTEXT ) ); 01692 01693 exception.ExceptionCode = STATUS_BREAKPOINT; 01694 exception.ExceptionRecord = (PEXCEPTION_RECORD) NULL; 01695 exception.NumberParameters = 0; 01696 exception.ExceptionFlags = EXCEPTION_NONCONTINUABLE; 01697 exception.ExceptionAddress = (PVOID) PROGRAM_COUNTER (context); 01698 01699 RtlCopyMemory( &block[DH_EXCEPTION_RECORD], 01700 &exception, 01701 sizeof( EXCEPTION_RECORD ) ); 01702 01703 // 01704 // Init dump type to FULL 01705 // 01706 01707 block[DH_DUMP_TYPE] = DUMP_TYPE_FULL; 01708 01709 // 01710 // Set the timestamp 01711 // 01712 #ifdef _WIN64 01713 RtlCopyMemory( &block[DH_CRASH_DUMP_TIMESTAMP], 01714 (PCHAR)( &SharedUserData->SystemLowTime), 01715 sizeof( LARGE_INTEGER) ); 01716 #else 01717 RtlCopyMemory( &block[DH_CRASH_DUMP_TIMESTAMP], 01718 (PCHAR)( &SharedUserData->SystemTime), 01719 sizeof( LARGE_INTEGER) ); 01720 #endif 01721 01722 // 01723 // Set the Required dump size in the dump header. In the case of 01724 // a summary dump the file allocation size can be significantly larger 01725 // then the amount of used space. 01726 // 01727 01728 RtlZeroMemory( &block[DH_REQUIRED_DUMP_SPACE], sizeof(LARGE_INTEGER)); 01729 01730 if (dcb->Flags & DCB_DUMP_ENABLED) { 01731 01732 // 01733 // If summary dump try to create the dump header 01734 // 01735 01736 if ( (dcb->Flags & DCB_SUMMARY_DUMP_ENABLED) ) { 01737 01738 // 01739 // Initialize the summary dump 01740 // 01741 01742 pSummaryHeader = IopInitializeSummaryDump(dcb); 01743 01744 if ( !pSummaryHeader ) { 01745 01746 // 01747 // No summary dump header so return. 01748 // 01749 01750 IoDebugPrint((1,"IoWriteCrashDump: Error Null summary dump header\n")); 01751 01752 IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL; 01753 01754 return FALSE; 01755 } 01756 } 01757 01758 IopInitializeDumpSpaceAndType (dcb, block, pSummaryHeader); 01759 } 01760 01761 // 01762 // All of the pieces of the header file have been generated. Before 01763 // mapping or writing anything to the disk, the I- & D-stream caches 01764 // must be flushed so that page color coherency is kept. Sweep both 01765 // caches now. 01766 // 01767 01768 KeSweepCurrentDcache(); 01769 KeSweepCurrentIcache(); 01770 01771 // 01772 // Create MDL for dump. 01773 // 01774 01775 mdl = (PMDL) &localMdl[0]; 01776 MmCreateMdl( mdl, NULL, PAGE_SIZE ); 01777 mdl->MdlFlags |= MDL_PAGES_LOCKED; 01778 01779 mcb = dcb->FileDescriptorArray; 01780 01781 page = MmGetMdlPfnArray(mdl); 01782 *page = dcb->HeaderPfn; 01783 mdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA; 01784 01785 bytesRemaining = PAGE_SIZE; 01786 memoryAddress = (ULONG_PTR) dcb->HeaderPage; 01787 01788 // 01789 // All of the pieces of the header file have been generated. Write 01790 // the header page to the paging file, using the appropriate drivers, 01791 // etc. 01792 // 01793 01794 IoDebugPrint((2,"IoWriteCrashDump: Writing dump header to disk\n")); 01795 01796 while (bytesRemaining) { 01797 01798 if (mcb[0].QuadPart <= bytesRemaining) { 01799 byteCount = mcb[0].LowPart; 01800 } else { 01801 byteCount = bytesRemaining; 01802 } 01803 01804 mdl->ByteCount = byteCount; 01805 mdl->ByteOffset = (ULONG)(memoryAddress & (PAGE_SIZE - 1)); 01806 mdl->MappedSystemVa = (PVOID) memoryAddress; 01807 mdl->StartVa = PAGE_ALIGN ((PVOID)memoryAddress); 01808 01809 // 01810 // Write to disk. 01811 // 01812 01813 if (!NT_SUCCESS( write( &mcb[1], mdl ) )) { 01814 IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL; 01815 return FALSE; 01816 } 01817 01818 // 01819 // Adjust bytes remaining. 01820 // 01821 01822 bytesRemaining -= byteCount; 01823 memoryAddress += byteCount; 01824 mcb[0].QuadPart = mcb[0].QuadPart - byteCount; 01825 mcb[1].QuadPart = mcb[1].QuadPart + byteCount; 01826 01827 if (!mcb[0].QuadPart) { 01828 mcb += 2; 01829 } 01830 } 01831 01832 IoDebugPrint((2,"IoWriteCrashDump: Header Page written\n")); 01833 01834 01835 // 01836 // If only requesting a header dump, we are now done. 01837 // 01838 01839 if (dcb->Flags & DCB_DUMP_HEADER_ENABLED) { 01840 IoDebugPrint((2,"IoWriteCrashDump: Only Dumping Dump Header\n")); 01841 goto FinishDump; 01842 } 01843 01844 // 01845 // The header page has been written. If this is a triage-dump, write 01846 // the dump information and bail. Otherwise, fall through and do the 01847 // full or summary dump. 01848 // 01849 01850 if (dcb->Flags & DCB_TRIAGE_DUMP_ENABLED) { 01851 status = IopWriteTriageDump (dcb->TriageDumpFlags, 01852 write, 01853 mcb, 01854 mdl, 01855 dwTransferSize, 01856 context, 01857 dcb->TriageDumpBuffer, 01858 dcb->TriageDumpBufferSize - PAGE_SIZE, 01859 dcb->BuildNumber, 01860 dcb->Flags 01861 ); 01862 01863 if (!NT_SUCCESS (status)) { 01864 IoDebugPrint((1, "IoWriteCrashDump: Failed to write triage-dump\n")); 01865 IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL; 01866 return FALSE; 01867 } 01868 01869 IoDebugPrint((1, "IoWriteCrashDump: Successfully wrote triage-dump\n")); 01870 goto FinishDump; 01871 } 01872 01873 // 01874 // The header page has been written to the paging file. If a full dump 01875 // of all of physical memory is to be written, write it now. 01876 // 01877 01878 if (dcb->Flags & DCB_DUMP_ENABLED) { 01879 01880 PFN_NUMBER pagesDoneSoFar = 0; 01881 ULONG currentPercentage = 0; 01882 ULONG maximumPercentage = 0; 01883 01884 01885 // 01886 // Actual Pages is the number of pages to dump. 01887 // 01888 01889 ActualPages = dcb->MemoryDescriptor->NumberOfPages; 01890 01891 if (dcb->Flags & DCB_SUMMARY_DUMP_ENABLED) { 01892 01893 PRTL_BITMAP PageMap; 01894 01895 ASSERT ( pSummaryHeader != NULL ); 01896 01897 PageMap = (PRTL_BITMAP)(pSummaryHeader + 1); 01898 ASSERT (PageMap != NULL); 01899 01900 // 01901 // At this point the dump header header has been sucessfully 01902 // written. Write the summary dump header. 01903 // 01904 01905 status = IopWriteSummaryHeader( 01906 pSummaryHeader, 01907 write, 01908 &mcb, 01909 mdl, 01910 dwTransferSize, 01911 (dcb->HeaderSize - PAGE_SIZE) 01912 ); 01913 01914 if (!NT_SUCCESS (status)) { 01915 IoDebugPrint((1,"IoWriteCrashDump: Error writing summary dump header\n")); 01916 IopFinalCrashDumpStatus = status; 01917 return FALSE; 01918 } 01919 01920 IoDebugPrint((2,"IoWriteCrashDump: Sucessfully wrote summary dump header\n")); 01921 01922 ActualPages = pSummaryHeader->Pages; 01923 01924 } 01925 01926 IoDebugPrint((2,"IoWriteCrashDump: Writing Memory Dump\n")); 01927 01928 // 01929 // Set the virtual file offset and initialize loop variables and 01930 // constants. 01931 // 01932 01933 memoryAddress = (ULONG_PTR)dcb->MemoryDescriptor->Run[0].BasePage * PAGE_SIZE; 01934 01935 if ( dcb->Flags & DCB_SUMMARY_DUMP_ENABLED ) { 01936 01937 PRTL_BITMAP BitMap; 01938 01939 BitMap = (PRTL_BITMAP)(pSummaryHeader+1); 01940 01941 status = IopWriteSummaryDump ( 01942 BitMap, 01943 write, 01944 &dumpStack->ProgMsg, 01945 messageBuffer, 01946 mcb, 01947 dwTransferSize 01948 ); 01949 01950 if (!NT_SUCCESS (status)) { 01951 IoDebugPrint((1, "IoWriteCrashDump: Failed to write triage-dump\n")); 01952 IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL; 01953 return FALSE; 01954 } 01955 01956 IoDebugPrint((1, "IoWriteCrashDump: Successfully wrote triage-dump\n")); 01957 goto FinishDump; 01958 } 01959 01960 // 01961 // Now loop, writing all of physical memory to the paging file. 01962 // 01963 01964 while (mcb[0].QuadPart) { 01965 01966 diskByteOffset = mcb[1]; 01967 01968 // 01969 // Calculate byte offset; 01970 // 01971 01972 byteOffset = (ULONG)(memoryAddress & (PAGE_SIZE - 1)); 01973 01974 if (dwTransferSize <= mcb[0].QuadPart) { 01975 byteCount = dwTransferSize - byteOffset; 01976 } else { 01977 byteCount = mcb[0].LowPart; 01978 } 01979 pagesDoneSoFar += byteCount / PAGE_SIZE; 01980 01981 currentPercentage = (ULONG)((pagesDoneSoFar * 100) / 01982 ActualPages); 01983 01984 if (currentPercentage > maximumPercentage) { 01985 01986 maximumPercentage = currentPercentage; 01987 // 01988 // Update message on screen. 01989 // 01990 01991 sprintf( messageBuffer, "%Z: %3d\r", &dumpStack->ProgMsg, maximumPercentage ); 01992 InbvDisplayString( messageBuffer ); 01993 01994 } 01995 01996 // 01997 // Map the physical memory and write it to the 01998 // current segment of the file. 01999 // 02000 02001 IopMapPhysicalMemory( mdl, 02002 memoryAddress, 02003 &dcb->MemoryDescriptor->Run[0], 02004 byteCount 02005 ); 02006 02007 02008 // 02009 // Write the next segment. 02010 // 02011 02012 if (!NT_SUCCESS( write( &diskByteOffset, mdl ) )) { 02013 IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL; 02014 return FALSE; 02015 } 02016 02017 // 02018 // Adjust pointers for next part. 02019 // 02020 02021 memoryAddress += byteCount; 02022 mcb[0].QuadPart = mcb[0].QuadPart - byteCount; 02023 mcb[1].QuadPart = mcb[1].QuadPart + byteCount; 02024 02025 if (!mcb[0].QuadPart) { 02026 mcb += 2; 02027 } 02028 02029 if (pagesDoneSoFar >= ActualPages) { 02030 break; 02031 02032 } 02033 02034 } 02035 02036 IoDebugPrint((2,"IoWriteCrashDump: memory dump written\n")); 02037 } 02038 02039 FinishDump: 02040 02041 sprintf( messageBuffer, "%Z", &dumpStack->DoneMsg ); 02042 InbvDisplayString( messageBuffer ); 02043 02044 // 02045 // Sweep the cache so the debugger will work. 02046 // 02047 02048 KeSweepCurrentDcache(); 02049 KeSweepCurrentIcache(); 02050 02051 // 02052 // Have the dump flush the adapter and disk caches. 02053 // 02054 02055 finishUp(); 02056 02057 // 02058 // Indicate to the debugger that the dump has been successfully 02059 // written. 02060 // 02061 02062 IopFinalCrashDumpStatus = STATUS_SUCCESS; 02063 } 02064 02065 // 02066 // Check to see whether or not auto-reboots are enabled and, if so, 02067 // reboot now. 02068 // 02069 02070 if (dcb->Flags & DCB_AUTO_REBOOT) { 02071 IoDebugPrint (( 0, "IODUMP: Autorebooting\n" )); 02072 KeReturnToFirmware( HalRebootRoutine ); 02073 } 02074 02075 return TRUE; 02076 } 02077 02078 02079 02080 VOID 02081 IopMapPhysicalMemory( 02082 IN OUT PMDL Mdl, 02083 IN ULONG_PTR MemoryAddress, 02084 IN PPHYSICAL_MEMORY_RUN PhysicalMemoryRun, 02085 IN ULONG Length 02086 ) 02087 02088 /*++ 02089 02090 Routine Description: 02091 02092 This routine is invoked to fill in the specified MDL (Memory Descriptor 02093 List) w/the appropriate information to map the specified memory address 02094 range. 02095 02096 Arguments: 02097 02098 Mdl - Address of the MDL to be filled in. 02099 02100 MemoryAddress - Pseudo-virtual address being mapped. 02101 02102 PhysicalMemoryRun - Base address of the physical memory run list. 02103 02104 Length - Length of transfer to be mapped. 02105 02106 Return Value: 02107 02108 None. 02109 02110 --*/ 02111 02112 { 02113 PPHYSICAL_MEMORY_RUN pmr = PhysicalMemoryRun; 02114 PPFN_NUMBER page; 02115 PFN_NUMBER pages; 02116 PFN_NUMBER base; 02117 PFN_NUMBER currentBase; 02118 02119 // 02120 // Begin by determining the base physical page of the start of the address 02121 // range and filling in the MDL appropriately. 02122 // 02123 Mdl->StartVa = PAGE_ALIGN( (PVOID) (MemoryAddress) ); 02124 Mdl->ByteOffset = (ULONG)(MemoryAddress & (PAGE_SIZE - 1)); 02125 Mdl->ByteCount = Length; 02126 02127 // 02128 // Get the page frame index for the base address. 02129 // 02130 02131 base = (PFN_NUMBER) ((ULONG_PTR)(Mdl->StartVa) >> PAGE_SHIFT); 02132 pages = COMPUTE_PAGES_SPANNED(MemoryAddress, Length); 02133 currentBase = pmr->BasePage; 02134 page = MmGetMdlPfnArray(Mdl); 02135 02136 // 02137 // Map all of the pages for this transfer until there are no more remaining 02138 // to be mapped. 02139 // 02140 02141 while (pages) { 02142 02143 // 02144 // Find the memory run that maps the beginning of this transfer. 02145 // 02146 02147 while (currentBase + pmr->PageCount <= base) { 02148 currentBase += pmr->PageCount; 02149 pmr++; 02150 } 02151 02152 // 02153 // The current memory run maps the start of this transfer. Capture 02154 // the base page for the start of the transfer. 02155 // 02156 02157 *page++ = pmr->BasePage + (PFN_NUMBER)(base++ - currentBase); 02158 pages--; 02159 } 02160 02161 // 02162 // All of the PFNs for the address range have been filled in so map the 02163 // physical memory into virtual address space. 02164 // 02165 02166 MmMapMemoryDumpMdl( Mdl ); 02167 } 02168 02169 02170 02171 VOID 02172 IopAddPageToPageMap( 02173 IN ULONG dwMaxPage, 02174 IN PRTL_BITMAP pBitMapHeader, 02175 IN ULONG dwPageFrameIndex, 02176 IN ULONG dwNumberOfPages 02177 ) 02178 { 02179 // 02180 // Sometimes we get PFNs that are out of range. Just ignore them. 02181 // 02182 02183 if (dwPageFrameIndex >= dwMaxPage) { 02184 return; 02185 } 02186 02187 RtlSetBits (pBitMapHeader, dwPageFrameIndex, dwNumberOfPages); 02188 } 02189 02190 02191 02192 VOID 02193 IopRemovePageFromPageMap( 02194 IN ULONG dwMaxPage, 02195 IN PRTL_BITMAP pBitMapHeader, 02196 IN ULONG dwPageFrameIndex, 02197 IN ULONG dwNumberOfPages 02198 ) 02199 { 02200 // 02201 // Sometimes we get PFNs that are out of range. Just ignore them. 02202 // 02203 02204 if (dwPageFrameIndex >= dwMaxPage) { 02205 return; 02206 } 02207 02208 IoDebugPrint( (6, "RtlClearBits max:%x pfn:%x, pages:%x\n",(dwMaxPage), (dwPageFrameIndex), (dwNumberOfPages) )); \ 02209 RtlClearBits (pBitMapHeader, dwPageFrameIndex, dwNumberOfPages); 02210 02211 } 02212 02213 02214 02215 NTKERNELAPI 02216 NTSTATUS 02217 IoGetCrashDumpInformation( 02218 OUT PSYSTEM_CRASH_DUMP_INFORMATION pCrashDumpInfo 02219 ) 02220 02221 /*++ 02222 02223 Routine Description: 02224 02225 This function checks to see if an open crash dump section exists and 02226 if so creates a handle to the section and returns that value 02227 in the CrashDumpInformation structure. 02228 02229 02230 Arguments: 02231 02232 CrashInfo - Supplies a pointer to the crash dump information 02233 structure. 02234 02235 Return Value: 02236 02237 Status of the operation. A handle value of zero indicates no 02238 crash dump was located. 02239 02240 --*/ 02241 { 02242 02243 if (!IopDumpControlBlock) { 02244 return STATUS_NOT_FOUND; 02245 } 02246 02247 // 02248 // NB: The section object is for direct dump support, which has been 02249 // removed. 02250 // 02251 02252 pCrashDumpInfo->hDumpSection = NULL; 02253 return STATUS_SUCCESS; 02254 } 02255 02256 02257 02258 NTKERNELAPI 02259 NTSTATUS 02260 IoGetCrashDumpStateInformation( 02261 OUT PSYSTEM_CRASH_STATE_INFORMATION pCrashDumpState 02262 ) 02263 02264 /*++ 02265 02266 Routine Description: 02267 02268 This routine returns sets the state variable for direct dump (fast dump) 02269 02270 02271 Arguments: 02272 02273 CrashInfo - Supplies a pointer to the crash dump state information 02274 structure. 02275 02276 Return Value: 02277 02278 Status of the operation. A handle value of zero indicates no 02279 crash dump was located. 02280 02281 --*/ 02282 02283 { 02284 pCrashDumpState->ValidDirectDump = FALSE; 02285 02286 return STATUS_SUCCESS; 02287 } 02288 02289 02290 NTSTATUS 02291 IoSetDumpRange( 02292 IN PVOID DumpContext, 02293 IN PVOID StartVa, 02294 IN ULONG_PTR Pages, 02295 IN BOOLEAN IsPhysicalAddress 02296 ) 02297 02298 /*++ 02299 02300 Routine Description: 02301 02302 This routine includes this range of memory in the dump 02303 02304 Arguments: 02305 02306 DumpContext - dump context 02307 02308 StartVa - Starting VA 02309 02310 Pages - The number of pages to include 02311 02312 IsPhysicalAddress - true if direct physical address translation 02313 02314 Return Value: 02315 02316 STATUS_SUCCESS - On success. 02317 02318 NTSTATUS - Error. 02319 02320 --*/ 02321 { 02322 PCHAR Va; 02323 PRTL_BITMAP pBitMapHeader; 02324 PHYSICAL_ADDRESS phyAddr; 02325 PSUMMARY_DUMP_HEADER pHeader; 02326 BOOLEAN AllPagesSet; 02327 02328 02329 Va = StartVa; 02330 pHeader = (PSUMMARY_DUMP_HEADER) DumpContext; 02331 pBitMapHeader = (PRTL_BITMAP)(pHeader + 1); 02332 AllPagesSet = TRUE; 02333 02334 // 02335 // Win64 can have really large page addresses. This dump code does 02336 // not handle that yet. Note that before this assert is removed 02337 // the casts of Pages to ULONG must be removed. 02338 // 02339 02340 ASSERT(Pages <= MAXULONG); 02341 02342 // 02343 // IsPhysicalAddress indicates that the va is virtually / physically 02344 // contiguous. 02345 // 02346 02347 if (IsPhysicalAddress) { 02348 02349 phyAddr = MmGetPhysicalAddress (Va); 02350 IopAddPageToPageMap (pHeader->BitmapSize, 02351 pBitMapHeader, 02352 (ULONG)(phyAddr.QuadPart >> PAGE_SHIFT), 02353 (ULONG) Pages 02354 ); 02355 02356 } else { 02357 02358 // 02359 // Not physically contiguous. 02360 // 02361 02362 while (Pages) { 02363 02364 // 02365 // Only do a translation for valid pages. 02366 // 02367 02368 if ( MmIsAddressValid(Va) ) { 02369 02370 // 02371 // Get the physical mapping. Note: this does not require a lock 02372 // 02373 02374 phyAddr = MmGetPhysicalAddress (Va); 02375 02376 IopAddPageToPageMap (pHeader->BitmapSize, 02377 pBitMapHeader, 02378 (ULONG)(phyAddr.QuadPart >> PAGE_SHIFT), 02379 1); 02380 02381 if (phyAddr.QuadPart >> PAGE_SHIFT > pHeader->BitmapSize) { 02382 AllPagesSet = FALSE; 02383 } 02384 } 02385 02386 Va += PAGE_SIZE; 02387 Pages--; 02388 } 02389 } 02390 02391 if (AllPagesSet) { 02392 return STATUS_SUCCESS; 02393 } 02394 02395 return STATUS_INVALID_ADDRESS; 02396 } 02397 02398 02399 NTSTATUS 02400 IoFreeDumpRange( 02401 IN PVOID DumpContext, 02402 IN PVOID StartVa, 02403 IN ULONG_PTR Pages, 02404 IN BOOLEAN IsPhysicalAddress 02405 ) 02406 /*++ 02407 02408 Routine Description: 02409 02410 This routine excludes this range of memory in the dump. 02411 02412 Arguments: 02413 02414 DumpContext - dump context 02415 02416 StartVa - Starting VA 02417 02418 Pages - The number of pages to include 02419 02420 IsPhysicalAddress - true if direct physical address translation 02421 02422 Return Value: 02423 02424 STATUS_SUCCESS - On success. 02425 02426 NTSTATUS - Error. 02427 02428 --*/ 02429 { 02430 PCHAR Va; 02431 PRTL_BITMAP pBitMapHeader; 02432 PHYSICAL_ADDRESS phyAddr; 02433 PSUMMARY_DUMP_HEADER pHeader; 02434 02435 // 02436 // Round to page size. 02437 // 02438 02439 Va = StartVa; 02440 pHeader = (PSUMMARY_DUMP_HEADER)DumpContext; 02441 pBitMapHeader = (PRTL_BITMAP)(pHeader + 1); 02442 02443 // 02444 // Win64 can have really large page addresses. This dump code does 02445 // not handle that yet. Note that before this assert is removed 02446 // the casts of Pages to ULONG must be removed. 02447 // 02448 02449 ASSERT (Pages <= MAXULONG); 02450 02451 if (IsPhysicalAddress) { 02452 02453 phyAddr = MmGetPhysicalAddress(Va); 02454 02455 IopRemovePageFromPageMap (pHeader->BitmapSize, 02456 pBitMapHeader, 02457 (ULONG)(phyAddr.QuadPart >> PAGE_SHIFT), 02458 (ULONG) Pages 02459 ); 02460 } else { 02461 02462 while (Pages) { 02463 02464 // 02465 // Only do a translation for valid pages. 02466 // 02467 02468 if ( MmIsAddressValid (Va) ) { 02469 phyAddr = MmGetPhysicalAddress (Va); 02470 02471 IoDebugPrint((3,"IoFreeDumpRange:Va: %x Pages: %x IsPhysical: %x phyAddr %I64x\n", 02472 StartVa,Pages,IsPhysicalAddress, phyAddr.QuadPart)); 02473 02474 IopRemovePageFromPageMap (pHeader->BitmapSize, 02475 pBitMapHeader, 02476 (ULONG)(phyAddr.QuadPart >> PAGE_SHIFT), 02477 1); 02478 02479 } 02480 02481 Va += PAGE_SIZE; 02482 Pages--; 02483 } 02484 } 02485 02486 return STATUS_SUCCESS; 02487 } 02488 02489 02490 02491 LARGE_INTEGER 02492 IopCalculateRequiredDumpSpace( 02493 IN ULONG dwDmpFlags, 02494 IN ULONG dwHeaderSize, 02495 IN PFN_NUMBER dwMaxPages, 02496 IN PFN_NUMBER dwMaxSummaryPages 02497 ) 02498 02499 /*++ 02500 02501 Routine Description: 02502 02503 This routine is used to calcuate required dump space 02504 02505 1. Crash dump summary must be at least 1 page in length. 02506 02507 2. Summary dump must be large enough for kernel memory plus header, 02508 plus summary header. 02509 02510 3. Full dump must be large enough for header plus all physical memory. 02511 02512 Arguments: 02513 02514 dwDmpFlags - Dump Control Block (DCB) flags. 02515 02516 dwHeaderSize - The size of the dump header. 02517 02518 dwMaxPages - All physical memory. 02519 02520 dwMaxSummaryPages - Maximum pages in summary dump. 02521 02522 Return Value: 02523 02524 Size of the dump file 02525 02526 --*/ 02527 { 02528 LARGE_INTEGER maxMemorySize; 02529 02530 // 02531 // Dump header or dump summary. 02532 // 02533 02534 if ( (dwDmpFlags & DCB_DUMP_HEADER_ENABLED) || 02535 ( !( dwDmpFlags & DCB_DUMP_ENABLED ) && 02536 ( dwDmpFlags & DCB_SUMMARY_ENABLED ) ) ) { 02537 02538 maxMemorySize.QuadPart = IO_DUMP_MINIMUM_FILE_SIZE; 02539 return maxMemorySize; 02540 } 02541 02542 if (dwDmpFlags & DCB_TRIAGE_DUMP_ENABLED) { 02543 02544 maxMemorySize.QuadPart = TRIAGE_DUMP_SIZE; 02545 return maxMemorySize; 02546 } 02547 02548 if (dwDmpFlags & DCB_SUMMARY_DUMP_ENABLED) { 02549 ULONG summaryHeaderSize; 02550 ULONG dwGB; 02551 02552 maxMemorySize.QuadPart = (dwMaxSummaryPages) * PAGE_SIZE; 02553 02554 // 02555 // If biased then max kernel memory is 1GB otherwise it is 2GB 02556 // 02557 02558 dwGB = 1024 * 1024 * 1024; 02559 02560 if (maxMemorySize.QuadPart > (2 * dwGB) ) { 02561 if (MmVirtualBias) { 02562 maxMemorySize.QuadPart = dwGB; 02563 } else { 02564 maxMemorySize.QuadPart = (2 * dwGB); 02565 } 02566 } 02567 02568 // 02569 // Calculate the summary header size. Includes the header plus bitmap 02570 // 02571 summaryHeaderSize = (ULONG) ROUND_TO_PAGES( 02572 sizeof(SUMMARY_DUMP_HEADER) + 02573 sizeof(RTL_BITMAP) + 02574 ( ( (maxMemorySize.QuadPart >> PAGE_SHIFT ) >> 5 ) << 2 ) + 02575 dwHeaderSize 02576 ); 02577 02578 maxMemorySize.QuadPart+= summaryHeaderSize; 02579 02580 return maxMemorySize; 02581 02582 } 02583 02584 // 02585 // Full memory dump is #pages * pagesize plus 1 page for the dump header. 02586 // 02587 02588 maxMemorySize.QuadPart = (dwMaxPages * PAGE_SIZE) + dwHeaderSize; 02589 02590 return maxMemorySize; 02591 02592 } 02593 02594 02595 02596 // 02597 // Triage-dump support routines. 02598 // 02599 02600 02601 NTSTATUS 02602 IopGetLoadedDriverInfo( 02603 OUT ULONG * lpDriverCount, 02604 OUT ULONG * lpSizeOfStringData 02605 ) 02606 02607 /*++ 02608 02609 Routine Description: 02610 02611 Get information about all loaded drivers. 02612 02613 Arguments: 02614 02615 lpDriverCount - Buffer to return the count of all the drivers that are 02616 currently loaded in the system. 02617 02618 lpSizeOfStringData - Buffer to return the sum of the sizes of all driver 02619 name strings (FullDllName). This does not include the size 02620 of the UNICODE_STRING structure or a trailing NULL byte. 02621 02622 Return Values: 02623 02624 NTSTATUS 02625 02626 --*/ 02627 02628 { 02629 ULONG DriverCount = 0; 02630 ULONG SizeOfStringData = 0; 02631 PLIST_ENTRY NextEntry; 02632 PLDR_DATA_TABLE_ENTRY DriverEntry; 02633 02634 02635 NextEntry = PsLoadedModuleList.Flink; 02636 while (NextEntry != &PsLoadedModuleList) { 02637 02638 DriverEntry = CONTAINING_RECORD (NextEntry, 02639 LDR_DATA_TABLE_ENTRY, 02640 InLoadOrderLinks 02641 ); 02642 02643 if (!IopIsAddressRangeValid (DriverEntry, sizeof (*DriverEntry)) || 02644 !IopIsAddressRangeValid (DriverEntry->BaseDllName.Buffer, 02645 DriverEntry->BaseDllName.Length)) { 02646 02647 return STATUS_UNSUCCESSFUL; 02648 } 02649 02650 DriverCount++; 02651 SizeOfStringData += DriverEntry->FullDllName.Length; 02652 NextEntry = NextEntry->Flink; 02653 } 02654 02655 *lpDriverCount = DriverCount; 02656 *lpSizeOfStringData = SizeOfStringData; 02657 02658 return STATUS_SUCCESS; 02659 } 02660 02661 #define DmpPoolStringSize(DumpString)\ 02662 (sizeof (DUMP_STRING) + sizeof (WCHAR) * ( DumpString->Length + 1 )) 02663 02664 #define DmpNextPoolString(DumpString) \ 02665 (PDUMP_STRING) ( \ 02666 ALIGN_UP_POINTER( \ 02667 ((LPBYTE) DumpString) + DmpPoolStringSize (DumpString), \ 02668 ULONGLONG \ 02669 ) \ 02670 ) 02671 02672 #define ALIGN_8(_x) ALIGN_UP(_x, DWORDLONG) 02673 02674 02675 #ifndef IndexByByte 02676 #define IndexByByte(Pointer, Index) (&(((BYTE*) (Pointer)) [Index])) 02677 #endif 02678 02679 02680 NTSTATUS 02681 IopWriteDriverList( 02682 IN ULONG_PTR BufferAddress, 02683 IN ULONG BufferSize, 02684 IN ULONG DriverListOffset, 02685 IN ULONG StringPoolOffset 02686 ) 02687 02688 /*++ 02689 02690 Routine Description: 02691 02692 Write the triage dump driver list to the buffer. 02693 02694 Arguments: 02695 02696 BufferAddress - The address of the buffer. 02697 02698 BufferSize - The size of the buffer. 02699 02700 DriverListOffset - The offset within the buffer where the driver list 02701 should be written. 02702 02703 StringPoolOffset - The offset within the buffer where the driver list's 02704 string pool should start. If there are no other strings for the triage 02705 dump other than driver name strings, this will be the string pool 02706 offset. 02707 02708 Return Value: 02709 02710 NTSTATUS 02711 02712 --*/ 02713 02714 { 02715 ULONG i = 0; 02716 PLIST_ENTRY NextEntry; 02717 PLDR_DATA_TABLE_ENTRY DriverEntry; 02718 PDUMP_DRIVER_ENTRY DumpImageArray; 02719 PDUMP_STRING DumpStringName = NULL; 02720 PIMAGE_NT_HEADERS NtHeaders; 02721 02722 ASSERT (DriverListOffset != 0); 02723 ASSERT (StringPoolOffset != 0); 02724 02725 02726 DumpImageArray = (PDUMP_DRIVER_ENTRY) (BufferAddress + DriverListOffset); 02727 DumpStringName = (PDUMP_STRING) (BufferAddress + StringPoolOffset); 02728 02729 NextEntry = PsLoadedModuleList.Flink; 02730 02731 while (NextEntry != &PsLoadedModuleList) { 02732 02733 DriverEntry = CONTAINING_RECORD (NextEntry, 02734 LDR_DATA_TABLE_ENTRY, 02735 InLoadOrderLinks); 02736 02737 // 02738 // Verify the memory is valid before reading anything from it. 02739 // 02740 02741 if (!IopIsAddressRangeValid (DriverEntry, sizeof (*DriverEntry)) || 02742 !IopIsAddressRangeValid (DriverEntry->BaseDllName.Buffer, 02743 DriverEntry->BaseDllName.Length)) { 02744 02745 return STATUS_UNSUCCESSFUL; 02746 } 02747 02748 // 02749 // Build the entry in the string pool. We guarantee all strings are 02750 // NULL terminated as well as length prefixed. 02751 // 02752 02753 DumpStringName->Length = DriverEntry->BaseDllName.Length / 2; 02754 RtlCopyMemory (DumpStringName->Buffer, 02755 DriverEntry->BaseDllName.Buffer, 02756 DumpStringName->Length * sizeof (WCHAR) 02757 ); 02758 02759 DumpStringName->Buffer[ DumpStringName->Length ] = '\000'; 02760 02761 RtlCopyMemory (&DumpImageArray [i].LdrEntry, 02762 DriverEntry, 02763 sizeof (DumpImageArray [i].LdrEntry) 02764 ); 02765 02766 // 02767 // Add the time/date stamp. 02768 // 02769 02770 DumpImageArray[i].LdrEntry.TimeDateStamp = 0; 02771 DumpImageArray[i].LdrEntry.SizeOfImage = 0; 02772 02773 if ( MmDbgReadCheck (DriverEntry->DllBase ) != NULL ) { 02774 02775 NtHeaders = RtlImageNtHeader (DriverEntry->DllBase); 02776 ASSERT ( NtHeaders ); 02777 DumpImageArray[i].LdrEntry.TimeDateStamp = NtHeaders->FileHeader.TimeDateStamp; 02778 DumpImageArray[i].LdrEntry.SizeOfImage = NtHeaders->OptionalHeader.SizeOfImage; 02779 } 02780 02781 DumpImageArray [i].DriverNameOffset = 02782 (ULONG)((ULONG_PTR) DumpStringName - BufferAddress); 02783 02784 i++; 02785 DumpStringName = DmpNextPoolString (DumpStringName); 02786 NextEntry = NextEntry->Flink; 02787 } 02788 02789 return STATUS_SUCCESS; 02790 } 02791 02792 02793 02794 NTSTATUS 02795 IopWriteTriageDump( 02796 IN ULONG Fields, 02797 IN PDUMP_DRIVER_WRITE DriverWriteRoutine, 02798 IN OUT PLARGE_INTEGER Mcb, 02799 IN OUT PMDL Mdl, 02800 IN ULONG DriverTransferSize, 02801 IN PCONTEXT Context, 02802 IN BYTE* Buffer, 02803 IN ULONG BufferSize, 02804 IN ULONG ServicePackBuild, 02805 IN ULONG TriageOptions 02806 ) 02807 02808 /*++ 02809 02810 Routine Description: 02811 02812 Write the Triage-Dump to the MCB. 02813 02814 Arguments: 02815 02816 Fields - The set of fields that should be written. 02817 02818 DriverWriteRoutine - The write routine for the driver. 02819 02820 Mcb - Message Control Block where the data is to be written. 02821 02822 Mdl - A MDL descrbing the data to be written (??). 02823 02824 DriverTransferSize - The maximum transfer size for the driver. 02825 02826 Context - The context. 02827 02828 Buffer - The buffer to use as a scratch buffer. 02829 02830 BufferSize - The size of the buffer. 02831 02832 ServicePackBuild - Service Pack BuildNumber. 02833 02834 TriageOptions - Triage Options. 02835 02836 Return Values: 02837 02838 STATUS_SUCCESS - On success. 02839 02840 NTSTATUS - Otherwise. 02841 02842 Comments: 02843 02844 This function assumes that exactly one header page was written. 02845 02846 --*/ 02847 02848 { 02849 ULONG SizeOfSection; 02850 ULONG SizeOfStringData; 02851 ULONG DriverCount = 0; 02852 LPVOID Address = NULL; 02853 ULONG BytesToWrite = 0; 02854 ULONG_PTR BufferAddress = 0; 02855 NTSTATUS Status; 02856 ULONG_PTR Offset; 02857 ULONG_PTR StartOfStackRegion = 0; 02858 PTRIAGE_DUMP_HEADER TriageDumpHeader = NULL; 02859 PLDR_DATA_TABLE_ENTRY DriverEntry = NULL; 02860 PDUMP_DRIVER_ENTRY DumpImageArray = NULL; 02861 PDUMP_STRING DumpStringName = NULL; 02862 PETHREAD Thread = NULL; 02863 02864 IoDebugPrint ((0, "[IopWriteTriageDump] BufferSize = %#x ServicePackBuild = %d\n", 02865 BufferSize, 02866 ServicePackBuild)); 02867 02868 // 02869 // Setup the triage-dump header. 02870 // 02871 02872 if (BufferSize < sizeof (TRIAGE_DUMP_HEADER) + sizeof (DWORD)) { 02873 return STATUS_NO_MEMORY; 02874 } 02875 02876 TriageDumpHeader = (PTRIAGE_DUMP_HEADER) Buffer; 02877 RtlZeroMemory (TriageDumpHeader, sizeof (*TriageDumpHeader)); 02878 02879 // 02880 // The normal dump header is of size PAGE_SIZE. 02881 // 02882 02883 TriageDumpHeader->SizeOfDump = BufferSize + PAGE_SIZE; 02884 02885 // 02886 // Adjust the BufferSize so we can write the final status DWORD at the 02887 // end. 02888 // 02889 02890 BufferSize -= sizeof (DWORD); 02891 RtlZeroMemory (IndexByByte (Buffer, BufferSize), sizeof (DWORD)); 02892 02893 TriageDumpHeader->ValidOffset = ( TriageDumpHeader->SizeOfDump - sizeof (ULONG) ); 02894 TriageDumpHeader->ContextOffset = DH_CONTEXT_RECORD * sizeof (ULONG); 02895 TriageDumpHeader->ExceptionOffset = DH_EXCEPTION_RECORD * sizeof (ULONG); 02896 TriageDumpHeader->BrokenDriverOffset = 0; 02897 TriageDumpHeader->ServicePackBuild = ServicePackBuild; 02898 TriageDumpHeader->TriageOptions = TriageOptions; 02899 02900 Offset = ALIGN_8 (PAGE_SIZE + sizeof (TRIAGE_DUMP_HEADER)); 02901 02902 // 02903 // Set the Mm Offset, if necessary. 02904 // 02905 02906 SizeOfSection = ALIGN_8 (MmSizeOfTriageInformation()); 02907 02908 if (Offset + SizeOfSection < BufferSize) { 02909 TriageDumpHeader->MmOffset = (ULONG)Offset; 02910 Offset += SizeOfSection; 02911 } 02912 02913 // 02914 // Set the Unloaded Drivers Offset, if necessary. 02915 // 02916 02917 SizeOfSection = ALIGN_8 (MmSizeOfUnloadedDriverInformation()); 02918 02919 if (Offset + SizeOfSection < BufferSize) { 02920 TriageDumpHeader->UnloadedDriversOffset = (ULONG)Offset; 02921 Offset += SizeOfSection; 02922 } 02923 02924 // 02925 // Set the Prcb Offset, if necessary. 02926 // 02927 02928 if (Fields & TRIAGE_DUMP_PRCB) { 02929 SizeOfSection = ALIGN_8 (sizeof (KPRCB)); 02930 02931 if (Offset + SizeOfSection < BufferSize) { 02932 TriageDumpHeader->PrcbOffset = (ULONG)Offset; 02933 Offset += SizeOfSection; 02934 } 02935 } 02936 02937 // 02938 // Set the Process Offset, if necessary. 02939 // 02940 02941 if (Fields & TRIAGE_DUMP_PROCESS) { 02942 SizeOfSection = ALIGN_8 (sizeof (EPROCESS)); 02943 02944 if (Offset + SizeOfSection < BufferSize) { 02945 TriageDumpHeader->ProcessOffset = (ULONG)Offset; 02946 Offset += SizeOfSection; 02947 } 02948 } 02949 02950 // 02951 // Set the Thread Offset, if necessary. 02952 // 02953 02954 if (Fields & TRIAGE_DUMP_THREAD) { 02955 SizeOfSection = ALIGN_8 (sizeof (ETHREAD)); 02956 02957 if (Offset + SizeOfSection < BufferSize) { 02958 TriageDumpHeader->ThreadOffset = (ULONG)Offset; 02959 Offset += SizeOfSection; 02960 } 02961 } 02962 02963 // 02964 // Set the CallStack Offset, if necessary. 02965 // 02966 02967 Thread = PsGetCurrentThread (); 02968 02969 if (Fields & TRIAGE_DUMP_STACK) { 02970 02971 // 02972 // If there is a stack, calculate its size. 02973 // 02974 02975 if (Thread->Tcb.KernelStackResident) { 02976 02977 ULONG_PTR StackBase; 02978 02979 StackBase = (ULONG_PTR) Thread->Tcb.InitialStack; 02980 02981 ASSERT ( StackBase > STACK_POINTER (Context)); 02982 02983 // 02984 // There is a valid stack. Note that we limit the size of 02985 // the triage dump stack to MAX_TRIAGE_STACK_SIZE (currently 02986 // 16 KB). 02987 // 02988 02989 StartOfStackRegion = (ULONG_PTR) STACK_POINTER (Context); 02990 SizeOfSection = (ULONG) min ( StackBase - (ULONG_PTR) STACK_POINTER (Context), 02991 MAX_TRIAGE_STACK_SIZE 02992 ); 02993 02994 ASSERT ( StartOfStackRegion + SizeOfSection <= StackBase); 02995 02996 } else { 02997 02998 // 02999 // There is not a valid stack. 03000 // 03001 03002 SizeOfSection = 0; 03003 } 03004 03005 if (SizeOfSection && Offset + SizeOfSection < BufferSize) { 03006 TriageDumpHeader->CallStackOffset = (ULONG)Offset; 03007 TriageDumpHeader->SizeOfCallStack = SizeOfSection; 03008 TriageDumpHeader->BaseOfStack = (ULONG) StartOfStackRegion; 03009 Offset += SizeOfSection; 03010 } 03011 } 03012 03013 // 03014 // Set the Driver List Offset, if necessary. 03015 // 03016 03017 Status = IopGetLoadedDriverInfo (&DriverCount, &SizeOfStringData); 03018 03019 if (NT_SUCCESS (Status) && Fields & TRIAGE_DUMP_DRIVER_LIST) { 03020 SizeOfSection = ALIGN_8 (DriverCount * sizeof (DUMP_DRIVER_ENTRY)); 03021 03022 if (SizeOfSection && (Offset + SizeOfSection < BufferSize)) { 03023 TriageDumpHeader->DriverListOffset = (ULONG)Offset; 03024 TriageDumpHeader->DriverCount = DriverCount; 03025 Offset += SizeOfSection; 03026 } 03027 03028 } else { 03029 03030 SizeOfSection = 0; 03031 SizeOfStringData = 0; 03032 } 03033 03034 // 03035 // Set the String Pool offset. 03036 // 03037 03038 SizeOfSection = ALIGN_8 (SizeOfStringData + 03039 DriverCount * (sizeof (WCHAR) + sizeof (DUMP_STRING))); 03040 03041 if (SizeOfSection && (Offset + SizeOfSection < BufferSize)) { 03042 TriageDumpHeader->StringPoolOffset = (ULONG)Offset; 03043 TriageDumpHeader->StringPoolSize = SizeOfSection; 03044 Offset += SizeOfSection; 03045 } 03046 03047 03048 BytesToWrite = (ULONG)Offset; 03049 BufferAddress = ((ULONG_PTR) Buffer) - PAGE_SIZE ; 03050 03051 // 03052 // Write the Mm information. 03053 // 03054 03055 if (TriageDumpHeader->MmOffset) { 03056 03057 Address = (LPVOID) (BufferAddress + TriageDumpHeader->MmOffset); 03058 MmWriteTriageInformation (Address); 03059 } 03060 03061 if (TriageDumpHeader->UnloadedDriversOffset) { 03062 03063 Address = (LPVOID) (BufferAddress + TriageDumpHeader->UnloadedDriversOffset); 03064 MmWriteUnloadedDriverInformation (Address); 03065 } 03066 03067 // 03068 // Write the PRCB. 03069 // 03070 03071 if (TriageDumpHeader->PrcbOffset) { 03072 03073 Address = (LPVOID) (BufferAddress + TriageDumpHeader->PrcbOffset); 03074 RtlCopyMemory (Address, 03075 KeGetCurrentPrcb (), 03076 sizeof (KPRCB) 03077 ); 03078 } 03079 03080 // 03081 // Write the EPROCESS. 03082 // 03083 03084 if (TriageDumpHeader->ProcessOffset) { 03085 03086 Address = (LPVOID) (BufferAddress + TriageDumpHeader->ProcessOffset); 03087 RtlCopyMemory (Address, 03088 PsGetCurrentProcess (), 03089 sizeof (EPROCESS) 03090 ); 03091 } 03092 03093 // 03094 // Write the ETHREAD. 03095 // 03096 03097 if (TriageDumpHeader->ThreadOffset) { 03098 03099 Address = (LPVOID) (BufferAddress + TriageDumpHeader->ThreadOffset); 03100 RtlCopyMemory (Address, 03101 KeGetCurrentThread (), 03102 sizeof (ETHREAD) 03103 ); 03104 } 03105 03106 // 03107 // Write the Call Stack. 03108 // 03109 03110 if (TriageDumpHeader->CallStackOffset) { 03111 03112 ASSERT (Thread); 03113 ASSERT (TriageDumpHeader->SizeOfCallStack != 0); 03114 03115 Address = (LPVOID) (BufferAddress + TriageDumpHeader->CallStackOffset); 03116 RtlCopyMemory (Address, 03117 (PVOID) StartOfStackRegion, 03118 TriageDumpHeader->SizeOfCallStack 03119 ); 03120 } 03121 03122 // 03123 // Write the Driver List. 03124 // 03125 03126 if (TriageDumpHeader->DriverListOffset && 03127 TriageDumpHeader->StringPoolOffset) { 03128 03129 Status = IopWriteDriverList (BufferAddress, 03130 BufferSize, 03131 TriageDumpHeader->DriverListOffset, 03132 TriageDumpHeader->StringPoolOffset 03133 ); 03134 03135 if (!NT_SUCCESS (Status)) { 03136 TriageDumpHeader->DriverListOffset = 0; 03137 } 03138 } 03139 03140 ASSERT (BytesToWrite < BufferSize); 03141 ASSERT (ALIGN_UP (BytesToWrite, PAGE_SIZE) < BufferSize); 03142 03143 IoDebugPrint ((3, "TRIAGEDUMP: Calling IopWriteToDisk with:\n" 03144 "\tBytesToWrite = %#x\n" 03145 "\tBytesToWrite (Aligned) = %#x\n" 03146 "\tBufferSize = %#x\n", 03147 BytesToWrite, 03148 ALIGN_UP (BytesToWrite, PAGE_SIZE), 03149 BufferSize)); 03150 03151 03152 // 03153 // Write the valid status to the end of the dump. 03154 // 03155 03156 *((ULONG *)IndexByByte (Buffer, BufferSize)) = TRIAGE_DUMP_VALID ; 03157 03158 // 03159 // Re-adjust the buffer size. 03160 // 03161 03162 BufferSize += sizeof (DWORD); 03163 03164 // 03165 // NOTE: This routine writes the entire buffer, even if it is not 03166 // all required. 03167 // 03168 03169 Status = IopWriteToDisk (Buffer, 03170 BufferSize, 03171 DriverWriteRoutine, 03172 &Mcb, 03173 Mdl, 03174 DriverTransferSize 03175 ); 03176 03177 return Status; 03178 } 03179 03180 03181 03182 NTSTATUS 03183 IopWritePageToDisk( 03184 IN PDUMP_DRIVER_WRITE DriverWrite, 03185 IN OUT PLARGE_INTEGER * McbBuffer, 03186 IN OUT ULONG DriverTransferSize, 03187 IN PFN_NUMBER PageFrameIndex 03188 ) 03189 03190 /*++ 03191 03192 Routine Description: 03193 03194 Write the page described by PageFrameIndex to the disk/file (DriverWrite, 03195 McbBuffer) and update the MCB buffer to reflect the new position in the 03196 file. 03197 03198 Arguments: 03199 03200 DriverWrite - The driver write routine. 03201 03202 McbBuffer - A pointer to the MCB array. This array is terminated by 03203 a zero-length MCB entry. On success, this pointer is updated 03204 to reflect the new position in the MCB array. 03205 03206 NB: MCB[0] is the size and MCB[1] is the offset. 03207 03208 DriverTransferSize - The maximum transfer size for this driver. 03209 03210 PageFrameIndex - The page to be written. 03211 03212 Return Values: 03213 03214 NTSTATUS code. 03215 03216 --*/ 03217 03218 { 03219 NTSTATUS Status; 03220 PFN_NUMBER MdlHack [ (sizeof (MDL) / sizeof (PFN_NUMBER)) + 1]; 03221 PPFN_NUMBER PfnArray; 03222 PLARGE_INTEGER Mcb; 03223 ULONG ByteCount; 03224 ULONG ByteOffset; 03225 ULONG BytesToWrite; 03226 PMDL TempMdl; 03227 03228 03229 ASSERT ( DriverWrite ); 03230 ASSERT ( McbBuffer ); 03231 ASSERT ( DriverTransferSize && DriverTransferSize >= PAGE_SIZE ); 03232 03233 // 03234 // Initialization 03235 // 03236 03237 TempMdl = (PMDL) &MdlHack; 03238 Mcb = *McbBuffer; 03239 BytesToWrite = PAGE_SIZE; 03240 03241 03242 // 03243 // Initialze the MDL to point to this page. 03244 // 03245 03246 MmInitializeMdl (TempMdl, NULL, PAGE_SIZE); 03247 03248 PfnArray = MmGetMdlPfnArray ( TempMdl ); 03249 PfnArray[0] = PageFrameIndex; 03250 03251 03252 // 03253 // We loop for the cases when the space remaining in this block (Mcb [0]) 03254 // is less than one page. Generally the Mcb will be large enough to hold 03255 // the entire page and this loop will only be executed once. When Mcb[0] 03256 // is less than a page, we will write the first part of the page to this 03257 // Mcb then increment the Mcb and write the remaining part to the next 03258 // page. 03259 // 03260 03261 ByteOffset = 0; 03262 03263 while ( BytesToWrite ) { 03264 03265 ASSERT ( Mcb[0].QuadPart != 0 ); 03266 03267 ByteCount = (ULONG) min3 ((LONGLONG) BytesToWrite, 03268 (LONGLONG) DriverTransferSize, 03269 Mcb[0].QuadPart 03270 ); 03271 03272 ASSERT ( ByteCount != 0 ); 03273 03274 // 03275 // Update the MDL byte count and byte offset. 03276 // 03277 03278 TempMdl->ByteCount = ByteCount; 03279 TempMdl->ByteOffset = ByteOffset; 03280 03281 // 03282 // Map the MDL. The flags are updated to show that MappedSsytemVa is 03283 // valid, which should probably be done in MmMapMemoryDumpMdl. 03284 // 03285 03286 MmMapMemoryDumpMdl ( TempMdl ); 03287 TempMdl->MdlFlags |= ( MDL_PAGES_LOCKED | MDL_MAPPED_TO_SYSTEM_VA ); 03288 TempMdl->StartVa = PAGE_ALIGN (TempMdl->MappedSystemVa); 03289 03290 Status = DriverWrite ( &Mcb[1], TempMdl ); 03291 03292 03293 if (!NT_SUCCESS (Status)) { 03294 return Status; 03295 } 03296 03297 BytesToWrite -= ByteCount; 03298 ByteOffset += ByteCount; 03299 03300 Mcb[0].QuadPart -= ByteCount; 03301 Mcb[1].QuadPart += ByteCount; 03302 03303 03304 // 03305 // If there is no more room for this MCB, go to the next one. 03306 // 03307 03308 if ( Mcb[0].QuadPart == 0 ) { 03309 03310 Mcb += 2; 03311 03312 // 03313 // We have filled up all the space in the paging file. 03314 // 03315 03316 if ( Mcb[0].QuadPart == 0) { 03317 return STATUS_END_OF_FILE; 03318 } 03319 } 03320 } 03321 03322 *McbBuffer = Mcb; 03323 03324 return Status; 03325 } 03326 03327 03328 NTSTATUS 03329 IopWriteSummaryDump( 03330 IN PRTL_BITMAP PageMap, 03331 IN PDUMP_DRIVER_WRITE DriverWriteRoutine, 03332 IN PANSI_STRING ProgressMessage, 03333 IN PUCHAR MessageBuffer, 03334 IN OUT PLARGE_INTEGER Mcb, 03335 IN OUT ULONG DriverTransferSize 03336 ) 03337 03338 /*++ 03339 03340 Routine Description: 03341 03342 Write a summary dump to the disk. 03343 03344 Arguments: 03345 03346 03347 PageMap - A bitmap of the pages that need to be written. 03348 03349 DriverWriteRoutine - The driver's write routine. 03350 03351 ProgressMessage - The "Percent Complete" message. 03352 03353 MessageBuffer - A message buffer we can use to update percentage complete 03354 status. 03355 03356 Mcb - Message Control Block where the data is to be written. 03357 03358 DriverTransferSize - The maximum transfer size for the driver. 03359 03360 Return Values: 03361 03362 NTSTATUS code. 03363 03364 --*/ 03365 03366 { 03367 PVOID Va; 03368 PFN_NUMBER PageFrameIndex; 03369 PHYSICAL_ADDRESS PhysicalAddress; 03370 NTSTATUS Status; 03371 03372 ULONG WriteCount; 03373 ULONG MaxWriteCount; 03374 ULONG Step; 03375 03376 03377 ASSERT ( DriverWriteRoutine != NULL ); 03378 ASSERT ( Mcb != NULL ); 03379 ASSERT ( DriverTransferSize != 0 ); 03380 03381 03382 MaxWriteCount = RtlNumberOfSetBits ( PageMap ); 03383 Step = MaxWriteCount / 100; 03384 03385 IoDebugPrint ((1, "IODUMP: Summary Dump\n" 03386 " Writing %x pages to disk from a total of %x\n", 03387 MaxWriteCount, 03388 PageMap->SizeOfBitMap)); 03389 03390 // 03391 // Loop over all pages in the system and write those that are set 03392 // in the bitmap. 03393 // 03394 03395 WriteCount = 0; 03396 for ( PageFrameIndex = 0; 03397 PageFrameIndex < PageMap->SizeOfBitMap; 03398 PageFrameIndex++) { 03399 03400 03401 // 03402 // If this page needs to be included in the dump file. 03403 // 03404 03405 if ( RtlCheckBit (PageMap, PageFrameIndex) ) { 03406 03407 if (++WriteCount % Step == 0) { 03408 03409 sprintf (MessageBuffer, 03410 "%Z: %3d\r", 03411 ProgressMessage, 03412 (WriteCount * 100) / MaxWriteCount); 03413 03414 InbvDisplayString ( MessageBuffer ); 03415 } 03416 03417 ASSERT ( WriteCount <= MaxWriteCount ); 03418 03419 // 03420 // Write the page to disk. 03421 // 03422 03423 Status = IopWritePageToDisk ( 03424 DriverWriteRoutine, 03425 &Mcb, 03426 DriverTransferSize, 03427 PageFrameIndex 03428 ); 03429 03430 if (!NT_SUCCESS (Status)) { 03431 03432 return STATUS_UNSUCCESSFUL; 03433 } 03434 } 03435 } 03436 03437 return STATUS_SUCCESS; 03438 } 03439 03440 03441 PSUMMARY_DUMP_HEADER 03442 IopInitializeSummaryDump( 03443 IN PDUMP_CONTROL_BLOCK pDcb 03444 ) 03445 /*++ 03446 03447 Routine Description: 03448 03449 This routine creates a summary dump header. In particular it initializes 03450 a bitmap that contains a map of kernel memory. 03451 03452 Arguments: 03453 03454 PDUMP_CONTROL_BLOCK - A pointer to the dump control block. 03455 03456 Return Value: 03457 03458 Non-NULL - A pointer to the summary dump header 03459 03460 NULL - Error 03461 03462 --*/ 03463 { 03464 PULONG pdwBlock; 03465 PSUMMARY_DUMP_HEADER pSummaryHeader; 03466 ULONG dwActualPages; 03467 03468 // 03469 // Get the dump header page. 03470 // 03471 03472 pdwBlock = pDcb->HeaderPage; 03473 03474 // 03475 // The summary dump starts 1 page after the header. 03476 // 03477 03478 pSummaryHeader = (PSUMMARY_DUMP_HEADER)&pdwBlock[ DH_SUMMARY_DUMP_RECORD ]; 03479 03480 // 03481 // Fill the header with signatures. 03482 // 03483 RtlFillMemoryUlong( pSummaryHeader, 03484 sizeof(SUMMARY_DUMP_HEADER), 03485 'PMDS' ); 03486 03487 // 03488 // Set the size and valid signature. 03489 // 03490 03491 pSummaryHeader->BitmapSize = (ULONG)( MmPhysicalMemoryBlock->Run[MmPhysicalMemoryBlock->NumberOfRuns-1].BasePage + 03492 MmPhysicalMemoryBlock->Run[MmPhysicalMemoryBlock->NumberOfRuns-1].PageCount ); 03493 pSummaryHeader->ValidDump = 'PMUD'; 03494 03495 // 03496 // Construct the kernel memory bitmap. 03497 // 03498 03499 dwActualPages = IopCreateSummaryDump(pSummaryHeader); 03500 03501 IoDebugPrint((2,"[IopInitializeSummaryDump]: Kernel Pages = %x\n",dwActualPages)); 03502 03503 if (!dwActualPages) { 03504 return NULL; 03505 } 03506 03507 // 03508 // Set the actual number of physical pages in the summary dump 03509 // 03510 03511 pSummaryHeader->Pages = dwActualPages; 03512 pSummaryHeader->HeaderSize = pDcb->HeaderSize; 03513 03514 return pSummaryHeader; 03515 } 03516 03517 03518 03519 NTSTATUS 03520 IopWriteSummaryHeader( 03521 IN PSUMMARY_DUMP_HEADER pSummaryHeader, 03522 IN PDUMP_DRIVER_WRITE pfWrite, 03523 IN OUT PLARGE_INTEGER * McbBuffer, 03524 IN OUT PMDL pMdl, 03525 IN ULONG dwWriteSize, 03526 IN ULONG dwLength 03527 ) 03528 /*++ 03529 03530 Routine Description: 03531 03532 Write the summary dump header to the dump file. 03533 03534 Arguments: 03535 03536 pSummaryHeader - pointer to the summary dump bitmap 03537 03538 pfWrite - dump driver write function 03539 03540 McbBuffer - pointer to the MCB array. 03541 03542 pMdl - Pointer to an MDL 03543 03544 dwWriteSize - the max transfer size for the dump driver 03545 03546 dwLength - the length of this transfer 03547 03548 Return Value: 03549 03550 Updated MCB 03551 03552 --*/ 03553 { 03554 NTSTATUS Status; 03555 ULONG dwBytesRemaining; 03556 ULONG_PTR dwMemoryAddress; 03557 ULONG dwByteOffset; 03558 ULONG dwByteCount; 03559 PLARGE_INTEGER pMcb; 03560 03561 dwBytesRemaining = dwLength; 03562 dwMemoryAddress = (ULONG_PTR) pSummaryHeader; 03563 pMcb = *McbBuffer; 03564 03565 IoDebugPrint (( 0, "IoWriteCrashDump: Writing SUMMARY dump header to disk\n" )); 03566 03567 while (dwBytesRemaining) { 03568 03569 // Calculate byte offset 03570 dwByteOffset = (ULONG)(dwMemoryAddress & (PAGE_SIZE - 1)); 03571 03572 // 03573 // See if the number of bytes to write is greator than the crash 03574 // drives max transfer. 03575 // 03576 03577 if (dwBytesRemaining <= dwWriteSize) { 03578 dwByteCount = dwBytesRemaining; 03579 } else { 03580 dwByteCount = dwWriteSize; 03581 } 03582 03583 // 03584 // If the byteCount is greater than the remaining mcb then correct it. 03585 // 03586 03587 if (dwByteCount > pMcb[0].QuadPart) { 03588 dwByteCount = pMcb[0].LowPart; 03589 } 03590 03591 pMdl->ByteCount = dwByteCount; 03592 pMdl->ByteOffset = dwByteOffset; 03593 pMdl->MappedSystemVa = (PVOID) dwMemoryAddress; 03594 03595 // 03596 // Get the actual physical frame and create an mdl. 03597 // 03598 03599 IopMapVirtualToPhysicalMdl(pMdl, dwMemoryAddress, dwByteCount); 03600 03601 // 03602 // Write to disk. 03603 // 03604 Status = pfWrite( &pMcb[1], pMdl ); 03605 03606 if ( !NT_SUCCESS (Status) ) { 03607 return Status; 03608 } 03609 03610 // 03611 // Adjust bytes remaining. 03612 // 03613 03614 dwBytesRemaining -= dwByteCount; 03615 dwMemoryAddress += dwByteCount; 03616 03617 pMcb[0].QuadPart = pMcb[0].QuadPart - dwByteCount; 03618 pMcb[1].QuadPart = pMcb[1].QuadPart + dwByteCount; 03619 03620 if (pMcb[0].QuadPart == 0) { 03621 pMcb += 2; 03622 } 03623 03624 if (pMcb[0].QuadPart == 0) { 03625 return STATUS_END_OF_FILE; 03626 } 03627 } 03628 03629 IoDebugPrint((2, "IoWriteCrashDump: Writing SUMMARY dump header to disk\n" )); 03630 03631 *McbBuffer = pMcb; 03632 return STATUS_SUCCESS; 03633 } 03634 03635 03636 03637 NTSTATUS 03638 IopWriteToDisk( 03639 IN PVOID Buffer, 03640 IN ULONG WriteLength, 03641 IN PDUMP_DRIVER_WRITE DriverWriteRoutine, 03642 IN OUT PLARGE_INTEGER * McbBuffer, 03643 IN OUT PMDL Mdl, 03644 IN ULONG DriverTransferSize 03645 ) 03646 /*++ 03647 03648 Routine Description: 03649 03650 Write the summary dump header to the dump file. 03651 03652 Arguments: 03653 03654 Buffer - Pointer to the buffer to write. 03655 03656 WriteLength - The length of this transfer. 03657 03658 DriverWriteRoutine - Dump driver write function. 03659 03660 McbBuffer - Pointer to the dump file Mapped Control Block. 03661 03662 Mdl - Pointer to an MDL. 03663 03664 DriverTransferSize - The max transfer size for the dump driver. 03665 03666 03667 Return Value: 03668 03669 03670 --*/ 03671 { 03672 ULONG dwBytesRemaining; 03673 ULONG_PTR dwMemoryAddress; 03674 ULONG dwByteOffset; 03675 ULONG dwByteCount; 03676 PLARGE_INTEGER Mcb; 03677 03678 ASSERT (Buffer); 03679 ASSERT (WriteLength); 03680 ASSERT (DriverWriteRoutine); 03681 ASSERT (McbBuffer && *McbBuffer); 03682 ASSERT (Mdl); 03683 ASSERT (DriverTransferSize >= IO_DUMP_MINIMUM_TRANSFER_SIZE && 03684 DriverTransferSize <= IO_DUMP_MAXIMUM_TRANSFER_SIZE); 03685 03686 03687 Mcb = *McbBuffer; 03688 dwBytesRemaining = WriteLength; 03689 dwMemoryAddress = (ULONG_PTR) Buffer; 03690 03691 IoDebugPrint(( 2, "IoWriteToDisk: Writing %d bytes to disk.\n", WriteLength )); 03692 03693 while (dwBytesRemaining) { 03694 03695 ASSERT (Mcb [0].QuadPart != 0); 03696 ASSERT (IopDumpControlBlock->FileDescriptorArray <= Mcb && 03697 (LPBYTE) Mcb < (LPBYTE) IopDumpControlBlock->FileDescriptorArray + 03698 IopDumpControlBlock->FileDescriptorSize 03699 ); 03700 03701 dwByteOffset = BYTE_OFFSET (dwMemoryAddress); 03702 03703 // 03704 // See if the number of bytes to write is greator than the crash 03705 // drives max transfer. 03706 // 03707 03708 dwByteCount = min ( dwBytesRemaining, DriverTransferSize ); 03709 03710 // 03711 // If the byteCount is greater than the remaining mcb then correct it. 03712 // 03713 03714 if (dwByteCount > Mcb[0].QuadPart) { 03715 dwByteCount = Mcb[0].LowPart; 03716 } 03717 03718 Mdl->ByteCount = dwByteCount; 03719 Mdl->ByteOffset = dwByteOffset; 03720 Mdl->MappedSystemVa = (PVOID) dwMemoryAddress; 03721 03722 // 03723 // Get the actual physical frame and create an mdl. 03724 // 03725 03726 IopMapVirtualToPhysicalMdl(Mdl, dwMemoryAddress, dwByteCount); 03727 03728 if (!NT_SUCCESS( DriverWriteRoutine ( &Mcb[1], Mdl ) )) { 03729 IoDebugPrint ((1, "IopWriteToDisk: Failed write.\n")); 03730 return STATUS_UNSUCCESSFUL; 03731 } 03732 03733 // 03734 // Adjust bytes remaining. 03735 // 03736 03737 ASSERT (dwBytesRemaining >= dwByteCount); 03738 ASSERT (dwByteCount != 0); 03739 03740 dwBytesRemaining -= dwByteCount; 03741 dwMemoryAddress += dwByteCount; 03742 03743 Mcb[0].QuadPart -= dwByteCount; 03744 Mcb[1].QuadPart += dwByteCount; 03745 03746 if (Mcb[0].QuadPart == 0) { 03747 Mcb += 2; 03748 } 03749 } 03750 03751 IoDebugPrint ((2, "IopWriteToDisk: Successfully wrote %d bytes.\n", WriteLength)); 03752 03753 *McbBuffer = Mcb; 03754 return STATUS_SUCCESS; 03755 } 03756 03757 03758 VOID 03759 IopMapVirtualToPhysicalMdl( 03760 IN OUT PMDL pMdl, 03761 IN ULONG_PTR dwMemoryAddress, 03762 IN ULONG dwLength 03763 ) 03764 { 03765 PPFN_NUMBER pdwPage; 03766 ULONG dwPages; 03767 ULONG dwBase; 03768 ULONG dwCurrentBase; 03769 ULONG_PTR dwBaseVa; 03770 PHYSICAL_ADDRESS PhysicalAddress; 03771 03772 // 03773 // Begin by determining the base physical page of the start of the address 03774 // range and filling in the MDL appropriately. 03775 // 03776 03777 pMdl->StartVa = PAGE_ALIGN((PVOID)dwMemoryAddress); 03778 pMdl->ByteOffset= (ULONG)(dwMemoryAddress & (PAGE_SIZE - 1)); 03779 pMdl->ByteCount = dwLength; 03780 dwBaseVa = dwMemoryAddress & ~(PAGE_SIZE -1); 03781 pMdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA; 03782 03783 // 03784 // Compute the number of pages spanned 03785 // 03786 03787 dwPages = COMPUTE_PAGES_SPANNED( dwMemoryAddress, dwLength ); 03788 pdwPage = MmGetMdlPfnArray(pMdl); 03789 03790 // 03791 // Map all of the pages for this transfer until there are no more remaining 03792 // to be mapped. 03793 // 03794 IoDebugPrint((3,"MapVirtualToPhysical: VA: %08x off: %08x Len:%08x base: %08x \n",pMdl->StartVa,pMdl->ByteOffset,pMdl->ByteCount,dwBaseVa)); 03795 03796 while (dwPages) { 03797 PhysicalAddress = MmGetPhysicalAddress( (PVOID)dwBaseVa ); 03798 IoDebugPrint( (3,"Physical Frame: %08x Adr: %08x\n",( PhysicalAddress.QuadPart >> PAGE_SHIFT),dwBaseVa ) ); 03799 *pdwPage++ = (PFN_NUMBER)(PhysicalAddress.QuadPart >> PAGE_SHIFT); 03800 dwBaseVa +=PAGE_SIZE; 03801 dwPages--; 03802 } 03803 03804 // 03805 // All of the PFNs for the address range have been filled in so map the 03806 // physical memory into virtual address space using crash dump PTE. 03807 // 03808 03809 // MmMapMemoryDumpMdl( pMdl ); 03810 } 03811 03812 03813 03814 ULONG 03815 IopCreateSummaryDump ( 03816 IN PSUMMARY_DUMP_HEADER pHeader 03817 ) 03818 /*++ 03819 03820 Routine Description: 03821 03822 This routine determines the kernel memory and data structures to include 03823 in the summary memory dump. 03824 03825 NOTE: This function uses MmGetPhysicalAddress. MmGetPhysicalAddress does 03826 not acquire any locks. It uses a set of macros for translation. 03827 03828 03829 Arguments: 03830 03831 pHeader - Pointer to the dump header 03832 03833 pDcb - Dump control block 03834 03835 Return Value: 03836 03837 Status 03838 03839 --*/ 03840 { 03841 PRTL_BITMAP pBitMapHeader = (PRTL_BITMAP)(pHeader+1); 03842 ULONG Pages; 03843 PCHAR VA; 03844 ULONG UserPages; 03845 PHYSICAL_ADDRESS PhyAddr; 03846 ULONG i; 03847 PULONG pBitMapBuffer; 03848 PUCHAR pBitMapBytes; 03849 LARGE_INTEGER dumpFileSize; 03850 PULONG block; 03851 ULONG numDumpPages; 03852 03853 // 03854 // The bitmap is the last structure in the header. The 03855 // buffer is allocated directly after the bitmap header. 03856 // 03857 // Initialize Bit Map, set the size and buffer address. 03858 // 03859 03860 pBitMapHeader->SizeOfBitMap = pHeader->BitmapSize; 03861 pBitMapBuffer = (PULONG)( pBitMapHeader + 1); 03862 pBitMapHeader->Buffer = pBitMapBuffer; 03863 pBitMapBytes = (PUCHAR)pBitMapBuffer; 03864 03865 // 03866 // Clear all bits 03867 // 03868 03869 RtlClearAllBits (pBitMapHeader); 03870 03871 // 03872 // Have MM initialize the kernel memory to dump 03873 // 03874 03875 MmSetKernelDumpRange(pHeader); 03876 03877 // 03878 // Exclude non-existent memory 03879 // 03880 03881 IopDeleteNonExistentMemory(pHeader, MmPhysicalMemoryBlock); 03882 03883 03884 Pages = RtlNumberOfSetBits ( pBitMapHeader ); 03885 IoDebugPrint((2,"IopLocalSetBits = %x\n",Pages)); 03886 03887 // 03888 // See If we have room to Include user va for the current process 03889 // 03890 03891 block = IopDumpControlBlock->HeaderPage; 03892 dumpFileSize.LowPart= block [DH_REQUIRED_DUMP_SPACE]; 03893 dumpFileSize.HighPart= block [DH_REQUIRED_DUMP_SPACE + 1]; 03894 03895 dumpFileSize.QuadPart -= IopDumpControlBlock->HeaderSize; 03896 03897 // 03898 // Total physical pages will not exceed 2<<32 for sometime 03899 // 03900 03901 numDumpPages= (ULONG)(dumpFileSize.QuadPart >> PAGE_SHIFT); 03902 IoDebugPrint ((2,"IopCreateSummaryDump: numDumpPages: %x Pages : %x\n", numDumpPages,Pages)); 03903 03904 // 03905 // Only copy user virtual if there is enough room in the dump file. 03906 // 03907 03908 UserPages = 0; 03909 03910 if (Pages < numDumpPages ) { 03911 03912 // 03913 // Stride through user VA and include all valid pages 03914 // 03915 03916 for (VA = 0; VA < (PCHAR)MmHighestUserAddress; VA+=PAGE_SIZE ) { 03917 03918 if ( MmIsAddressValid( VA ) ) { 03919 03920 if ( NT_SUCCESS(IoSetDumpRange(pHeader,VA, 1, FALSE ) ) ) { 03921 03922 UserPages++; 03923 03924 // 03925 // Break if there is no more room in the dump file 03926 // 03927 03928 if (UserPages+Pages >= numDumpPages ) { 03929 break; 03930 } 03931 } 03932 } 03933 } 03934 03935 } 03936 03937 Pages+= UserPages; 03938 03939 IoDebugPrint((2,"IopCreateSummaryDump number of user mode pages = %x\n",UserPages)); 03940 03941 IoDebugPrint((2, "SummaryDump: Dump SummaryDumpHeader\n")); 03942 IoDebugPrint((2, "SdBitmapSize =%x\n", pHeader->BitmapSize)); 03943 IoDebugPrint((2, "SdAllBits =%x\n", Pages)); 03944 IoDebugPrint((2, "&SdBitmapBuffer[0]=%x\n", pBitMapHeader->Buffer)); 03945 03946 03947 return Pages; 03948 03949 } 03950 03951 03952 VOID 03953 IopDeleteNonExistentMemory( 03954 PSUMMARY_DUMP_HEADER pHeader, 03955 PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock 03956 ) 03957 /*++ 03958 03959 Routine Description: 03960 03961 This deletes non existent memory. Non existent memory is defined as the 03962 unassigned memory between memory runs. For example, memory between 03963 (run[0].base + size) and run[1].base. 03964 03965 Arguments: 03966 03967 pHeader - This is a pointer to the summary dump header. 03968 03969 dwStartingIndex - The starting bit index in the bitmap (starting page). 03970 03971 dwMemoryAddress - Pseudo-virtual address being mapped. 03972 03973 dwByteCount - The number of bytes to copy. 03974 03975 dwMaxBitmapBit - The limit or the highest possible valid bit in the bitmap. 03976 03977 pMdl - The MDL to create. 03978 03979 Return Value: 03980 03981 (none) 03982 03983 --*/ 03984 { 03985 PPHYSICAL_MEMORY_RUN Run; 03986 ULONG NumberOfRuns; 03987 ULONG i; 03988 PFN_NUMBER CurrentPageFrame, NextPageFrame; 03989 PRTL_BITMAP pBitMapHeader; 03990 03991 NumberOfRuns = MmPhysicalMemoryBlock->NumberOfRuns; 03992 03993 Run = &MmPhysicalMemoryBlock->Run[0]; 03994 03995 pBitMapHeader = (PRTL_BITMAP)(pHeader + 1); 03996 i = 0; 03997 03998 CurrentPageFrame = 1; 03999 04000 NextPageFrame = Run->BasePage; 04001 04002 // 04003 // Remove the gap from 0 till the first run. 04004 // 04005 04006 if (NextPageFrame > CurrentPageFrame) { 04007 04008 IoDebugPrint( (2,"DeleteNonExistentMemory: %x - %x\n", 04009 CurrentPageFrame, 04010 (NextPageFrame - CurrentPageFrame) ) ); 04011 04012 // 04013 // FIXFIX - handle page frame numbers greater than 32 bits. 04014 // 04015 04016 IopRemovePageFromPageMap (pHeader->BitmapSize, 04017 pBitMapHeader, 04018 (ULONG)CurrentPageFrame, 04019 (ULONG)(NextPageFrame-CurrentPageFrame) 04020 ); 04021 04022 } 04023 04024 // 04025 // Remove the gaps between runs. 04026 // 04027 04028 while (i < NumberOfRuns - 1) { 04029 04030 CurrentPageFrame = Run->BasePage + Run->PageCount; 04031 IoDebugPrint((2, "Run[%x]: Base=%x, Pages=%x\n", i, Run->BasePage, Run->PageCount)); 04032 04033 i++; 04034 Run++; 04035 04036 // 04037 // Get the next starting BasePage. 04038 // 04039 04040 NextPageFrame = Run->BasePage; 04041 04042 if (NextPageFrame != CurrentPageFrame) { 04043 04044 IoDebugPrint((2, "DeleteNonExistentMemory: %x - %x\n", NextPageFrame, CurrentPageFrame)); 04045 04046 // 04047 // FIXFIX - handle page frame numbers greater than 32 bits. 04048 // 04049 04050 IopRemovePageFromPageMap (pHeader->BitmapSize, 04051 pBitMapHeader, 04052 (ULONG)CurrentPageFrame, 04053 (ULONG)(NextPageFrame - CurrentPageFrame) 04054 ); 04055 } 04056 } 04057 } 04058 04059 04060 NTSTATUS 04061 IopCompleteDumpInitialization( 04062 IN HANDLE FileHandle 04063 ) 04064 04065 /*++ 04066 04067 Routine Description: 04068 04069 This routine is invoked after the dump file is created. 04070 04071 The purpose is to obtain the retrieval pointers so that they can then be 04072 used later to write the dump. The last step is to checksum the 04073 IopDumpControlBlock. 04074 04075 Fields in the IopDumpControlBlock are updated if necessary and the 04076 IopDumpControlBlockChecksum is initialized. 04077 04078 This is the final step in dump initialization. 04079 04080 Arguments: 04081 04082 FileHandle - Handle to the dump file just created. 04083 04084 Return Value: 04085 04086 STATUS_SUCCESS - Indicates success. 04087 04088 Other NTSTATUS - Failure. 04089 04090 --*/ 04091 04092 { 04093 NTSTATUS Status; 04094 NTSTATUS ErrorToLog; 04095 ULONG i; 04096 LARGE_INTEGER RequestedFileSize; 04097 PLARGE_INTEGER mcb; 04098 PFILE_OBJECT FileObject; 04099 PDEVICE_OBJECT DeviceObject; 04100 IO_STATUS_BLOCK IoStatusBlock; 04101 FILE_STANDARD_INFORMATION StandardFileInfo; 04102 04103 Status = STATUS_UNSUCCESSFUL; 04104 ErrorToLog = STATUS_SUCCESS; // No error 04105 FileObject = NULL; 04106 DeviceObject = NULL; 04107 04108 Status = ObReferenceObjectByHandle( FileHandle, 04109 0, 04110 IoFileObjectType, 04111 KernelMode, 04112 (PVOID *) &FileObject, 04113 NULL 04114 ); 04115 04116 if ( !NT_SUCCESS (Status) ) { 04117 ASSERT (FALSE); 04118 goto Cleanup; 04119 } 04120 04121 04122 DeviceObject = FileObject->DeviceObject; 04123 04124 // 04125 // If this device object represents the boot partition then query 04126 // the retrieval pointers for the file. 04127 // 04128 04129 if ( !(DeviceObject->Flags & DO_SYSTEM_BOOT_PARTITION) ) { 04130 04131 KdPrint (("IODUMP: Cannot dump to pagefile on non-system partition.\n")); 04132 goto Cleanup; 04133 } 04134 04135 Status = ZwQueryInformationFile( 04136 FileHandle, 04137 &IoStatusBlock, 04138 &StandardFileInfo, 04139 sizeof (StandardFileInfo), 04140 FileStandardInformation 04141 ); 04142 04143 if (Status == STATUS_PENDING) { 04144 Status = KeWaitForSingleObject( &FileObject->Event, 04145 Executive, 04146 KernelMode, 04147 FALSE, 04148 NULL 04149 ); 04150 Status = IoStatusBlock.Status; 04151 } 04152 04153 if ( !NT_SUCCESS (Status) ) { 04154 KdPrint (("CRASHDUMP: Failed ZwQueryInformationFile\n")); 04155 goto Cleanup; 04156 } 04157 04158 // 04159 // Do not ask for more space than is in the pagefile. 04160 // 04161 04162 RequestedFileSize = IopDumpControlBlock->DumpFileSize; 04163 04164 if (RequestedFileSize.QuadPart > StandardFileInfo.EndOfFile.QuadPart) { 04165 RequestedFileSize = StandardFileInfo.EndOfFile; 04166 } 04167 04168 Status = ZwFsControlFile( 04169 FileHandle, 04170 NULL, 04171 NULL, 04172 NULL, 04173 &IoStatusBlock, 04174 FSCTL_QUERY_RETRIEVAL_POINTERS, 04175 &RequestedFileSize, 04176 sizeof( LARGE_INTEGER ), 04177 &mcb, 04178 sizeof( PVOID ) 04179 ); 04180 04181 if (Status == STATUS_PENDING) { 04182 Status = KeWaitForSingleObject( &FileObject->Event, 04183 Executive, 04184 KernelMode, 04185 FALSE, 04186 NULL ); 04187 Status = IoStatusBlock.Status; 04188 } 04189 04190 04191 // 04192 // NOTE: If you fail here, put a BP on ntfs!NtfsQueryRetrievalPointers 04193 // or FatQueryRetrievalPointers and see why you failed. 04194 // 04195 04196 if ( !NT_SUCCESS (Status) ) { 04197 KdPrint (("CRASHDUMP: ZwFsControlFile returnd %d\n", Status)); 04198 ErrorToLog = IO_DUMP_POINTER_FAILURE; 04199 goto Cleanup; 04200 } 04201 04202 // 04203 // This paging file is on the system boot partition, and 04204 // the retrieval pointers for the file were just successfully 04205 // queried. Walk the MCB to size it, and then checksum it. 04206 // 04207 04208 for (i = 0; mcb [i].QuadPart; i++) { 04209 NOTHING; 04210 } 04211 04212 // 04213 // Write back fields of the IopDumpControlBlock. 04214 // 04215 04216 IopDumpControlBlock->FileDescriptorArray = mcb; 04217 IopDumpControlBlock->FileDescriptorSize = (i + 1) * sizeof (LARGE_INTEGER); 04218 IopDumpControlBlock->DumpFileSize = RequestedFileSize; 04219 IopDumpControlBlockChecksum = IopGetDumpControlBlockCheck ( IopDumpControlBlock ); 04220 04221 Status = STATUS_SUCCESS; 04222 04223 Cleanup: 04224 04225 if (Status != STATUS_SUCCESS && 04226 ErrorToLog != STATUS_SUCCESS ) { 04227 04228 IopLogErrorEvent (0, 04229 4, 04230 STATUS_SUCCESS, 04231 ErrorToLog, 04232 0, 04233 NULL, 04234 0, 04235 NULL 04236 ); 04237 } 04238 04239 DeviceObject = NULL; 04240 04241 if ( FileObject ) { 04242 ObDereferenceObject( FileObject ); 04243 FileObject = NULL; 04244 } 04245 04246 return Status; 04247 04248 } 04249 04250 04251 VOID 04252 IopFreeDCB( 04253 BOOLEAN FreeDCB 04254 ) 04255 04256 /*++ 04257 04258 Routine Description: 04259 04260 Free dump control block storage. 04261 04262 Arguments: 04263 04264 FreeDCB - Implictly free storage for the dump control block. 04265 04266 Return Value: 04267 04268 None 04269 04270 --*/ 04271 { 04272 PDUMP_CONTROL_BLOCK dcb; 04273 NTSTATUS dwStatus; 04274 BOOLEAN ShouldFreeDCB; 04275 04276 dcb = IopDumpControlBlock; 04277 04278 04279 if (dcb) { 04280 04281 if (dcb->MemoryDescriptor) { 04282 ExFreePool (dcb->MemoryDescriptor); 04283 dcb->MemoryDescriptor = NULL; 04284 } 04285 04286 if (dcb->HeaderPage) { 04287 ExFreePool (dcb->HeaderPage); 04288 dcb->HeaderPage = NULL; 04289 } 04290 04291 if (dcb->FileDescriptorArray) { 04292 ExFreePool (dcb->FileDescriptorArray); 04293 dcb->FileDescriptorArray = NULL; 04294 } 04295 04296 if (dcb->DumpStack) { 04297 IoFreeDumpStack (dcb->DumpStack); 04298 dcb->DumpStack = NULL; 04299 } 04300 04301 ShouldFreeDCB = FreeDCB | !( dcb->Flags & DCB_AUTO_REBOOT); 04302 04303 // 04304 // Disable all options that require dump file access 04305 // 04306 04307 dcb->Flags = dcb->Flags & DCB_AUTO_REBOOT; 04308 04309 IoDebugPrint((2,"[IopFreeDCB] Should Free DCB = %s\n",(ShouldFreeDCB ? "TRUE" : "FALSE"))); 04310 04311 if (ShouldFreeDCB) { 04312 IopDumpControlBlock = NULL; 04313 ExFreePool( dcb ); 04314 IoDebugPrint((2,"[IopFreeDCB]: Freeing Dump Control Block\n")); 04315 } 04316 } 04317 04318 IoDebugPrint((2,"[IopFreeDCB]: CRASH DUMP DISABLED\n")); 04319 04320 } 04321 04322 04323 04324 NTSTATUS 04325 IoSetCrashDumpState( 04326 IN SYSTEM_CRASH_STATE_INFORMATION *pDumpState 04327 ) 04328 04329 /*++ 04330 04331 Routine Description: 04332 04333 Disable the current crash dump. Optionally, configure a new crash dump. 04334 04335 Arguments: 04336 04337 pDumpState - If ValidDirectDump = TRUE enable a new dump 04338 FALSE Disable crash dump 04339 04340 Return Value: 04341 04342 STATUS_SUCCESS - The operation was successful 04343 04344 W32ERROR - Otherwise 04345 04346 --*/ 04347 { 04348 NTSTATUS Status; 04349 ULONG crashConfigurationInProgress; 04350 04351 // 04352 // Check the sentinal 04353 // 04354 04355 crashConfigurationInProgress = InterlockedExchange(&IopCrashDumpStateChange,1); 04356 04357 if (crashConfigurationInProgress) { 04358 return STATUS_SUCCESS; 04359 } 04360 04361 // 04362 // If crash dumps disabled return success 04363 // 04364 04365 if (!pDumpState->ValidDirectDump) { 04366 IopFreeDCB(FALSE); 04367 Status = STATUS_SUCCESS; 04368 } else { 04369 Status = STATUS_INVALID_DEVICE_REQUEST; 04370 } 04371 04372 InterlockedExchange(&IopCrashDumpStateChange,0); 04373 04374 return Status; 04375 } 04376 04377 04378 VOID 04379 IopReadDumpRegistry( 04380 OUT PULONG dumpControl, 04381 OUT PULONG numberOfHeaderPages, 04382 OUT PULONG autoReboot, 04383 OUT PULONG dumpFileSize 04384 ) 04385 /*++ 04386 04387 Routine Description: 04388 04389 This routine reads the dump parameters from the registry. 04390 04391 Arguments: 04392 04393 dumpControl - Supplies a pointer to the dumpControl flags to set. 04394 04395 Return Value: 04396 04397 None. 04398 04399 --*/ 04400 04401 { 04402 HANDLE keyHandle; 04403 HANDLE crashHandle; 04404 LOGICAL crashHandleOpened; 04405 UNICODE_STRING keyName; 04406 NTSTATUS status; 04407 PKEY_VALUE_FULL_INFORMATION keyValueInformation; 04408 PDUMP_CONTROL_BLOCK dcb; 04409 ULONG handleValue; 04410 04411 *dumpControl = 0; 04412 *autoReboot = 0; 04413 *dumpFileSize = 0; 04414 04415 *numberOfHeaderPages = 1; // Dump header 04416 04417 // 04418 // Begin by opening the path to the control for dumping memory. Note 04419 // that if it does not exist, then no dumps will occur. 04420 // 04421 04422 crashHandleOpened = FALSE; 04423 04424 RtlInitUnicodeString( &keyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control" ); 04425 04426 status = IopOpenRegistryKey( &keyHandle, 04427 (HANDLE) NULL, 04428 &keyName, 04429 KEY_READ, 04430 FALSE ); 04431 04432 if (!NT_SUCCESS( status )) { 04433 return; 04434 } 04435 04436 RtlInitUnicodeString( &keyName, L"CrashControl" ); 04437 status = IopOpenRegistryKey( &crashHandle, 04438 keyHandle, 04439 &keyName, 04440 KEY_READ, 04441 FALSE ); 04442 04443 NtClose( keyHandle ); 04444 04445 if (!NT_SUCCESS( status )) { 04446 return; 04447 } 04448 04449 crashHandleOpened = TRUE; 04450 04451 // 04452 // Now get the value of the crash control to determine whether or not 04453 // dumping is enabled. 04454 // 04455 04456 status = IopGetRegistryValue( crashHandle, 04457 L"CrashDumpEnabled", 04458 &keyValueInformation ); 04459 04460 if (NT_SUCCESS (status)) { 04461 04462 if (keyValueInformation->DataLength) { 04463 04464 handleValue = * ((PULONG) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset)); 04465 ExFreePool( keyValueInformation ); 04466 04467 if (handleValue) { 04468 04469 *dumpControl |= DCB_DUMP_ENABLED; 04470 04471 // 04472 // If handleValue equals summary dump or the amount of physical 04473 // memory is greater than 2GB, then enable summary dump 04474 // 04475 04476 if ( handleValue == 3 ) { 04477 04478 *dumpControl |= DCB_TRIAGE_DUMP_ENABLED; 04479 04480 } else if ( handleValue == 4 ) { 04481 04482 *dumpControl |= ( DCB_TRIAGE_DUMP_ENABLED | DCB_TRIAGE_DUMP_ACT_UPON_ENABLED ); 04483 04484 } else if ( ( handleValue == 2 ) || 04485 ( MmPhysicalMemoryBlock->NumberOfPages >= ( 0x80000000 >> PAGE_SHIFT ) ) ) { 04486 04487 *dumpControl |= DCB_SUMMARY_DUMP_ENABLED; 04488 04489 IoDebugPrint((2,"IopInitializeDCB: SUMMARY DUMP ENABLED \n")); 04490 04491 // 04492 // Allocate enough storage for the dump header, summary 04493 // dump header and bitmap. 04494 // 04495 04496 *numberOfHeaderPages = BYTES_TO_PAGES( 04497 PAGE_SIZE + 04498 ( ( MmPhysicalMemoryBlock->NumberOfPages >> 5) << 2 ) + 04499 sizeof(SUMMARY_DUMP_HEADER) 04500 ); 04501 04502 IoDebugPrint((2,"IopInitializeDCB: NumberOfHeader Pages = %x\n",numberOfHeaderPages)); 04503 04504 } 04505 } 04506 } 04507 } 04508 04509 status = IopGetRegistryValue( crashHandle, 04510 L"LogEvent", 04511 &keyValueInformation ); 04512 04513 if (NT_SUCCESS( status )) { 04514 if (keyValueInformation->DataLength) { 04515 handleValue = * ((PULONG) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset)); 04516 ExFreePool( keyValueInformation); 04517 if (handleValue) { 04518 *dumpControl |= DCB_SUMMARY_ENABLED; 04519 } 04520 } 04521 } 04522 04523 status = IopGetRegistryValue( crashHandle, 04524 L"SendAlert", 04525 &keyValueInformation ); 04526 04527 if (NT_SUCCESS( status )) { 04528 if (keyValueInformation->DataLength) { 04529 handleValue = * ((PULONG) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset)); 04530 ExFreePool( keyValueInformation); 04531 if (handleValue) { 04532 *dumpControl |= DCB_SUMMARY_ENABLED; 04533 } 04534 } 04535 } 04536 04537 // 04538 // Now determine whether or not automatic reboot is enabled. 04539 // 04540 04541 status = IopGetRegistryValue( crashHandle, 04542 L"AutoReboot", 04543 &keyValueInformation ); 04544 04545 04546 if (NT_SUCCESS( status )) { 04547 if (keyValueInformation->DataLength) { 04548 *autoReboot = * ((PULONG) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset)); 04549 } 04550 ExFreePool( keyValueInformation ); 04551 } 04552 04553 // 04554 // If we aren't auto rebooting or crashing then return now. 04555 // 04556 04557 if (*dumpControl == 0 && *autoReboot == 0) { 04558 if (crashHandleOpened == TRUE) { 04559 NtClose( crashHandle ); 04560 } 04561 return; 04562 } 04563 04564 status = IopGetRegistryValue( crashHandle, 04565 L"DumpFileSize", 04566 &keyValueInformation ); 04567 04568 if (NT_SUCCESS( status )) { 04569 if (keyValueInformation->DataLength) { 04570 *dumpFileSize = * ((PULONG) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset)); 04571 } 04572 04573 ExFreePool( keyValueInformation ); 04574 } 04575 return; 04576 } 04577 04578 04579 BOOLEAN 04580 IopInitializeDCB( 04581 ) 04582 /*++ 04583 04584 Routine Description: 04585 04586 This routine initializes the Dump Control Block (DCB). It allocates the 04587 DCB and reads the crashdump parameters from the registry. 04588 04589 Arguments: 04590 04591 04592 Return Value: 04593 04594 The final function value is TRUE if everything worked, else FALSE. 04595 04596 --*/ 04597 04598 { 04599 HANDLE keyHandle; 04600 HANDLE crashHandle; 04601 LOGICAL crashHandleOpened; 04602 UNICODE_STRING keyName; 04603 NTSTATUS status; 04604 PKEY_VALUE_FULL_INFORMATION keyValueInformation; 04605 PDUMP_CONTROL_BLOCK dcb; 04606 ULONG dumpControl; 04607 ULONG handleValue; 04608 ULONG autoReboot; 04609 PCHAR partitionName; 04610 ULONG dcbSize; 04611 LARGE_INTEGER page; 04612 ULONG numberOfHeaderPages; 04613 ULONG dumpFileSize; 04614 04615 // 04616 // Read all the registry default values first. 04617 // 04618 04619 IopReadDumpRegistry ( &dumpControl, 04620 &numberOfHeaderPages, 04621 &autoReboot, 04622 &dumpFileSize); 04623 04624 // 04625 // If we aren't crashing or auto rebooting then return now. 04626 // 04627 04628 if (dumpControl == 0 && autoReboot == 0) { 04629 04630 // 04631 // At some point, we will conditionally on system size, type, etc, 04632 // set dump defaults like the below and skip over the return. 04633 // 04634 // *dumpControl = (DCB_DUMP_ENABLED | DCB_TRIAGE_DUMP_ENABLED); 04635 // *autoReboot = 1; 04636 // *dumpFileSize = ? 04637 // 04638 04639 return TRUE; 04640 } 04641 04642 if (dumpControl & DCB_TRIAGE_DUMP_ENABLED) { 04643 dumpControl &= ~DCB_SUMMARY_ENABLED; 04644 dumpFileSize = TRIAGE_DUMP_SIZE; 04645 } 04646 04647 // 04648 // Allocate and initialize the structures necessary to describe and control 04649 // the post-bugcheck code. 04650 // 04651 04652 dcbSize = sizeof( DUMP_CONTROL_BLOCK ) + sizeof( MINIPORT_NODE ); 04653 dcb = ExAllocatePoolWithTag( NonPagedPool, dcbSize, 'pmuD' ); 04654 if (!dcb) { 04655 IoDebugPrint((1, "IopInitializeDCB: Not enough pool to allocate DCB0\n" )); 04656 IopLogErrorEvent(0,1,STATUS_SUCCESS,IO_DUMP_INITIALIZATION_FAILURE,0,NULL,0,NULL); 04657 return FALSE; 04658 } 04659 04660 RtlZeroMemory( dcb, dcbSize ); 04661 dcb->Type = IO_TYPE_DCB; 04662 dcb->Size = (USHORT) dcbSize; 04663 dcb->Flags = (UCHAR) (dumpControl | (autoReboot ? DCB_AUTO_REBOOT : 0)); 04664 dcb->NumberProcessors = KeNumberProcessors; 04665 dcb->ProcessorArchitecture = KeProcessorArchitecture; 04666 dcb->MinorVersion = (USHORT) NtBuildNumber; 04667 dcb->MajorVersion = (USHORT) ((NtBuildNumber >> 28) & 0xfffffff); 04668 dcb->BuildNumber = CmNtCSDVersion; 04669 dcb->TriageDumpFlags = DEFAULT_TRIAGE_DUMP_FLAGS; 04670 04671 dcb->DumpFileSize.QuadPart = dumpFileSize; 04672 04673 // 04674 // Allocate memory descriptors. 04675 // 04676 04677 dcb->MemoryDescriptorLength = sizeof( PHYSICAL_MEMORY_DESCRIPTOR ) - sizeof( PHYSICAL_MEMORY_RUN ) + 04678 (MmPhysicalMemoryBlock->NumberOfRuns * sizeof( PHYSICAL_MEMORY_RUN )); 04679 dcb->MemoryDescriptor = ExAllocatePoolWithTag ( 04680 NonPagedPool, 04681 dcb->MemoryDescriptorLength, 04682 'pmuD' 04683 ); 04684 if (!dcb->MemoryDescriptor) { 04685 ExFreePool (dcb); 04686 04687 IoDebugPrint((1, "IopInitializeDCB: Not enough pool to allocate DCB1\n" )); 04688 IopLogErrorEvent(0,1,STATUS_SUCCESS,IO_DUMP_INITIALIZATION_FAILURE,0,NULL,0,NULL); 04689 return FALSE; 04690 } 04691 04692 RtlCopyMemory ( 04693 dcb->MemoryDescriptor, 04694 MmPhysicalMemoryBlock, 04695 dcb->MemoryDescriptorLength 04696 ); 04697 04698 // 04699 // Allocate header page. 04700 // 04701 04702 dcb->HeaderSize = numberOfHeaderPages * PAGE_SIZE; 04703 dcb->HeaderPage = ExAllocatePoolWithTag( NonPagedPool, dcb->HeaderSize, 'pmuD' ); 04704 04705 if (!dcb->HeaderPage) { 04706 ExFreePool (dcb->MemoryDescriptor); 04707 ExFreePool (dcb); 04708 IoDebugPrint((1, "IopInitializeDCB: Not enough pool to allocate DCB2\n" )); 04709 IopLogErrorEvent(0,1,STATUS_SUCCESS,IO_DUMP_INITIALIZATION_FAILURE,0,NULL,0,NULL); 04710 return FALSE; 04711 } 04712 page = MmGetPhysicalAddress( dcb->HeaderPage ); 04713 dcb->HeaderPfn = (ULONG)(page.QuadPart >> PAGE_SHIFT); 04714 04715 04716 // 04717 // Allocate the triage-dump buffer. 04718 // 04719 04720 if (dumpControl & DCB_TRIAGE_DUMP_ENABLED) { 04721 04722 dcb->TriageDumpBuffer = ExAllocatePoolWithTag ( NonPagedPool, 04723 dumpFileSize, 04724 'pmuD' 04725 ); 04726 04727 if (!dcb->TriageDumpBuffer) { 04728 ExFreePool (dcb->HeaderPage); 04729 ExFreePool (dcb->MemoryDescriptor); 04730 ExFreePool (dcb); 04731 IoDebugPrint((1, "IopInitializeDCB: Not enough pool to allocate DCB3\n" )); 04732 IopLogErrorEvent(0,1,STATUS_SUCCESS,IO_DUMP_INITIALIZATION_FAILURE,0,NULL,0,NULL); 04733 return FALSE; 04734 } 04735 04736 dcb->TriageDumpBufferSize = dumpFileSize; 04737 } 04738 04739 IopDumpControlBlock = dcb; 04740 04741 return TRUE; 04742 } 04743 04744 04745 BOOLEAN 04746 IopConfigureCrashDump( 04747 IN HANDLE hPageFile 04748 ) 04749 /*++ 04750 04751 Routine Description: 04752 04753 This routine configures the system for crash dump. The following things 04754 are done: 04755 04756 1. Initialize the dump control block and init registry crashdump 04757 parameters. 04758 04759 2. Configure either page or fast dump. 04760 04761 3. Complete dump file initialization. 04762 04763 This routine is called as each page file is created. A return value of 04764 TRUE tells the caller (i.e., NtCreatePagingFiles, IoPageFileCreated) 04765 that crash dump has been configured. 04766 04767 04768 Arguments: 04769 04770 hPageFile - Handle to the paging file 04771 04772 Return Value: 04773 04774 TRUE - Configuration complete (or crash dump not enabled). 04775 04776 FALSE - Error, retry PageFile is not on boot partition. 04777 04778 --*/ 04779 { 04780 ULONG dwStatus; 04781 PFILE_OBJECT fileObject; 04782 PDEVICE_OBJECT deviceObject; 04783 04784 // 04785 // Only Init DCB Once. 04786 // 04787 04788 if (!IopDumpControlBlock) { 04789 if (!IopInitializeDCB()) { 04790 return TRUE; 04791 } 04792 } 04793 04794 // 04795 // Return crash dump not enabled 04796 // 04797 if (!IopDumpControlBlock){ 04798 return TRUE; 04799 } 04800 04801 // 04802 // Only autoreboot? 04803 // 04804 04805 if ( !( IopDumpControlBlock->Flags & (DCB_DUMP_ENABLED | DCB_SUMMARY_ENABLED) ) ) { 04806 return TRUE; 04807 } 04808 04809 // 04810 // Configure the paging file for crash dump. 04811 // 04812 04813 IoDebugPrint((2,"[IoPageFileCreated]: Page file dump\n")); 04814 04815 04816 dwStatus = ObReferenceObjectByHandle( 04817 hPageFile, 04818 0, 04819 IoFileObjectType, 04820 KernelMode, 04821 (PVOID *) &fileObject, 04822 NULL 04823 ); 04824 04825 if (!NT_SUCCESS( dwStatus )) { 04826 IoDebugPrint((1,"[IoPageFileCreated]: ObReferenceObjectByHandle for Paging file failed status = %x\n",dwStatus)); 04827 goto error_return; 04828 } 04829 04830 // 04831 // Get a pointer to the device object for this file. Note that it 04832 // cannot go away, since there is an open handle to it, so it is 04833 // OK to dereference it and then use it. 04834 // 04835 04836 deviceObject = fileObject->DeviceObject; 04837 04838 ObDereferenceObject( fileObject ); 04839 04840 // 04841 // If this device object does not represents the boot partition return 04842 // FALSE so MM will try again. 04843 // 04844 04845 if ( ! (deviceObject->Flags & DO_SYSTEM_BOOT_PARTITION) ) { 04846 return FALSE; 04847 } 04848 04849 // 04850 // Load paging file dump stack 04851 // 04852 04853 dwStatus = IoGetDumpStack (L"dump_", 04854 &IopDumpControlBlock->DumpStack, 04855 DeviceUsageTypeDumpFile, 04856 FALSE); 04857 04858 if (!NT_SUCCESS(dwStatus)) { 04859 IoDebugPrint((1, "IoPageFileCreated: Could not load dump stack status = %x\n",dwStatus) ); 04860 goto error_return; 04861 } 04862 04863 IopDumpControlBlock->DumpStack->Init.CrashDump = TRUE; 04864 04865 IopDumpControlBlock->DumpStack->Init.MemoryBlock = ExAllocatePoolWithTag ( 04866 NonPagedPool, 04867 IO_DUMP_MEMORY_BLOCK_PAGES * PAGE_SIZE, 04868 'pmuD' 04869 ); 04870 04871 if (!IopDumpControlBlock->DumpStack->Init.MemoryBlock) { 04872 dwStatus = STATUS_NO_MEMORY; 04873 goto error_return; 04874 } 04875 04876 04877 // 04878 // Calculate the amount of space required for the dump 04879 // 04880 IopDumpControlBlock->DumpFileSize =IopCalculateRequiredDumpSpace( 04881 IopDumpControlBlock->Flags, 04882 IopDumpControlBlock->HeaderSize, 04883 IopDumpControlBlock->MemoryDescriptor->NumberOfPages, 04884 IopDumpControlBlock->MemoryDescriptor->NumberOfPages 04885 ); 04886 04887 04888 // 04889 // Complete dump initialization 04890 // 04891 04892 dwStatus = IopCompleteDumpInitialization(hPageFile); 04893 04894 error_return: 04895 04896 // 04897 // The BOOT partition paging file could not be configured. 04898 // 1. Log an error message 04899 // 2. Return TRUE so that MM does not try again 04900 // 04901 04902 if (!NT_SUCCESS(dwStatus)) { 04903 IoDebugPrint((1,"IopPageFileCreated: Page File dump init FAILED status = %x\n",dwStatus)); 04904 04905 IopLogErrorEvent(0,3,STATUS_SUCCESS,IO_DUMP_PAGE_CONFIG_FAILED,0,NULL,0,NULL); 04906 04907 IopFreeDCB(FALSE); 04908 04909 } 04910 04911 return TRUE; 04912 } 04913 04914 04915 // 04916 // Debugging routines. 04917 // 04918 04919 #if DBG 04920 04921 ULONG IopDebugLevel = 0; 04922 UCHAR IopBuffer[128]; 04923 04924 04925 VOID 04926 IopDebugPrint( 04927 ULONG Level, 04928 PCHAR Format, 04929 ... 04930 ) 04931 { 04932 va_list ap; 04933 04934 va_start(ap, Format); 04935 04936 if (IopDebugLevel >= Level) { 04937 vsprintf(IopBuffer, Format, ap); 04938 DbgPrint(IopBuffer); 04939 } 04940 04941 va_end(ap); 04942 } 04943 04944 #endif //DBG

Generated on Sat May 15 19:39:47 2004 for test by doxygen 1.3.7