PDA

Просмотр полной версии : Intel APIC



Draeden
04.05.2008, 20:09
Меня не пускают в раздел ассемблера, поэтому пишу здесь.

Я пишу программу на ассемблере для Intel x86: нужно каждые 30 сек. сохранять экран в файл. Для этого я делаю перехват IRQ 0 и запускаю счётчик. Каждый раз при достижении нуля я пытаюсь сохранить 64 kb данных экрана с адресов A000:XXXX в файл, но при этом используется диск IRQ 14/15. Диск не может быть использован пока обрабатывается таймер: программа падает. Можно ли решить проблему ?

Draeden
05.05.2008, 18:14
Мда... видимо APIC не вызывает ажиотажа...

somewhere
07.05.2008, 17:06
Перед записью скажите контроллеру что вы уже закончили с таймером. Либо поменяйте на стеке адрес возврата, предварительно его сохранив. Потом по IRET свободно выйдите к процедуре записи на диск, а оттуда пошлете туда, где произошло аппаратное прерывание. Тему можно было бы разместить в разделе "Вопрошайка", здесь редко кто бывает.

Draeden
08.05.2008, 08:06
1. Сообщить APIC о завершении IRQ0:



int8handler:

mov al, 20h
out 20h, al

call writetofile

jmp dword ptr cs : oldint8handler


Две команды с портами разрешают прерывания более низкого приоритета на APIC0, или я не прав ? Я пробовал так делать, но всё равно не работает.

2. Насчёт смены адреса возврата не совсем понятно: чем это будет отличатся от простого прыжка в другую область кода ?



int8handler:

pop eax
push offset writetofile
push cs

iret

somewhere
08.05.2008, 09:33
2. Насчёт смены адреса возврата не совсем понятно: чем это будет отличатся от простого прыжка в другую область кода ?
Почти ничем, кроме того что сменится IOPL в регистре флагов. В защищенном режиме это важно, обычно я использую этот способ для "подвешивания" собственных обработчиков на системные дабы получить привелегии на выполнение собственного кода.
Вообще по хорошему перед записью на диск нужно освободить оба контроллера


mov al, 20h
out 020h, al
out 0A0h, al

потом не совсем понятно в каком режиме работает контроллер у вас. По умолчанию он работает в режиме приоритетов, а это значит что все прерывания второго контроллера (IRQ8 – IRQ15) оказыжутся между IRQ1 и IRQ3, так как именно IRQ2 используется для каскада двух контроллеров. Тогда значит надо перевести контроллер прерываний в режим специальной маски и отключить на время записи на диск прерывния IRQ0. Что посылать - я уже не помню, в порт 21h кинуть маску, в ней каждый бит соответствует прерыванию IRQ0 - IRQ7.

Draeden
08.05.2008, 18:09
Я попробовал отключать IRQ0 на время работы диска. Для контроля я запустил резидента, который ставит обработчик на IRQ0 и выводит время в левый верхний угол экрана. После чего я запустил резидента который должен сохранять данные экрана в файл. Время, показываемое в левом верхнем углу, останавливалось, а на диск обычно ничего не попадало ( иногда удавалось сохранить, иногда нет ). Не могли бы посмотреть код ?

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

somewhere
09.05.2008, 11:02
лучше выложите полный код проги - иногда все может быть правильно, но из-за всего одной ошибки может не работать вся прога. Например здесь в обработчике стоит pushf, который потом не снимается со стека и указатель постоянно уменьшается на 2 каждое прерывание.

Draeden
09.05.2008, 15:26
Спасибо за внимание. Вот весь код (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

somewhere
09.05.2008, 17:27
Основная ошибка - процедуре 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

Draeden
10.05.2008, 13:28
Спасибо, наконец то всё работает.