Intel APIC
Модератор: Duncon
Меня не пускают в раздел ассемблера, поэтому пишу здесь.
Я пишу программу на ассемблере для Intel x86: нужно каждые 30 сек. сохранять экран в файл. Для этого я делаю перехват IRQ 0 и запускаю счётчик. Каждый раз при достижении нуля я пытаюсь сохранить 64 kb данных экрана с адресов A000:XXXX в файл, но при этом используется диск IRQ 14/15. Диск не может быть использован пока обрабатывается таймер: программа падает. Можно ли решить проблему ?
Я пишу программу на ассемблере для Intel x86: нужно каждые 30 сек. сохранять экран в файл. Для этого я делаю перехват IRQ 0 и запускаю счётчик. Каждый раз при достижении нуля я пытаюсь сохранить 64 kb данных экрана с адресов A000:XXXX в файл, но при этом используется диск IRQ 14/15. Диск не может быть использован пока обрабатывается таймер: программа падает. Можно ли решить проблему ?
Мда... видимо APIC не вызывает ажиотажа...
Перед записью скажите контроллеру что вы уже закончили с таймером. Либо поменяйте на стеке адрес возврата, предварительно его сохранив. Потом по IRET свободно выйдите к процедуре записи на диск, а оттуда пошлете туда, где произошло аппаратное прерывание. Тему можно было бы разместить в разделе "Вопрошайка", здесь редко кто бывает.
It's a long way to the top if you wanna rock'n'roll
1. Сообщить APIC о завершении IRQ0:
Две команды с портами разрешают прерывания более низкого приоритета на APIC0, или я не прав ? Я пробовал так делать, но всё равно не работает.
2. Насчёт смены адреса возврата не совсем понятно: чем это будет отличатся от простого прыжка в другую область кода ?
Код: Выделить всё
int8handler:
mov al, 20h
out 20h, al
call writetofile
jmp dword ptr cs : oldint8handler
2. Насчёт смены адреса возврата не совсем понятно: чем это будет отличатся от простого прыжка в другую область кода ?
Код: Выделить всё
int8handler:
pop eax
push offset writetofile
push cs
iret
Почти ничем, кроме того что сменится IOPL в регистре флагов. В защищенном режиме это важно, обычно я использую этот способ для "подвешивания" собственных обработчиков на системные дабы получить привелегии на выполнение собственного кода." писал(а):2. Насчёт смены адреса возврата не совсем понятно: чем это будет отличатся от простого прыжка в другую область кода ?
Вообще по хорошему перед записью на диск нужно освободить оба контроллера
Код: Выделить всё
mov al, 20h
out 020h, al
out 0A0h, al
It's a long way to the top if you wanna rock'n'roll
Я попробовал отключать IRQ0 на время работы диска. Для контроля я запустил резидента, который ставит обработчик на IRQ0 и выводит время в левый верхний угол экрана. После чего я запустил резидента который должен сохранять данные экрана в файл. Время, показываемое в левом верхнем углу, останавливалось, а на диск обычно ничего не попадало ( иногда удавалось сохранить, иногда нет ). Не могли бы посмотреть код ?
P.S. извиняюсь за такой наглый вопрос, но это, видимо, самый простой вариант, к тому же я постарался убрать всё лишнее.
Также я попытался менять адрес возврата, результат тот же.
P.S. извиняюсь за такой наглый вопрос, но это, видимо, самый простой вариант, к тому же я постарался убрать всё лишнее.
Код: Выделить всё
<...>
main:
jmp init
; timer handler: saves screen every -time- ticks
timerhandler:
pushf
call dword ptr cs : oldtimer
cmp cs : elapsed, 0
je save
dec cs : elapsed
iret
save:
push ax
in al, 21h
or al, 1
out 21h, al
call savescreen
in al, 21h
and al, not 1
out 21h, al
pop ax
mov cs : elapsed, time
iret
<...>
savescreen:
<...>
; Resident data
oldtimer dw ?, ? ; original timer handler
time = 18 ; save to a file every 3 seconds
elapsed dw time ; elapsed ticks
; Initialization: set hooks and stay resident
init:
<...>
; Set hook on timer
<...>
; Stay resident
<...>
end main
Код: Выделить всё
timerhandler:
<...>
pop dword ptr cs : oldretaddr
push cs
push offset savescr
iret
savescr:
call savescreen
jmp dword ptr cs : oldretaddr
лучше выложите полный код проги - иногда все может быть правильно, но из-за всего одной ошибки может не работать вся прога. Например здесь в обработчике стоит pushf, который потом не снимается со стека и указатель постоянно уменьшается на 2 каждое прерывание.
It's a long way to the top if you wanna rock'n'roll
Спасибо за внимание. Вот весь код (tasm):
Код: Выделить всё
.model tiny
.386
.code
org 80h
cllen = $
org 82h
cldata = $
org 100h
; Main entry
main:
jmp init
; timer handler: saves screen every -time- ticks
timerhandler:
pushf
call dword ptr cs : oldtimer
cmp cs : elapsed, 0
je save
dec cs : elapsed
iret
save:
pop dword ptr cs : oldretaddr
push cs
push offset savescr
iret
savescr:
call savescreen
jmp dword ptr cs : oldretaddr
; kb handler: loads screen at Ctrl + L pressed
kbhandler:
push ax
in al, 60h
cmp al, 26h ; 'L' key
jne exitkbh
call loadscreen
exitkbh:
pop ax
jmp dword ptr cs : oldkb
; Saves screen to buffer
savescreen:
pusha
push ds
mov ah, 3Ch
xor cx, cx
push cs
pop ds
mov dx, offset cldata
int 21h
jc ssexit
mov bx, ax
mov ah, 40h
mov cx, -1
push 0A000h
pop ds
xor dx, dx
int 21h
mov ah, 3Eh
int 21h
ssexit:
pop ds
popa
retn
; Loads screen from buffer
loadscreen:
; Resident data
oldtimer dw ?, ? ; original timer handler
oldkb dw ?, ? ; original kb handler
time = 18 ; save to a file every 3 seconds
elapsed dw time ; elapsed ticks
oldretaddr dw ?, ? ; used in INT 8 handler
; Initialization: set hooks and stay resident
init:
xor bx, bx
mov bl, byte ptr ds : [ offset cllen ]
test bx, bx
jz showusage
mov byte ptr ds : [ offset cldata - 1 + bx ], 0
; Set hook on timer
mov bx, 8
mov ax, offset timerhandler
mov dx, offset oldtimer
call hook
; Set hook on keyboard
mov bx, 9
mov ax, offset kbhandler
mov dx, offset oldkb
call hook
call savescreen
; Stay resident
mov ah, 27h
mov dx, offset init
int 27h
showusage:
mov ah, 9
mov dx, offset usage
int 21h
retn
usage db 13, 10
db 'Resident screen saver', 13, 10
db 'Written by Draeden', 13, 10
db 13, 10
db 'Usage: rss filename', 13, 10
db ' filename - some file to keep the screen data', 13, 10
db 36
; Sets a hook on interrupt
;
; Arguments:
;
; BX = interrupt
; AX = new handler
; DI = ( dword ) place for old handler
hook:
push bx
push ds
push 0
pop ds
shl bx, 2
push dword ptr ds : [ bx ]
pop dword ptr cs : [ di ]
push cs
push ax
pop dword ptr ds : [ bx ]
pop ds
pop bx
retn
end main
Основная ошибка - процедуре hook передавался параметр в DX хотя надо было в DI
Я не знаю как у вас тут "периодически" работало, т.к. работать вообще не должно было. Вот подправленый и рабочий код. Я убрал хук с клавы (для тестов не нужен был) и добавил индикатор записи для себя. А так вроде все
Я не знаю как у вас тут "периодически" работало, т.к. работать вообще не должно было. Вот подправленый и рабочий код. Я убрал хук с клавы (для тестов не нужен был) и добавил индикатор записи для себя. А так вроде все
Код: Выделить всё
.model tiny
.386
.code
org 80h
cllen = $
org 82h
cldata = $
org 100h
; Main entry
main:
jmp init
; timer handler: saves screen every -time- ticks
timerhandler:
pusha
cmp cs : elapsed, 0
jz save
dec cs : elapsed
jmp @exitint
save:
in al, 21h
or al, 1
out 21h, al
call savescreen
in al, 21h
and al, not 1
out 21h, al
mov cs:elapsed, time
@exitint:
popa
jmp dword ptr cs : oldtimer
; kb handler: loads screen at Ctrl + L pressed
kbhandler:
push ax
in al, 60h
cmp al, 26h ; 'L' key
jne exitkbh
call loadscreen
exitkbh:
pop ax
jmp dword ptr cs : oldkb
; Saves screen to buffer
savescreen:
pusha
push ds
mov ax, 0B800h
mov ds, ax
mov word ptr ds:[0], 0F41h
mov ah, 3Ch
xor cx, cx
push cs
pop ds
mov dx, offset cldata
int 21h
jc ssexit
mov bx, ax
mov ah, 40h
mov cx, -1
push 0A000h
pop ds
xor dx, dx
int 21h
mov ah, 3Eh
int 21h
ssexit:
pop ds
popa
retn
; Loads screen from buffer
loadscreen:
; Resident data
oldtimer dw ?, ? ; original timer handler
oldkb dw ?, ? ; original kb handler
time = 18 ; save to a file every 3 seconds
elapsed dw time ; elapsed ticks
oldretaddr dw ?, ? ; used in INT 8 handler
; Initialization: set hooks and stay resident
init:
xor bx, bx
mov bl, byte ptr ds : [ offset cllen ]
test bx, bx
jz showusage
mov byte ptr ds : [ offset cldata - 1 + bx ], 0
; Set hook on timer
mov bx, 8
mov ax, offset timerhandler
mov di, offset oldtimer
call hook
; Set hook on keyboard
mov bx, 9
mov ax, offset kbhandler
mov dx, offset oldkb
;call hook
;call savescreen
; Stay resident
mov ah, 27h
mov dx, offset init
int 27h
showusage:
mov ah, 9
mov dx, offset usage
int 21h
retn
usage db 13, 10
db 'Resident screen saver', 13, 10
db 'Written by Draeden', 13, 10
db 13, 10
db 'Usage: rss filename', 13, 10
db ' filename - some file to keep the screen data', 13, 10
db 36
; Sets a hook on interrupt
;
; Arguments:
;
; BX = interrupt
; AX = new handler
; DI = ( dword ) place for old handler
hook:
push bx
push ds
push 0
pop ds
shl bx, 2
push dword ptr ds : [ bx ]
pop dword ptr cs : [ di ]
push cs
push ax
pop dword ptr ds : [ bx ]
pop ds
pop bx
retn
end main
It's a long way to the top if you wanna rock'n'roll
Спасибо, наконец то всё работает.