1 /* $Id: diskdump.c 29690 2007-10-19 23:21:45Z dreimer $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS Kernel
5 * FILE: services/storage/diskdump/diskdump.c
6 * PURPOSE: Dumping crash data to the pagefile
10 /* INCLUDES *****************************************************************/
16 #include <../class/include/class2.h>
17 #include <diskdump/diskdump.h>
18 #include <ndk/rtlfuncs.h>
20 #include "../scsiport/scsiport_int.h"
25 /* It's already defined in scsiport_int.h */
27 #define VERSION "0.0.1"
29 #undef KeGetCurrentIrql
30 /* PROTOTYPES ***************************************************************/
33 DiskDumpPrepare(PDEVICE_OBJECT DeviceObject
, PDUMP_POINTERS DumpPointers
);
35 DiskDumpScsiInvalid(VOID
);
37 _DiskDumpScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
38 IN PVOID HwDeviceExtension
,
45 DiskDumpWrite(LARGE_INTEGER StartAddress
, PMDL Mdl
);
47 typedef VOID (*SCSIPORTNOTIFICATION
)(IN SCSI_NOTIFICATION_TYPE NotificationType
,
48 IN PVOID HwDeviceExtension
,
51 /* GLOBALS ******************************************************************/
53 MM_CORE_DUMP_FUNCTIONS DiskDumpFunctions
=
55 (PVOID
)DiskDumpPrepare
,
58 (PVOID
)DiskDumpFinish
,
69 static SCSI_REQUEST_BLOCK CoreDumpSrb
;
70 static DUMP_POINTERS CoreDumpPointers
;
71 static PDEVICE_OBJECT CoreDumpClassDevice
;
72 static PDEVICE_EXTENSION CoreDumpClass2DeviceExtension
;
73 static PDEVICE_OBJECT CoreDumpPortDevice
;
74 static SCSI_PORT_DEVICE_EXTENSION
* CoreDumpPortDeviceExtension
;
75 BOOLEAN IsDumping
= FALSE
;
76 static PDRIVER_OBJECT DiskDumpDriver
;
77 static UCHAR DiskDumpSenseData
[SENSE_BUFFER_SIZE
];
78 static BOOLEAN IrqComplete
, IrqNextRequest
;
79 PVOID OldScsiPortNotification
;
80 static SUBSTITUTE_EXPORT DiskDumpExports
[] =
82 {"ScsiPortConvertPhysicalAddressToUlong", 2, NULL
, NULL
},
83 {"ScsiPortConvertUlongToPhysicalAddress", 3, NULL
, NULL
},
84 {"ScsiPortFreeDeviceBase", 5, NULL
, DiskDumpScsiInvalid
},
85 {"ScsiPortGetBusData", 6, NULL
, DiskDumpScsiInvalid
},
86 {"ScsiPortGetDeviceBase", 7, NULL
, DiskDumpScsiInvalid
},
87 {"ScsiPortInitialize", 13, NULL
, DiskDumpScsiInvalid
},
88 {"ScsiPortNotification", 17, NULL
, _DiskDumpScsiPortNotification
},
89 {"ScsiPortReadPortBufferUlong", 19, NULL
, NULL
},
90 {"ScsiPortReadPortBufferUshort", 20, NULL
, NULL
},
91 {"ScsiPortReadPortUchar", 21, NULL
, NULL
},
92 {"ScsiPortReadPortUshort", 23, NULL
, NULL
},
93 {"ScsiPortStallExecution", 31, NULL
, NULL
},
94 {"ScsiPortWritePortBufferUlong", 34, NULL
, NULL
},
95 {"ScsiPortWritePortBufferUshort", 35, NULL
, NULL
},
96 {"ScsiPortWritePortUchar", 36, NULL
, NULL
},
97 {"ScsiDebugPrint", 0, NULL
, NULL
},
100 /* FUNCTIONS ****************************************************************/
105 DiskDumpScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
106 IN PVOID HwDeviceExtension
,
109 if (NotificationType
== RequestComplete
)
113 if (NotificationType
== NextRequest
)
115 IrqNextRequest
= TRUE
;
120 DiskDumpScsiInvalid(VOID
)
122 DbgPrint("DISKDUMP: Error: Miniport called a function not supported at dump time.\n");
127 DiskDumpBuildRequest(LARGE_INTEGER StartingOffset
, PMDL Mdl
)
129 LARGE_INTEGER StartingBlock
;
130 PSCSI_REQUEST_BLOCK Srb
;
132 ULONG LogicalBlockAddress
;
133 USHORT TransferBlocks
;
135 /* Calculate logical block address */
136 StartingBlock
.QuadPart
= StartingOffset
.QuadPart
>> CoreDumpClass2DeviceExtension
->SectorShift
;
137 LogicalBlockAddress
= (ULONG
)StartingBlock
.u
.LowPart
;
139 DPRINT("Logical block address: %lu\n", LogicalBlockAddress
);
141 /* Allocate and initialize an SRB */
145 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
); //SCSI_REQUEST_BLOCK_SIZE;
146 Srb
->OriginalRequest
= NULL
;
147 Srb
->PathId
= CoreDumpClass2DeviceExtension
->PathId
;
148 Srb
->TargetId
= CoreDumpClass2DeviceExtension
->TargetId
;
149 Srb
->Lun
= CoreDumpClass2DeviceExtension
->Lun
;
150 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
151 Srb
->DataBuffer
= Mdl
->MappedSystemVa
;
152 Srb
->DataTransferLength
= PAGE_SIZE
;
153 Srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
154 Srb
->QueueSortKey
= LogicalBlockAddress
;
156 Srb
->SenseInfoBuffer
= DiskDumpSenseData
;
157 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
160 ((Srb
->DataTransferLength
+ 0xFFFF) >> 16) * CoreDumpClass2DeviceExtension
->TimeOutValue
;
162 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
167 Cdb
= (PCDB
)Srb
->Cdb
;
169 /* Initialize ATAPI packet (12 bytes) */
170 RtlZeroMemory(Cdb
, MAXIMUM_CDB_SIZE
);
172 Cdb
->CDB10
.LogicalUnitNumber
= CoreDumpClass2DeviceExtension
->Lun
;
173 TransferBlocks
= (USHORT
)(PAGE_SIZE
>>
174 CoreDumpClass2DeviceExtension
->SectorShift
);
176 /* Copy little endian values into CDB in big endian format */
177 Cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte3
;
178 Cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte2
;
179 Cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte1
;
180 Cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte0
;
182 Cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)&TransferBlocks
)->Byte1
;
183 Cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)&TransferBlocks
)->Byte0
;
187 Srb
->SrbFlags
|= SRB_FLAGS_DATA_OUT
;
188 Cdb
->CDB10
.OperationCode
= SCSIOP_WRITE
;
190 /* Leave caching disabled. */
194 DiskDumpIsr(PKINTERRUPT Interrupt
, PVOID ServiceContext
)
196 if (!CoreDumpPortDeviceExtension
->HwInterrupt(&CoreDumpPortDeviceExtension
->MiniPortDeviceExtension
))
206 KIRQL CurrentIrql
= KeGetCurrentIrql();
208 if (CurrentIrql
>= CoreDumpPortDeviceExtension
->Interrupt
->SynchronizeIrql
)
210 DbgPrint("DISKDUMP: Error: Crash inside high priority interrupt routine.\n");
211 return(STATUS_UNSUCCESSFUL
);
213 CoreDumpPortDeviceExtension
->Interrupt
->ServiceRoutine
= DiskDumpIsr
;
215 return(STATUS_SUCCESS
);
221 return(STATUS_SUCCESS
);
225 DiskDumpWrite(LARGE_INTEGER Address
, PMDL Mdl
)
227 KIRQL OldIrql
= 0, OldIrql2
= 0;
228 KIRQL CurrentIrql
= KeGetCurrentIrql();
230 if (CurrentIrql
< (CoreDumpPortDeviceExtension
->Interrupt
->SynchronizeIrql
- 1))
232 KeRaiseIrql(CoreDumpPortDeviceExtension
->Interrupt
->SynchronizeIrql
- 1, &OldIrql
);
235 /* Adjust the address for the start of the partition. */
237 (CoreDumpClass2DeviceExtension
->StartingOffset
.QuadPart
+ CoreDumpClass2DeviceExtension
->DMByteSkew
);
239 /* Assume the device is always able to transfer a page so no need to split up the transfer. */
241 /* Build an SRB to describe the write. */
242 DiskDumpBuildRequest(Address
, Mdl
);
244 /* Start i/o on the HBA. */
245 IrqComplete
= IrqNextRequest
= FALSE
;
246 KeRaiseIrql(CoreDumpPortDeviceExtension
->Interrupt
->SynchronizeIrql
, &OldIrql2
);
247 if (!CoreDumpPortDeviceExtension
->HwStartIo(&CoreDumpPortDeviceExtension
->MiniPortDeviceExtension
,
250 KeLowerIrql(OldIrql
);
251 DbgPrint("DISKDUMP: Error: Miniport HwStartIo failed.\n");
252 return(STATUS_UNSUCCESSFUL
);
254 KeLowerIrql(OldIrql2
);
256 /* Wait for the miniport to finish. */
258 while (!IrqComplete
|| !IrqNextRequest
)
262 if (CurrentIrql
< (CoreDumpPortDeviceExtension
->Interrupt
->SynchronizeIrql
- 1))
264 KeLowerIrql(OldIrql
);
268 /* Check the result. */
269 if (SRB_STATUS(CoreDumpSrb
.SrbStatus
) != SRB_STATUS_SUCCESS
)
271 DbgPrint("DISKDUMP: Error: SRB failed.\n");
272 return(STATUS_UNSUCCESSFUL
);
274 return(STATUS_SUCCESS
);
278 DiskDumpPrepare(PDEVICE_OBJECT DeviceObject
, PDUMP_POINTERS DumpPointers
)
280 PIMAGE_NT_HEADERS NtHeader
;
281 PVOID ImportDirectory
;
282 ULONG ImportDirectorySize
;
283 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory
;
288 PVOID
* ImportAddressList
;
289 PULONG FunctionNameList
;
291 /* Save the information from the kernel. */
292 CoreDumpClassDevice
= DeviceObject
;
293 CoreDumpPointers
= *DumpPointers
;
294 CoreDumpClass2DeviceExtension
= (PDEVICE_EXTENSION
)CoreDumpClassDevice
->DeviceExtension
;
295 CoreDumpPortDevice
= DumpPointers
->DeviceObject
;
296 CoreDumpPortDeviceExtension
= CoreDumpPortDevice
->DeviceExtension
;
298 /* Replace all the miniport driver's imports with our functions. */
299 DriverBase
= CoreDumpPortDevice
->DriverObject
->DriverStart
;
300 NtHeader
= RtlImageNtHeader(DriverBase
);
301 ImportDirectory
= RtlImageDirectoryEntryToData(DriverBase
,
303 IMAGE_DIRECTORY_ENTRY_IMPORT
,
304 &ImportDirectorySize
);
305 if (ImportDirectory
== NULL
|| ImportDirectorySize
== 0)
307 DbgPrint("DISKDUMP: Error: Miniport has no imports?\n");
308 return(STATUS_UNSUCCESSFUL
);
310 /* Process each import module */
311 ImportModuleDirectory
= (PIMAGE_IMPORT_DESCRIPTOR
)ImportDirectory
;
312 DPRINT("Processeing import directory at %p\n", ImportModuleDirectory
);
313 while (ImportModuleDirectory
->Name
)
315 /* Check to make sure that import lib is kernel */
316 Name
= (PCHAR
) DriverBase
+ ImportModuleDirectory
->Name
;
318 if (strcmp(Name
, "scsiport.sys") != 0)
320 DbgPrint("DISKDUMP: Warning: Miniport has illegal imports.\n");
321 ImportModuleDirectory
++;
325 /* Get the import address list */
326 ImportAddressList
= (PVOID
*) ((PUCHAR
)DriverBase
+
327 (ULONG_PTR
)ImportModuleDirectory
->FirstThunk
);
329 /* Get the list of functions to import */
330 if (ImportModuleDirectory
->OriginalFirstThunk
!= 0)
332 FunctionNameList
= (PULONG
) ((PUCHAR
)DriverBase
+
333 (ULONG_PTR
)ImportModuleDirectory
->OriginalFirstThunk
);
337 FunctionNameList
= (PULONG
) ((PUCHAR
)DriverBase
+
338 (ULONG_PTR
)ImportModuleDirectory
->FirstThunk
);
340 /* Walk through function list and fixup addresses */
341 while (*FunctionNameList
!= 0L)
343 if ((*FunctionNameList
) & 0x80000000) // hint
347 Hint
= (*FunctionNameList
) & 0xffff;
351 Name
= (PCHAR
)((ULONG_PTR
)DriverBase
+
352 (ULONG_PTR
)*FunctionNameList
+ 2);
353 Hint
= *(PUSHORT
)((ULONG_PTR
)DriverBase
+ (ULONG_PTR
)*FunctionNameList
);
356 DPRINT(" Hint:%04x Name:%s\n", Hint
, pName
);
359 for (i
= 0; i
< (sizeof(DiskDumpExports
) / sizeof(DiskDumpExports
[0])); i
++)
361 if (DiskDumpExports
[i
].Ordinal
== Hint
||
362 (Name
!= NULL
&& strcmp(DiskDumpExports
[i
].Name
, Name
) == 0))
367 if (i
== (sizeof(DiskDumpExports
) / sizeof(DiskDumpExports
[0])))
369 DbgPrint("DISKDUMP: Error: Miniport imports unknown symbol %s.\n", Name
);
370 return(STATUS_UNSUCCESSFUL
);
372 if (strcmp(Name
, "ScsiPortNotification") == 0)
374 OldScsiPortNotification
= *ImportAddressList
;
376 DiskDumpExports
[i
].OldFunction
= *ImportAddressList
;
377 if (DiskDumpExports
[i
].NewFunction
!= NULL
)
379 *ImportAddressList
= DiskDumpExports
[i
].NewFunction
;
385 ImportModuleDirectory
++;
387 return(STATUS_SUCCESS
);
390 /**********************************************************************
395 * This function initializes the driver, locates and claims
396 * hardware resources, and creates various NT objects needed
397 * to process I/O requests.
404 * System allocated Driver Object for this driver
407 * Name of registry driver service key
414 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
415 IN PUNICODE_STRING RegistryPath
)
417 DiskDumpDriver
= DriverObject
;
418 return(STATUS_SUCCESS
);