Системное программное обеспечение персональных ЭВМ


Пример 1



Пример 1

/*== ПРИМЕР 15.1 ==*/ /*============== Резидентная программа ===================*/ /* Модель памяти - small. /* При компиляции установить: Options -> Compiler -> Code generation -> Test stack overflow -> Off !!! */ #include <dos.h> #include <stdio.h> #include <string.h> #define byte unsigned char #define word unsigned int /* адрес в виде - сегмент:смещение */ typedef struct { word segm,offs; } addr; /* Описания функций */ byte check_tsr(void); /* проверка наличия TSR-программы в памяти */ void get_context(void); /* запоминание своего контекста */ void set_vectors(void); /* установка своих векторов */ void restore_vectors(void); /* восстановление векторов */ void far *get_vector(int n); /* чтение вектора */ void set_vector(int n, void far *v); /* установка вект. */ void act_tsr(void); /* активизация TSR-программы */ void self_kill(void); /* самовыгрузка TSR-программы */ void tsr_exec(void); /* прикладная часть TSR-программы */ /* описания новых обработчиков прерываний */ void interrupt new_8(); void interrupt new_9(); void interrupt new_13(); void interrupt new_28(); void interrupt new_2F(); void interrupt new_24(); /* номера обрабатываемых прерываний */ int int_nums[] = { 8, 9, 0x13, 0x28, 0x2f }; void interrupt (* new_v[])() = { /* адреса новых обработчиков */ new_8, new_9, new_13, new_28, new_2F }; /* области сохранения старых векторов */ void interrupt (* old_v[5])(); addr a_2F; /* адрес старого обработчика INT 2F */ /* Флаги */ byte far *dos_flag; /* адрес флажка занятости DOS */ byte tsr_run = 0; /* "TSR выполняется" (1) */ byte hot_key = 0; /* "горячая клавиша нажата"(1) */ byte disk_op = 0; /* "дисковая операция" (1) */ byte key_byte; /* байт символа/состояния клавиатуры */ word cflag; /* регистр флагов процессора */ /* набор команд перехода на обработчики прерываний */ struct far_jmp { byte jmp; /* код команды */ void interrupt (* int_h)(); /* адрес */ } far *jmpar; word jmp_segm; /* сегм.адрес блока команд перехода */ /* переменные контекста */ byte old_ctrl_break; /* состояние обработки Ctrl-Break прерванной программы */ addr old_stack; /* сегмент и указатель стека прерванной программы */ addr tsr_stack; /* то же - TSR-программы */ word old_pid; /* PID прерванной программы */ word tsr_pid; /* то же - TSR-программы */ addr old_dta; /* адрес DTA прерванной программы */ addr tsr_dta; /* то же - TSR-программы */ void interrupt (* old_24)(); /* адрес обработчика критической ошибки прерванной программы */ /* общие переменные */ word sizeprogram = 17000/16; /* размер программы, определенный опытным путем */ word hot_scan = 2; /* scan-код горячей клавиши - "1" */ word hot_status =8; /* маска спец.клавиши - Alt */ char tsr_mark[] = "TSR-программа 15_1 загружена"; /* опознавательная строка символов */ char far *mark; byte com_func; /* номер коммуникационной функции прерывания 2F */ word far *ast; /* адрес в стеке */ word mcb_seg; /* адрес блока MCB */ byte screen[160]; /* для сохранения части экрана */ union REGS rr; struct SREGS sr; int i, n; /*-------------------------------------------------------*/ /* ==== Пусковая программа ====*/ main(int argn, char *argc[]) { /* проверка - не является ли программа уже резидентной */ /* check_tsr возвращает 0, если уже резидентна */ /* check_tsr присваивает значение переменной com_func */ mark=(char far *)tsr_mark; if (!check_tsr()) { /*--- программа уже резидентна --*/ /* с каким параметром вызвана программа ? */ if (argn>1) { if (!strcmp(argc[1],"/Q")) { /* /Q - обращение к коммуникации для выгрузки */ rr.h.ah=com_func; rr.h.al=0x30; /* коммуникационное прерывание */ int86x(0x2f,&rr,&rr,&sr); printf("TSR-программа 15_1 выгружена\n"); } else /* неправильный вызов */ printf("15_1 - инсталляция\n15_1 /Q - выгрузка\n"); } else { /* параметров нет - попытка повторной инсталляции */ printf("!!! УЖЕ- %s -УЖЕ !!!\n",tsr_mark); printf("Функция прерывания 2Fh - %02Xh\n",com_func); } } else { /*--- программа не резидентна --*/ get_context(); /* запоминание своего контекста */ /* освобождение своего блока окружения */ sr.es=peek(tsr_pid,0x2c); rr.h.ah=0x49; intdosx(&rr,&rr,&sr); set_vectors(); /* установка своих векторов */ /* получение адреса флажка занятости DOS */ rr.h.ah=0x34; intdosx(&rr,&rr,&sr); dos_flag=(byte far *)MK_FP(sr.es,rr.x.bx); /* завершение программы с оставлением ее резидентной */ printf("%s\n",tsr_mark); rr.h.ah=0x31; rr.h.al=0; rr.x.dx=sizeprogram; intdos(&rr,&rr); } } /*---------------------------------------------*/ /*==== Обработчик прерывания от клавиатуры ====*/ void interrupt new_9() { /* чтение scan-кода и проверка его на совпадение с кодом горячей клавиши; проверка состояния переключателей */ if (inportb(0x60)==hot_scan) { key_byte=peekb(0x40,0x17); if ((key_byte&hot_status) == hot_status) { /* посылка подтверждения в клавиатуру */ key_byte=inportb(0x61); outportb(0x61,key_byte|0x80); outportb(0x61,key_byte); /* сброс контроллера прерываний */ outportb(0x20,0x20); if (!tsr_run) /* блок.реентерабельного вызова */ hot_key=1; /* установка флага горячей клавиши */ } else (*old_v[1])(); /* системный обработчик */ } else (*old_v[1])(); /* системный обработчик */ } /*------------------------------------------*/ /*==== Обработчик прерывания от таймера ====*/ void interrupt new_8() { (*old_v[0])(); /* cистемный обработчик */ if (hot_key && !(*dos_flag)) /* если нажата горячая клавиша и не установлен флажок занятости DOS... */ if (!disk_op) { /* ...и не выплоняется дисковая операция */ hot_key=0; /* сброс флага горячей клавиши */ act_tsr(); /* активизация */ } } /*--------------------------------------------------*/ /*==== Обработчик прерывания обращения к дискам ====*/ void interrupt new_13(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,fl) word bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,fl; { disk_op++; /* флаг дисковой операции */ (*old_v[2])(); /* системный обработчик int 13 */ /* возврат регистров, установленных сист.обработчиком */ ax=_AX; cx=_CX; dx=_DX; /* обращение к int 2F, которая записывает регистр флагов в static-переменную cflags */ _AX=0x10; new_2F(); fl=cflag; --disk_op; /* сброс флага дисковых операций */ } /*-------------------------------------*/ /*==== Обработчик прерывания DOSOK ====*/ void interrupt new_28() { (*old_v[3])(); /* Системный обработчик */ if (hot_key && *dos_flag) { /* если нажата горячая клавиша и установлен флажок занятости */ hot_key=0; /* сброс флага горячей клавиши */ act_tsr(); /* активизация */ } } /*-------------------------------------------------------*/ /*==== Обработчик прерывания 24 - критические ошибки ====*/ void interrupt new_24 (bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,fl) word bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,fl; { ax=0; } /*------------------------------------------------*/ /*==== Чтение вектора ====*/ void far *get_vector(int in) { rr.h.ah=0x35; rr.h.al=in; intdosx(&rr,&rr,&sr); return(MK_FP(sr.es,rr.x.bx)); } /*------------------------------------------------*/ /*==== Запись вектора ====*/ void set_vector(int in, void far *v) { rr.h.ah=0x25; rr.h.al=in; sr.ds=FP_SEG(v); rr.x.dx=FP_OFF(v); intdosx(&rr,&rr,&sr); } /*------------------------------------------------*/ /*==== Перехват векторов прерываний ====*/ void set_vectors(void) { /* выделение памяти для команд перехода */ rr.h.ah=0x48; rr.x.bx=2; intdos(&rr,&rr); jmp_segm=rr.x.ax; jmpar=(struct far_jmp far *)MK_FP(jmp_segm,0); for (i=0;i<5;i++) { /* получение старых векторов */ old_v[i]=get_vector(int_nums[i]); /* запись кодов команд FAR JMP */ jmpar[i].jmp=0xea; /* запись адресов наших обработчиков */ jmpar[i].int_h=new_v[i]; /* установка вектора на соответствующий jmp */ set_vector(int_nums[i],(void far *)(jmpar+i)); } /* адрес мультиплексного прерывания запоминается */ a_2F.segm=FP_SEG(old_v[4]); a_2F.offs=FP_OFF(old_v[4]); } /*-----------------------------------------------*/ /*==== Восстановление векторов прерываний ====*/ void restore_vectors(void) { for (i=n=0;i<5;i++) { /* если вектор наш - восстановить его */ if ( get_vector(int_nums[i])== (void far *)(jmpar+i)) set_vector(int_nums[i],old_v[i]); else { /* если нет - запись адреса старого обработчика в команду перехода */ jmpar[i].int_h=old_v[i]; n++; } } /* если не все векторы восстановлены - блок команд перехода помечается принадлежащим DOS */ if (n) poke(jmp_segm-1,1,8); } /*-------------------------------------------------------*/ /*==== Запоминание своего контекста ====*/ void get_context(void) { /* сохранение своего сегмента стека */ tsr_stack.segm=_SS; tsr_stack.offs=_SP-100; /* сохранение адреса своей DTA */ rr.h.ah=0x2f; intdosx(&rr,&rr,&sr); tsr_dta.segm=sr.es; tsr_dta.offs=rr.x.bx; /* сохранение своего PID */ rr.h.ah=0x62; intdos(&rr,&rr); tsr_pid=rr.x.bx; } /*-------------------------------------------------------*/ /*==== Переключение контекстов и активизация TSR-программы ====*/ void act_tsr(void) { tsr_run=1; /* установка флага "TSR работает" */ /*= изменение контекста при активизации TSR-программы =*/ /* переключение на стек TSR-программы */ disable(); old_stack.offs=_SP; old_stack.segm=_SS; _SP=tsr_stack.offs; _SS=tsr_stack.segm; enable(); /* подключение к вектору критических ситуаций */ old_24=get_vector(0x24); set_vector(0x24,new_24); /* переключение статуса обработки Ctrl-Break */ rr.h.ah=0x33; rr.h.al=0; intdos(&rr,&rr); old_ctrl_break=rr.h.dl; rr.h.ah=0x33; rr.h.al=1; rr.h.dl=0; intdos(&rr,&rr); /* переключение на DTA TSR-программы */ rr.h.ah=0x2f; intdosx(&rr,&rr,&sr); old_dta.segm=sr.es; old_dta.offs=rr.x.bx; rr.h.ah=0x1e; sr.ds=tsr_dta.segm; rr.x.dx=tsr_dta.offs; intdosx(&rr,&rr,&sr); /* переключение на PID TSR-программы */ rr.h.ah=0x62; intdos(&rr,&rr); old_pid=rr.x.bx; rr.h.ah=0x50; rr.x.bx=tsr_pid; intdos(&rr,&rr); /*= выполнение "прикладной части" =*/ tsr_exec(); /*= восстановление контекста прерванной программы =*/ /* восстановление PID */ rr.h.ah=0x50; rr.x.bx=old_pid; intdos(&rr,&rr); /* восстановление DTA */ rr.h.ah=0x1e; sr.ds=old_dta.segm; rr.x.dx=old_dta.offs; intdosx(&rr,&rr,&sr); /* восстановление Ctrl-Break */ rr.h.ah=0x33; rr.h.al=1; rr.h.dl=old_ctrl_break; intdos(&rr,&rr); /* восстановление обработчика критических ситуаций */ set_vector(0x24,old_24); /* восстановление стека */ disable(); _SP=old_stack.offs; _SS=old_stack.segm; enable(); tsr_run=0; } /*------------------------------------------*/ /*==== "Прикладная" часть TSR-программы ====*/ void tsr_exec(void) { char *s; int i; /* сохранение экрана и вывод сообщения */ for (i=0, s=tsr_mark; *s; ) { screen[i]=peekb(0xb800,i); pokeb(0xb800,i++,*s++); screen[i]=peekb(0xb800,i); pokeb(0xb800,i++,0x40); } screen[i]=0; /* ожидание нажатия клавиши */ do { rr.h.ah=1; int86(0x16,&rr,&rr); } while (rr.x.flags&0x0040); rr.h.ah=0; int86(0x16,&rr,&rr); /* восстановление экрана */ for(i=0;screen[i];i++) pokeb(0xb800,i,screen[i]); } /*---------------------------------------------------*/ /*==== Обработчик прерывания 0x2F (коммуникации) ====*/ void interrupt new_2F(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,fl) word bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,fl; { if ((ax>>8)==com_func) { /* подфункции */ switch (ax&0xff) { case 0: /* проверка возможности установки */ ax|=0xff; /* запрет установки */ es=FP_SEG(mark); bx=FP_OFF(mark); break; case 0x10: /* программный вызов TSR */ act_tsr(); ax=0; break; case 0x20: /* получение регистра флагов */ cflag=fl; break; case 0x30: /* выгрузка */ self_kill(); ax=0; break; default: ax=0xffff; } } else { /* возврат из нашего обработчика в старый обработчик */ for (ast=(word far *)&bp; ast<=(word far *)&flags; ast++) *(ast-3)=*ast; cx=a_2F.offs; bx=a_2F.segm; _SP-=6; } } /*-------------------------------------------------------*/ /*==== Поиск свободных функций 2F или функции, занятой 15_1 ===*/ byte check_tsr(void) { byte a, b; char far *s1; char *s2; com_func=0; for (a=0xff; a>=0xc0; a--) { rr.h.ah=a; rr.h.al=0; int86x(0x2f,&rr,&rr,&sr); b=rr.h.al; /* запоминание первого свободного номера функции */ if (!(b+com_func)) com_func=a; if (b==0xff) /* функция занята */ { s1=(MK_FP(sr.es,rr.x.bx)); for (s2=tsr_mark; *s2; s1++,s2++) if (*s1!=*s2) break; if (*s2) continue; /* занята нами */ com_func=a; return (0); } } return (1); } /*-----------------------------------------------*/ /*==== Операции по уничтожению TSR-программы ====*/ void self_kill(void) { /* восстановление системных векторов прерываний */ restore_vectors(); /* определение начала цепочки MCB */ rr.h.ah=0x52; intdosx(&rr,&rr,&sr); mcb_seg=peek(sr.es,rr.x.bx-2); while (peekb(mcb_seg,0)==0x4d) { /* выборка из MCB признака последний/нет */ if (peek(mcb_seg,1)==tsr_pid) { /* выборка из MCB PID программы-хозяина, если он совпадает с нашим, блок памяти освобождается rr.h.ah=0x49; sr.es=mcb_seg+1; intdosx(&rr,&rr,&sr);*/ poke(mcb_seg,1,0); } /* переход к следующему MCB в цепочке */ mcb_seg+=peek(mcb_seg,3)+1; } }




- Начало -  - Назад -  - Вперед -