Страница 4 из 6 Подготовка вызова требуемой функции приложения
Следующая операция - подготовка вызова требуемой функции приложения. Эта операция осуществляется с помощью функции VMM Simulate_Far_Call, которая помещает передаваемые ей в качестве параметров селектор и смещение требуемой функции приложения в поля структуры клиента Client_CS и Client_IP. В результате, когда VMM, передавая управление приложению, снимет со стека структуру клиента и выполнит переход по оставшимся в стеке значениям Client_CS и Client_IP, то в регистрах CS:IP окажется адрес интересующей нас функции, которая и начнет немедленно выполняться. Для того чтобы не потерять то место в приложении, на котором произошла его приостановка из-за прихода прерывания, текущее содержимое полей Client_CS и Client_IP сохраняется в созданной перед этим копии структуры клиента. Наконец, вызовом Resume_Exec управление передается в приложение. Еще раз подчеркнем, что этот вызов функции приложения является вложенным в VMM и что возможности вызываемой функции весьма ограниченны. Фактически она работает в чуждой для приложения операционной среде. В частности, как уже отмечалось, содержимое сегментных регистров (кроме CS) не соответствует сегментам приложения. Для того чтобы функция isr() могла обратиться к глобальным переменным приложения (адресуемым через регистр DS), мы передаем ей селектор сегмента данных приложения. Вернемся ненадолго к тексту приложения. Функция isr(), которую мы вызываем из драйвера, имеет следующий вид: void isr(int segment,int dt){ ... } Поскольку мы в драйвере протолкнули в стек сначала данные Data, а затем селектор DSseg, они расположились в стеке приложения в правильном с точки зрения этой функции порядке, поэтому она может обращаться к своим локальным переменным segment и dt, как если бы была вызвана обычным образом оператором: isr(DSseg,Data); После завершения функции isr() управление возвращается в VMM, а из него в драйвер на команду, следующую за вызовом Resume_Exec. Этот переход может потребовать пары сотен команд и нескольких десятков микросекунд. Отложенная процедура драйвера завершается очевидными вызовами End_Nest_Exec - окончания вложенного блока выполнения и Pop_Client_State - восстановления структуры клиента. Описанная методика организации взаимодействия обработчика аппаратных прерываний, включенного в состав драйвера, и самого приложения относительно сложна и тем не менее не обеспечивает необходимые функциональные возможности обработчику прерываний приложения, в котором запрещается вызов функций Windows. Для того чтобы по сигналу прерывания вывести на экран результаты измерений, нам пришлось создавать специальный цикл обработки сообщений с постоянным опросом флага request. Установка флага обработчиком прерываний приложения приводила к выполнению функции PostMessage() и посылке в приложение сообщения WM_USER, в ответ на которое мы уже могли выполнять любые программные действия безо всяких ограничений. |