首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >IRQ双重故障

IRQ双重故障
EN

Stack Overflow用户
提问于 2016-08-10 04:07:55
回答 1查看 158关注 0票数 1

我有一个问题,关于我的第一个车手(维修站)的制作。这个问题在我之前录制的视频中得到了很好的解释:https://www.youtube.com/watch?v=hjvTtVbaics&feature=youtu.be。让我先展示一下我的计时器驱动:

timer.c++:

代码语言:javascript
复制
#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()
{

}

下面是我的irq c++代码:

irq.c++:

代码语言:javascript
复制
#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(0x04,PIC_MASTER_MASK);
        p8b_irq.out(0x02,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(0,PIC_MASTER_MASK);
        p8b_irq.out(0,PIC_SLAVE_MASK);
    }

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

    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:

代码语言:javascript
复制
.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

在我开始之前,我的github在这里,所以你可以看到我的整个代码:https://github.com/amanuel2/OS_Mirror,.So,基本上发生的是。正如你可以在我的timer.c++上看到的,如果我注释了if语句,它会打印一秒钟过去的错误,并在qemu上显示错误(双重错误),如果我不这样做,它不会打印任何东西,并且会打印双重错误。从视频中可以看到: urlhttps://www.youtube.com/watch?v=hjvTtVbaics&feature=youtu.be[/url]](https://www.youtube.com/watch?v=hjvTtVbaics&feature=youtu.be[/url])。如果能帮上忙,我们将不胜感激!

编辑:

有时它决定只在qemu上显示错误消息,而不是说已经过了一秒,甚至是除以0错误,并给出了以下结果:

代码语言:javascript
复制
qemu: fatal: Trying to execute code outside RAM or ROM at 0x491019d0

EAX=00000000 EBX=00009500 ECX=00000700 EDX=0010159e
ESI=00000000 EDI=00109000 EBP=00107122 ESP=001031ee
EIP=001019d0 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 49000000 0008ffff 00589a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     00103114 00000017
IDT=     00102900 000007ff
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 
DR6=ffff0ff0 DR7=00000400
CCS=00000010 CCD=001031ce CCO=ADDL    
EFER=0000000000000000
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000
make: *** [Makefile:56: qemu] Aborted (core dumped)

我已经试着调试了一段时间了。

另一个问题是它在改变……这不是一个稳定的错误,你可以在viedo上看到:https://www.youtube.com/watch?v=fHQE_vIu_wU&feature=youtu.be

EN

回答 1

Stack Overflow用户

发布于 2016-08-10 05:15:46

首先,在你的重映射图片代码中有一些小问题:

代码语言:javascript
复制
    p8b_irq.out(0x21,PIC_MASTER_MASK);
    p8b_irq.out(0x28,PIC_SLAVE_MASK);

主-> 0x21(33) ~ 0x28从-> 0x28 ~ 0x2f

正如您现在可能会想到的那样,您实际上打算将master映射到0x20~0x27。但是因为你有一个通用的IRQ处理程序,所以它不会致命。

现在,对于崩溃,让我们跟踪IRQ是如何处理的:

  • 自从你看到一条消息以来,它表明你的IDT is
  • CPU跳到标签irq0 (然后是cli和两次按下)
  • 跳到common_handler_irq
  • pusha
  • invoke Cirq_handler,这基本上就完成了nothing.
    • popa
    • iret

如果仔细查看堆栈,就会发现还剩下两个push,iret只会跳转到任何值--而不是简历地址。

这就是“尝试在RAM或ROM之外执行代码”的原因。

要修复它,请在iret之前相应地调整堆栈。

另请注意,irq_handler没有使用正确的参数调用,*reg也是假的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38859542

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档