Прерывания при стандартном режиме работы системы 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; просмотров: 980;