Intel APIC

Для любителей обсудить что круче Linux или Win32, Java или C#.

Модератор: Duncon

Ответить
Draeden
Сообщения: 14
Зарегистрирован: 04 май 2008, 19:45
Контактная информация:

04 май 2008, 20:09

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

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

05 май 2008, 18:14

Мда... видимо APIC не вызывает ажиотажа...
Аватара пользователя
somewhere
Сообщения: 1837
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

07 май 2008, 17:06

Перед записью скажите контроллеру что вы уже закончили с таймером. Либо поменяйте на стеке адрес возврата, предварительно его сохранив. Потом по IRET свободно выйдите к процедуре записи на диск, а оттуда пошлете туда, где произошло аппаратное прерывание. Тему можно было бы разместить в разделе "Вопрошайка", здесь редко кто бывает.
It's a long way to the top if you wanna rock'n'roll
Draeden
Сообщения: 14
Зарегистрирован: 04 май 2008, 19:45
Контактная информация:

08 май 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
Сообщения: 1837
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

08 май 2008, 09:33

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

Код: Выделить всё

mov al, 20h
out 020h, al
out 0A0h, al
потом не совсем понятно в каком режиме работает контроллер у вас. По умолчанию он работает в режиме приоритетов, а это значит что все прерывания второго контроллера (IRQ8 – IRQ15) оказыжутся между IRQ1 и IRQ3, так как именно IRQ2 используется для каскада двух контроллеров. Тогда значит надо перевести контроллер прерываний в режим специальной маски и отключить на время записи на диск прерывния IRQ0. Что посылать - я уже не помню, в порт 21h кинуть маску, в ней каждый бит соответствует прерыванию IRQ0 - IRQ7.
It's a long way to the top if you wanna rock'n'roll
Draeden
Сообщения: 14
Зарегистрирован: 04 май 2008, 19:45
Контактная информация:

08 май 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
Сообщения: 1837
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

09 май 2008, 11:02

лучше выложите полный код проги - иногда все может быть правильно, но из-за всего одной ошибки может не работать вся прога. Например здесь в обработчике стоит pushf, который потом не снимается со стека и указатель постоянно уменьшается на 2 каждое прерывание.
It's a long way to the top if you wanna rock'n'roll
Draeden
Сообщения: 14
Зарегистрирован: 04 май 2008, 19:45
Контактная информация:

09 май 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
Сообщения: 1837
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

09 май 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
It's a long way to the top if you wanna rock'n'roll
Draeden
Сообщения: 14
Зарегистрирован: 04 май 2008, 19:45
Контактная информация:

10 май 2008, 13:28

Спасибо, наконец то всё работает.
Ответить