ReactOS源代码分析APIC机制

来源:互联网 发布:乌鲁木齐seo 公司 编辑:程序博客网 时间:2024/06/18 04:21

上图是APIC的组成,其中PIIX3是一个和之前标准中断控制器兼容的中断控制器,而Host-to-PCI桥是系统中与外设相连的桥(可能是北桥)。APIC包含IOAPIC和Local APIC,Local APIC包含在处理器内部,Local APIC用于处理器之间的相互中断,而IOAPIC处于系统芯片组中,IOAPIC用于处理外部IO提交的中断。IOAPIC和Local APIC通过APIC总线进行数据和控制的传送。不过,在IOAPIC和Local APIC之间传递的不是简单地电平信息,所有的中断在IOAPIC中编码成中断消息之后传递给Local APIC。

IOAPIC包含一系列可以变成的寄存器,这些寄存器中的IOREGSEL和IOWIN被编码到处理器的内存地址空间中,同时可以利用这两个寄存器间接访问其他的APIC寄存器。在Windows系统中将Local APIC的地址映射到映射到物理地址0XFFE00000,IOAPIC默认的物理地址是0XFEC00000。当然,物理地址最终还是要调整为虚拟地址进行访问的。Local APIC映射到内存地址空间的虚拟地址为0XFFFE0000,而IOAPIC映射的虚拟地址是0XFFD06000.

为了访问IOAPIC的寄存器,首先写一个字节到IOREGSEL寄存器中。这8位作为IOAPIC中将被访问的寄存器的索引号,而IOWIN寄存器中的数据将被写入到指定的寄存器中,需要注意的是IOWIN被当做一个双字格式进行访问。下表是每个寄存器在IOAPIC中的偏移,而Local APIC中的寄存器相对IOAPIC要多,在英特尔的官方文档的第三册的第十章有介绍。

Local APIC中相应寄存器的偏移在APIC.h头文件中有定义。

APIC系统支持255个中断向量,但是Intel保留了0-15号向量,可用的向量是16-25,同时引进一个概念叫做任务优先级。windows系统中的IRQL等于任务优先级/16,所以可用的优先级是2-15.这个任务优先级存放在本地APIC的任务优先级寄存器TPR中。优先级低于TPR优先级的中断都会被屏蔽,而同一个任务优先级中的16个中断向量可以进一步细粒度地区分中断的优先级。

VOIDFORCEINLINEApicRaiseIrql(KIRQL Irql){    ApicWrite(APIC_TPR, IrqlToTpr(Irql));}

这是提升系统的IRQL的操作,写操作的实现根据上面的介绍很简单.利用APIC_TPR作为偏移,APIC中的IOREGSEL作为基地址,然后将IrqToTpr作为数据存放到IOWIN中,就实现将相应的TPR写入到Local APIC的任务优先级寄存器中。

下面是IOAPIC中关于IO重定位表的定义:

typedef union _IOAPIC_REDIRECTION_REGISTER{    ULONGLONG LongLong;    struct    {        ULONG Long0;        ULONG Long1;    };    struct    {        ULONGLONG Vector:8;        ULONGLONG DeliveryMode:3;        ULONGLONG DestinationMode:1;        ULONGLONG DeliveryStatus:1;        ULONGLONG Polarity:1;        ULONGLONG RemoteIRR:1;        ULONGLONG TriggerMode:1;        ULONGLONG Mask:1;        ULONGLONG Reserved:39;        ULONGLONG Destination:8;    };} IOAPIC_REDIRECTION_REGISTER;

通过上面的定义可以发现,整个IO重定位表一项包含8个字节。最低8位表示中断向量,正好是256项。然后三位表示中断的发送模式,主要定义目标对中断的相应操作。接下来一位用于指示最高8位怎样指定处理中断的目标,因为有可能需要指定处理中断的处理器。而发送状态位则指示整个中断发送之后的状态。polarity设置中断激发的电平。remoteIRR则用于设置水平激发的中断,当IOAPIC接受中断的时候,设置这个位为1,在中断处理之后设置这个位为0.TriggerMode则用于指示激发模式。Mask则用于设置这个中断是否被屏蔽。

BOOLEANNTAPIHalEnableSystemInterrupt(    IN ULONG Vector,    IN KIRQL Irql,    IN KINTERRUPT_MODE InterruptMode){    IOAPIC_REDIRECTION_REGISTER ReDirReg;    PKPRCB Prcb = KeGetCurrentPrcb();    UCHAR Index;    Index = HalpVectorToIndex[Vector];    if (Index == 0xff)    {        return FALSE;    }    ReDirReg = ApicReadIORedirectionEntry(Index);    if (ReDirReg.Vector != Vector)    {        ReDirReg.Vector = Vector;        ReDirReg.DeliveryMode = APIC_MT_LowestPriority;        ReDirReg.DestinationMode = APIC_DM_Logical;        ReDirReg.Destination = 0;    }    if (ReDirReg.DestinationMode == APIC_DM_Logical)    {        ReDirReg.Destination |= ApicLogicalId(Prcb->Number);    }    ReDirReg.TriggerMode = 1 - InterruptMode;    ReDirReg.Mask = FALSE;    ApicWriteIORedirectionEntry(Index, ReDirReg);    return TRUE;}

上面是对APIC中的中断重定位表的设置,首先读取原来的IO重定位表,如果和现在的目标向量不对应则重新设置中断向量,以及发送模式和目标,最后将修改后的重定位表填充到APIC的表项当中。

KIRQLFASTCALLHalpVectorToIrql(UCHAR Vector){    return TprToIrql(Vector);}UCHARFASTCALLHalpVectorToIrq(UCHAR Vector){    return HalpVectorToIndex[Vector];}
上面两个函数体现了中断向量和IRQL以及中断信号的管理。TprToIrql通过将Vector除以16得到索引号寻找数组当中的Irql,实质上这里的vector更像是一个任务优先级。而Vector也会有一个函数将其进行一定的映射,得到IDT表项的入口索引,在中断发生的时候作为IDT的索引查找系统中的中断处理向量。











0 0
原创粉丝点击