3 * Copyright (C) 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: services/storage/diskdump/diskdump.c
24 * PURPOSE: Dumping crash data to the pagefile
25 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
28 /* INCLUDES *****************************************************************/
30 #include <ddk/ntddk.h>
32 #include <ddk/ntdddisk.h>
33 #include <ddk/ntddscsi.h>
34 #include <include/class2.h>
35 #include <diskdump/diskdump.h>
37 #include <ndk/extypes.h>
38 #include <ndk/rtlfuncs.h>
39 #include "../scsiport/scsiport_int.h"
44 /* It's already defined in scsiport_int.h */
46 #define VERSION "0.0.1"
48 #undef KeGetCurrentIrql
49 /* PROTOTYPES ***************************************************************/
52 DiskDumpPrepare(PDEVICE_OBJECT DeviceObject
, PDUMP_POINTERS DumpPointers
);
54 DiskDumpScsiInvalid(VOID
);
56 _DiskDumpScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
57 IN PVOID HwDeviceExtension
,
64 DiskDumpWrite(LARGE_INTEGER StartAddress
, PMDL Mdl
);
66 typedef VOID (*SCSIPORTNOTIFICATION
)(IN SCSI_NOTIFICATION_TYPE NotificationType
,
67 IN PVOID HwDeviceExtension
,
70 /* GLOBALS ******************************************************************/
72 MM_CORE_DUMP_FUNCTIONS DiskDumpFunctions
=
74 (PVOID
)DiskDumpPrepare
,
77 (PVOID
)DiskDumpFinish
,
88 static SCSI_REQUEST_BLOCK CoreDumpSrb
;
89 static DUMP_POINTERS CoreDumpPointers
;
90 static PDEVICE_OBJECT CoreDumpClassDevice
;
91 static PDEVICE_EXTENSION CoreDumpClass2DeviceExtension
;
92 static PDEVICE_OBJECT CoreDumpPortDevice
;
93 static SCSI_PORT_DEVICE_EXTENSION
* CoreDumpPortDeviceExtension
;
94 BOOLEAN IsDumping
= FALSE
;
95 static PDRIVER_OBJECT DiskDumpDriver
;
96 static UCHAR DiskDumpSenseData
[SENSE_BUFFER_SIZE
];
97 static BOOLEAN IrqComplete
, IrqNextRequest
;
98 PVOID OldScsiPortNotification
;
99 static SUBSTITUTE_EXPORT DiskDumpExports
[] =
101 {"ScsiPortConvertPhysicalAddressToUlong", 2, NULL
, NULL
},
102 {"ScsiPortConvertUlongToPhysicalAddress", 3, NULL
, NULL
},
103 {"ScsiPortFreeDeviceBase", 5, NULL
, DiskDumpScsiInvalid
},
104 {"ScsiPortGetBusData", 6, NULL
, DiskDumpScsiInvalid
},
105 {"ScsiPortGetDeviceBase", 7, DiskDumpScsiInvalid
},
106 {"ScsiPortInitialize", 13, NULL
, DiskDumpScsiInvalid
},
107 {"ScsiPortNotification", 17, NULL
, _DiskDumpScsiPortNotification
},
108 {"ScsiPortReadPortBufferUlong", 19, NULL
},
109 {"ScsiPortReadPortBufferUshort", 20, NULL
},
110 {"ScsiPortReadPortUchar", 21, NULL
, NULL
},
111 {"ScsiPortReadPortUshort", 23, NULL
, NULL
},
112 {"ScsiPortStallExecution", 31, NULL
, NULL
},
113 {"ScsiPortWritePortBufferUlong", 34, NULL
},
114 {"ScsiPortWritePortBufferUshort", 35, NULL
},
115 {"ScsiPortWritePortUchar", 36, NULL
, NULL
},
116 {"ScsiDebugPrint", 0, NULL
, NULL
},
119 /* FUNCTIONS ****************************************************************/
124 DiskDumpScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
125 IN PVOID HwDeviceExtension
,
128 if (NotificationType
== RequestComplete
)
132 if (NotificationType
== NextRequest
)
134 IrqNextRequest
= TRUE
;
139 DiskDumpScsiInvalid(VOID
)
141 DbgPrint("DISKDUMP: Error: Miniport called a function not supported at dump time.\n");
146 DiskDumpBuildRequest(LARGE_INTEGER StartingOffset
, PMDL Mdl
)
148 LARGE_INTEGER StartingBlock
;
149 PSCSI_REQUEST_BLOCK Srb
;
151 ULONG LogicalBlockAddress
;
152 USHORT TransferBlocks
;
154 /* Calculate logical block address */
155 StartingBlock
.QuadPart
= StartingOffset
.QuadPart
>> CoreDumpClass2DeviceExtension
->SectorShift
;
156 LogicalBlockAddress
= (ULONG
)StartingBlock
.u
.LowPart
;
158 DPRINT("Logical block address: %lu\n", LogicalBlockAddress
);
160 /* Allocate and initialize an SRB */
164 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
); //SCSI_REQUEST_BLOCK_SIZE;
165 Srb
->OriginalRequest
= NULL
;
166 Srb
->PathId
= CoreDumpClass2DeviceExtension
->PathId
;
167 Srb
->TargetId
= CoreDumpClass2DeviceExtension
->TargetId
;
168 Srb
->Lun
= CoreDumpClass2DeviceExtension
->Lun
;
169 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
170 Srb
->DataBuffer
= Mdl
->MappedSystemVa
;
171 Srb
->DataTransferLength
= PAGE_SIZE
;
172 Srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
173 Srb
->QueueSortKey
= LogicalBlockAddress
;
175 Srb
->SenseInfoBuffer
= DiskDumpSenseData
;
176 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
179 ((Srb
->DataTransferLength
+ 0xFFFF) >> 16) * CoreDumpClass2DeviceExtension
->TimeOutValue
;
181 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
186 Cdb
= (PCDB
)Srb
->Cdb
;
188 /* Initialize ATAPI packet (12 bytes) */
189 RtlZeroMemory(Cdb
, MAXIMUM_CDB_SIZE
);
191 Cdb
->CDB10
.LogicalUnitNumber
= CoreDumpClass2DeviceExtension
->Lun
;
192 TransferBlocks
= (USHORT
)(PAGE_SIZE
>>
193 CoreDumpClass2DeviceExtension
->SectorShift
);
195 /* Copy little endian values into CDB in big endian format */
196 Cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte3
;
197 Cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte2
;
198 Cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte1
;
199 Cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte0
;
201 Cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)&TransferBlocks
)->Byte1
;
202 Cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)&TransferBlocks
)->Byte0
;
206 Srb
->SrbFlags
|= SRB_FLAGS_DATA_OUT
;
207 Cdb
->CDB10
.OperationCode
= SCSIOP_WRITE
;
209 /* Leave caching disabled. */
213 DiskDumpIsr(PKINTERRUPT Interrupt
, PVOID ServiceContext
)
215 if (!CoreDumpPortDeviceExtension
->HwInterrupt(&CoreDumpPortDeviceExtension
->MiniPortDeviceExtension
))
225 KIRQL CurrentIrql
= KeGetCurrentIrql();
227 if (CurrentIrql
>= CoreDumpPortDeviceExtension
->Interrupt
->SynchronizeIrql
)
229 DbgPrint("DISKDUMP: Error: Crash inside high priority interrupt routine.\n");
230 return(STATUS_UNSUCCESSFUL
);
232 CoreDumpPortDeviceExtension
->Interrupt
->ServiceRoutine
= DiskDumpIsr
;
234 return(STATUS_SUCCESS
);
240 return(STATUS_SUCCESS
);
244 DiskDumpWrite(LARGE_INTEGER Address
, PMDL Mdl
)
246 KIRQL OldIrql
, OldIrql2
;
247 KIRQL CurrentIrql
= KeGetCurrentIrql();
249 if (CurrentIrql
< (CoreDumpPortDeviceExtension
->Interrupt
->SynchronizeIrql
- 1))
251 KeRaiseIrql(CoreDumpPortDeviceExtension
->Interrupt
->SynchronizeIrql
- 1, &OldIrql
);
254 /* Adjust the address for the start of the partition. */
256 (CoreDumpClass2DeviceExtension
->StartingOffset
.QuadPart
+ CoreDumpClass2DeviceExtension
->DMByteSkew
);
258 /* Assume the device is always able to transfer a page so no need to split up the transfer. */
260 /* Build an SRB to describe the write. */
261 DiskDumpBuildRequest(Address
, Mdl
);
263 /* Start i/o on the HBA. */
264 IrqComplete
= IrqNextRequest
= FALSE
;
265 KeRaiseIrql(CoreDumpPortDeviceExtension
->Interrupt
->SynchronizeIrql
, &OldIrql2
);
266 if (!CoreDumpPortDeviceExtension
->HwStartIo(&CoreDumpPortDeviceExtension
->MiniPortDeviceExtension
,
269 KeLowerIrql(OldIrql
);
270 DbgPrint("DISKDUMP: Error: Miniport HwStartIo failed.\n");
271 return(STATUS_UNSUCCESSFUL
);
273 KeLowerIrql(OldIrql2
);
275 /* Wait for the miniport to finish. */
277 while (!IrqComplete
|| !IrqNextRequest
)
281 if (CurrentIrql
< (CoreDumpPortDeviceExtension
->Interrupt
->SynchronizeIrql
- 1))
283 KeLowerIrql(OldIrql
);
287 /* Check the result. */
288 if (SRB_STATUS(CoreDumpSrb
.SrbStatus
) != SRB_STATUS_SUCCESS
)
290 DbgPrint("DISKDUMP: Error: SRB failed.\n");
291 return(STATUS_UNSUCCESSFUL
);
293 return(STATUS_SUCCESS
);
297 DiskDumpPrepare(PDEVICE_OBJECT DeviceObject
, PDUMP_POINTERS DumpPointers
)
299 PIMAGE_NT_HEADERS NtHeader
;
300 PVOID ImportDirectory
;
301 ULONG ImportDirectorySize
;
302 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory
;
307 PVOID
* ImportAddressList
;
308 PULONG FunctionNameList
;
310 /* Save the information from the kernel. */
311 CoreDumpClassDevice
= DeviceObject
;
312 CoreDumpPointers
= *DumpPointers
;
313 CoreDumpClass2DeviceExtension
= (PDEVICE_EXTENSION
)CoreDumpClassDevice
->DeviceExtension
;
314 CoreDumpPortDevice
= DumpPointers
->DeviceObject
;
315 CoreDumpPortDeviceExtension
= CoreDumpPortDevice
->DeviceExtension
;
317 /* Replace all the miniport driver's imports with our functions. */
318 DriverBase
= CoreDumpPortDevice
->DriverObject
->DriverStart
;
319 NtHeader
= RtlImageNtHeader(DriverBase
);
320 ImportDirectory
= RtlImageDirectoryEntryToData(DriverBase
,
322 IMAGE_DIRECTORY_ENTRY_IMPORT
,
323 &ImportDirectorySize
);
324 if (ImportDirectory
== NULL
|| ImportDirectorySize
== 0)
326 DbgPrint("DISKDUMP: Error: Miniport has no imports?\n");
327 return(STATUS_UNSUCCESSFUL
);
329 /* Process each import module */
330 ImportModuleDirectory
= (PIMAGE_IMPORT_DESCRIPTOR
)ImportDirectory
;
331 DPRINT("Processeing import directory at %p\n", ImportModuleDirectory
);
332 while (ImportModuleDirectory
->Name
)
334 /* Check to make sure that import lib is kernel */
335 Name
= (PCHAR
) DriverBase
+ ImportModuleDirectory
->Name
;
337 if (strcmp(Name
, "scsiport.sys") != 0)
339 DbgPrint("DISKDUMP: Warning: Miniport has illegal imports.\n");
340 ImportModuleDirectory
++;
344 /* Get the import address list */
345 ImportAddressList
= (PVOID
*) ((PUCHAR
)DriverBase
+
346 (ULONG_PTR
)ImportModuleDirectory
->FirstThunk
);
348 /* Get the list of functions to import */
349 if (ImportModuleDirectory
->OriginalFirstThunk
!= 0)
351 FunctionNameList
= (PULONG
) ((PUCHAR
)DriverBase
+
352 (ULONG_PTR
)ImportModuleDirectory
->OriginalFirstThunk
);
356 FunctionNameList
= (PULONG
) ((PUCHAR
)DriverBase
+
357 (ULONG_PTR
)ImportModuleDirectory
->FirstThunk
);
359 /* Walk through function list and fixup addresses */
360 while (*FunctionNameList
!= 0L)
362 if ((*FunctionNameList
) & 0x80000000) // hint
366 Hint
= (*FunctionNameList
) & 0xffff;
370 Name
= (PCHAR
)((DWORD
)DriverBase
+
371 *FunctionNameList
+ 2);
372 Hint
= *(PWORD
)((DWORD
)DriverBase
+ *FunctionNameList
);
375 DPRINT(" Hint:%04x Name:%s\n", Hint
, pName
);
378 for (i
= 0; i
< (sizeof(DiskDumpExports
) / sizeof(DiskDumpExports
[0])); i
++)
380 if (DiskDumpExports
[i
].Ordinal
== Hint
||
381 (Name
!= NULL
&& strcmp(DiskDumpExports
[i
].Name
, Name
) == 0))
386 if (i
== (sizeof(DiskDumpExports
) / sizeof(DiskDumpExports
[0])))
388 DbgPrint("DISKDUMP: Error: Miniport imports unknown symbol %s.\n", Name
);
389 return(STATUS_UNSUCCESSFUL
);
391 if (strcmp(Name
, "ScsiPortNotification") == 0)
393 OldScsiPortNotification
= *ImportAddressList
;
395 DiskDumpExports
[i
].OldFunction
= *ImportAddressList
;
396 if (DiskDumpExports
[i
].NewFunction
!= NULL
)
398 *ImportAddressList
= DiskDumpExports
[i
].NewFunction
;
404 ImportModuleDirectory
++;
406 return(STATUS_SUCCESS
);
409 /**********************************************************************
414 * This function initializes the driver, locates and claims
415 * hardware resources, and creates various NT objects needed
416 * to process I/O requests.
423 * System allocated Driver Object for this driver
426 * Name of registry driver service key
433 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
434 IN PUNICODE_STRING RegistryPath
)
436 DiskDumpDriver
= DriverObject
;
437 return(STATUS_SUCCESS
);