Четверг, 17.07.2025, 23:20 Приветствую Вас Гость

On-line: Книги, учебники, статьи

Главная | Регистрация | Вход | RSS

Глава 7. Структура и написание драйверов .VXD(1)

Глава 7. Структура и написание драйверов .VXD

Последнюю главу нашей книги я посящаю написанию виртуальных драйверов. Сокращение VxD следует понимать как Virtual Device Driver, "x" относится к слову Device (имеется в виду любое устройство). Вопрос несколько устаревает, так как в Windows 98 принята на вооружение несколько иная концепция драйверов устройств, а Windows NT никогда не поддерживала VxD-драйверы, а использует модель, которая называется kernel mode (режим ядра). Все же программирование VxD остается актуальным по сей день, и знать основные положения должен каждый программирующий на языке ассемблера. В данной главе, отходя от нашей обычной практики, мы будем интенсивно использовать макроопределения, содержащиеся во включаемых (inc) файлах пакета DDK. Тем самым нам удастся поместить весь материал в одну главу. Кроме того, данная глава ориентирована на работу с MASM32.

I

Для программирования VxD-драйверов нам понадобятся файлы VMM.INC, SHELL.INC, VCOND.INC и др., которые можно найти в пакете DDK (Device Development Kit), свободно распространяемом фирмой Microsoft.

При загрузке Windows программа WIN.COM загружает драйвер VMM32.VXD, называемый Менеджером Виртуальной Машины (Virtual Machine Manager), который инициализирует другие VxD-драйверы. Затем VMM переключает процессор в защищенный режим и инициализирует системную виртуальную машину. Кроме уже сказанного, VMM обеспечивает сервис для других драйверов VXD. При запуске DOS-приложения для него выделяется виртуальная машина, так что приложению "кажется", что оно работает с настоящей машиной. При запуске обычных 32-битных приложений они работают в системной виртуальной машине. Приложения, работающие в разных виртуальных машинах, не подозревают о существовании других виртуальных машин. Одним из главных назначений виртуальных драйверов является обеспечение бесконфликтного коллективного доступа к физической аппаратуре для всех одновременно работающих виртуальных машин. Еще одна задача, которую приходится решать виртуальным драйверам, - это осуществление взаимодействия системной виртуальной машиной с другими виртуальными машинами.

Следует отметить, что в Windows существуют и так называемые обычные драйверы, имеющие расширение DRV и структуру DLL-библиотеки, которые экспортируют API-функции для работы с некоторыми внешними устройствами (например, видеоадаптером). Эти драйверы получают доступ к внешним устройствам не напрямую, а посредством VxD-драйверов. Поскольку драйверы VxD работают в нулевом кольце защиты, они имеют доступ к любому участку памяти и напрямую, посредством портов ввод-вывода, обращаются к внешним устройствам.

Все виртуальные драйверы делятся на два класса - статические и динамические. Статические драйверы загружаются во время загрузки системы и остаются в памяти до выхода из системы. Статические драйверы существовали еще в Windows 3.x. Динамические драйверы могут загружаться и выгружаться системой по мере необходимости. Они в основном используются для обслуживания устройств "Plug and Play" и загружаются менеджером конфигурации. Загрузить динамический виртуальный драйвер можно и из обычного приложения при помощи обычных функций работы с файлами.

Имеется три механизма взаимодействия виртуальных драйверов друг с другом.

  1. Управляющие сообщения. Эти сообщения посылает виртуальным драйверам менеджер виртуальной машины. Драйверы также могут обмениваться информацией посредством таких сообщений. Это очень напоминает сообщения Windows и взаимодействия приложений друг с другом и операционной системой через эти сообщения.
  2. Функции обратного вызова. Виртуальный драйвер может позволить вызов функции обратного вызова другому драйверу.
  3. Виртуальные драйверы и менеджер виртуальной машины могут экспортировать определенные функции для вызова из других виртуальных драйверов. Для вызова функции необходимо знать уникальный номер виртуального драйвера, который экспортирует данную функцию и номер этой функции.

Формат виртуальных драйверов называется LE-форматом, сокращенно от "linear executable". Данный формат поддерживает наличие как 16-битного, так и 32-битного кода. Это актуально для статических виртуальных драйверов, которые часть работы (инициализация) выполняют в реальном (незащищенном) режиме. В Windows NT драйверы грузятся в защищенном режиме, по этой причине данный формат в этой операционной системе не используется.

Код и данные в файле LE-формата располагаются в сегментах. Ниже мы опишем возможные классы сегментов.

LCODE - код или данные, заключенные в этом коде, не могут сбрасываться системой на диск (paging).

PCODE - код может временно помещаться на диск.

PDATE - аналогично предыдущему, но здесь хранятся данные.

ICODE - здесь располагается код инициализации, после инициализации сегмент удаляется из памяти.

DBOCODE - используется при запуске драйвера "под отладчиком".

SCODE - статические код и данные. Всегда остается в памяти, даже если драйвер выгружается.

RCODE — содержит 16-битный код для инициализации в реальном режиме.

16ICODE - 16-битный код инициализации в защищенном режиме.

MCODE - содержит строки сообщений.

Перечисленные классы сегментов не задаются непосредственно в тексте программы. Сегменты и классы объявляются в DEF-файле. Файл vmm.inc содержит огромное количество макросов, и нам не избежать пользоваться ими. Это позволит материал, который я хочу изложить, вместить в одну главу.

II

Начнем с содержимого DEF-файла. Содержимое показано на Рис. 4.7. Здесь перечислены сегменты на все случаи жизни. Вам нет необходимости использовать все определенные здесь сегменты. Т.о. образом данный файл можно использовать при создании любого виртуального драйвера. Сегменты, принадлежащие к одному классу, после компоновки объединяются в один сегмент. Менять следует только первую строку, где задается имя драйвера. Отметим, что имя драйвера следует задавать заглавными буквами. Кроме того, в первой строке можно задать тип драйвера. По умолчанию этот тип статический. Если бы мы записали строку VXD VXD1 DYNAMIC, то компоновщик создал бы динамический виртуальный драйвер.

VXD VXD1
SEGMENTS
_LPTEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE
_LTEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE
_LDATA CLASS 'LCODE' PRELOAD NONDISCARDABLE
_TEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE
_DATA CLASS 'LCODE' PRELOAD NONDISCARDABLE
CONST CLASS 'LCODE' PRELOAD NONDISCARDABLE
_TLS CLASS 'LCODE' PRELOAD NONDISCARDABLE
_BSS CLASS 'LCODE' PRELOAD NONDISCARDABLE
_LMGTABLE CLASS 'MCODE' PRELOAD NONDISCARDABLE IOPL
_LMSGDATA CLASS 'MCODE' PRELOAD NONDISCARDABLE IOPL
_IMSGTABLE CLASS 'MCODE' PRELOAD DISCARDABLE IOPL
_IMSGDATA CLASS 'MCODE' PRELOAD DISCARDABLE IOPL
_ITEXT CLASS 'ICODE' DISCARDABLE
_IDATA CLASS 'ICODE' DISCARDABLE
_PTEXT CLASS 'PCODE' NONDISCARDABLE
_PMSGTABLE CLASS 'MCODE' NONDISCARDABLE IOPL
_PMSGDATA CLASS 'MCODE' NONDISCARDABLE IOPL
_PDATA CLASS 'PDATA' NONDISCARDABLE SHARED
_STEXT CLASS 'SCODE' RESIDENT
_SDATA CLASS 'SCODE' RESIDENT
_DBOSTART CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
_DBOCODE CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
_DBODATA CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
_16ICODE CLASS '16ICODE' PRELOAD DISCARDABLE
_RCODE CLASS 'RCODE'
EXPORTS
VXD1_DDB @1

Рис. 4.7.1. Файл VXD.DEF используемый для компоновки виртуального драйвера.

В конце файла указывается единственная экспортируемая переменная — блок описания устройства. DDB - Device Descriptor Block. В этот блок, состоящий из 22 полей, который определен в файле vmm.inc, содержит информацию о виртуальном драйвере (см. ниже).

В файле vmm.inc определены макроимена для всех записанных выше сегментов. Например, для сегмента _LTEXT задано имя VxD_LOCKED_CODE SEG, а для _RCODE имя VxD_REAL_INIT_SEG. Мы будем использовать эти имена в своих программах.

Обратимся теперь к трансляции виртуальных драйверов. Ниже записаны строки, в результате выполнения которых может быть получен виртуальный драйвер.

 ml /coff /c /Сх /DMASM6 /DBLD_COFF /DIS_32 vxd1.asm
 link /vxd /def:vxd.def vxd1.obj

Константы MASM6, BLD_COFF, IS_32 используются операторами условной трансляции, которые заданы в файлах vmm.inc и vcond.inc. Отметим, что если Вы используете DEF-файл в том виде, как мы его определили на Рис. 4.7.1, то при компоновке будут появляться сообщения об отсутствии той или иной секции, что смело можно проигнорировать.

Для того чтобы выполнить какие-либо действия, нам часто придется использовать макроопределения из файла vmm.inc. Познакомимся с некоторыми из них.

Во-первых, конечно, это Declare_Virtual_Device. Этот макрос заполняет структуру DDB, несколько облегчая нашу задачу. Вот его полный формат (саму структуру макроса, довольно сложную, можно изучить в файле vmm.inc):

 Declare_Virtual_Device Name, MajorVer, MinorVer, CtrlProc,
 DeviceID, InitOrder, V86Proc, PMProc, RefData

Разберем параметры.
Name - имя виртуального драйвера. Должно совпадать с именем, определенным в DEF-файле.
MajorVer, MinorVer - младшая и старшая части версии драйвера.
CtrlProc - имя управляющей процедуры драйвера. Эта процедура принимает и обрабатывает сообщения, приходящие на драйвер. Принято формировать имя процедуры из двух частей: имя драйвера и добавка Control. Например, если имя нашего драйвера будет VXD1, то имя процедуры следует взять VXD1_Control.
DeviceID - 16-битный уникальный идентификатор виртуального драйвера. Необходимо указывать в том случае, когда виртуальный драйвер будет предоставлять свой сервис другим драйверам. Кроме того, идентификатор может понадобиться, если ваш драйвер собирается работать в реальном режиме.
InitOrder - порядок загрузки драйвера. Это всего лишь номер. Драйверы, имеющие меньший номер, загружаются в первую очередь. Имеет смысл для статических драйверов.
V86Proc, PMProc - специфицируют адреса функций, которые будет экспортировать драйвер для DOS- и обычных приложений. Если экспортирование не предполагается, параметры следует опустить.
Ref_Data - ссылка на данные, используемые супервизором ввода-вывода. Обычно опускается.

Макросы Begin_control_dispatch и End_control_dispatch используются для определения управляющей процедуры. Выглядит это следующим образом.

 Begin control_dispatch VXD1

 Control_Dispatch message, function

 End_control_dispatch VXD1

Макрос Control_Dispatch определяет, какие сообщения какими функциями будут обрабатываться. Например:

 Begin_control_dispatch VXD1

 Control_Dispatch INIT_COMPLETE, INIT

 End_control_dispatch VXD1

Итак, у нас все готово, чтобы собрать простейший драйвер, точнее его скелет, даже пока не понимая весь механизм его работы.

.386P
include vmm.inc
include vcond.inc
DECLARE_VIRTUAL_DEVICE VXD1,1,0, VXD1_Control, \
UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDER

Begin_control_dispatch VXD1
Control_Dispatch INIT_COMPLETE, INIT
End_control_dispatch VXD1

VxD_LOCKED_CODE_SEG
BeginProc INIT
EndProc INIT
VxD_LOCKED_CODE_ENDS

end
Вход на сайт
Поиск
Календарь
«  Июль 2025  »
ПнВтСрЧтПтСбВс
 123456
78910111213
14151617181920
21222324252627
28293031
Архив записей
Наш опрос
Как Вам удобнее??
Всего ответов: 341
Мини-чат
Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • Статистика

    Онлайн всего: 1
    Гостей: 1
    Пользователей: 0