48554 (Разработка драйвера виртуального жесткого диска), страница 4
Описание файла
Документ из архива "Разработка драйвера виртуального жесткого диска", который расположен в категории "". Всё это находится в предмете "информатика" из 1 семестр, которые можно найти в файловом архиве . Не смотря на прямую связь этого архива с , его также можно найти и в других разделах. Архив можно найти в разделе "курсовые/домашние работы", в предмете "информатика, программирование" в общих файлах.
Онлайн просмотр документа "48554"
Текст 4 страницы из документа "48554"
DBGPRINT( DBG_COMP_INIT, DBG_LEVEL_INFO, ("IRP_MJ_CREATE (%p)\n", Irp) );
COMPLETE_REQUEST( Irp, status, 0 );
break;
case IRP_MJ_CLOSE:
DBGPRINT( DBG_COMP_INIT, DBG_LEVEL_INFO, ("IRP_MJ_CLOSE (%p)\n", Irp) );
COMPLETE_REQUEST( Irp, status, 0 );
break;
default:
status = STATUS_NOT_IMPLEMENTED;
COMPLETE_REQUEST( Irp, status, 0 );
ASSERTMSG("BUG: we should never get here", 0);
break;
} // switch
В качестве проверки, если мы получили пакет с другим кодом, то возвратим ошибочный статус.
Обработка запросов на запись или чтение , также реализуется в одной процедуре, т.к. отличия в действиях заключаются в направлении копирования данных: из буфера в образ диска или наоборот. Для выполнения запроса, требуется, чтобы виртуальный диск находился в состоянии WORKING:
if ( devExt->DevState != WORKING )
{
// Устройство не готово или удалено, отменить любые запросы
DBGPRINT( DBG_COMP_READ, DBG_LEVEL_WARN, ("Device not ready\n" ) );
status = STATUS_INVALID_DEVICE_STATE;
COMPLETE_REQUEST( Irp, status, information );
}
Далее требуется проверить, что переданные параметры(начальное смещение Parameters.Read.ByteOffset и количество байт Parameters.Read.Length) не выходят за границы нашего диска, чтобы обеспечить корректность операции чтения/записи. Дополнительно количество байт должно быть кратно размеру сектора на диске:
if (RtlLargeIntegerGreaterThan(
RtlLargeIntegerAdd(
irpStack->Parameters.Read.ByteOffset,
RtlConvertUlongToLargeInteger(irpStack->Parameters.Read.Length)),
RtlConvertUlongToLargeInteger(devExt->DiskRegInfo.DiskSize)) ||
(irpStack->Parameters.Read.Length & (devExt->DiskGeometry.BytesPerSector - 1)))
{
DBGPRINT( DBG_COMP_READ, DBG_LEVEL_ERROR,
(
"Error invalid parameter\n"
"ByteOffset: %x\n"
"Length: %d\n"
"Operation: %x\n",
irpStack->Parameters.Read.ByteOffset,
irpStack->Parameters.Read.Length,
irpStack->MajorFunction
));
status = STATUS_INVALID_PARAMETER;
COMPLETE_REQUEST( Irp, status, information );
IoReleaseRemoveLock(&devExt->RemoveLock, Irp);
return status;
}
Если какой-либо из параметров не верен, то статус обработки запроса будет равен STATUS_INVALID_PARAMETER (неверные параметры).
Драйвер использует прямой метод передачи буфера данных, нам передается MDL список для буфера пользователя в параметре Irp->MdlAddress, который мы отображаем в адресное пространство ядра с помощью функции MmGetSystemAddressForMdlSafe:
ASSERT ( Irp->MdlAddress != NULL );
currentAddress = MmGetSystemAddressForMdlSafe(Irp->MdlAddress,NormalPagePriority);
if ( currentAddress == NULL )
{
status = STATUS_INSUFFICIENT_RESOURCES;
COMPLETE_REQUEST( Irp, status, information );
IoReleaseRemoveLock(&devExt->RemoveLock, Irp);
DBGPRINT( DBG_COMP_READ, DBG_LEVEL_ERROR, ("Unable to get the system-space virtual address\n" ) );
return status;}
Когда адрес получен адрес буфера (currentAddress), можно произвести копирование данных с помощью функции RtlMoveMemory
information = irpStack->Parameters.Read.Length;
switch (irpStack->MajorFunction)
{
case IRP_MJ_READ:
RtlMoveMemory(
currentAddress,
devExt->DiskImage + irpStack->Parameters.Read.ByteOffset.LowPart,
irpStack->Parameters.Read.Length);
break;
case IRP_MJ_WRITE:
RtlMoveMemory(
devExt->DiskImage + irpStack->Parameters.Read.ByteOffset.LowPart,
currentAddress, irpStack->Parameters.Read.Length);
break;
default:
information = 0;
break;
}
status = STATUS_SUCCESS;
COMPLETE_REQUEST( Irp, status, information );
При этом поле information содержит количество байт, которые были записаны/прочитаны.
3.4.3 Обработка расширенных запросов
Поскольку наш драйвер обращается с виртуальным диском, при следующих запросах выполнять каких-либо действий не требуется, просто сообщить, что запрос успешно обработан. Это запросы:
case IOCTL_DISK_IS_WRITABLE://проверка можно ли на диск записывать данные
{
DBGPRINT( DBG_COMP_IOCTL, DBG_LEVEL_INFO, ("IOCTL_DISK_IS_WRITABLE \n" ) );
status = STATUS_SUCCESS;
break;
}
case IOCTL_MOUNTMGR_QUERY_POINTS: // сообщить о символической ссылке для тома
{
DBGPRINT( DBG_COMP_IOCTL, DBG_LEVEL_INFO, ("IOCTL_MOUNTMGR_QUERY_POINTS\n" ) );
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
case IOCTL_DISK_FORMAT_TRACKS: //Форматировать дорожки
{
DBGPRINT( DBG_COMP_IOCTL, DBG_LEVEL_INFO, ("IOCTL_DISK_FORMAT_TRACKS\n" ) );
status = STATUS_SUCCESS ;
break;
}
case IOCTL_DISK_MEDIA_REMOVAL: //блокировать извлечение носителя
{
DBGPRINT( DBG_COMP_IOCTL, DBG_LEVEL_INFO, ("IOCTL_DISK_MEDIA_REMOVAL\n" ) );
status = STATUS_SUCCESS ;
break;
}
case IOCTL_DISK_VERIFY: //провреить данные
{
PVERIFY_INFORMATION verifyInformation;
DBGPRINT( DBG_COMP_IOCTL, DBG_LEVEL_INFO, ("IOCTL_DISK_VERIFY\n" ) );
status = STATUS_SUCCESS ;
break;
}
case IOCTL_DISK_CHECK_VERIFY:// проверить, сменился ли носитель
{
DBGPRINT( DBG_COMP_IOCTL, DBG_LEVEL_INFO, ("IOCTL_DISK_CHECK_VERIFY\n" ) );
status = STATUS_SUCCESS ;
break;
}
Запрос IOCTL_DISK_GET_PARTITION_INFO, требует сообщить информацию о разделах на диске. На рамдиске имеется один раздел. Результатом обработки запроса будет структура PARTITION_INFORMATION
typedef struct _PARTITION_INFORMATION
{
LARGE_INTEGER Ошибка! Недопустимый объект гиперссылки.; //смещение, с которого начинается раздел
LARGE_INTEGER Ошибка! Недопустимый объект гиперссылки.;//размер раздела
DWORD Ошибка! Недопустимый объект гиперссылки.; //скрытых секторов
DWORD Ошибка! Недопустимый объект гиперссылки.; //порядковый номер раздела
BYTE Ошибка! Недопустимый объект гиперссылки.; //тип раздела
BOOLEAN Ошибка! Недопустимый объект гиперссылки.; //TRUE - раздел является загрузочным
BOOLEAN Ошибка! Недопустимый объект гиперссылки.; //распознан ли раздел
BOOLEAN Ошибка! Недопустимый объект гиперссылки.; //TRUE – изменились параметры раздела
}
Тип раздела Ошибка! Недопустимый объект гиперссылки. для виртуального диска может быть PARTITION_FAT_12 или PARTITION_FAT_16(он определяется при инициализации и хранится в расширении драйвера). Остальные поля заполняются следующим образом:
case IOCTL_DISK_GET_PARTITION_INFO:
{
DBGPRINT( DBG_COMP_IOCTL, DBG_LEVEL_INFO, ("IOCTL_DISK_GET_PARTITION_INFO \n" ) );
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength { DBGPRINT( DBG_COMP_IOCTL, DBG_LEVEL_INFO, ("Output buffer too small... \n" ) ); status = STATUS_BUFFER_TOO_SMALL; // Нужен буфер больше information = sizeof(PARTITION_INFORMATION); } else { PPARTITION_INFORMATION outputBuffer; outputBuffer = ( PPARTITION_INFORMATION )Irp->AssociatedIrp.SystemBuffer; outputBuffer->PartitionType = (UCHAR)devExt->DiskRegInfo.PartitionType; outputBuffer->BootIndicator = FALSE; outputBuffer->RecognizedPartition = FALSE outputBuffer->RewritePartition = FALSE; outputBuffer->StartingOffset = RtlConvertUlongToLargeInteger(0); outputBuffer->PartitionLength = RtlConvertUlongToLargeInteger(devExt->DiskRegInfo.DiskSize); outputBuffer->HiddenSectors = (ULONG) (1L); outputBuffer->PartitionNumber = (ULONG) (1L); status = STATUS_SUCCESS; information = sizeof( PARTITION_INFORMATION ); } break; } Запросы IOCTL_DISK_GET_MEDIA_TYPES, IOCTL_DISK_GET_DRIVE _GEOMETRY нужны для поучения информации о геометрии диска, для этого надо заполнить структуру DISK_GEOMETRY описанную в разделе 2.7.: typedef struct _DISK_GEOMETRY { LARGE_INTEGER Ошибка! Недопустимый объект гиперссылки.; //количество цилиндров MEDIA_TYPE Ошибка! Недопустимый объект гиперссылки.; //тип носителя ULONG Ошибка! Недопустимый объект гиперссылки.; //количество дорожек на цилиндр ULONG Ошибка! Недопустимый объект гиперссылки.; //количество секторов на дорожку ULONG Ошибка! Недопустимый объект гиперссылки.; //размер сектора в байтах } DISK_GEOMETRY, *PDISK_GEOMETRY; Все остальные параметры заранее рассчитаны и определены при инициализации, и нужно только эту структуру скопировать из расширения устройства: PDISK_GEOMETRY outputBuffer; outputBuffer = ( PDISK_GEOMETRY ) Irp->AssociatedIrp.SystemBuffer; RtlCopyMemory( outputBuffer, &(devExt->DiskGeometry), sizeof(DISK_GEOMETRY) ); status = STATUS_SUCCESS; DBGPRINT(DBG_COMP_IOCTL,DBG_LEVEL_INFO,("IOCTL_DISK_GET_DRIVE_GEOMETRY-OK!\n")); information = sizeof( DISK_GEOMETRY ); При запуске устройства мы получаем IRP пакет с кодом IRP_MN_START_DEVICE: case IRP_MN_START_DEVICE: { KeInitializeEvent( &event, NotificationEvent, FALSE); IoCopyCurrentIrpStackLocationToNext( Irp ); IoSetCompletionRoutine( Irp, (PIO_COMPLETION_ROUTINE) RamDskIoCompletionRoutine, (PVOID) &event, TRUE, TRUE, TRUE ); status = IoCallDriver( devExt->LowerDeviceObject, Irp ); if (status == STATUS_PENDING) { KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL ); } if ( NT_SUCCESS(status) ) { // успешно запущен нижний драйвер devExt->DevState = WORKING; } COMPLETE_REQUEST( Irp, status, 0 ); break; } Мы пересылаем пакет драйверу, который находится ниже при помощи вызова функции IoCallDriver. Если нижние драйвер находится в состоянии обработки (STATUS_PENDING), то просто усыплем наш драйвер с помощью функции KeWaitForSingleObject и просыпаемся по событию завершения операции нижним драйвером. При остановке устройства(IRP_MN_STOP_DEVICE), просто пересылаем запрос нижнему драйверу и устанавливаем состояние устройства STOPPED: case IRP_MN_STOP_DEVICE: { devExt->DevState = STOPPED; Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation( Irp ); status = IoCallDriver( devExt->LowerDeviceObject, Irp ); break; } При обработке запросов IRP_MN_SURPRISE_REMOVAL, IRP_MN_QUERY_ REMOVE_DEVICE, IRP_MN_QUERY_STOP_DEVICE, производятся аналогичные действия, с установкой соответствующего статуса: case IRP_MN_QUERY_STOP_DEVICE: { devExt->DevState = PENDINGSTOP; Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation( Irp ); status = IoCallDriver( devExt->LowerDeviceObject, Irp ); break; } case IRP_MN_STOP_DEVICE: { devExt->DevState = STOPPED; Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation( Irp ); status = IoCallDriver( devExt->LowerDeviceObject, Irp ); break; } case IRP_MN_QUERY_REMOVE_DEVICE: { devExt->DevState = PENDINGREMOVE; Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation( Irp ); status = IoCallDriver( devExt->LowerDeviceObject, Irp ); break; } case IRP_MN_SURPRISE_REMOVAL: { devExt->DevState = SURPRISEREMOVED; Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation( Irp ); status = IoCallDriver( devExt->LowerDeviceObject, Irp ); break; } При удалении устройства IRP_MN_REMOVE_DEVICE, мы вызываем функцию RamDskRemoveDevice, которая освобождает выделенную при инициализации память, символическую ссылку (она будет описана далее): case IRP_MN_REMOVE_DEVICE: { RamDskRemoveDevice( DeviceObject, Irp ); lockHeld = FALSE; break; } Выгрузка драйвера состоит из двух частей: удаление объекта устройства и выгрузка самого драйвера. При удалении объекта устройства, менеджер ввода вывода посылает IRP пакет IRP_MN_REMOVE_DEVICE, тогда вызывается процедура RamDskRemove Device. IRP пакет передаем дальше драйверу нижнего уровня с помощью функции IoCallDriver. Статус драйвера устанавливается в состояние устройство удалено, чтобы новые запросы не могли быть выполнены. С помощью функции IoReleaseRemoveLockAndWait ждем пока текущие запросы не обработаются. Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation( Irp ); status = IoCallDriver( devExt->LowerDeviceObject, Irp ); devExt->DevState = REMOVED; IoReleaseRemoveLockAndWait(&devExt->RemoveLock, Irp); driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, RAMDSK_DRIVER_EXTENSION_KEY); ASSERT ( driverExtension != NULL ); driverExtension->DeviceInitialized = FALSE; RamDskCleanUp( DeviceObject ); Перед удалением расширения объекта устройства в процедуре RamDskCleanUp освобождается память под образ диска, удаляется символическая ссылка и сам функциональный объект устройства. Также далее сбрасывается признак DeviceInitialized инициализации устройства. При выгрузке самого драйвера вызывается процедура RamDskUnload, которая должна обязательно присутствовать, чтобы драйвер мог выгружаться. VOID RamDskUnload(IN PDRIVER_OBJECT DriverObject) { PRAMDSK_DRIVER_EXTENSION driverExtension; DBGPRINT( DBG_COMP_INIT, DBG_LEVEL_INFO, ("Driver Unload\n") ); ASSERT(DriverObject->DeviceObject == NULL); driverExtension = IoGetDriverObjectExtension(DriverObject,RAMDSK_DRIVER_EXTENSION_KEY); ASSERT ( driverExtension != NULL ); if ( driverExtension->RegistryPath.Buffer ) { ExFreePool( driverExtension->RegistryPath.Buffer );
3.4.4 Обработка запросов Plug and Play
3.4.5 Выгрузка драйвера