Страница 6 из 13 Доступ к памяти В контексте приложения Win32 или виртуальной машины DOS драйвер имеет прямой доступ к их адресному пространству. Для виртуальных машин требуется лишь приведение 16-разрядных адресов типа «сегмент:смещение» к линейным, расположенным в пределах первого мегабайта 32-разрядного адресного пространства. В контексте 16-разрядного приложения Windows подобной «прямой видимости» нет, и для прямого доступа к данным приложения необходимо выполнить отображение (mapping) фрагментов 16-разрядного адресного пространства приложения в «плоское» (flat) 32-разрядное адресное пространство драйвера. В результате этой операции в области системных адресов создаются страницы, отображенные на те же адреса физической памяти, что и заданные адреса 16-разрядного приложения. После завершения работы с данными отображение необходимо прекратить (unmap), чтобы освободить созданные в системной области страницы. Поскольку системная область (system arena) доступна для чтения всем приложениям Win32, они могут считывать локальные данные VxD по возвращенным им указателям. Однако доступ приложений к системой области памяти в общем случае не рекомендуется. Повторная входимость VMM в общем случае не является повторно-входимым (реентерабельным) модулем. Функции VMM делятся на асинхронные, которые могут быть вызваны в любой момент (даже внутри обработчика прерывания), и обычные, которые могут вызваны лишь внутри «вертикального» потока управления, когда управление передается строго сверху вниз, без рекурсий. Большинство функций VxD, вызываемых извне, не требует обеспечения повторной входимости. Однако вызовы функций, происходящие в результате асинхронных событий (обычно это прерывания), могут накладываться, если обработка предыдущего вызова не успела завершиться или реализована некорректно. Поэтому при проектировании VxD, имеющих дело с асинхронными событиями, этому вопросу необходимо уделять особое внимание. Загрузка, работа и выгрузка драйвера Все VxD загружаются в системную область памяти (system memory arena), начинающуюся с адреса 0xC0000000. Сразу после загрузки статическому драйверу — сообщение DEVICE_INIT; динамическому драйверу передается сообщение SYS_DYNAMIC_DEVICE_INIT. Последовательность передачи сообщений при инициализации статического драйвера на самом деле немного сложнее; точное описание процесса можно найти в документации DDK. Фаза инициализации драйвера обычно состоит в установке начальных значений переменных, запросе рабочих областей памяти, настройке режимов работы устройств, назначении векторов прерываний, каналов DMA и т.п. После отработки фазы инициализации драйвер может быть вызван любым из предусмотренных способов по запросам от системы и/или приложений. Передаваемые системные сообщения отражают происходящие в системе события. При выгрузке динамического драйвера он получает сообщение SYS_DYNAMIC_DEVICE_EXIT, по которому обычно выполняется освобождение используемых областей памяти, закрытие объектов, деактивация управляемых устройств и т.п. После отработки этого сообщения динамический драйвер удаляется из памяти. Ответственность за корректную «чистку» перед выгрузкой динамического драйвера возложена на его разработчика. Система не в состоянии проверить, действительно ли удалены все ссылки на объекты драйвера; если, например, драйвер сделал запрос на таймерное или иное событие, после чего был выгружен и не аннулировал этого запроса — при наступлении события VMM попытается вызвать заданную процедуру обработки, которая к этому времени уже не существует, что приведет к непредсказуемым последствиям, вплоть до полного зависания системы. |