NTSTATUS NTAPI DiskInitFdo( IN PDEVICE_OBJECT Fdo ) /*++ Routine Description: This routine is called to do one-time initialization of new device objects Arguments: Fdo - a pointer to the functional device object for this device Return Value: status --*/ { PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; PDISK_DATA diskData = (PDISK_DATA) fdoExtension->CommonExtension.DriverData; //ULONG srbFlags = 0; ULONG timeOut = 0; ULONG bytesPerSector; //UCHAR sectorShift; //BOOLEAN dmActive = FALSE; PULONG dmSkew; //ULONG dmByteSkew; NTSTATUS status; PAGED_CODE(); // // Build the lookaside list for srb's for the physical disk. Should only // need a couple. If this fails then we don't have an emergency SRB so // fail the call to initialize. // ClassInitializeSrbLookasideList((PCOMMON_DEVICE_EXTENSION) fdoExtension, PARTITION0_LIST_SIZE); // // Because all requests share a common sense buffer, it is possible // for the buffer to be overwritten if the port driver completes // multiple failed requests that require a request sense before the // class driver's completion routine can consume the data in the buffer. // To prevent this, we allow the port driver to allocate a unique sense // buffer each time it needs one. We are responsible for freeing this // buffer. This also allows the adapter to be configured to support // additional sense data beyond the minimum 18 bytes. // fdoExtension->SrbFlags = SRB_FLAGS_PORT_DRIVER_ALLOCSENSE; // // Initialize the srb flags. // if (fdoExtension->DeviceDescriptor->CommandQueueing && fdoExtension->AdapterDescriptor->CommandQueueing) { fdoExtension->SrbFlags = SRB_FLAGS_QUEUE_ACTION_ENABLE; } if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) { SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT); } // // Look for controllers that require special flags. // ClassScanForSpecial(fdoExtension, DiskBadControllers, DiskSetSpecialHacks); // // Look into the registry to see if this device // requires special attention - [ like a hack ] // DiskScanRegistryForSpecial(fdoExtension); //srbFlags = fdoExtension->SrbFlags; // // Clear buffer for drive geometry. // RtlZeroMemory(&(fdoExtension->DiskGeometry), sizeof(DISK_GEOMETRY)); // // Allocate request sense buffer. // fdoExtension->SenseData = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE, DISK_TAG_START); if (fdoExtension->SenseData == NULL) { // // The buffer can not be allocated. // DebugPrint((1, "DiskInitFdo: Can not allocate request sense buffer\n")); status = STATUS_INSUFFICIENT_RESOURCES; return status; } // // Physical device object will describe the entire // device, starting at byte offset 0. // fdoExtension->CommonExtension.StartingOffset.QuadPart = (LONGLONG)(0); // // Set timeout value in seconds. // timeOut = ClassQueryTimeOutRegistryValue(Fdo); if (timeOut) { fdoExtension->TimeOutValue = timeOut; } else { fdoExtension->TimeOutValue = SCSI_DISK_TIMEOUT; } // // If this is a removable drive, build an entry in devicemap\scsi // indicating it's physicaldriveN name, set up the appropriate // update partitions routine and set the flags correctly. // note: only do this after the timeout value is set, above. // if (fdoExtension->DeviceDescriptor->RemovableMedia) { ClassUpdateInformationInRegistry( Fdo, "PhysicalDrive", fdoExtension->DeviceNumber, NULL, 0); // // Enable media change notification for removable disks // ClassInitializeMediaChangeDetection(fdoExtension, "Disk"); SET_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA); diskData->UpdatePartitionRoutine = DiskUpdateRemovablePartitions; } else { SET_FLAG(fdoExtension->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE); diskData->UpdatePartitionRoutine = DiskUpdatePartitions; } // // Read the drive capacity. Don't use the disk version of the routine here // since we don't know the disk signature yet - the disk version will // attempt to determine the BIOS reported geometry. // status = ClassReadDriveCapacity(Fdo); // // If the read capcity failed then just return, unless this is a // removable disk where a device object partition needs to be created. // if (!NT_SUCCESS(status) && !(Fdo->Characteristics & FILE_REMOVABLE_MEDIA)) { DebugPrint((1, "DiskInitFdo: Can't read capacity for device %p\n", Fdo)); if (fdoExtension->DeviceDescriptor->RemovableMedia) { fdoExtension->DiskGeometry.MediaType = RemovableMedia; Fdo->Flags &= ~DO_VERIFY_VOLUME; } else { fdoExtension->DiskGeometry.MediaType = FixedMedia; } status = STATUS_SUCCESS; } // // Set up sector size fields. // // Stack variables will be used to update // the partition device extensions. // // The device extension field SectorShift is // used to calculate sectors in I/O transfers. // // The DiskGeometry structure is used to service // IOCTls used by the format utility. // bytesPerSector = fdoExtension->DiskGeometry.BytesPerSector; // // Make sure sector size is not zero. // if (bytesPerSector == 0) { // // Default sector size for disk is 512. // bytesPerSector = fdoExtension->DiskGeometry.BytesPerSector = 512; } //sectorShift = fdoExtension->SectorShift; // // Determine is DM Driver is loaded on an IDE drive that is // under control of Atapi - this could be either a crashdump or // an Atapi device is sharing the controller with an IDE disk. // HalExamineMBR(fdoExtension->CommonExtension.DeviceObject, fdoExtension->DiskGeometry.BytesPerSector, (ULONG)0x54, (PVOID*)&dmSkew); if (dmSkew) { // // Update the device extension, so that the call to IoReadPartitionTable // will get the correct information. Any I/O to this disk will have // to be skewed by *dmSkew sectors aka DMByteSkew. // fdoExtension->DMSkew = *dmSkew; fdoExtension->DMActive = TRUE; fdoExtension->DMByteSkew = fdoExtension->DMSkew * bytesPerSector; // // Save away the infomation that we need, since this deviceExtension will soon be // blown away. // //dmActive = TRUE; //dmByteSkew = fdoExtension->DMByteSkew; } #if defined(_X86_) // // Try to read the signature off the disk and determine the correct drive // geometry based on that. This requires rereading the disk size to get // the cylinder count updated correctly. // if(fdoExtension->DeviceDescriptor->RemovableMedia == FALSE) { DiskReadSignature(Fdo); DiskReadDriveCapacity(Fdo); } #endif // // Register interfaces for this device // { UNICODE_STRING interfaceName; RtlInitUnicodeString(&interfaceName, NULL); status = IoRegisterDeviceInterface(fdoExtension->LowerPdo, (LPGUID) &DiskClassGuid, NULL, &interfaceName); if(NT_SUCCESS(status)) { diskData->DiskInterfaceString = interfaceName; status = IoSetDeviceInterfaceState(&interfaceName, TRUE); } else { interfaceName.Buffer = NULL; } if(!NT_SUCCESS(status)) { DebugPrint((1, "DiskInitFdo: Unable to register or set disk DCA " "for fdo %p [%lx]\n", Fdo, status)); RtlFreeUnicodeString(&interfaceName); RtlInitUnicodeString(&(diskData->DiskInterfaceString), NULL); } } DiskCreateSymbolicLinks(Fdo); // // Determine the type of disk and enable failure preiction in the hardware // and enable failure prediction polling. // if (InitSafeBootMode == 0) { DiskDetectFailurePrediction(fdoExtension, &diskData->FailurePredictionCapability); if (diskData->FailurePredictionCapability != FailurePredictionNone) { // // Cool, we've got some sort of failure prediction, enable it // at the hardware and then enable polling for it // // // By default we allow performance to be degradeded if failure // prediction is enabled. // // TODO: Make a registry entry ? // diskData->AllowFPPerfHit = TRUE; // // Enable polling only after Atapi and SBP2 add support for the new // SRB flag that indicates that the request should not reset the // drive spin down idle timer. // status = DiskEnableDisableFailurePredictPolling(fdoExtension, TRUE, DISK_DEFAULT_FAILURE_POLLING_PERIOD); DebugPrint((3, "DiskInitFdo: Failure Prediction Poll enabled as " "%d for device %p\n", diskData->FailurePredictionCapability, Fdo)); } } else { // // In safe boot mode we do not enable failure prediction, as perhaps // it is the reason why normal boot does not work // diskData->FailurePredictionCapability = FailurePredictionNone; } // // Initialize the verify mutex // KeInitializeMutex(&diskData->VerifyMutex, MAX_SECTORS_PER_VERIFY); return(STATUS_SUCCESS); } // end DiskInitFdo()
NTSTATUS DiskInitFdo( IN PDEVICE_OBJECT Fdo ) /*++ Routine Description: This routine is called to do one-time initialization of new device objects Arguments: Fdo - a pointer to the functional device object for this device Return Value: status --*/ { PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; PDISK_DATA diskData = (PDISK_DATA) fdoExtension->CommonExtension.DriverData; ULONG srbFlags = 0; ULONG timeOut = 0; ULONG bytesPerSector; PULONG dmSkew; NTSTATUS status = STATUS_SUCCESS; PAGED_CODE(); // // Build the lookaside list for srb's for the physical disk. Should only // need a couple. If this fails then we don't have an emergency SRB so // fail the call to initialize. // ClassInitializeSrbLookasideList((PCOMMON_DEVICE_EXTENSION) fdoExtension, PARTITION0_LIST_SIZE); if (fdoExtension->DeviceDescriptor->RemovableMedia) { SET_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA); } // // Initialize the srb flags. // // // Because all requests share a common sense buffer, it is possible // for the buffer to be overwritten if the port driver completes // multiple failed requests that require a request sense before the // class driver's completion routine can consume the data in the buffer. // To prevent this, we allow the port driver to allocate a unique sense // buffer each time it needs one. We are responsible for freeing this // buffer. This also allows the adapter to be configured to support // additional sense data beyond the minimum 18 bytes. // SET_FLAG(fdoExtension->SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE); if (fdoExtension->DeviceDescriptor->CommandQueueing && fdoExtension->AdapterDescriptor->CommandQueueing) { SET_FLAG(fdoExtension->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE); } // // Look for controllers that require special flags. // ClassScanForSpecial(fdoExtension, DiskBadControllers, DiskSetSpecialHacks); // // Clear buffer for drive geometry. // RtlZeroMemory(&(fdoExtension->DiskGeometry), sizeof(DISK_GEOMETRY)); // // Allocate request sense buffer. // fdoExtension->SenseData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, SENSE_BUFFER_SIZE_EX, DISK_TAG_START); if (fdoExtension->SenseData == NULL) { // // The buffer can not be allocated. // TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "DiskInitFdo: Can not allocate request sense buffer\n")); status = STATUS_INSUFFICIENT_RESOURCES; return status; } // // Set the buffer size of SenseData // fdoExtension->SenseDataLength = SENSE_BUFFER_SIZE_EX; // // Physical device object will describe the entire // device, starting at byte offset 0. // fdoExtension->CommonExtension.StartingOffset.QuadPart = (LONGLONG)(0); // // Set timeout value in seconds. // if ( (fdoExtension->MiniportDescriptor != NULL) && (fdoExtension->MiniportDescriptor->IoTimeoutValue > 0) ) { // // use the value set by Storport miniport driver // fdoExtension->TimeOutValue = fdoExtension->MiniportDescriptor->IoTimeoutValue; } else { // // get timeout value from registry // timeOut = ClassQueryTimeOutRegistryValue(Fdo); if (timeOut) { fdoExtension->TimeOutValue = timeOut; } else { fdoExtension->TimeOutValue = SCSI_DISK_TIMEOUT; } } // // If this is a removable drive, build an entry in devicemap\scsi // indicating it's physicaldriveN name, set up the appropriate // update partitions routine and set the flags correctly. // note: only do this after the timeout value is set, above. // if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) { ClassUpdateInformationInRegistry( Fdo, "PhysicalDrive", fdoExtension->DeviceNumber, NULL, 0); // // Enable media change notification for removable disks // ClassInitializeMediaChangeDetection(fdoExtension, (PUCHAR)"Disk"); } else { SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT); SET_FLAG(fdoExtension->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE); } // // The commands we send during the init could cause the flags to change // in case of any error. Save the SRB flags locally and restore it at // the end of this function, so that the class driver can get it. // srbFlags = fdoExtension->SrbFlags; // // Read the drive capacity. Don't use the disk version of the routine here // since we don't know the disk signature yet - the disk version will // attempt to determine the BIOS reported geometry. // (VOID)ClassReadDriveCapacity(Fdo); // // Set up sector size fields. // // Stack variables will be used to update // the partition device extensions. // // The device extension field SectorShift is // used to calculate sectors in I/O transfers. // // The DiskGeometry structure is used to service // IOCTls used by the format utility. // bytesPerSector = fdoExtension->DiskGeometry.BytesPerSector; // // Make sure sector size is not zero. // if (bytesPerSector == 0) { // // Default sector size for disk is 512. // bytesPerSector = fdoExtension->DiskGeometry.BytesPerSector = 512; fdoExtension->SectorShift = 9; } // // Determine is DM Driver is loaded on an IDE drive that is // under control of Atapi - this could be either a crashdump or // an Atapi device is sharing the controller with an IDE disk. // HalExamineMBR(fdoExtension->CommonExtension.DeviceObject, fdoExtension->DiskGeometry.BytesPerSector, (ULONG)0x54, &dmSkew); if (dmSkew) { // // Update the device extension, so that the call to IoReadPartitionTable // will get the correct information. Any I/O to this disk will have // to be skewed by *dmSkew sectors aka DMByteSkew. // fdoExtension->DMSkew = *dmSkew; fdoExtension->DMActive = TRUE; fdoExtension->DMByteSkew = fdoExtension->DMSkew * bytesPerSector; FREE_POOL(dmSkew); } #if defined(_X86_) || defined(_AMD64_) // // Try to read the signature off the disk and determine the correct drive // geometry based on that. This requires rereading the disk size to get // the cylinder count updated correctly. // if(!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) { DiskReadSignature(Fdo); DiskReadDriveCapacity(Fdo); if (diskData->GeometrySource == DiskGeometryUnknown) { // // Neither the BIOS nor the port driver could provide us with a reliable // geometry. Before we use the default, look to see if it was partitioned // under Windows NT4 [or earlier] and apply the one that was used back then // if (DiskIsNT4Geometry(fdoExtension)) { diskData->RealGeometry = fdoExtension->DiskGeometry; diskData->RealGeometry.SectorsPerTrack = 0x20; diskData->RealGeometry.TracksPerCylinder = 0x40; fdoExtension->DiskGeometry = diskData->RealGeometry; diskData->GeometrySource = DiskGeometryFromNT4; } } } #endif DiskCreateSymbolicLinks(Fdo); // // Get the SCSI address if it's available for use with SMART ioctls. // SMART ioctls are used for failure prediction, so we need to get // the SCSI address before initializing failure prediction. // { PIRP irp; KEVENT event; IO_STATUS_BLOCK statusBlock = { 0 }; KeInitializeEvent(&event, SynchronizationEvent, FALSE); irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_ADDRESS, fdoExtension->CommonExtension.LowerDeviceObject, NULL, 0L, &(diskData->ScsiAddress), sizeof(SCSI_ADDRESS), FALSE, &event, &statusBlock); status = STATUS_UNSUCCESSFUL; if(irp != NULL) { status = IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp); if(status == STATUS_PENDING) { KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); status = statusBlock.Status; } } } // // Determine the type of disk and enable failure prediction in the hardware // and enable failure prediction polling. // if (*InitSafeBootMode == 0) { DiskDetectFailurePrediction(fdoExtension, &diskData->FailurePredictionCapability, NT_SUCCESS(status)); if (diskData->FailurePredictionCapability != FailurePredictionNone) { // // Cool, we've got some sort of failure prediction, enable it // at the hardware and then enable polling for it // // // By default we allow performance to be degradeded if failure // prediction is enabled. // diskData->AllowFPPerfHit = TRUE; // // Enable polling only after Atapi and SBP2 add support for the new // SRB flag that indicates that the request should not reset the // drive spin down idle timer. // status = DiskEnableDisableFailurePredictPolling(fdoExtension, TRUE, DISK_DEFAULT_FAILURE_POLLING_PERIOD); TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "DiskInitFdo: Failure Prediction Poll enabled as " "%d for device %p, Status = %lx\n", diskData->FailurePredictionCapability, Fdo, status)); } } else { // // In safe boot mode we do not enable failure prediction, as perhaps // it is the reason why normal boot does not work // diskData->FailurePredictionCapability = FailurePredictionNone; } // // Initialize the verify mutex // KeInitializeMutex(&diskData->VerifyMutex, MAX_SECTORS_PER_VERIFY); // // Initialize the flush group context // RtlZeroMemory(&diskData->FlushContext, sizeof(DISK_GROUP_CONTEXT)); InitializeListHead(&diskData->FlushContext.CurrList); InitializeListHead(&diskData->FlushContext.NextList); KeInitializeSpinLock(&diskData->FlushContext.Spinlock); KeInitializeEvent(&diskData->FlushContext.Event, SynchronizationEvent, FALSE); // // Restore the saved value // fdoExtension->SrbFlags = srbFlags; return STATUS_SUCCESS; } // end DiskInitFdo()
NTSTATUS INIT_FUNCTION NTAPI IopCreateArcNamesDisk(IN PLOADER_PARAMETER_BLOCK LoaderBlock, IN BOOLEAN SingleDisk, IN PBOOLEAN FoundBoot) { PIRP Irp; PVOID Data; KEVENT Event; NTSTATUS Status; PLIST_ENTRY NextEntry; PFILE_OBJECT FileObject; DISK_GEOMETRY DiskGeometry; PDEVICE_OBJECT DeviceObject; LARGE_INTEGER StartingOffset; PULONG PartitionBuffer = NULL; IO_STATUS_BLOCK IoStatusBlock; CHAR Buffer[128], ArcBuffer[128]; BOOLEAN NotEnabledPresent = FALSE; STORAGE_DEVICE_NUMBER DeviceNumber; PARC_DISK_SIGNATURE ArcDiskSignature; PWSTR SymbolicLinkList, lSymbolicLinkList; PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = NULL; UNICODE_STRING DeviceStringW, ArcNameStringW, HalPathStringW; ULONG DiskNumber, DiskCount, CheckSum, i, Signature, EnabledDisks = 0; PARC_DISK_INFORMATION ArcDiskInformation = LoaderBlock->ArcDiskInformation; ANSI_STRING ArcBootString, ArcSystemString, DeviceStringA, ArcNameStringA, HalPathStringA; /* Initialise device number */ DeviceNumber.DeviceNumber = 0xFFFFFFFF; /* Get all the disks present in the system */ DiskCount = IoGetConfigurationInformation()->DiskCount; /* Get enabled disks and check if result matches */ Status = IopFetchConfigurationInformation(&SymbolicLinkList, GUID_DEVINTERFACE_DISK, DiskCount, &EnabledDisks); if (!NT_SUCCESS(Status)) { NotEnabledPresent = TRUE; } /* Save symbolic link list address in order to free it after */ lSymbolicLinkList = SymbolicLinkList; /* Build the boot strings */ RtlInitAnsiString(&ArcBootString, LoaderBlock->ArcBootDeviceName); RtlInitAnsiString(&ArcSystemString, LoaderBlock->ArcHalDeviceName); /* If we have more enabled disks, take that into account */ if (EnabledDisks > DiskCount) { DiskCount = EnabledDisks; } /* If we'll have to browse for none enabled disks, fix higher count */ if (NotEnabledPresent && !EnabledDisks) { DiskCount += 20; } /* Finally, if in spite of all that work, we still don't have disks, leave */ if (!DiskCount) { goto Cleanup; } /* Start browsing disks */ for (DiskNumber = 0; DiskNumber < DiskCount; DiskNumber++) { /* Check if we have an enabled disk */ if (lSymbolicLinkList && *lSymbolicLinkList != UNICODE_NULL) { /* Create its device name using first symbolic link */ RtlInitUnicodeString(&DeviceStringW, lSymbolicLinkList); /* Then, update symbolic links list */ lSymbolicLinkList += wcslen(lSymbolicLinkList) + (sizeof(UNICODE_NULL) / sizeof(WCHAR)); /* Get its associated device object and file object */ Status = IoGetDeviceObjectPointer(&DeviceStringW, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject); if (NT_SUCCESS(Status)) { /* Now, we'll ask the device its device number */ Irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER, DeviceObject, NULL, 0, &DeviceNumber, sizeof(STORAGE_DEVICE_NUMBER), FALSE, &Event, &IoStatusBlock); /* Missing resources is a shame... No need to go farther */ if (!Irp) { ObDereferenceObject(FileObject); Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } /* Call the driver, and wait for it if needed */ KeInitializeEvent(&Event, NotificationEvent, FALSE); Status = IoCallDriver(DeviceObject, Irp); if (Status == STATUS_PENDING) { KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); Status = IoStatusBlock.Status; } /* If we didn't get the appriopriate data, just skip that disk */ if (!NT_SUCCESS(Status)) { ObDereferenceObject(FileObject); continue; } } /* End of enabled disks enumeration */ if (NotEnabledPresent && *lSymbolicLinkList == UNICODE_NULL) { /* No enabled disk worked, reset field */ if (DeviceNumber.DeviceNumber == 0xFFFFFFFF) { DeviceNumber.DeviceNumber = 0; } /* Update disk number to enable the following not enabled disks */ if (DeviceNumber.DeviceNumber > DiskNumber) { DiskNumber = DeviceNumber.DeviceNumber; } /* Increase a bit more */ DiskCount = DiskNumber + 20; } } else { /* Create device name for the disk */ sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", DiskNumber); RtlInitAnsiString(&DeviceStringA, Buffer); Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE); if (!NT_SUCCESS(Status)) { goto Cleanup; } /* Get its device object */ Status = IoGetDeviceObjectPointer(&DeviceStringW, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject); RtlFreeUnicodeString(&DeviceStringW); /* This is a security measure, to ensure DiskNumber will be used */ DeviceNumber.DeviceNumber = 0xFFFFFFFF; } /* Something failed somewhere earlier, just skip the disk */ if (!NT_SUCCESS(Status)) { continue; } /* Let's ask the disk for its geometry */ Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY, DeviceObject, NULL, 0, &DiskGeometry, sizeof(DISK_GEOMETRY), FALSE, &Event, &IoStatusBlock); /* Missing resources is a shame... No need to go farther */ if (!Irp) { ObDereferenceObject(FileObject); Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } /* Call the driver, and wait for it if needed */ KeInitializeEvent(&Event, NotificationEvent, FALSE); Status = IoCallDriver(DeviceObject, Irp); if (Status == STATUS_PENDING) { KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); Status = IoStatusBlock.Status; } /* Failure, skip disk */ if (!NT_SUCCESS(Status)) { ObDereferenceObject(FileObject); continue; } /* Read the partition table */ Status = IoReadPartitionTableEx(DeviceObject, &DriveLayout); if (!NT_SUCCESS(Status)) { ObDereferenceObject(FileObject); continue; } /* Ensure we have at least 512 bytes per sector */ if (DiskGeometry.BytesPerSector < 512) { DiskGeometry.BytesPerSector = 512; } /* Check MBR type against EZ Drive type */ StartingOffset.QuadPart = 0; HalExamineMBR(DeviceObject, DiskGeometry.BytesPerSector, 0x55, &Data); if (Data) { /* If MBR is of the EZ Drive type, we'll read after it */ StartingOffset.QuadPart = DiskGeometry.BytesPerSector; ExFreePool(Data); } /* Allocate for reading enough data for checksum */ PartitionBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, DiskGeometry.BytesPerSector, TAG_IO); if (!PartitionBuffer) { ObDereferenceObject(FileObject); Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } /* Read a sector for computing checksum */ Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, DeviceObject, PartitionBuffer, DiskGeometry.BytesPerSector, &StartingOffset, &Event, &IoStatusBlock); if (!Irp) { ObDereferenceObject(FileObject); Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } /* Call the driver to perform reading */ KeInitializeEvent(&Event, NotificationEvent, FALSE); Status = IoCallDriver(DeviceObject, Irp); if (Status == STATUS_PENDING) { KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); Status = IoStatusBlock.Status; } if (!NT_SUCCESS(Status)) { ExFreePool(DriveLayout); ExFreePoolWithTag(PartitionBuffer, TAG_IO); ObDereferenceObject(FileObject); continue; } ObDereferenceObject(FileObject); /* Calculate checksum, that's an easy computation, just adds read data */ for (i = 0, CheckSum = 0; i < 512 / sizeof(ULONG) ; i++) { CheckSum += PartitionBuffer[i]; } /* Browse each ARC disk */ for (NextEntry = ArcDiskInformation->DiskSignatureListHead.Flink; NextEntry != &ArcDiskInformation->DiskSignatureListHead; NextEntry = NextEntry->Flink) { ArcDiskSignature = CONTAINING_RECORD(NextEntry, ARC_DISK_SIGNATURE, ListEntry); /* If they matches, ie * - There's only one disk for both BIOS and detected/enabled * - Signatures are matching * - Checksums are matching * - This is MBR */ if (((SingleDisk && DiskCount == 1) || (IopVerifyDiskSignature(DriveLayout, ArcDiskSignature, &Signature) && (ArcDiskSignature->CheckSum + CheckSum == 0))) && (DriveLayout->PartitionStyle == PARTITION_STYLE_MBR)) { /* Create device name */ sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", (DeviceNumber.DeviceNumber != 0xFFFFFFFF) ? DeviceNumber.DeviceNumber : DiskNumber); RtlInitAnsiString(&DeviceStringA, Buffer); Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE); if (!NT_SUCCESS(Status)) { goto Cleanup; } /* Create ARC name */ sprintf(ArcBuffer, "\\ArcName\\%s", ArcDiskSignature->ArcName); RtlInitAnsiString(&ArcNameStringA, ArcBuffer); Status = RtlAnsiStringToUnicodeString(&ArcNameStringW, &ArcNameStringA, TRUE); if (!NT_SUCCESS(Status)) { RtlFreeUnicodeString(&DeviceStringW); goto Cleanup; } /* Link both */ IoCreateSymbolicLink(&ArcNameStringW, &DeviceStringW); /* And release resources */ RtlFreeUnicodeString(&ArcNameStringW); RtlFreeUnicodeString(&DeviceStringW); /* Now, browse for every partition */ for (i = 1; i <= DriveLayout->PartitionCount; i++) { /* Create device name */ sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition%lu", (DeviceNumber.DeviceNumber != 0xFFFFFFFF) ? DeviceNumber.DeviceNumber : DiskNumber, i); RtlInitAnsiString(&DeviceStringA, Buffer); Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE); if (!NT_SUCCESS(Status)) { goto Cleanup; } /* Create partial ARC name */ sprintf(ArcBuffer, "%spartition(%lu)", ArcDiskSignature->ArcName, i); RtlInitAnsiString(&ArcNameStringA, ArcBuffer); /* Is that boot device? */ if (RtlEqualString(&ArcNameStringA, &ArcBootString, TRUE)) { DPRINT("Found boot device\n"); *FoundBoot = TRUE; } /* Is that system partition? */ if (RtlEqualString(&ArcNameStringA, &ArcSystemString, TRUE)) { /* Create HAL path name */ RtlInitAnsiString(&HalPathStringA, LoaderBlock->NtHalPathName); Status = RtlAnsiStringToUnicodeString(&HalPathStringW, &HalPathStringA, TRUE); if (!NT_SUCCESS(Status)) { RtlFreeUnicodeString(&DeviceStringW); goto Cleanup; } /* Then store those information to registry */ IopStoreSystemPartitionInformation(&DeviceStringW, &HalPathStringW); RtlFreeUnicodeString(&HalPathStringW); } /* Create complete ARC name */ sprintf(ArcBuffer, "\\ArcName\\%spartition(%lu)", ArcDiskSignature->ArcName, i); RtlInitAnsiString(&ArcNameStringA, ArcBuffer); Status = RtlAnsiStringToUnicodeString(&ArcNameStringW, &ArcNameStringA, TRUE); if (!NT_SUCCESS(Status)) { RtlFreeUnicodeString(&DeviceStringW); goto Cleanup; } /* Link device name & ARC name */ IoCreateSymbolicLink(&ArcNameStringW, &DeviceStringW); /* Release strings */ RtlFreeUnicodeString(&ArcNameStringW); RtlFreeUnicodeString(&DeviceStringW); } } else { /* In case there's a valid partition, a matching signature, BUT a none matching checksum, or there's a duplicate signature, or even worse a virus played with partition table */ if (ArcDiskSignature->Signature == Signature && (ArcDiskSignature->CheckSum + CheckSum != 0) && ArcDiskSignature->ValidPartitionTable) { DPRINT("Be careful, or you have a duplicate disk signature, or a virus altered your MBR!\n"); } } } /* Release memory before jumping to next item */ ExFreePool(DriveLayout); DriveLayout = NULL; ExFreePoolWithTag(PartitionBuffer, TAG_IO); PartitionBuffer = NULL; } Status = STATUS_SUCCESS; Cleanup: if (SymbolicLinkList) { ExFreePool(SymbolicLinkList); } if (DriveLayout) { ExFreePool(DriveLayout); } if (PartitionBuffer) { ExFreePoolWithTag(PartitionBuffer, TAG_IO); } return Status; }