Виртуальный драйвер для обслуживания аппаратных прерываний
Страница 6. Изменение программы драйвера


 

Изменение программы драйвера

Посмотрим теперь, как изменится программа драйвера. 

Программа драйвера для обслуживания аппаратных прерываний

...  
 WM_USER=SPM_UM_AlwaysSchedule+400h;Код сообщения WM_USER  
 include shell.inc     ;Дополнительный включаемый файл  
 ...  
 ;======================  
 VxD_DATA_SEG  
 Data dw 0,0       ;32-битовая ячейка с данным для передачи в приложение  
 hwnd dd 0      ;32-битовая ячейка для получения дескриптора окна  
 IRQ_Handle dd 0     ;Дескриптор виртуального прерывания  
 VMyD_Int13_Desc label dword;32-битовый адрес следующей далее структуры  
 VPICD_IRQ_Descriptor <5,,OFFSET32 VMyD_Int_13>;Структура с данными о прерывании  
 VxD_DATA_ENDS  
 ;======================  
 VxD_CODE_SEG  
 BeginProc VMyD_Control  
 ...  
 EndProc VMyD_Control  
 ;----------------------  
 BeginProc VMyD_Device_Init  
 ...  
 EndProc VMyD_Device_Init  
 ;-------------------------  
 ;API-процедура, вызываемая из приложения   
 ;При вызове: BX=C0, CX=C1, DX=C2, DI=дескриптор главного окна  
 BeginProc API_Handler  
 ;Получим параметры из приложения  
      movzx     EAX,[EBP.Client_DI]  
      mov     hwnd,EAX  
 ;Общий сброс  
 ...  
 ;Размаскируем уровень 5 в физическом контроллере прерываний  
 ...  
 ;Засылаем управляющие слова по каналам  
 ...  
 ;Засылаем константы в каналы  
 ...  
 ;Установим флаг S2 разрешения счета  
 ...  
      ret  
 EndProc     API_Handler  
 ;-------------------------  
 ;Процедура обработки аппаратного прерывания IRQ5 (вектор 13)  
 BeginProc VMyD_Int_13, High_Freq  
 ;Получим результат измерений из выходного регистра счетчика  
      ...  
      mov     Data,AX     ;Результат в младшей половине Data  
 ;Выполним завершающие действия в PIC и вызовем функцию приложения  
      mov     EAX,IRQ_Handle  
      VxDCall VPICD_Phys_EOI;EOI в физический контроллер прерываний  
      VxDCall VPICD_Physically_Mask;Маскируем наш уровень  
 ;Перейдем на синхронный уровень. Это все иначе  
      push     0     ;Таймаут  
      push     CAAFL_RING0     ;Событие кольца 0  
      push     0     ;Данные для передачи в процедуру отложенных прерываний  
      push     OFFSET32 Reflect_Int;Вызываемая процедура отложенных прерываний  
      VxDCall _SHELL_CallAtAppyTime;Вызвать во "время приложения"  
      add     ESP,4*4     ;Компенсация стека  
      clc  
      ret  
 EndProc VMyD_Int_13  
 ;-------------------------  
 ;Процедура уровня отложенных прерываний. Это тоже иначе   
 BeginProc Reflect_Int  
      push     0     ;Данные для функции обратного вызова  
      push     0     ;Адрес функции обратного вызова  
      push     0     ;lParam  
      push     Data     ;wParam  
      push     WM_USER  ;Код сообщения  
      push     hwnd     ;Окно-адресат  
      VxDCall _SHELL_PostMessage;Поставить сообщение в очередь   
      add     ESP,4*6     ;Компенсация стека  
      clc  
      ret  
 EndProc     Reflect_Int  
 VxD_CODE_ENDS  
 end VMyD_Real_Init  

В начале текста драйвера необходимо подключить еще один заголовочный файл SHELL.INC и определить значение константы WM_USER. В Windows эта константа имеет длину 16 бит и равна 400h, однако функции _SHELL_PostMessage необходимо передать 32-битовое слово, причем сам код сообщения WM_USER должен находиться в младшей половине этого слова, а в старшую половину следует поместить информацию о диспетчеризации. В нашем случае эта информация выглядит как константа: SPM_UM_AlwaysSchedule.

В сегменте данных удалены ячейки для адреса функции обратного вызова isr и селектора DS. Ячейка для результата измерений объявлена как два слова, поскольку все параметры функции Shell_PostMessage имеют размер 32 бит. Добавлена ячейка hwnd для получения в нее из приложения дескриптора главного окна. Сам дескриптор имеет размер 16 бит, однако передавать его той же функции Shell_PostMessage надо в виде длинного слова.

В начале API-процедуры из структуры клиента (конкретно - из регистра DI) извлекается дескриптор окна и после расширения до длинного слова помещается в ячейку hwnd.

Остальные изменения касаются лишь способа перехода на уровень отложенных прерываний и состава процедуры ReflectInt, работающей на этом уровне.

Для перехода на синхронный уровень в данном случае используется системный вызов _SHELL_CallAtAppyTime, осуществляющий передачу управления указанной в вызове процедуре ReflectInt во <время приложения>, то есть когда управление будет возвращено из VMM в приложение. В этой процедуре уже можно будет поставить сообщение WM_USER в очередь сообщений главного окна нашего приложения.

В процедуре уровня отложенных прерываний ReflectInt после помещения в стек необходимых параметров вызывается системная функция _Shell_PostMessage, которая и посылает в приложение сообщение WM_USER. Легко увидеть, что программист должен в этом случае полностью сформировать весь состав структуры сообщения msg - дескриптор окна-адресата, код сообщения, а также оба параметра, входящие во все сообщения Windows, - wParam и lParam. Параметром wParam мы в данном примере пользуемся для передачи в приложение результата измерения из ячейки Data. При необходимости можно было использовать и lParam.

Функция обратного вызова, адрес которой можно было указать в числе параметров, вызывается Windows после успешной постановки в очередь посылаемого сообщения. Мы эту функцию не используем.

Для задач управления аппаратурой, работающей в режиме прерываний, важной характеристикой является время отклика на прерывание, то есть временная задержка от момента поступления прерывания до выполнения первой команды обработчика. Как мы увидели, при использовании виртуального драйвера системные издержки перехода на прикладной обработчик, включенный в состав драйвера, составляют около 40 команд, на выполнение которых на машине средней производительности может понадобиться 10...15 мкс. При использовании системы MS-DOS этих издержек не было бы вовсе, так как в реальном режиме переход на обработчик прерываний процессор осуществляет практически мгновенно. Если же реализовать обработку прерываний без помощи виртуального драйвера, как это было сделано в предыдущей части статьи, то переход на прикладной обработчик прерываний потребовал бы 200...300 команд, а время задержки увеличилось бы (на таком же компьютере) до 120...180 мкс, то есть более чем на порядок.

 
« Предыдущая статья   Следующая статья »