2015-10-20 1 views
2

Here - это исходный код моей ОС.Почему мой ISR для IRQ0 (8253 Timer Interrupt) из 8259 выполнен?

Я убедился, что, когда процессор получает прерывание от 8259 PIC (программируемый контроллер прерываний), он всегда «правильно смещает» в массив ISR (процедуры обслуживания прерываний). (Вы можете найти весь код here.):

isrs: 
    dd _isr0 
    dd _isr1 
    dd _irq_unhandled 
    dd _irq_unhandled 
    dd _irq_unhandled 
    .... 
    dd _isr32 
    dd _isr33 

обработчиков прерываний еще не реализован, обозначается _irq_unhandled. До сих пор я исправлял ошибки процессора и прерывания программного обеспечения (ловушки). Например, когда моя программа пытается делить на ноль, она переходит на _isr0. Или когда я попробую int 1, int 2, int 7 или что-то подобное, проиндексирован и вызывается правильный ISR в массиве isrs (IDT; таблица дескрипторов прерываний). Но теперь, я не могу получить ПОС, чтобы выполнить мой обработчик прерывания _isr32:

_isr32: 
    mov bl, 5 
    mov bh, 15 
    ; mov eax, MovCur 
    ; and eax, 0xFFFF 
    call MovCur 

    mov eax, PicIntrMsg 
    ; and eax, 0xFFFF ; retrieve offset only when base address is something different than 0 
    ; call 0x38:0x1008a 
    call Puts32 

    mov al, 0x20 
    out 0x20, al 
    ret 

_isr32 только печатает сообщение, чтобы показать, что он был вызван и посылает ВЗ (конец прерывания) сообщение на ПОС. Вот процедура для включения ПОС, все прерывания отключены, кроме таймера и клавиатуры:

%define IRQ_0 0x20    ; IRQs 0-7 mapped to use interrupts 0x20-0x27 
%define IRQ_8 0x28    ; IRQs 8-15 mapped to use interrupts 0x28-0x36 

; Initialization Control Word 1 
%define ICW1_SEND_IC4 0x1 
%define ICW1_SINGLE 0x2 
%define ICW1_ADDRESS_INTERVAL_4 0x4 ; if set, use addresss inter, else 8 
%define ICW1_LEVEL_TRIGGERED 0x8 
%define ICW1_PIC_INITIALIZED 0x10 
%define ICW1_IVT_ADDR1 0x20 
%define ICW1_IVT_ADDR2 0x40 
%define ICW1_IVT_ADDR3 0x80 

; Initialization 
; 1. write ICW1 to port 20h 
; 2. write ICW2 to port 21h 
; 3. if ICW1 bit D1=1 do nothing 
; if ICW1 bit D1=0 write ICW3 to port 20h 
; 4. write ICW4 to port 21h 
; 5. OCW's can follow in any order 
; http://stanislavs.org/helppc/8259.html 
MapPIC: 
    cli 
    ; Setup ICW1 
    mov al, (ICW1_SEND_IC4 | ICW1_PIC_INITIALIZED) 
    out 0x20, al 
    out 0xa0, al 

    ; Setup ICW2 
    ; send ICW 2 to primary PIC 
    ; the first 31 interrupts (0x0-0x1F) are reserved 
    mov al, IRQ_0  ; Primary PIC handled IRQ 0..7. IRQ 0 is now mapped to interrupt number 0x20 
    out 0x21, al 

    ; send ICW 2 to secondary controller 
    mov al, IRQ_8  ; Secondary PIC handles IRQ's 8..15. IRQ 8 is now mapped to use interrupt 0x28 
    out 0xa1, al 

    ; Setup ICW3 
    mov al, 0x4     ; 0x4 = 0100 Second bit (IR Line 2) 
    out 0x21, al ; send to data register 

    ; Send ICW 3 to secondary PIC 
    mov al, 0x2  ; 0010=> IR line 2 
    out 0xa1, al ; write to data register of secondary PIC 

    ; Setup ICW4 
    mov al, 0x1  ; bit 0 enables 80x86 mode 

    ; send ICW 4 to both primary and secondary PICs 
    out 0x21, al 
    out 0xA1, al 

    ; All done. Null out the data registers 
    mov al, 0 
    out 0x21, al 
    out 0xa1, al 

    ; Disable all IRQs, except the timer and the keyboard 
    mov al, 0xfc 
    out 0x21, al 
    out 0xA1, al 

    ret 

(полный исходный код находится в pic.inc).

Проверка журнала Bochs, в IRQ0 пришел с ПОС, а также прерывания клавиатуры:

... 
00030543642d[PIC ] IRQ line 0 now low 
00030543646d[PIC ] IRQ line 0 now high 
00030763342d[PIC ] IRQ line 0 now low 
00030763346d[PIC ] IRQ line 0 now high 
00030916000i[KBD ] internal keyboard buffer full, ignoring scancode.(27) 
00030983046d[PIC ] IRQ line 0 now low 
00030983050d[PIC ] IRQ line 0 now high 
00031048000i[KBD ] internal keyboard buffer full, ignoring scancode.(26) 
00031202746d[PIC ] IRQ line 0 now low 
00031202750d[PIC ] IRQ line 0 now high 
... 

Вы можете проверить полный журнал here. PIC инициализируется правильно, в соответствии с журнала:

00014765045d[PIC ] master: init command 1 found 
00014765045d[PIC ]   requires 4 = 1 
00014765045d[PIC ]   cascade mode: [0=cascade,1=single] 0 
00014765045d[PIC ] master: ICW1: edge triggered mode selected 
00014765046d[PIC ] IO write to 00a0 = 11 
00014765046d[PIC ] slave: init command 1 found 
00014765046d[PIC ]  requires 4 = 1 
00014765046d[PIC ]  cascade mode: [0=cascade,1=single] 0 
00014765046d[PIC ] slave: ICW1: edge triggered mode selected 
00014765048d[PIC ] IO write to 0021 = 20 
00014765048d[PIC ] master: init command 2 = 20 
00014765048d[PIC ]   offset = INT 20 
00014765050d[PIC ] IO write to 00a1 = 28 
00014765050d[PIC ] slave: init command 2 = 28 
00014765050d[PIC ]  offset = INT 28 
00014765052d[PIC ] IO write to 0021 = 04 
00014765052d[PIC ] master: init command 3 = 04 
00014765054d[PIC ] IO write to 00a1 = 02 
00014765054d[PIC ] slave: init command 3 = 02 
00014765056d[PIC ] IO write to 0021 = 01 
00014765056d[PIC ] master: init command 4 = 01 
00014765056d[PIC ] normal EOI interrupt 
00014765056d[PIC ]  80x86 mode 
00014765057d[PIC ] IO write to 00a1 = 01 
00014765057d[PIC ] slave: init command 4 = 01 
00014765057d[PIC ] normal EOI interrupt 
00014765057d[PIC ]  80x86 mode 
00014765059d[PIC ] IO write to 0021 = fb 
00014765059d[PIC ] setting master pic IMR to fb 
00014765060d[PIC ] IO write to 00a1 = fb 
00014765060d[PIC ] setting slave pic IMR to fb 
00014765064d[PIC ] IO write to 0021 = 00 
00014765064d[PIC ] setting master pic IMR to 00 

Несмотря на все это, она по-прежнему идет не так, и я не знаю, что мне не хватает. Кто-нибудь может мне помочь?

+0

Инициализация ПИК действительно выглядит правильно ...вы уверены, что «обнуление» регистров данных не требуется? – Downvoter

+0

Вы инициализировали 'ss: esp'? – Downvoter

+0

@cad Я пробовал не отменять, но это то же самое. Но, когда ISR был введен, я не задал 'ss'. Я только установил другие регистры сегментов, как вы можете видеть здесь [https://github.com/tuhdo/os-study/blob/master/include/idt.inc#L141). Это важно, и какое значение я должен установить 'ss'? В настоящее время моя ОС может вводить прерывание, когда происходит исключение (т. Е. Деление на 0), выбирает правильный ISR, выполняет и возвращает предыдущую инструкцию. Что-то не хватает? –

ответ

2

Переключение в пользовательское пространство делает мою ОС неспособной получить прерывания от ПОС. Если я не вхожу в пользовательское пространство (т. Е. Бесконечный цикл в пространстве ядра), ОС может получать прерывания PIC в порядке. Оказалось, что sysenter disable IF bit in EFLAGS register. Когда я ввожу sti в запись системного вызова (это переход к подпрограмме зависит от номера системного вызова), прерывание снова работает отлично. В моем коде подпрограмма называется Sysenter_Entry, которая сравнивает номер syscall в eax и прыгает соответственно (мне нужно будет превратиться в массив указателей функций в будущем).

Sysenter_Entry: 
    sti ; This solved the problem. VERY IMPORTANT. 
    mov  bx, 0x10  ; set data segments to data selector (0x10) 
    mov  ds, bx 
    ; sysenter jumps here, is is executing this code at prividege level 0. Simular to Call Gates, normally we will 
    ; provide a single entry point for all system calls. 
    cmp eax, 0 
    je clrscr 
    cmp eax, 1 
    je monitor_out 
    cmp eax, 2 
    je test_intr_kernel_space 
    cmp eax, 3 
    je test_intr_pic 
    cmp eax, 4 
    je STOP 
    ; mov eax, GoodbyeMsg 
    ; call Puts32 
syscall_exit: 
    ; restore back the stack for userspace afterward 
    mov bx, 0x23 
    mov ds, bx 
    sysexit 

Кроме того, при переключении на пользовательское приложение в первый раз с iret, IF бит также отключен, и мне нужно установить бит IF и положить его обратно в EFLAGS зарегистрироваться pushf для прерывания функционировать в пользовательском пространстве.

После прерывания бит устанавливается соответствующим образом (либо sti или модификации EFLAGS), я могу подтвердить прерывание работает, видя ISR получил колл и проверка Bochs войти с последовательностями, как это:

.... 
04433276227d[PIC ] IRQ line 0 now high 
04433276227d[PIC ] signalling IRQ(0) 
04433277486d[PIC ] IO write to 0020 = 20 
04433372617d[PIC ] IRQ line 0 now low 
.... 

То есть, IRQ0 высок, тогда ответ процессора с 0x20 для подтверждения прерывания и IRQ0 снова низкий.

+1

Я рад, что вы его отсортировали :) Я ненавижу 8259. Самая первая работа, которую я когда-либо делал, касалась этого устройства, и я не мог заставить его прерывать не один раз, независимо от того, какой режим, сколько разрешить прерывания и что бы ни было EOI 0x20's я отправил его .... –

+0

Я чувствую боль. Настолько разочаровывающе. Мне любопытно: в чем была ваша проблема и как ее решить? –

+1

Боюсь, я сдался и опросил устройство вместо того, чтобы использовать правильный драйвер :( –