IOAPIC重定位中断处理函数思路整理

因为小可并非硬件编程出身,汇编基础又比较差。。。所以刚开始理解利用IOAPIC重定位技术的时候相当困难。

何为IOAPIC?

首先,必须认识到它是一个硬件,可编程的硬件。我理解的它在整个流程中的作用如图:

首先,必须创建一个新的中断项,也就是在IDT表中搜索到一个空闲的项,代码如下

P2C_U8 p2cGetIdleIdtVec()
{
    P2C_U8 i;
    PP2C_IDTENTRY idt_addr = (PP2C_IDTENTRY)p2cGetIdt();

    // 从vec20搜索到2a即可。
    for(i=0x20;i<0x2a;i++)
    {
        // 如果类型为0说明是空闲位置,返回即可。
        if(idt_addr[i].type == 0)
        {
            return i;
        }
    }
    return 0;
}

复制中断表中索引为0x93的项到新项

P2C_U8 p2cCopyANewIdt93(P2C_U8 id,void *interrupt_proc)
{
    // 我们写入一个新的中断门。这个门完全拷贝原来的0x93
    // 上的idtentry,只是中断处理函数的地址不同。
    PP2C_IDTENTRY idt_addr = (PP2C_IDTENTRY)p2cGetIdt();
    idt_addr[id] = idt_addr[0x93];
    idt_addr[id].offset_low = P2C_LOW16_OF_32(interrupt_proc);
    idt_addr[id].offset_high = P2C_HIGH16_OF_32(interrupt_proc);
    return id;
}

然后将ioapic重定位表中关于键盘中断IRQ1的处理地址替换掉,修改ioapic重定位表需要使用两个寄存器。

一个是IOREGSEL寄存器(只低8位有用)     一个是IOWIN寄存器(32位)

首先在IOREGSEL寄存器指定要访问的ioapic寄存器的编号,然后修改IOWIN寄存器中的内容即可达到目的

Windows把这两个寄存器分别映射到内存的物理地址0xFEC00000和0xFEC00010处

获取IOREGSEL寄存器的代码为

P2C_U8 *io_reg_sel;
    PHYSICAL_ADDRESS    phys ;
    PVOID paddr;
    RtlZeroMemory(&phys,sizeof(PHYSICAL_ADDRESS));
    phys.u.LowPart = 0xfec00000;
    paddr = MmMapIoSpace(phys, 0x14, MmNonCached);

IOWIN寄存器往后偏移0x10

    P2C_U32 *io_win;
    io_win = (P2C_U32 *)((P2C_U8 *)(paddr) + 0x10);

然后使用IOREGSEL寄存器选择第0x12项,为IRQ1的项

*io_reg_sel = 0x12;

设置新的中断号

        ch1 = *io_win;
        ch1 &= 0xffffff00;
        ch1 |= (P2C_U32)new_ch;
        *io_win = ch1;

完成!

 

posted @ 2015-05-04 13:05  银翼的魔术师  阅读(1860)  评论(0编辑  收藏  举报