|
|
| Посл.отвђт | Сообщен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 |