📄 geometry.c
字号:
if(found) {
ULONG cylinders;
ULONG sectorsPerTrack;
ULONG tracksPerCylinder;
ULONG sectors;
ULONG length;
//
// Point to the array of drive parameters.
//
cylinders = diskInfo->DriveParameters.MaxCylinders + 1;
sectorsPerTrack = diskInfo->DriveParameters.SectorsPerTrack;
tracksPerCylinder = diskInfo->DriveParameters.MaxHeads + 1;
//
// Since the BIOS may not report the full drive, recalculate the drive
// size based on the volume size and the BIOS values for tracks per
// cylinder and sectors per track..
//
length = tracksPerCylinder * sectorsPerTrack;
if (length == 0) {
//
// The BIOS information is bogus.
//
DebugPrint((1, "DiskUpdateGeometry: H (%d) or S(%d) is zero\n",
tracksPerCylinder, sectorsPerTrack));
return DiskGeometryUnknown;
}
//
// since we are copying the structure RealGeometry here, we should
// really initialize all the fields, especially since a zero'd
// BytesPerSector field would cause a trap in xHalReadPartitionTable()
//
diskData->RealGeometry = FdoExtension->DiskGeometry;
//
// Save the geometry information away in the disk data block and
// set the bit indicating that we found a valid one.
//
diskData->RealGeometry.SectorsPerTrack = sectorsPerTrack;
diskData->RealGeometry.TracksPerCylinder = tracksPerCylinder;
diskData->RealGeometry.Cylinders.QuadPart = (LONGLONG)cylinders;
DebugPrint((1, "DiskUpdateGeometry: BIOS spt %#x, #heads %#x, "
"#cylinders %#x\n",
sectorsPerTrack, tracksPerCylinder, cylinders));
diskData->GeometrySource = DiskGeometryFromBios;
diskInfo->Device = FdoExtension->DeviceObject;
//
// Increment the count of used geometry entries.
//
InterlockedIncrement(&DetectInfoUsedCount);
} else {
DebugPrint((1, "DiskUpdateGeometry: no match found for signature %#08lx\n", diskData->Mbr.Signature));
}
if(diskData->GeometrySource == DiskGeometryUnknown) {
//
// We couldn't find a geometry from the BIOS. Check with the port
// driver and see if it can provide one.
//
status = DiskGetPortGeometry(FdoExtension, &(diskData->RealGeometry));
if(NT_SUCCESS(status)) {
//
// Check the geometry to make sure it's valid.
//
if((diskData->RealGeometry.TracksPerCylinder *
diskData->RealGeometry.SectorsPerTrack) != 0) {
diskData->GeometrySource = DiskGeometryFromPort;
DebugPrint((1, "DiskUpdateGeometry: using Port geometry for disk %#p\n", FdoExtension));
if (diskData->RealGeometry.BytesPerSector == 0) {
DebugPrint((0, "DiskDriverReinit: Port driver failed to "
"set BytesPerSector in the RealGeometry\n"));
diskData->RealGeometry.BytesPerSector =
FdoExtension->DiskGeometry.BytesPerSector;
if (diskData->RealGeometry.BytesPerSector == 0) {
ASSERT(!"BytesPerSector is still zero!");
}
}
}
}
}
//
// If we came up with a "real" geometry for this drive then set it in the
// device extension.
//
if (diskData->GeometrySource != DiskGeometryUnknown) {
FdoExtension->DiskGeometry = diskData->RealGeometry;
}
return diskData->GeometrySource;
}
NTSTATUS
DiskUpdateRemovableGeometry (
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
)
/*++
Routine Description:
This routine updates the geometry of the disk. It will query the port
driver to see if it can provide any geometry info. If not it will use
the current head & sector count.
Based on these values & the capacity of the drive as reported by
ClassReadDriveCapacity it will determine a new cylinder count for the
device.
Arguments:
Fdo - Supplies the functional device object whos size needs to be updated.
Return Value:
Returns the status of the opertion.
--*/
{
PCOMMON_DEVICE_EXTENSION commonExtension = &(FdoExtension->CommonExtension);
PDISK_DATA diskData = commonExtension->DriverData;
PDISK_GEOMETRY geometry = &(diskData->RealGeometry);
NTSTATUS status;
PAGED_CODE();
ASSERT_FDO(commonExtension->DeviceObject);
if (FdoExtension->DeviceDescriptor) {
ASSERT(FdoExtension->DeviceDescriptor->RemovableMedia);
}
ASSERT(TEST_FLAG(FdoExtension->DeviceObject->Characteristics,
FILE_REMOVABLE_MEDIA));
//
// Attempt to determine the disk geometry. First we'll check with the
// port driver to see what it suggests for a value.
//
status = DiskGetPortGeometry(FdoExtension, geometry);
if(NT_SUCCESS(status) &&
((geometry->TracksPerCylinder * geometry->SectorsPerTrack) != 0)) {
FdoExtension->DiskGeometry = (*geometry);
}
return status;
}
NTSTATUS
DiskGetPortGeometry(
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
OUT PDISK_GEOMETRY Geometry
)
/*++
Routine Description:
This routine will query the port driver for disk geometry. Some port
drivers (in particular IDEPORT) may be able to provide geometry for the
device.
Arguments:
FdoExtension - the device object for the disk.
Geometry - a structure to save the geometry information into (if any is
available)
Return Value:
STATUS_SUCCESS if geometry information can be provided or
error status indicating why it can't.
--*/
{
PCOMMON_DEVICE_EXTENSION commonExtension = &(FdoExtension->CommonExtension);
PIRP irp;
PIO_STACK_LOCATION irpStack;
KEVENT event;
NTSTATUS status;
PAGED_CODE();
//
// Build an irp to send IOCTL_DISK_GET_DRIVE_GEOMETRY to the lower driver.
//
irp = IoAllocateIrp(commonExtension->LowerDeviceObject->StackSize, FALSE);
if(irp == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
irpStack = IoGetNextIrpStackLocation(irp);
irpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
irpStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_DISK_GET_DRIVE_GEOMETRY;
irpStack->Parameters.DeviceIoControl.OutputBufferLength =
sizeof(DISK_GEOMETRY);
irp->AssociatedIrp.SystemBuffer = Geometry;
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
IoSetCompletionRoutine(irp,
ClassSignalCompletion,
&event,
TRUE,
TRUE,
TRUE);
status = IoCallDriver(commonExtension->LowerDeviceObject, irp);
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = irp->IoStatus.Status;
IoFreeIrp(irp);
return status;
}
BOOLEAN
DiskIsNT4Geometry(
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
)
/*++
Routine Description:
The default geometry that was used in partitioning disks under Windows NT 4.0 was
Sectors per Track = 0x20 = 32
Tracks per Cylinder = 0x40 = 64
This was changed in Windows 2000 to
Sectors per Track = 0x3F = 63
Tracks per Cylinder = 0xFF = 255
If neither the BIOS nor the port driver can report the correct geometry, we will
default to the new numbers on such disks. Now LVM uses the geometry when creating
logical volumes and dynamic disks. So reporting an incorrect geometry will cause
the entire extended partition / dynamic disk to be destroyed
In this routine, we will look at the Master Boot Record. In 90% of the cases, the
first entry corresponds to a partition that starts on the first track. If this is
so, we shall retrieve the logical block address associated with it and calculate
the correct geometry. Now, all partitions start on a cylinder boundary. So, for
the remaining 10% we will look at the ending CHS number to determine the geometry
--*/
{
PUSHORT readBuffer = NULL;
BOOLEAN bFoundNT4 = FALSE;
PAGED_CODE();
readBuffer = ExAllocatePoolWithTag(NonPagedPool, FdoExtension->DiskGeometry.BytesPerSector, DISK_TAG_UPDATE_GEOM);
if (readBuffer)
{
KEVENT event;
LARGE_INTEGER diskOffset;
IO_STATUS_BLOCK ioStatus = { 0 };
PIRP irp;
KeInitializeEvent(&event, NotificationEvent, FALSE);
//
// Read the Master Boot Record at disk offset 0
//
diskOffset.QuadPart = 0;
irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, FdoExtension->DeviceObject, readBuffer, FdoExtension->DiskGeometry.BytesPerSector, &diskOffset, &event, &ioStatus);
if (irp)
{
PIO_STACK_LOCATION irpSp = IoGetNextIrpStackLocation(irp);
NTSTATUS status;
irpSp->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
status = IoCallDriver(FdoExtension->DeviceObject, irp);
if (status == STATUS_PENDING)
{
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = ioStatus.Status;
}
if (NT_SUCCESS(status))
{
//
// Match the boot record signature
//
if (readBuffer[BOOT_SIGNATURE_OFFSET] == BOOT_RECORD_SIGNATURE)
{
PPARTITION_DESCRIPTOR partitionTableEntry = (PPARTITION_DESCRIPTOR)&readBuffer[PARTITION_TABLE_OFFSET];
ULONG uCount = 0;
//
// Walk the entries looking for a clue as to what the geometry might be
//
for (uCount = 0; uCount < NUM_PARTITION_TABLE_ENTRIES; uCount++)
{
//
// We are only concerned if there might be a logical volume or if this disk is part of a dynamic set
//
if (IsContainerPartition(partitionTableEntry->PartitionType) || partitionTableEntry->PartitionType == PARTITION_LDM)
{
//
// In 90% of the cases, the first entry corresponds to a partition that starts on the first track
//
if (partitionTableEntry->StartingTrack == 1 && GET_STARTING_SECTOR(partitionTableEntry) == 0x20)
{
bFoundNT4 = TRUE;
break;
}
//
// In almost every case, the ending CHS number is on a cylinder boundary
//
if (partitionTableEntry->EndingTrack == 0x3F && GET_ENDING_S_OF_CHS(partitionTableEntry) == 0x20)
{
bFoundNT4 = TRUE;
break;
}
}
partitionTableEntry++;
}
}
else
{
//
// The Master Boot Record is invalid
//
}
}
}
ExFreePool(readBuffer);
}
return bFoundNT4;
}
NTSTATUS
DiskReadDriveCapacity(
IN PDEVICE_OBJECT Fdo
)
/*++
Routine Description:
This routine is used by disk.sys as a wrapper for the classpnp API
ClassReadDriveCapacity. It will perform some additional operations to
attempt to determine drive geometry before it calls the classpnp version
of the routine.
For fixed disks this involves calling DiskUpdateGeometry which will check
various sources (the BIOS, the port driver) for geometry information.
Arguments:
Fdo - a pointer to the device object to be checked.
Return Value:
status of ClassReadDriveCapacity.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -