2016-08-09 2 views
0

현재 내 IRQ는 트리플 폴트이며 0으로 나누기를 제공합니다. Here은 내가 기록한 viedo입니다.IRQ 처리기 트리플 오류

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 

것처럼 그 IRQ0 제거하면 install_irq 함수 호출) (++ irq.c에서 viedo에 도시 된 상기 트리플의 단층 꺼져있을 꺼야 ...하지만 내가 그 타이머 드라이버를 올바르게 처리하는 방법을 모르겠다면 ...

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는 다른 처리를 요구할 수있다, 수동 스위치의 경우 분기를 할 수있는 "일반 IRQ 처리기"접근 방식 (클럭 사이클과 오염 캐시를 낭비) 예를 들어, EOI 노예). IDT에 직접 핸들러를 설치하십시오.


조사 요약 : 그것은 다시 매핑 코드가 오류를 일으켰습니다 조사 후

, 마스크는 PIT 무시받을하도록 0xFF로 설정했다. 이 값을 고정하면 (마스크를 0으로 설정) 타이머가 트리거되었음을 나타내는 트리플 폴트가 발생하지만 IDT/IRQ 체인의 다른 곳에 문제가 발생합니다.

+0

캘빈, 나는 당신의 anwser에 관한 많은 질문을 가지고 있습니다. 나는 채팅방을 홍수시키고 싶지 않습니다, 그래서 여기에 올지도 모릅니다 : https://kobra.io/#/e/-KOjaiMeGtgwYkEsAvuu. 그것에 대해 토론하기 위해서? 감사합니다 – amanuel2

+1

@Dsafds C에서 ISR을 호출 할 수 없으므로 C 코드에서 ISR을 함수로 선언하지 않는 것이 좋습니다. 또한 다른 방을 "넘치게"하지 않도록 채팅 할 새 방을 만들 수 있습니다. –