2016-08-09 12 views
0

В настоящее время мой IRQ является тройным сбоем и дает деление на 0 ошибок. Here - это видео, которое я записал, и это покажет вам это в действии.IRQ Handler Triple Fault

irq.C++

#include "irq.h" 

#define PIC_MASTER_CONTROL 0x20 
#define PIC_MASTER_MASK 0x21 
#define PIC_SLAVE_CONTROL 0xa0 
#define PIC_SLAVE_MASK 0xa1 


typedef void(*regs_func)(struct regs *r); 


/*Get all irq's*/ 
extern "C" void irq0(void); 
extern "C" void irq1(void); 
extern "C" void irq2(void); 
extern "C" void irq3(void); 
extern "C" void irq4(void); 
extern "C" void irq5(void); 
extern "C" void irq6(void); 
extern "C" void irq7(void); 
extern "C" void irq8(void); 
extern "C" void irq9(void); 
extern "C" void irq10(void); 
extern "C" void irq11(void); 
extern "C" void irq12(void); 
extern "C" void irq13(void); 
extern "C" void irq14(void); 
extern "C" void irq15(void); 


extern void panic(const char* exception); 

regs_func irq_routines[16] = { 
    0,0,0,0,0,0,0,0 
    ,0,0,0,0,0,0,0,0 
}; 

static PORT::Port8Bits p8b_irq; 
static SerialPort sp_irq; 

//Basically a declaration of IDT_ENTRY in 
//idt.c++ 
struct idt_entry { 
    uint16_t base_lo; 
    uint16_t sel; // Kernel segment goes here. 
    uint8_t always0; 
    uint8_t flags; // Set using the table. 
    uint16_t base_hi; 
}__attribute__((packed)); 

//Get the Exact IDT array from idt.c++ 
extern struct idt_entry idt[256]; 

static inline void idt_set_gate(uint8_t num, void(*handler)(void), uint16_t sel, 
       uint8_t flags) 
{ 
    idt[num].base_lo = (uintptr_t)handler >> 0 & 0xFFFF; 
    idt[num].base_hi = (uintptr_t)handler >> 16 & 0xffff; 
    idt[num].always0 = 0; 
    idt[num].sel = sel; 
    idt[num].flags = flags; 
} 

IRQ::IRQ(){}; 
IRQ::~IRQ(){}; 

/* Normally, IRQs 0 to 7 are mapped to entries 8 to 15. This 
* is a problem in protected mode, because IDT entry 8 is a 
* Double Fault! Without remapping, every time IRQ0 fires, 
* you get a Double Fault Exception, which is NOT actually 
* what's happening. We send commands to the Programmable 
* Interrupt Controller (PICs - also called the 8259's) in 
* order to make IRQ0 to 15 be remapped to IDT entries 32 to 
* 47 */ 
void IRQ::irq_remap() 
{ 

     // ICW1 - begin initialization 
    p8b_irq.out(0x11,PIC_MASTER_CONTROL); 
    p8b_irq.out(0x11,PIC_SLAVE_CONTROL); 

    // Remap interrupts beyond 0x20 because the first 32 are cpu exceptions 
    p8b_irq.out(0x21,PIC_MASTER_MASK); 
    p8b_irq.out(0x28,PIC_SLAVE_MASK); 

    // ICW3 - setup cascading 
    p8b_irq.out(0x00,PIC_MASTER_MASK); 
    p8b_irq.out(0x00,PIC_SLAVE_MASK); 

    // ICW4 - environment info 
    p8b_irq.out(0x01,PIC_MASTER_MASK); 
    p8b_irq.out(0x01,PIC_SLAVE_MASK); 

    // mask interrupts 
    p8b_irq.out(0xff,PIC_MASTER_MASK); 
    p8b_irq.out(0xff,PIC_SLAVE_MASK); 
} 

void install_handler_irq(int irq, regs_func handler) 
{ 
    printf(" \n Installer IRQ %d \n ", irq); 
    irq_routines[irq] = handler; 
    irq0(); 
} 

void uninstall_handler_irq(int irq) 
{ 
    irq_routines[irq] = 0; 
} 




/* First remap the interrupt controllers, and then we install 
* the appropriate ISRs to the correct entries in the IDT. This 
* is just like installing the exception handlers */ 

void IRQ::install_irqs() 
{ 
    this->irq_remap(); 
    idt_set_gate(32, irq0, 0x08, 0x8E); 
    idt_set_gate(33, irq1, 0x08, 0x8E); 
    idt_set_gate(34, irq2, 0x08, 0x8E); 
    idt_set_gate(35, irq3, 0x08, 0x8E); 
    idt_set_gate(36, irq4, 0x08, 0x8E); 
    idt_set_gate(37, irq5, 0x08, 0x8E); 
    idt_set_gate(38, irq6, 0x08, 0x8E); 
    idt_set_gate(39, irq7, 0x08, 0x8E); 
    idt_set_gate(40, irq8, 0x08, 0x8E); 
    idt_set_gate(41, irq9, 0x08, 0x8E); 
    idt_set_gate(42, irq10, 0x08, 0x8E); 
    idt_set_gate(43, irq11, 0x08, 0x8E); 
    idt_set_gate(44, irq12, 0x08, 0x8E); 
    idt_set_gate(45, irq13, 0x08, 0x8E); 
    idt_set_gate(46, irq14, 0x08, 0x8E);  
    idt_set_gate(47, irq15, 0x08, 0x8E); 

} 

/* Each of the IRQ ISRs point to this function, rather than 
* the 'fault_handler' in 'isrs.c'. The IRQ Controllers need 
* to be told when you are done servicing them, so you need 
* to send them an "End of Interrupt" command (0x20). There 
* are two 8259 chips: The first exists at 0x20, the second 
* exists at 0xA0. If the second controller (an IRQ from 8 to 
* 15) gets an interrupt, you need to acknowledge the 
* interrupt at BOTH controllers, otherwise, you only send 
* an EOI command to the first controller. If you don't send 
* an EOI, you won't raise any more IRQs */ 
extern "C" void irq_handler(struct regs *r) 
{ 
    printf("IRQ Being Handled"); 
} 

irq.S:

.section .text 
.extern irq_handler 
.extern test_func 

     .macro irq number 
      .global irq\number 
      irq\number: 
       cli 
       pushl $0 
       pushl $\number 
       jmp common_handler_irq 
     .endm 

common_handler_irq: 
     # save registers 


      pusha 

     # call C++ Handler 
      call irq_handler 

     # restore registers 
      popa 
      iret 

#TODO FOR LOOP 
irq 0 
irq 1 
irq 2 
irq 3 
irq 4 
irq 5 
irq 6 
irq 7 
irq 8 
irq 9 
irq 10 
irq 11 
irq 12 
irq 13 
irq 14 
irq 15 

Как показано на viedo в irq.C++, если я удалить эту IRQ0() вызова в функции install_irq, тройной разломы будет отключен ... Но если я удалю, то я не знаю, как правильно обрабатывать мой драйвер таймера ...

timer.C++:

#include "timer.h" 

    /* This will keep track of how many ticks that the system 
    * has been running for */ 

    typedef void(*regs_func)(struct regs *r); 


    static int32_t timer_ticks = 0; 

    extern void install_handler_irq(int irq, regs_func handler); 


    /* Handles the timer. In this case, it's very simple: We 
    * increment the 'Timer::timer_ticks' variable every time the 
    * timer fires. By default, the timer fires 18.222 times 
    * per second. Why 18.222Hz? Some engineer at IBM must've 
    * been smoking something funky */ 
    void timer_handler_driver(struct regs *r) 
    { 
     /* Increment our 'tick count' */ 
     timer_ticks++; 

     /* Every 18 clocks (approximately 1 second), we will 
     * display a message on the screen */ 
     if (timer_ticks % 18 == 0) 
     { 
      printf("One second has passed\n"); 
     } 
    } 

    Timer::Timer() 
    { 
    } 

    /* This will continuously loop until the given time has 
    * been reached */ 
    void Timer::timer_wait(int ticks) 
    { 
     unsigned long eticks; 

     eticks = timer_ticks + ticks; 
     while((unsigned)timer_ticks < eticks); 
    } 

    void Timer::install_timer() 
    { 
     install_handler_irq(0, timer_handler_driver); 
    } 

    /* Sets up the system clock by installing the timer handler 
    * into IRQ0 */ 
    Timer::~Timer() 
    { 

    } 

Если вы хотите увидеть мой весь код. Я обновляю свой код здесь в github: https://github.com/amanuel2/OS_Mirror. Помощь будет принята с благодарностью, я уже давно застрял в этой проблеме. Спасибо за прочтение.

ответ

1

irq0() - это процедура обслуживания прерываний, которая заканчивается iret. Вы не можете выполнять вызовы C в эту процедуру. Если вы действительно хотите вызвать прерывание, используйте инструкцию int.

Однако вам не нужно вручную запускать таймер IRQ, он должен срабатывать, как только вы настроили таймер/APIC и получите прерывания после sti.

В качестве побочного примечания это считается плохой практикой (расточительствование тактового цикла и загрязняющего кеша) для подхода «обычного обработчика IRQ», который тогда просто для ручной ветви switch-case, а также для другого IRQ может потребоваться различная обработка (например, EOI для подчиненных). Просто установите обработчики непосредственно в IDT.


Резюме Исследование:

После расследования было код переназначить вызвало ошибку, маска была установлена ​​с 0xff таким образом, что PIT игнорируются. Фиксация этого (установка 0 для маскировки) вызывает тройную ошибку, которая указывает, что таймер затем запускается, но в другом месте цепи IDT/IRQ возникнут проблемы.

+0

Calvin, у меня есть много вопросов относительно вашего anwser. Я не хочу наводнять чат, так что вы можете прийти сюда: https://kobra.io/#/e/-KOjaiMeGtgwYkEsAvuu. Обсуждать об этом? Thankyou – amanuel2

+1

@Dsafds Поскольку ваши ISR не могут быть вызваны с C, было бы неплохо не объявлять их как функции в вашем C-коде. Кроме того, вы можете создать новую комнату здесь, чтобы пообщаться, чтобы вы не «наводнили» какую-то другую комнату. –

 Смежные вопросы

  • Нет связанных вопросов^_^