xen中的中断和异常

可编程控制器APIC的作用就是观察IRQ线,并且将接收的IRQ信号转换为中断向量.

IRQ描述符(irq_desc_t)

irq_desc[]数组包含NR_IRQS个IRQ描述符,和IDT中的门描述符一一对应,IRQ描述符提供服务的PIC电路信息,当前IRQ的状态.

typedef struct irq_desc {
    unsigned int status;        /* IRQ status */
    hw_irq_controller *handler;//指向与pic电路的I/O交互函数
    struct msi_desc   *msi_desc;
    struct irqaction *action;   /* IRQ action list */
    int irq;//irq号
    spinlock_t lock;
    struct arch_irq_desc arch;
    cpumask_var_t affinity;

    /* irq ratelimit */
    s_time_t rl_quantum_start;
    unsigned int rl_cnt;
    struct list_head rl_link;
} __cacheline_aligned irq_desc_t;

IDT的建立,IDT的第一次初始化是在进入保护模式之前.

        /* Initialise IDT with simple error defaults. */
        leaq    ignore_int(%rip),%rcx
        movl    %ecx,%eax
        andl    $0xFFFF0000,%eax
        orl     $0x00008E00,%eax
        shlq    $32,%rax
        movl    %ecx,%edx
        andl    $0x0000FFFF,%edx
        orl     $(__HYPERVISOR_CS64<<16),%edx
        orq     %rdx,%rax
        shrq    $32,%rcx
        movl    %ecx,%edx
        leaq    idt_table(%rip),%rdi
        movl    $256,%ecx
1:      movq    %rax,(%rdi)
        movq    %rdx,8(%rdi)
        addq    $16,%rdi
        loop    1b

第二次初始化

void __init init_IRQ(void)
{
    int vector, irq, cpu = smp_processor_id();

    init_bsp_APIC();

    init_8259A(0);

    BUG_ON(init_irq_data() < 0);

    for ( vector = FIRST_DYNAMIC_VECTOR; vector < NR_VECTORS; vector++ )
    {
        if (vector == HYPERCALL_VECTOR || vector == LEGACY_SYSCALL_VECTOR)
            continue;
        BUG_ON(!interrupt[vector]);
        set_intr_gate(vector, interrupt[vector]);
    }

    for (irq = 0; platform_legacy_irq(irq); irq++) {
        struct irq_desc *desc = irq_to_desc(irq);
        
        if ( irq == 2 ) /* IRQ2 doesn't exist */
            continue;
        desc->handler = &i8259A_irq_type;
        per_cpu(vector_irq, cpu)[FIRST_LEGACY_VECTOR + irq] = irq;
        cpumask_copy(desc->arch.cpu_mask, cpumask_of(cpu));
        desc->arch.vector = FIRST_LEGACY_VECTOR + irq;
    }
    
    per_cpu(vector_irq, cpu)[IRQ0_VECTOR] = 0;

    apic_intr_init();

    /* Set the clock to HZ Hz */
#define CLOCK_TICK_RATE 1193182 /* crystal freq (Hz) */
#define LATCH (((CLOCK_TICK_RATE)+(HZ/2))/HZ)
    outb_p(0x34, PIT_MODE);        /* binary, mode 2, LSB/MSB, ch 0 */
    outb_p(LATCH & 0xff, PIT_CH0); /* LSB */
    outb(LATCH >> 8, PIT_CH0);     /* MSB */

    setup_irq(2, &cascade);
}
第二次初始化为中断设置了一个公共的处理函数common_interrupt,该函数主要完成3项工作,保存寄存器的值,调用do_IRQ,跳转到中断返回函数ret_from_intr

#define BUILD_COMMON_IRQ()                      \
__asm__(                                        \
    "\n" __ALIGN_STR"\n"                        \
    "common_interrupt:\n\t"                     \
    STR(SAVE_ALL) "\n\t"                        \
    "movq %rsp,%rdi\n\t"                        \
    "callq " STR(do_IRQ) "\n\t"                 \
    "jmp ret_from_intr\n");

#define BUILD_IRQ(nr)                           \
    "pushq $0\n\t"                              \
    "movl $"#nr",4(%rsp)\n\t"                   \
    "jmp common_interrupt"

整个中断的初始化构成就完成了.

看看一个物理中断发生的响应过程是怎样的

一个中断的发生首先APIC将IRQ转化为中断向量,根据中断向量来调用IDT中的中断处理函数,即SAVE_ALL do_IRQ,ret_from_intr

do_IRQ将中断分发给每个domain去处理,domain中的物理中断和事件通道绑定,即事件通道会被设置为1,

evtchn_do_upcall----->do_IRQ---->__do_IRQ

虚拟中断没有APIC的那一部分,直接设置对应事件通道的pending位

中断由设备来申请,申请中会填写中断号对应的irq_desc结构,并将处理历程加入到中断的处理队列中.


xen中异常的处理

在xen的启动阶段,xen会设置异常的处理函数trap_init,其中会调用percpu_traps_init来完成超级调用,双重错误,NMI延迟的异常的初始化.处理程序的功能是:

保存寄存器的值,跳转到异常处理函数,返回.

guestOS的异常处理

启动时候通过超级调用初始化VIDT,异常发生的时候先由xen处理异常,如果是guest_mode则交给do_guest_trap来处理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值