Не работает ввод с клавиатуры, после вызова резидентной программы, перехватывающий ввод с клавиатуры(assembler,dos)
.model tiny
.CODE
org 100h
.386
start:
jmp install_handler
str db "hello world",0dh,0ah,'$'
db 0eah
old_int dd ?
int_handler proc far
pushf
call old_int
pusha
push es
push ds
push cs
pop ds
push 0B800h
pop es
mov si,19h
mov bx,0
str_search:
mov cx,50h
mov di,0
search_scobok:
mov al,07h
mov es:[bx+1],al
mov al,28h
cmp es:[bx],al
jne not_28h
push bx
inc di
not_28h:
mov al,29h
cmp es:[bx],al
jne not_29h
cmp di,0
je wrong_29h
pop ax
dec di
jmp not_29h
wrong_29h:
mov al,1Dh
mov es:[bx+1],al
not_29h:
add bx,2
loop search_scobok
mov cx,di
cmp di,0
je no_wrong_28h
mov dx,bx
paint_28h:
pop bx
mov al,1Dh
mov es:[bx+1],al
loop paint_28h
mov bx,dx
no_wrong_28h:
sub si,1
cmp si,0
jne str_search
pop ds
pop es
popa
IRET
int_handler endp
install_handler:
mov ax,3509h
int 21h ;get vect
mov word ptr old_int,bx
mov word ptr old_int + 2,es
mov dx,offset int_handler
mov ax,2509h
int 21h ;set vect
;mov ax,3100h
;mov dx,(install_handler - start + 10Fh)/16
;mov dx,0FFFFh/16
;int 21h ;stay resident
mov ah,49h
mov es,ds:[2Ch]
int 21h
lea dx,install_handler
int 27h
end start
После запуска программы, ввод просто не работает. Не могу понять что я делаю не так. Программа проверяет правильность растановки скобок ( )
Ответы (1 шт):
При нажатии клавиши, клавиатура генерит аппаратное прерывание
IRQ-1, которое поступает в контролёр APIC. Теперь, посредством сигналаINTR(Request) APIC доставляет IRQ и связанный с ним вектор(9) - в процессор, на что CPU отвечает контролёру сигналом подтвержденияINTA(Acknowledgment). Далее, CPU передаёт управление по векторуint-9h, обработчик которого просто считывает с порта(60h) клавиатуры скан-код нажатой клавиши, и записывает его в память кольцевой очереди клавиатуры. Теперь прерываниеint-16hизвлекает клавишу из очереди, и добавив к скан-коду ascii - вручает его пользовательскому запросу. Таким образом получаем выстроенную по приоритету цепочку:IRQ-1 --> int-9h --> int-16h.Фишка в том, что на машинах АТ,
int-9hпередаёт управление вint-15h(расширенный сервис), который и помещает скан-код в клавиатурную очередь. Этот сервис имеет довольно внушительный список функций, и только егоAH=4Fhотвечает за клавиатуру. По сути, функция была введена специально для того, чтобы пользователь не перехватывал аппаратныйint-9h, а воспользовались услугами более безобидного программногоint-15h. Основное требование - если обработчик что-нибудь меняет, то на выходе должен сбросить флаг(CF) в нуль. Вот пример резидента, который парсит клавиатурный ввод:
;// FASM-code
;//------------
org 100h
jmp @setup ;// уходим на перехват..
old15h: dw 0,0 ;// место под оригинальный вектор
;// Новый обработчик прерывания INT-15h
;//-------------------------------------
new15h: pushf ;// флаги в стек
cmp ah,4Fh ;// это сервис клавиатуры?
jе @keyb ;// если да
call far [cs:old15h] ;// иначе: зовём оригинальный обработчик,
iret ;// ..и возврат управления системе.
@keyb: ;//<----- значит была нажата клавиша!
;//<----- её скан-код лежит в регистре AL
;//***************************************
;//***** ЗДЕСЬ ОБРАБАТЫВАЕМ ВВОД *********
;//******* НА СВОЁ УСМОТРЕНИЕ ************
;//***************************************
popf ;// восстановить флаги,
clc ;// ..и среди них сбросить CF=0.
retf 2 ;// выйти из обработчика
;// Инициализация резидента TSR
;//-------------------------------------
@setup: push es ;// (+) AH=35h портит регистр ES
mov ax,3515h ;// читаем вектор(15) из таблицы IVT
int 21h ;// ES:BX = результат
mov [old15h],bx ;// запомним его смещение,
mov [old15h+2],es ;// ..и сегмент.
pop es ;// (-)
mov ax,2515h ;// перехват прерывания(15)
mov dx,new15h ;// CS:DX = адрес нового обработчика
int 21h ;//
mov dx,@setup ;// всё-что выше метки "@setup",
int 27h ;// ..останется в памяти как резидент.