Chinaunix首页 | 论坛 | 博客
  • 博客访问: 386099
  • 博文数量: 44
  • 博客积分: 2060
  • 博客等级: 上尉
  • 技术积分: 528
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-17 20:50
文章分类
文章存档

2011年(1)

2010年(28)

2008年(15)

分类: LINUX

2008-04-28 21:12:58

Linux的中断子系统

从这章开始,我们来看看Linux中断子系统的实现。

、Pin、GSI、Vector

这几个概念经常把人搅晕掉,下面的内容经常要用到它们,还是先说清楚为妙。

IRQ是PIC时代的产物,由于ISA设备通常是连接到固定的PIC管脚,所以说一个设备的IRQ实际是指它连接的PIC管脚号。IRQ暗示着中断优先级,例如IRQ0比IRQ3有着更高的优先级。当前进到APIC时代后,或许是出于习惯,人们仍习惯用IRQ表示一个设备的中断号,但对于16以下的IRQ,它们可能不再与IOAPIC的管脚对应,例如PIT此时接的是2号管脚。

Pin是管脚号,通常它表示IOAPIC的管脚(前面说了,PIC时代我们用IRQ)。Pin的最大值受IOAPIC管脚数限制,目前取值范围是[0,23]。

GSI是ACPI引入的概念,全称是Global System Interrupt。它为系统中每个中断源指定一个唯一的中断号。下图展示了GSI的思想:

图2-1

图2-1中有3个IOAPIC:IOAPIC0~2。IOAPIC0有24个管脚,其GSI base为0,每个管脚的GSI=GSI base + pin,故IOAPIC0的GSI范围为[0~23]。IOAPIC2有16个管脚,GSI base为24,GSI范围为[24,39],依次类推。ACPI要求ISA的16个IRQ应该被identify map到GSI的[0,15]。

IRQ和GSI在APIC系统中常常被混用,实际上对15以上的IRQ,它和GSI相等。我们在谈到IRQ时,一定要注意它所处的语境。

Vector是CPU的概念,是中断在IDT表中的索引。每个IRQ(或GSI)都对应一个Vector。在PIC模式下,IRQ对应的vector=start vector + IRQ;在APIC模式下,IRQ/GSI的vector由操作系统分配。

中断探测

操作系统如何知道平台上硬件中断系统的情况?BIOS告诉它的。表,是BIOS报告系统资源的通常方式。MP spec定义了MP table,ACPI规范定义了MADT(Multiple APIC Description Table)。虽然构建方式不一样,但从OS看来两者大同小异,都支持LAPIC entry、IOAPIC entry,以及其它几个与它们相关的entry。这些entry描述了平台APIC硬件的情况。下面根据Linux两条不同的中断探测路径,介绍如何根据MP table或MADT构建中断子系统的主要数据结构。

关键数据结构

Linux最初实现的是MP spec相关规范,故定义一组符合MP spec的数据结构来管理平台硬件。ACPI被引入后,虽然汇报硬件资源的方式变了,但仍可以使用MP spec的数据结构来管理。Linux的ACPI解析路径,实际上是用ACPI的方式读表,填充MP spec的数据结构。由此看来,我们只要理解MP spec数据结构就可以了,和中断相关的有如下几个:

笔者:这些结构体和MP spec规定的各个entry结构是相同的,下面表格将两者列在一起说明,以后就不单独画MP spec各entry的结构表了。

struct mpc_config_ioapic:对应MP spec的IOAPIC entry ,各字段如下:

结构体成员

MP spec字段

长度(byte)

描述

mpc_type

TYPE

1

类型,2(IOAPIC ENTRY)

mpc_apicid

IOAPIC ID

1

IOAPIC ID

mpc_apicver

IOAPIC Version

1

IOAPIC版本

mpc_flags

IOAPIC Flags:EN

1

最低bit有效,其余bit预留

0:IOAPIC disabled

1:IOAPIC enabled

mpc_apicaddr

IOAPIC Address

4

该IOAPIC基地址

表2-1 IOAPIC entry和struct mpc_config_ioapic

内核用mp_ioapics全局数组存放系统中所有IOAPIC对应的struct mpc_config_ioapic,nr_ioapics为IOAPIC数量。目前Linux最多支持64个IOAPIC,当数量超过时可以配置MAX_IO_APICS宏扩大限制。

struct mpc_config_intsrc:对应MP spec的IO interrupt entry,代表各个中断源(一个IOAPIC管脚连接一个中断源)各字段如下:

结构体成员

MP spec字段

长度(byte)

描述

mpc_type

TYPE

1

3(IOAPIC interrupt)

mpc_irqtype

INTERRUPT TYPE

1

INT:APIC模式中断

NMI:不可屏蔽中断

SMI:系统管理中断

ExtINT:vector由PIC提供。如果8259用作外部PIC,即PIC INTR接APIC的一个管脚,vector由8259提供

mpc_irqflag

PO:位于2byte 0bit

EL:位于2byte 1bit

2

PO:中断管脚极性

EL:触发模式

mpc_srcbus

SOURCE BUS ID

1

产生中断的总线

mpc_srcbusirq

SOURCE BUS IRQ

1

相对于产生中断的总线,该中断管脚代表的中断号。例如0,相对于ISA总线即IRQ0

mpc_dstapic

DESTINATION IOAPIC ID

1

该中断连接的IOAPIC。0xff标识连接到所有的IOAPIC

mpc_dstirq

DESTINATION IOAPIC INTN#

1

连接到IOAPIC的管脚号

表2-2 IO interrupt entry和mpc_config_intsrc

不同总线中断共享情况:如果两个IO interrupt entry的destination(IOAPIC ID、INTN#)相同,则共享。例如IPCI-device1/INTA#和ISA-IRQ2如对应相同的destination,则两者共享,接同样的IOAPIC和INTN#。

中断共享和中断丢失

我们不讨论Level触发的情况,因为意义不大,它可以共享且不会丢失中断。

Edge触发,问题就比较多了。它通常对应ISA设备,一个常见的说法是“ISA设备不能共享中断”,但也有人说这是个“superstition”(内核邮件列表曾有关于它的争论)。

从能找到的资料来看,标准的ISA设备是不支持中断共享的,但问题是有很多非标准实现的存在。从操作系统的角度看,支持ISA中断共享并非难事,我们完全可以使用level触发同样的方式去处理edge触发(例如Linux的实现)。Edge共享的一个难题是,当一个设备在另一个设备的中断正在被处理时发起中断,该中断会丢失(或者说要等到另一个设备再发起中断时才会处理),因为此时该中断管脚通常是被屏蔽的。为了解决这个问题,一些非标准的实现会用“re-trigger while in service”、“sequencing of interrupt-generating”加以保证。前者会在一个中断服务完后再触发一次中断;后者会保证中断事件顺序产生,即处理完一个再产生一个。无论怎样,我们尽量在操作系统中支持ISA中断共享,但应该认识到edge中断是不应该共享的。

从理论上分析,edge中断会丢失,Edge中断丢失出现在中断管脚被mask,设备又发起中断时。对于PIC,通过IMR屏蔽中断管脚时,到来的中断仍然会pending在IRR中,unmask中断会提交给CPU。对于APIC,操作系统在进行中断处理时不mask中断(至少Linux如此),尽力保证不丢中断。

内核用mp_irqs全局数组记录系统中所有的mpc_config_intsrc。目前支持的最大数——MAX_IRQ_SOURCES为256。

Struct mpc_config_lintsrc:定义和mpc_config_intsrc一样。只是mpc_dstapic代表LAPIC,且mpc_dstirq只能取值0或1。

阅读(3872) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~