tsr, обработчик прерывания
Взгляните пожалуйста:
text segment 'code'
assume cs:text,ds:text
org 256
main proc
jmp init
old_handler dd 0
new_h proc;
push ax
push bx
push cx
push dx
push ds
catch:
in al,60h
mov bl,al
push ax
in al,61h
or al,80h
out 61h,al
pop ax
cmp bl, 10h
ja not_our_key
je key_pressed
key_pressed:
mov cx, 5
mov al, 41h
mov ah, 0ah
int 10h
mov al,20H
out 20H,al
out 0a0h, al
xor al, al
;mov dl, 01h - стоит мне раскоментировать, как программа выдает ошибку
;mov ah, 06h
;int 21h
jmp exit
not_our_key:
pop ds
pop dx
pop cx
pop bx
pop ax
mov al, 20h
out 20h, al
out 0a0h, al
jmp cs:old_handler
;jmp exit
exit:
pop ds
pop dx
pop cx
pop bx
pop ax
mov al, 20h
out 20h, al
out 0a0h, al
iret
init proc;
mov ax, 3509h
int 21h
mov word ptr old_handler, bx
mov word ptr old_handler+2, es
mov ax, 2509h
mov dx, offset new_h
int 21h
mov dx,offset init
int 27h
init endp
text ends
end main
И объясните пожалуйста для чего нужны эти строчки:
push ax
in al,61h
or al,80h
out 61h,al
pop ax
и зачем нужно завершать обработчик таким образом:
mov al, 20h
out 20h, al
out 0a0h, al
поскольку программирую я недавно, и это черновой вариант программы прошу ни судить строга))
только по-моему нужно еще сбросить этот бит и снова послать
mov al, 20h/out 20h, al -- сигнал об окончании обработки прерывания (специфика контроллера клавиатуры, др. прерывания завершаются просто по iret)
а вот out 0a0h, al по-моему к клавиатуре не относится
насчёт того почему прога виснет пока ничего не скажу, может быть попозже (поразбираться надо)
некоторые функции доса нельзя использовать в обработчиках прерываний .
некоторые функции доса нельзя использовать в обработчиках прерываний
своими глазами видел похожую программу, перехват нажатий клавиш и вывод их скан кодов, но она была не резидентная. и использовался там int 21h. к тому же я вроде добавил команды:
mov al,20H
out 20H,al
как я понял они разрешают прерывания.
When your program gets control via a timer interrupt INT 08H or INT 1cH or the keyboard interrupt INT 09H or any asynchronously-generated event, you must be very careful about using DOS functions.
The reason is that DOS is not reentrant. DOS might be processing a service call at the time of the interrupt. If you then issue another INT 21H, you risk disaster.
In general, when InDOS is set, you may use only DOS fns 01H-0cH (low-level character I/O). When it is clear, you can use all DOS fns...
- так я как раз использую низкоуровненвый вывод. Вот я приведу пример программы, которую я нашел на этом форуме, ее написал некто Vov4ik. Она перехватывает прерывания и выводит их через int 21h, но она не резидентная:
model tiny
codeseg
org 100h
start:
mov ax,3509h
int 21h ; AL=vector to get ES:BX=return vector
mov [oldofs],bx
mov ax,es
mov [oldseg],ax
;-------------------------------------
mov ah,9
mov dx,offset mess
int 21h
;-------------------------------------
mov ax,2509h
mov dx,offset int9
int 21h ; AL=int num to set DS:DX=new handler
;---------- Настройка клавиатуры ---------------------------
mov al,0f3h
out 60h,al
call wait_kbd
mov al,01111111B ; Slower keyboard
out 60h,al
;-------------------------------------
jmp $ ; Main program ;-)
;--------------- Выход из программы ----------------------
exit:
; add sp,6
mov sp,0fffeh
mov dx,[oldofs] ;
mov ax,[oldseg] ;
mov ds,ax ;
mov ax,2509h ;
int 21h ; AL=int num to set DS:DX=new handler
mov al,20h
out 20h,al ; EOI
out 0a0h,al ; secondary
;-------------------------------------
mov al,0f3h
out 60h,al
call wait_kbd
mov al,0
out 60h,al ; Faster keyboard
ret
;-------------------------------------
int9:
in al,60h
mov bl,al
in al,61h
mov ah,al
or al,80h
out 61h,al
xchg ah,al
out 61h,al
mov al,bl
;-------------------------------------
cmp bl,0fah
je send_eoi ; ACK
test bl,80h ; something pressed
jz obrab
cmp bl,81h ; escape depressed
jne zero_cl
inc cl
cmp cl,3 ; Depressed
je exit
jmp obrab
zero_cl:
mov cl,0
obrab:
;-------------------------------------
push ax
shr al,4
call hex
pop ax
and al,0fh
call hex
mov dl,' '
call print
send_eoi:
mov al,20h
out 20h,al ; EOI signal
out 0a0h,al ; secondary
iret
;--------------- Вывод байта на экран ---------------------------------------
hex:
add al,'0'
cmp al,'9'
jbe nol
add al,'A'-'9'-1
nol:
mov dl,al
print:
mov ah,6
int 21h
ret
;------------------- Ожидание готовности клавиатуры ------------------
wait_kbd:
push cx
xor cx,cx
wk:
in al,64h
test al,10b
loopnz wk
pop cx
ret
;-------------------------------------
mess db 13,10,'Keyboard scancode viewer version 1.',13,10
db 'Copyright (c) 2006, ExTRA Laboratories [Vov4ik].',13,10
db 'Press ESCAPE three times to exit.',13,10,'$'
oldseg dw ?
oldofs dw ?
end start
я это к тому написал что проблема не в вызове дос а вашем обработчике -- ищите зло в нём. Вы гоняли свою программу в отладчике? Смотрели что происходит при вызове ДОС и тд?
А по поводу примера -- если прога не резидентная то мы можем монопольно использовать в обработчике ф-ции ДОС -- так что никаких ограничений тут нет.
Видите ли, я изучаю ассемблер менее семестра, и пользоваться дебаггером еще не научился. А по поводу обработчика - на что мне обратить внимание?
И кстати досовские программы каким дебаггером обрабатывать лучше?
в обработчике посмотрите вот что: он валится на вызове дос-функции или после; ещё попробуйте сделать не-резидентную версию и посмотрите будет ли она так же падать. ещё у вас там кажется идёт вызов старого обработчика, помотрите всё ли нормально с этим вызовом
ещё в вашем коде я не увидел инструкций запрета/разрешения прерываний (cli/sti) обычно их вставляют в обработчики прерываний
можете ещё если хотите выслать исполняемый файл (мне самому ассемблировать невозможно, нет тасма), может немного покопаюсь в нём
.186
.code
org 100h
start:
jmp init
new_timer proc
pusha
pushf
push es
push ds
mov al, active_task
cmp al, 0ffh
jnz end3
les bx, InDOSFlag
mov al, es:[bx]
test al, es:[bx-1]
jz end3
execute:
mov dl, 23h
mov ah, 06h
int 21h
;mov ah, 0eh
;mov bh, 0ah
;mov al, 41h
;int 10h
;mov al, 0
mov active_task, al
end3:
pop ds
pop es
popf
popa
jmp cs:old_timer
new_timer endp
new_h proc
cli
pusha
pushf
push es
push ds
in al,60h
mov bl,al
push ax
in al,61h
or al,80h
out 61h,al
pop ax
cmp bl, 10h
jnz not_our_key
jne key_pressed
key_pressed:
mov active_task, 0ffh
jmp end1
not_our_key:
pop ds
pop es
popf
popa
jmp cs:old_handler
end1:
sti
mov al, 20h
out 20h, al
popf
popa
ret
new_h endp
init proc;
mov ax, 3509h
int 21h
mov word ptr old_handler, bx
mov word ptr old_handler+2, es
mov ax, 2509h
mov dx, offset new_h
int 21h
mov ax, 3508h
int 21h
mov word ptr old_timer, bx
mov word ptr old_timer+2, es
mov ax, 2508h
mov dx, offset new_timer
int 21h
mov ah, 34h
int 21h
mov word ptr InDOSFlag, bx
mov word ptr InDOSFlag+2, es
mov dx,offset init
int 27h
init endp
old_handler dd 0
InDOSFlag dd 0
active_task db 0
old_timer dd 0
end start
int 27h
init endp
old_handler dd 0
InDOSFlag dd 0
active_task db 0
old_timer dd 0
end start
push ds
push cs
pop ds
правильно?
именно вы же оставляете резидент только до метки init
push ds
push cs
pop ds
правильно?
если так используете переменную
mov active_task, 0ffh
то да