· Начало · Отвђтить · Статистика · Поиск · FAQ · Правила · Установки · Язык · Выход · WASM.RU · Noir.Ru ·

 WASM Phorum —› WASM.ASSEMBLER —› [pmode, прерывания] Ищу ошибку третий день... 0% complete

Посл.отвђт Сообщенiе


Дата: Янв 14, 2004 04:04:37

Всё ковыряюсь с обработкой прерываний в защищённом режиме. После переключения в pm и перепрограммирования контроллера прерываний, визуализирую содержимое gdt и idt и ещё немного полезной инфы. Пристально смотрю в монитор, с увлечением разглядывая циферки & буковки. ВСЁ ПРАВИЛЬНО. Написан свой код для обработчика каждого из прерываний int0-int17. Прерывания int18-int31 обслуживает один и тот же обработчик. Также есть отдельные обработчики irq0 и irq1. irq2-irq7 обрабатываются пачкой, также как и irq8-irq15. Базовый вектор для первого контроллера 0x20, для второго 0x28. Во всех обрабочиках есть код, который изменяет цвет строки на экране, отражающий содержимое соответсвующего дескриптора в idt. Или группы строк (в случае обслуживания одним обработчиком нескольких прерываний).

Так вот, разглядываю, значит, буковки с циферками. Прерывания (немаскируемые тоже) разрешены. Однако я не наблюдаю измнения цвета строки, соответсвующей irq0, то есть таймеру. Но ведь таймер не может не работать! Далее, тыркаю клавиатуру. Успеваю заметить, как изменился цвет строки прерывания int10. И рестарт. Почему рестарт? В коде int10_handler (он ниже) есть строка jmp $. Так фигли перегружаться то? Ах да, быть может прерывание от таймера закончило этот вечный цикл? Но где тогда таймер был раньше? Ничего не понимаю.

Также пониманию не способствует следующее обстоятельство. Не поверив циферкам на экране, дописал несколько строк, вызывающих обработчики программных (int0-int31) прерываний как посредством команды int xx, так и напрямую, через call. И в том и в другом случае соответсвующие строки на экране загорались нужными цветами. То есть мой код работает как положено. Разве что когда через call вызывал, были глюки, ибо iretd читает из стэка отсутсвующий там регистр флагов... Но это мелочи. Не мелочь вот что. Аналогичным образом (через int xx) пытаясь вызвать обработчик аппаратного прерывания, вечно получал рестарт. Опять успевая заметить, что изменился цвет строки 10го прерывания. Почему?!

Господа, не дайте умереть в неведении.. Уж даже и не знаю, чего дальше делать. Жить спокойно не смогу, пока не разберусь. А ведь экзамен послезавтра ещё. По теории электроцепей. И не думаю я, что мои изыскания в области low level программерства будут положительно оценены преподом-тэцевиком на этом самом экзамене :(

Далее привожу некоторые куски кода, в которы, вероятнее всего, я мог допустить ошибку. Надюсь тебе будет не очень лень окинуть их взглядом :)

Заполнение idt:
; macro used to define interrupt descriptor (interrupt gate)
macro defidti sel, off, count
{
   repeat count
      dw off mod 0x10000 ; low word of interrupt handler offset in a segment
      dw sel             ; selector of the descriptor of the segment with a handler
      db 0x0             ; reserved, high 2 bits must be 0
      db 0xEE            ; bits 0-3: type of gate (1110 - interrupt gate)
                         ;    bit 4: reserved (must be 0)
                         ; bits 5-6: dpl
                         ;    bit 7: present flag
      dw off / 0x10000   ; high word of interrupt handler offset in a segment
   end repeat
}

; macro used to define interrupt descriptor (ловушка gate)
macro defidtl sel, off, count
{
   repeat count
      dw off mod 0x10000 ; low word of interrupt handler offset in a segment
      dw sel             ; selector of the descriptor of the segment with a handler
      db 0x0             ; reserved, high 2 bits must be 0
      db 0xEF            ; bits 0-3: type of gate (1110 - ловушка gate)
                         ;    bit 4: reserved (must be 0)
                         ; bits 5-6: dpl
                         ;    bit 7: present flag
      dw off / 0x10000   ; high word of interrupt handler offset in a segment
   end repeat
}

align 0x4
idt:
defidtl SCODE, int0_handler, 1
defidtl SCODE, int1_handler, 1
defidtl SCODE, int2_handler, 1
defidtl SCODE, int3_handler, 1
defidtl SCODE, int4_handler, 1
defidtl SCODE, int5_handler, 1
defidtl SCODE, int6_handler, 1
defidtl SCODE, int7_handler, 1
defidtl SCODE, int8_handler, 1
defidtl SCODE, int9_handler, 1
defidtl SCODE, int10_handler, 1
defidtl SCODE, int11_handler, 1
defidtl SCODE, int12_handler, 1
defidtl SCODE, int13_handler, 1
defidtl SCODE, int14_handler, 1
defidtl SCODE, int15_handler, 1
defidtl SCODE, int16_handler, 1
defidtl SCODE, int17_handler, 1
defidtl SCODE, int18_31_handler, 14
defidti SCODE, irq0_handler, 1    ; for irq0
defidti SCODE, irq1_handler, 1    ; for irq1 (keyboard)
defidti SCODE, irq2_7_handler, 6  ; for irq2-irq7
defidti SCODE, irq8_15_handler, 8 ; for irq8-irq15
defidtl SCODE, int_handler, 0xD0    ; for int48-int255

Инициализация контроллера прерываний:
   ; init pic
   mov   al, 000100001b ; icw1
   out   0x20, al			; for 1st controller
   out   0xA0, al			; for 2nd controller
   mov   al, 0x20			; icw2 for 1st controller
   out   0x21, al
   mov   al, 0x28 		; icw2 for 2nd controller
   out   0xA1, al
   mov   al, 00000100b 	; icw3 for 1st controller
   out   0x21, al
   mov   al, 00000010b 	; icw3 for 2nd controller
   out   0xA1, al
   mov   al, 00001101b 	; icw4 for 1st controller
   out   0x21, al
   mov   al, 00001001b 	; icw4 for 2nd controller
   out   0xA1, al

Код обрабочика прерывания таймера
irq0_handler:
   push  ax
   push  dx
   push  ds

   mov   ax, SDATA ; SDATA - селектор дескриптора
	mov   ds, ax    ; сегмента данных. База равна адресу сегмента
	   	          ; в который ДОС нас загрузил, размер = 64Kb   


   ; далее вызываем функцию подсветки строки
	; параметры: al - атрибут символов строки
	;            ah - индекс дескриптора
   mov   al, [.atr]
   mov   ah, 0x20
   call  highlight_idt_row

   inc   al
   jnz   @f
   mov   al, 0x8
@@:
   mov   [.atr], al

   mov   al, 0x20
   out   0x20, al

   pop   ds
   pop   dx
   pop   ax
   iretd
.atr db 0x9

Клавиатуры
irq1_handler:
   push  ax
   push  ds

   mov   ax, SDATA
   mov   ds, ax

   mov   al, [.atr]
   mov   ah, 0x21
   call  highlight_idt_row

   inc   al
   jnz   @f
   mov   al, 0x8
@@:
   mov   [.atr], al

   ; разрешаем работу контроллера клавы
   in    al, 0x61
   push  ax
   or    al, 0x80
   out   0x61, al
   pop   ax
   out   0x61, al

   mov   al, 0x20
   out   0x20, al

   pop   ds
   pop   ax
   iretd
.atr db 0xA


Кому интересно увидеть всё воочию, прилагаю исходник целиком и скомпилёную версию.

_1550493692__pmi.rar


Дата: Янв 14, 2004 09:19:33

Главное правильно инициализировать контроллер прерываний! Не знаю на сколько это у меня получилось, но таймер и клавиатура работают.
format binary

load_addr=7C00h
num_gates=32+16

org load_addr
	cli
	lgdt fword [cs:gdtr]
	lidt fword [cs:idtr]
	mov eax,cr0
	or eax,1
	mov cr0,eax
	jmp fword scode:start32;и никаких макросов!

use32
start32:
	mov eax,sdata
	mov ds,eax
	mov ss,eax
	mov eax,svid
	mov gs,eax
	xor eax,eax

	mov ecx,48*8
    .fillidt:
	lea eax,[calls+ecx+(scode shl 16)]	;int_gate_Lx
	mov [idt+ecx],eax
	mov dword [idt+ecx+4],8e00h
	mov eax,handler-calls-8			;Lx:
	sub eax,ecx				;call handler
	mov dword [calls+ecx],0E8909090h	
	mov [calls+ecx+4],eax
	sub ecx,8
	jnc .fillidt

	mov esi,pm8259
    .init8259:
	lodsw
	movzx edx,ah
	out dx,al
	cmp ax,0a00ah
	jnz .init8259

	sti
    .stop:    
	inc byte [gs:160]
	jmp .stop

handler:
	xchg [esp],eax;определение номера шлюза через который произошел вызов
	sub eax,calls+8
	shr eax,2
	inc byte [gs:eax]
	cmp eax,20h*2
	jb .halt
	cmp eax,21h*2
	jz .kb

	mov al,20h;irq0,irq2-irq15
	out 20h,al
	out 0a0h,al
	pop eax
	iretd

    .halt:;int0-int31
	inc byte [gs:eax]
	jmp .halt

    .kb:;irq1
	in al,64h
	shr eax,1
	jnc .kbexit
	in al,60h
	mov [gs:162],al
    .kbexit:	
	mov al,20h
	out 20h,al
	pop eax
	iretd

pm8259  dw 2011h,0a011h,2120h,0a128h,2104h,0a102h,211fh,0a11bh,200ah,0a00ah

rb ($+7) and -8 -$
gdt dd 0,0
scode = $-gdt
    dd 0ffffh,409a00h
sdata = $-gdt
    dd 0ffffh,9200h
smem = $-gdt
    dd 0ffffh,8f9200h
svid = $-gdt
    dd 80007fffh,920bh
gdt_size=$-gdt

gdtr	dw gdt_size-1,gdt,0
idtr	dw idt_size-1,idt,0
 
rb load_addr+510-$
dw 0AA55h

idt rd num_gates*2
idt_size=$-idt

calls rd num_gates*2

P.S: Откомпилированный файл прописать в boot.ini (можно вместо винды 8)


Дата: Янв 14, 2004 12:45:26

ошибка тут:

Инициализация контроллера прерываний:
; init pic
mov al, 000100001b ; icw1 <---------!!!!
out 0x20, al ; for 1st controller
out 0xA0, al ; for 2nd controller
mov al, 0x20 ; icw2 for 1st controller
out 0x21, al
mov al, 0x28 ; icw2 for 2nd controller
out 0xA1, al
mov al, 00000100b ; icw3 for 1st controller
out 0x21, al
mov al, 00000010b ; icw3 for 2nd controller
out 0xA1, al
mov al, 00001101b ; icw4 for 1st controller
out 0x21, al
mov al, 00001001b ; icw4 for 2nd controller
out 0xA1, al

надо icw1 00010001b(ты вставил лишний ноль), а то команда посылки icw1 не распознается, соотв-но обработчики остаются на тех же местах что и в DOS, и размер векторов остается тем же - четырехбайтным. Т.к запись в 21 и А1 порт распознается как маска разрешения прерывания,то последний байт ICW4 выглядит как запрет прерывания Int 0 и разрешения int 1 (00001101b )
Могу предложить процедурку для инициализации покороче:
cld
mov si,offset init_my_reroute_irq
push (20h)
pop dx
call reroute_master
mov dl,0A0h
reroute_master:
outsb
inc dx
outsb
outsb
outsb
ret

init_my_reroute_irq:
db 00010001b ;for master controller
db 20h
db 4
db 00001101b
db 00010001b ;for slave controller
db 28h
db 2
db 00001001b


Дата: Янв 14, 2004 18:39:12

coder

Мне вот любопытно, ты допускаешь не алгоритмические, а банальные ошибки, которые находятся простой отладкой. А как же ты этот код отлаживаешь? Если просто printf - то это бяка. Я бы предложил тебе использовать эмулятор с отладчиком - BOSCH. Ставь себе Линукс и этот эмулятор. И разбирайся - массу удовольствия получишь.


Дата: Янв 14, 2004 19:09:18

MrAssembler, вот уже 15 минут не могу выразить свою благодарность, ибо от безмерного счастия не в состоянии был попасть в нужные кнопки! :)

Black_mirror, спасибо за то, что в очередной раз не обделил меня своим внманием =)

volodya: Мне вот любопытно, ты допускаешь не алгоритмические, а банальные ошибки, которые находятся простой отладкой
Это у меня с третьего класса школы началось. Именно тогда в годовой контрольной по математике у меня была единственная ошибка. Ви будете смеяться, но так строка выглядела именно так: 2+2=5 :) С тех пор подобная фигня происходит со мной регулярно.

Что касается отладки, то не имея опыта работы с эмуляторами, нынешний свой pm-ный код я не отлаживаю. Во всяком случае в тардиционном смысле. Надеясь на свой разум (хехехе), который очень часто позволяет мне избегать небанальные ошибки, я просто пишу, компилю и запускаю. Если что-то идёт не так, как я предполагал, то сначала смотрю в книги, дабы убедетится в том, что моё понимание принципиальных вещей не протеворечит действительности, а потом ищу в своём коде вот такие вот пёрлы, как нынешний. Обычно нахожу за конечное время :) Но сейчас как-то всё не получалось...

Bosch есть. Под виндовсом правда. Когда-нибудь я с ним разберусь... Но ведь разбираться в страничной адресации и прерываниях в разы инетерснее ;) Поэтому bocsh пока заброшен.


Дата: Янв 14, 2004 19:22:36

Понял.


Дата: Янв 14, 2004 19:49:54

volodya, я тоже понял о чём примерно ты подумал, написав последнее сообщение :) Но когда-нибудь я исправлюсь и перстану допускать глупые ошибки. Я опять понимаю, что тебе объекивно пофик, но всё равно ;)


Дата: Янв 14, 2004 19:57:35

Если человек не допускает ошибок - он не человек. Я тоже частенько забывал и продолжаю забывать ставить спецификаторы в printf из-за чего получаю core dump ;)


Дата: Янв 15, 2004 00:26:13

printf вапче античеловеческая функция :) Я давно понял, что мы с ней несовместимы вкорне :)


Дата: Янв 15, 2004 10:35:55

coder,volodya, подкиньте плиз ентот bosch для виндузы (или для дос, если есть ;), а то тоже надо в pmode отладкой заниматься, а напрягаться лень ;)


Дата: Янв 15, 2004 12:21:01


Дата: Янв 19, 2004 09:48:25

big 10x :)


Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.062