Прерывания при стандартном режиме работы системы Windows

При написании драйвера, который будет выполняться в стандартном режиме работы системы Windows, необходимо учитывать возможность появления прерывания, когда процессор работает в реальном режиме. Даже если работают только приложения системы Windows, а не приложения системы MS-DOS, процессор часто переключается из реального в защищенный режим. Так как система Windows 3.1 не является операционной системой, а скорее представляет собой окружение пользовательского интерфейса, она возлагает выполнение определенного количества основных функций, включая функцию ввода-вывода файлов, на операционную систему (а именно MS-DOS).

Поэтому когда приложение системы Windows выполняет функцию MS-DOS ввода-вывода файла и процессор при этом работает в реальном режиме, устройство может прерывать ЦПУ. По умолчанию, если библиотека DLL обеспечила связь с прерыванием, то система Windows переключит ЦПУ в защищенный режим для обработки прерывания и, как только программа ISR завершит работу, переключит ЦПУ обратно в реальный режим для продолжения выполнения функций системы MS-DOS.

Хотя это в меньшей мере относится к ЦПУ 80386, переключение процессора из защищенного режима в реальный режим, например на процессоре 80286, создает огромные накладные расходы, требующие контролируемого сброса ЦПУ, который выполняется в течении миллисекунд. Если необходимо ускорить среднее время ответа, нужно предотвратить переключение процессора в защищенный режим, если он получает прерывание, работая в реальном режиме.

Обеспечение связи с вектором прерывания в защищенном режиме из библиотеки DLL системы Windows - тривиально, что и показано в программе SetPMVector, представленной в листинге 4 (программа bogus.c). Установление связи с вектором производится таким же способом, как и в системе MS-DOS, - с помощью функции setvector системы MS-DOS. Однако в отличие от вызова в системе MS-DOS, в системе Windows при обращении к функции передаются селектор и смещение, а не сегмент и смещение. Ядро системы Windows следит за всем. Функции следует передать нормальный селектор и смещение (натуральный указатель far для системы Windows), а не сегмент и смещение (натуральный указатель far для системы MS-DOS).

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

______________________________________________________________________

 

/*EM BOGUS.C - Драйвер фиктивного устройства библиотеки DLL

*

* SUMMARY (Резюме)

* Базовые функции LibMain, WEP

*

* COMMENTS (Комментарии)

*

* WARNINGS (Предупреждения)

*

*/

 

#include

#include "bogusa.h"

#include "pic.h"

#include "dpmi.h"

 

#define EXPORT _export _loadds

#include "bogus.h"

 

#define FAKE_PORT 0x141 /* Уровень фиктивности (bogosity) - 9.4 */

#define FAKE_IRQ 11 /* Уровень фиктивности (bogosity) - 9.8 */

 

#define FAKE_CTL_START 0x01

/* команда "начать" фиктивного порта (устанавливается в нуль) */

#define FAKE_CTL_EOI 0x02

/* EOI фиктивного порта */

#define FAKE_STAT_BUSY 0x01

/* индикация занятости фиктивного порта (zero=>busy) */

#define FAKE_STAT_IRQ 0x02

/* IRQ фиктивного порта (zero=>IRQ) */

#define FAKE_STAT_ERROR 0x04

/* ошибка ввода-вывода (zero=>error) (сбрасывается при чтении) */

 

/* Установить переменные для нашего номера прерывания */

 

#if (FAKE_IRQ<8)

#define INT_DEV (INT_MASTER_0+(FAKE_IRQ & 7))

#define PIC00 INTA00

#define PIC01 INTA01

#else

#define INT_DEV (INT_SLAVE_0+(FAKE_IRQ & 7))

#define PIC00 INTB00

#define PIC01 INTB01

#endif

#define INT_MASK (1 << (FAKE_IRQ & 7))

 

BOOL FAR PASCAL LibMain(HANDLE hInstance

/* обработчик библиотечного экземпляра*/

,WORD wDataSeg

/* сегмент данных по умолчанию */

,WORD cbHeap

/* размер динамической области по умолчанию */

,LPSTR lpszCmdLine) ;

/* командная строка */

int FAR PASCAL WEP(int fSystemExit) ;

#pragma alloc_text(INIT_TEXT,LibMain)

/* держать вместе с LIBENTRY.ASM */

#pragma alloc_text(FIXED_TEXT,WEP)

 

HANDLE hLibInstance ;

FARPROC lpfnPrevISR ; /* Сохраненная предыдущая программа ISR*/

DWORD lpfnPrevRMISR ;

/* Сохраненная предыдущая программа ISR реального режима*/

HANDLE hReflector ;

 

DWORD DPMI_AllocateRMCallback(FARPROC lpfnCallback,

_RMCS FAR *lpRMCS)

{

DWORD dwRet ;

_asm {

push ds

lds si,lpfnCallback

les di,lpRMCS

mov ax,DPMI_ALLOCRMC

int IVEC_DPMI

pop ds

jc lbl1

mov word ptr dwRet,dx ; возврат адреса обратного вызова

mov word ptr dwRet+2,cx

jmp short lbl2

lbl1:

mov word ptr dwRet,ax ; код ошибки в регистре ax

mov word ptr dwRet+2,0 ; возвратить seg=0,если произошла ошибка

lbl2:

}

 

return dwRet ;

}

 

DWORD DPMI_FreeRMCallback(FARPROC lpfnCallback)

{

DWORD wRet ;

 

_asm {

mov dx,word ptr lpfnCallback

mov cx,word ptr lpfnCallback+2

mov ax,DPMI_FREERMC

int IVEC_DPMI

jc lbl1

xor ax,ax

lbl1:

mov wRet,ax

}

return wRet ;

}

 

DWORD DPMI_GetRMVector(int iVector)

{

DWORD dwRet ;

_asm {

mov ax,DPMI_GETRMVEC

mov bl,byte ptr iVector

int 31h

mov word ptr dwRet,dx

mov word ptr dwRet+2,cx

}

return dwRet ;

}

 

void DPMI_SetRMVector(int iVector, DWORD lpfnRMISR)

{

_asm {

mov ax,DPMI_SETRMVEC

mov bl,byte ptr iVector

mov dx,word ptr lpfnRMISR

mov cx,word ptr lpfnRMISR+2

int 31h

}

}

 

FARPROC GetPMVector(int iVector)

{

FARPROC dwRet ;

_asm {

mov bl,byte ptr iVector

mov ah,35h

int 21h

mov word ptr dwRet,bx

mov word ptr dwRet+2,es ; Сохранить

}

return dwRet ;

}

 

void SetPMVector(int iVector, FARPROC lpfnISR)

{

_asm {

push ds

lds dx,lpfnISR

mov al,byte ptr iVector

mov ah,25h

int 21h ; Установить нашу программу ISR

pop ds

}

}

 

HANDLE AllocIntReflector(int iVector, FARPROC lpfnCallback)

{

DWORD dwDosMem ;

LPSTR lpLowRMISR ;

DWORD lpfnRMCallback ;

_RMCS FAR *lpSaveRegs ;

 

/* Распределить память DOS для программы обслуживания прерывания ISR,

*работающей в реальном режиме */

 

dwDosMem = GlobalDosAlloc(16 + sizeof (int) + sizeof (_RMCS) ;

 

if (dwDosMem == 0)

return 0;

lpLowRMISR = (LPSTR) MAKELONG(0,LOWORD(dwDosMem)) ;

lpSaveRegs = (_RMCS FAR *) (&lpLowRMISR[16]) ;

 

/* Распределить обратный вызов (callback), работающий в реальном

* режиме */

 

lpfnRMCallback =

DPMI_AllocateRMCallback((FARPROC)lpfnCallback,

lpSaveRegs)

;

if (HIWORD((DWORD)lpfnRMCallback == 0)

{

GlobalDosFree(LOWORD(dwDosMem)) ;

return 0;

}

/* Сгенерировать код в нижних адресах памяти (только 6 байтов)*/

lpLowRMISR[0] = 0x9A ; /* Вызов указателя на FAR */

*((DWORD FAR *)&(lpLowRMISR[1])) = lpfnRMCallback ;

lpLowRMISR[5] = 0xCF ; /*IRET */

*((int FAR *)&(lpLowRMISR[6])) = iVector ;

 

/* Установить связь с вектором прерываний реального режима */

DPMI_SetRMVector(iVector,MAKELONG(0,HIWORD(dwDosMem))) ;

 

return (HANDLE) LOWORD(dwDosMem) ;

/* возврат обработчика-отражателя */

}

 

void FreeIntReflector(HANDLE hReflector)

{

LPSTR lpLowRMISR ;

DWORD lpfnRMCallback ;

 

/* Получить адрес нижнего ISR в защищенном режиме */

lpLowRMISR = (LPSTR)MAKELONG(0,(WORD)hReflector) ;

 

/* Следует убедиться, что это отражатель */

if ((lpLowRMISR[0] != 0x9A) || (lpLowRMISR[5] != 0xCF))

return ; /* выход, если не отражатель */

 

/* Выбрать адрес обратного вызова и освободить обратный вызов */

lpfnRMCallback = *((DWORD FAR *)&((lpLowRMISR[1])) ;

DPMI_FreeRMCallback(lpfnRMCallback) ;

 

/* Освободить программу обслуживания прерываний реального режима*/

 

GlobalDosFree((WORD)hReflector) ;

}

 

/*XP< LibMain - основная библиотечная точка входа */

*

* ENTRY (вход)

*

* EXIT (выход)

*

* RETURNS (возврат)

* Если инициализация завершается успешно принимает значение, равное

* TRUE, в противном случае - FALSE

*

* WARNINGS (предупреждения)

*

* CALLS (вызовы)

*

* NOTES (примечание)

* Настоящая библиотечная точка входа находится в ассемблерном модуле

* LIBENTRY.ASM, а в данную точку просто передается управление

*

*/

BOOL FAR PASCAL LibMain(HANDLE hInstance

/* обработчик библиотечного экземпляра*/

,WORD wDataSeg

/* сегмент данных по умолчанию */

,WORD cbHeap

/* размер динамической области по умолчанию */

,LPSTR lpszCmdLine) ;

/* командная строка */

/*>*/

{

lpszCmdLine = lpszCmdLine ;

/* Избегать предупреждения -W4 */

wDataSeg = wDataSeg ;

cbHeap = cbHeap ;

hInstance = hInstance ;

/* Это может понадобиться позже для доступа к ресурсам из нашего

*исполнительного модуля */

 

return TRUE ;

}

 

/*XP< WEP - процедура выхода в системе Windows */

*

* ENTRY (вход)

* fSystemExit указывает на завершение сессии в системе Windows. В

* противном случае происходит только разгрузка данной библиотеки DLL.

* RETURNS (возврат)

* Всегда возвращается значение 1

*

* WARNINGS (предупреждения)

* Из-за ошибок в системе Windows 3.0 и более ранних версиях (а

* возможно и в более поздних версиях) данная функция должна быть

*помещена в фиксированный сегмент. Эти же ошибки приводят к тому, что

* значение DS сомнительно, а поэтому нельзя его использовать (также

* как и любые статические данные).

*

* В любом случае, несомненно не надо ничего делать в этой точке.

*

* CALLS (вызовы)

* Нет

* NOTES (примечания)

* Это стандартная процедура выхода DLL.

*

*/

int FAR PASCAL WEP(int fSystemExit)

/*>*/

{

fSystemExit = fSystemExit

/* Избегать предупреждения -W4 */

return 1 ; /* всегда указывает на успешное завершение */

}

 

int EXPORT FAR PASCAL BogusCheck(void)

{

BYTE bPortVal ;

 

_asm {

mov dx,FAKE_PORT

in al,dx ; Присутсвует фиктивное устройство ?

mov bPortVal,al

}

 

return ((bPortVal & 0x80) == 0) ;

/* Возвращает значение TRUE, если устройство присутствует */

 

}

 

void EXPORT FAR PASCAL BogusStart(HWND hWnd, WPARAM wParam)

{

wParamEvent = wParam ;

hWndEvent = hWnd ;

 

if (!lpfnPrevISR)

{

/* Сохранить предыдущую программу ISR и загрузить новую */

_asm cli

lpfnPrevISR = GetPMVector(INT_DEV) ;

SetPMVector(INT_DEV,(FARPROC)IntSvcRtn) ;

_asm sti

 

/* Сохранить предыдущую программу ISR реального режима и

*отразить на новую */

 

lpfnPrevRMISR = DPMI_GetRMVector(INT_DEV) ;

hReflector = AllocIntReflector(INT_DEV,(FARPROC)BogusCallback) ;

 

/* Разрешить прерывание и начать операцию ввода-вывода на

*устройстве */

_asm {

cli

in al,PIC01 ; разрешить прерывание

and al,NOT INT_MASK

out PIC01,al

sti

mov al,NOT FAKE_CTL_START

mov dx,FAKE_PORT

out dx,al ;начать операцию ввода-вывода на устройстве

}

}

}

 

int EXPORT FAR PASCAL BogusGetEvent(void)

{

WORD wCountRet ;

 

_asm {

mov ax,SEG wCount

mov es,ax

xor ax,ax

xchg ax,es:wCount ;получить счетчик, установить в нуль

mov wCountRet,ax

}

 

return wCountRet ;

}

 

void EXPORT FAR PASCAL BogusStop(void)

{

hWndEvent - 0x0000 ; /*команда для ISR "завершить работу"*/

if (!lpfnPrevISR)

return ; /* возвратиться, если программа не стартовала */

 

_asm {

mov dx,FAKE_PORT

l1:

in al,dx

rcr al,1

jnc l1 ; цикл, если занято

 

cli

in al,PIC01

or al,INT_MASK

out PIC01,al ; маскировать уровень прерывания

sti

}

 

DPMI_SetRMVector(INT_DEV, lpfnPrevRMISR) ;

/* Восстановить вектор реального режима */

FreeIntReflector(hReflector) ;

/* Освободить отражатель */

SetPMVector(INT_DEV, lpfnPrevISR) ;

/* Восстановить вектор защищенного режима */

 

lpfnPrevISR = NULL ;

}

/* конец файла*/

_____________________________________________________________________

 

Листинг 4. Программа bogus.c








Дата добавления: 2016-04-06; просмотров: 944;


Поиск по сайту:

При помощи поиска вы сможете найти нужную вам информацию.

Поделитесь с друзьями:

Если вам перенёс пользу информационный материал, или помог в учебе – поделитесь этим сайтом с друзьями и знакомыми.
helpiks.org - Хелпикс.Орг - 2014-2024 год. Материал сайта представляется для ознакомительного и учебного использования. | Поддержка
Генерация страницы за: 0.086 сек.