2016-08-09 12 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を(削除する場合++ irq.cにviedoに示すような)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ハンドラ」アプローチのための悪い習慣(クロックサイクルと汚染キャッシュの浪費)と考えられます。手動のスイッチケースブランチを行うだけで、異なるIRQも異なる処理を必要とする可能性があります。奴隷のためのEOI)。ハンドラをIDTに直接インストールするだけです。


調査概要:それは再マップコードは、障害の原因となった調査の後

、マスクはPITは無視されますように0xffを設定しました。タイマーを示すトリプル障害がその後トリガーされる原因となるが、他の場所IDT/IRQチェーンに問題があるでしょう(マスクに0を設定)これを修正。

+0

カルビン、私はあなたのanwserに関する多くの質問があります。私はチャットルームを洪水したくないので、ここに来るかもしれません:https://kobra.io/#/e/-KOjaiMeGtgwYkEsAvuu。それについて議論する?ありがとう – amanuel2

+1

@DsafdsあなたのISRには、あなたのCコードの関数として宣言しないで良いでしょうCから呼び出すことはできませんので。また、チャットするためにここに新しい部屋を作成して、他の部屋を「洪水」しないようにすることができます。 –