48554 (Разработка драйвера виртуального жесткого диска), страница 4

2016-07-30СтудИзба

Описание файла

Документ из архива "Разработка драйвера виртуального жесткого диска", который расположен в категории "". Всё это находится в предмете "информатика" из 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 );


3.4.4 Обработка запросов Plug and Play

При запуске устройства мы получаем 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;

}


3.4.5 Выгрузка драйвера

Выгрузка драйвера состоит из двух частей: удаление объекта устройства и выгрузка самого драйвера.

При удалении объекта устройства, менеджер ввода вывода посылает 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 );

Свежие статьи
Популярно сейчас
А знаете ли Вы, что из года в год задания практически не меняются? Математика, преподаваемая в учебных заведениях, никак не менялась минимум 30 лет. Найдите нужный учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Нет! Мы не выполняем работы на заказ, однако Вы можете попросить что-то выложить в наших социальных сетях.
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
4121
Авторов
на СтудИзбе
667
Средний доход
с одного платного файла
Обучение Подробнее