Interrupt in Linux(硬件篇)—— APIC2

1.2.2 LAPIC

收到来自IOAPIC的中断消息后,LAPIC会将该中断交由CPU处理。和IOAPIC比较,LAPIC具有更多的寄存器以及更复杂的机制。但对于处理来自IOAPIC的中断消息,最重要的寄存器还是IRRISR以及EOI

1-4显示了x86平台上,IRRISR的格式:

 

1-4 IRRISR构成

PIC中的IRRISR不同的是,LAPICISRIRR均为256bit寄存器,对应x86平台上的256个中断vector,其中0~15为架构预留。

u       IRR:功能和PIC的类似,代表LAPIC已接收中断,但还未交CPU处理。

u       ISR:功能和PIC类似,代表CPU已开始处理中断,但还未完成。与PIC有所不同的是,当CPU正在处理某中断时,同类型中断如果发生,相应的IRR bit会再次置一(PIC模式下,同类型的中断被屏蔽);如果某中断被pendingIRR中,同类型的中断发生,则ISR中相应的bit被置一。这说明在APIC系统中,同一类型中断最多可以被计数两次(想不通什么意思?想不通就联想一下Linux可信信号)。超过两次时,不同架构处理不一样。对于Pentium系列CPUP6架构,中断消息被LAPIC拒绝;对于Pentium4Xeon系列,新来的中断和IRR中对应的bit重叠。

笔者:上图还有个TMR寄存器,即Trigger Mode Register,用于表示当前正在处理中断的触发模式。1level0edge。对于level触发的中断,当软件写EOI时,会被广播到所有IOAPIC,消息中含有中断的vectorIOAPIC收到后检查自己的PRT表,把相应RTERemote IRR位清零。

对于IRRx86 spec说:CPU准备处理中断时,IRR中最高优先级的bit被清零,ISR中对应bit被置一。这样说不能算错,但至少不准确。根据《Multi-Processor Computer System With Interrupt Controllers Providing Remote Reading》一文中APIC的实现,只有对于edge触发的中断,ISR对应bit置一时IRR相应 bit才清零。对于level触发,IRR中的bit保留到软件写EOILAPIC收到IOAPIC发出的Level-deassert消息后才清零。

如果你仔细看了前面关于Remote IRR的介绍,此时一定会产生一个疑问。这里说同类型中断发生两次,会同时PendingISRIRR的对应bit中。问题是,前面Remote IRR的异或逻辑保证了在写EOI前,新的中断不会发过来啊?呵呵,或许你想到答案了,这种pending两次的机制,只对edge触发中断有效。

PIC一样,LAPIC同样需要软件写EOI来知会中断处理的完成,不同的是,LAPIC中的EOI是一个32bit寄存器,如下图:

 

1-5 EOI寄存器格式

X86架构中,对EOI0表示中断处理完成。由上述几个寄存器相互配合,一个典型的LAPIC中断处理流程是:

对于Pentium4Xeon系列:

1.         通过中断消息的destination field字段,确定该中断是否是发送给自己的。

2.         如果该中断的delivery modeNMISMIINITExtINTSIPI,直接交由CPU处理。

3.         如果不为2)中所列的中断,置一IRR中相应的bit

4.         当中断被pendingIRRISR中后,根据TPRPPR寄存器,判断当前最高优先级的中断是否能发送给CPU处理。

5.         软件写EOI通知中断处理完成。如果中断为level触发,该EOI广播到所有IOAPIC(见前)。NMISMIINITExtINTSIPI类型中断无需写EOI

 

对于Pentium系列和P6架构:

1.         确定该中断是否由自己接收。如果是一个IPI,且delivery modelowest priorityLAPIC与其它LAPIC一起仲裁该IPI由谁接收。

2.         若该中断由自己接收,且类型为NMISMIINITExtINITINIT-deassert、或MP协议中的IPI中断(BIPIFIPISIPI),直接交由CPU处理。

3.         将中断pendingIRRISR,若该已有相同的的中断pendingIRRISR上,拒绝该中断消息,并通知IOAPIC “retry”

4.         Pentium4Xeon系列流程。

5.         Pentium4Xeon系列流程。

1.2.3 IOAPIC发出的中断消息是如何找到LAPIC的?

上面两个流程的第一步都是确定是否由自己接收中断。前面我们提到,RTE中的Destination Field用于指定由哪个APIC接收,并且分为PhysicalLogical两种模式。对于LAPIC,两种模式有着不同的意义。

Physical模式:在该模式下,RTE中的Destination Field表示的是LAPIC ID。对于LAPIC来说,系统在RESET后,都会分配一个唯一的ID用作标识。在X86平台下,我们可以通过LAPIC ID寄存器得到它。图1-6为其格式:

 

 

1-6 Local APIC ID

操作系统或BIOS,通常会使用LAPIC ID唯一的标识一个CPU。在Pentium系列和P6架构中,由于APIC BUS最多只支持15LAPIC ID,即一个MP平台最多只能有15CPURTE中的destination field表示LAPIC ID时只用了4bitLAPIC ID寄存器也只有4bit可用。对于Pentium4Xeon系列,APIC ID被扩展至8bit,最多支持255LAPIC。系统RESET后,可以用CPUID指令(EAX写参数1EBX24~31即为返回的ID)获得默认的LAPIC ID。某些CPU允许软件更改默认的ID号,但通常来说,软件应该避免这样的行为。无论何时,CPUID指令返回的都是系统RESET后默认分配的LAPIC ID,即使当前的LAPIC ID寄存器已经被软件更改过。

题外话——关于APIC ID

APIC ID分为LAPIC IDIOAPIC ID。前者唯一的标识系统中某个LAPIC,后者唯一标识某个IOAPICLAPIC ID前面已经介绍了,根据MP specMultiple Processor Specification,多处理器规范)规定,LAPIC ID必须唯一,但可以不连续。与LAPIC ID不同,IOAPIC ID在系统RESET后统一清零,操作系统或BIOS负责验证IOAPIC ID是否唯一,如果有冲突检测到,由操作系统或BIOS重新分配。重分配的原则是从系统中所有LAPIC ID后最小的数字开始分配。例如当前系统有两个LAPICID01,则分配IOAPIC ID应该从2开始。

需要注意的是,MP specAPIC ID的分配规则只适用于系统用APIC BUS的情况。X86 spec4bitLAPIC ID可以表示15CPU,还有一个哪儿去了?我想是留给IOAPIC了。

笔者:LAPIC ID是从0开始分配的,IOAPIC ID在系统RESET后自动清0MP spec操作系统在探测到IOAPIC ID冲突时,有义务为它分配一个新的ID”。那相同的LAPIC IDIOAPIC ID算不算冲突呢?算,但是对于Pentium4Xeon系列使用前端总线通讯的系统,”It’s not an issue”。在此种系统中,LAPIC是要用ID参与前端总线竞争的,IOAPIC却不用,因为是北桥代理它竞争总线。IOAPIC ID只用于区分多个IOAPIC,它和LAPIC ID不在一个上下文。

APIC BUS下,IOAPIC ID要用于竞争总线,不能和LAPIC ID冲突,分配规则题外话中已说明。

当中断消息通过Physical模式发送时,LAPIC通过LAPIC ID来判断该中断是否由自己接收。

Logical模式:在该模式下,中断消息中的Destination Field包含的不是LAPIC ID,而是被称为MDAMessage Destination Address,消息目的地地址)的信息。此时,LAPIC需要两个额外的寄存器来判断自己是否为中断消息的目的地。它们是LDRDFR

LDR的格式如图1-7所示:

 

1-7 LDR格式

LDR全称是Logical Destination Register,逻辑目的地寄存器。该寄存器包含一个8bit的逻辑APIC ID(注意区分,它和LAPIC ID不是一个东西),在Logical模式下用于和MDA匹配。LDR的格式由DFR指定,DFR如图8所示:

 

1-8 DFR格式

DFRDestination Format Register,目的地格式寄存器。该寄存器包含一个4bitmode字段,用于指定LDR中的Logical APIC ID用何种方式与MDA匹配。通过这两个寄存器的配合,Logical模式又被分为了FlatCluster两种模式。

u       Flat模式:DFRmodel值为1111b,此时,LAPICMDALDRlogical APIC ID做位与,如结果不为0则接收中断。Logical APIC ID中每个bit代表一个LAPIC,故8bit最多代表8CPU

u       Cluster模式:DFRmodel值为0000b。我不得不说我可能会把你搞晕了,但实际上确实如此,x86TMD复杂了。Cluster模式又分为两种模式:Flat Cluster模式和Hierarchical Cluster模式。

l         Flat Cluster模式:该模式只支持P6架构和Pentium系列CPU,并假定所有APIC通过APIC BUS通讯。该模式将MDA编码为两个部分,高4bit为簇号,低4bit标识LAPIC在该簇内的ID(每个bit代表一个LAPIC,故一个簇最多有4LAPIC)。与之对应,LDRlogical APIC ID也被编码成同样两个部分。

工作在该模式时,LAPIC先将MDA的高4bitLogical APIC ID的高4bit比较,以确定自己是否是中断的目的簇。若是,将MDA的低4bitLogical APIC ID的低4bit位与,若值不为0则接收中断。否则拒绝。

通过这种方法,高4bit的簇号可以表示15个簇,低4bitID可以代表簇内的4CPU,最多可以支持60CPU。但由于APIC BUS的限制,具体的说是APIC Arb IDAPIC仲裁ID)的限制,该模式最多只支持15CPU

l         Hierarchical Cluster模式:支持P6架构和Pentium系列,以及XeonPentium4系列。该模式通过为每个簇引入一个簇管理器,将Flat Cluster模式中平等的簇构成一个具有等级结构的分级网络,并最多支持60CPU。这个话题太远了,相关spec没有更多资料,就不多做介绍了。

笔者:不要问我Hierarchical Cluster模式下,P6架构和Pentium系列如何突破APIC BUS对于15CPU的限制的,我真的不知道。

    通过这种方法,高4bit的簇号可以表示15个簇,实际上应该是0~1516个簇,但MDA1时为广播到所有LAPIC,笔者认为簇号1111b被预留给广播模式了。

对于Flat Cluster模式,我们举个例子吧(此例中,中断为Fix delivery mode。关于Lowest Prority的例子见后面内容)。假设有三个CPUlogical模式配置为(此时DFRmodel值为0000b):CPU1LDR值为0000 0001bCPU2LDR值为0001 0010bCPU3LDR值为0000 0100b,则CPU1CPU3为一簇,CPU2为另一簇。IOAPIC发出一条中断消息,其Destination Mode1destination field值为0000 00001b。三个LAPIC收到该消息后,CPU1CPU3通过destination field的高4bit判断出该消息目的地为本簇,再将自身Logical APIC ID的低4bitdestination field4bit位与,最终CPU1接收该中断消息,CPU2CPU3丢弃。

1-9总结了中断消息的Destination Field字段用于寻址LAPIC的几种模式:

 

1-9 Destination Field模式

1.2.4 TPRPPRAPRLowest priority —— 中断发给Whom

RTEdelivery mode有一中模式为lowest priority,即最低优先级,它是Linux配置RTE时使用的模式。这里的最低优先级不是指中断的优先级,而是指将中断发送给destination field列出的CPU中,优先级最低的一个。如何决定一个CPU的优先级呢?x86平台依靠TPR寄存器和PPR寄存器。

TPRtask priority register,任务优先级寄存器,它确定当前CPU可处理什么优先级别范围内的中断。具有如下的格式:

 

1-10 TPR寄存器

TPR寄存器接收0~1516个值,对应16CPU规定的中断优先级级别,值越大优先级越高。CPU只处理比TPR中值优先级别更高的中断。例如TPR中值为8,则级别小于等于8的中断被屏蔽(注意,屏蔽不代表拒绝,LAPIC接收它们,把它们pendingIRR中,但不交CPU处理。见前面LAPIC中断处理流程)。值15表示屏蔽所有中断;值0表示接收所有中断,噢,这也是LinuxTPR设置的默认值。注意,TPR是由软件读/写的,硬件不更改它。

题外话 —— x86的中断优先级级别

我们知道每个中断都有一个vector与之对应,x86平台共有256vector,除去架构预留和被异常等占去的0~31vector,可供外部中断使用的还有224个(噢,实际上只有223个,还要除去一个INT 80)。中断的优先级别由下列公式:

优先级别 = vector / 16

这里“/”c语言的除,不是数学里的除号,所以我们是没有小数的。16~255vector构成了1~1515个优先级别,中断拥有2~15级别。对于同一个级别的中断,vector号越大的优先级越高。例如vector3334都属于级别234的优先级就比33高。所以,对于8bitvector,又可以划分成两部分,高4bit表示中断优先级别,低4bit表示该中断在这一级别中的位置。

噢,应该讲清楚了,记住,TPR的值增加1,将会屏蔽16vector对应的中断。NMISMIExtINTINITstart-up delivery的中断不受TPR约束。

笔者:TPR,任务优先级寄存器 ,很容易的就让人和进程的优先级联想到一起。实际上,x86spec也强调这里的“Task”代表操作系统中的进程、线程、任务、程序 ……不过,Linux的进程优先级和它没有关系。如果Linux的中断处理例程线程化了,如果Linux具有更强的实时性,如果Linux跟着WindowsSolaris学习,如果 …… Linux或许会把它和进程优先级挂上勾。现在嘛,Linux没有那样做。不过,APIC设计TPR的目的,真是给Task用的,期望进程切换时也会更新TPR值,这是APIC的历史文档告诉我们的。

TPR8bit组成,从图中我们可以看到,0~1516个值应该写到高4bit去。如果我们同时也写了低4bit会怎么样?从关于TPR的论述来看,CPU会忽略低4bit的值。

PPRProcessor priority register,处理器优先级寄存器。该寄存器决定当前CPU正在处理的中断的优先级级别,以确定一个PendingIRR上的中断是否发送给CPU。与TPR不同,它的值由CPU写而不是软件写。PPR取值范围为[0,15],计算方式由下列伪代码描述:

If TPR[7:4] >= ISR[7:4] THEN

    PPR[7:0] = TPR[7:0]

ELSE

PPR[7:4] = ISRV[7:4]

PPR[3:0] = 0

这里,ISRV[7:4]标识当前ISR中,最高优先级中断对应vector的高4bit,如前面所说,这代表了该中断的优先级级别。简而言之,取TPR和正在服务的最高优先级中断中,优先级级别高的。好了,都知道了,IRRpending的中断,优先级级别必须高于PPR中值才会被发送给CPU处理,否则,继续等 ……

谁是Lowest Priority

有了前面两个寄存器的论述,现在可以看看Lowest Priority是怎么决定的了。先来从Pentium4Xeon系列说吧,它们要简单点(实际上更复杂,但因为资料少,我可以说的简单点。具体信息?去看mindshare那本讲前端总线的书吧,2000多页的英文读本)

对于这个系列,LAPICIOAPIC通过前端总线通讯。X86 spec对这个描述是:芯片组负责从destination filed列出的CPU中,选出一个优先级最低的接收中断。如果是Pentium4CPU会用一个特殊的总线周期(bus cycle)将每个CPU当前的任务优先级提交到总线,芯片组记录它们,并作为挑选最低优先级CPU的依据。完了,够简单吧^_^

笔者:从spec来看,无论是Xeon还是Pentium4,都是由芯片组选最低优先级CPU。依据是什么?spec讲的不清楚。但对于pentium4,提到了用一个特殊的bus cycle将当前各CPUtask priority提交到总线。这个task priority具体指什么?spec也没说。但在TPR相关章节中有这么一句话:注意,task priority用于决定CPU的仲裁优先级(见8.6.2.4Lowest Priority Delivery Mode。虽然没有明说,但我们有理由认为,这里的task priority就是TPR的值。

 P6架构的系统,依靠一个APR寄存器(Arbitration Priority Register,优先级仲裁寄存器)决定CPU优先级,其格式如图1-11

 

1-11 APR寄存器

APR值可由下列伪代码计算:

If ( (TPR[7:4] >= IRRV[7:4]) && (TPR[7:4] > ISRV[7:4]) )

   APR[7:0] = TPR[7:0]

Else

{

   APR[7:4] = max(TPR[7:4],IRRV[7:4],ISRV[7:4])

   APR[3:0] = 0

}

上述代码表述了这么一个意思:当TRP的值大于IRR中最高优先级中断的优先级级别,并大于ISR中最高优先级中断的优先级级别时,APR等于TPR。否则,APR4bitTPRIRRVISRV三者中优先级级别最高的;低4bit0

题外话 —— Focus Processor

对于P6架构和Pentium系列CPUspec提到了一个Focus Processor的概念。如果一个中断A正在被某CPU1处理,或者pendingCPU1IRR上,则称CPU1为中断AFocus Processor。当系统中有Focus Processor存在时,Focus Processor可能(may)接收该中断,不管自身的优先级是多少。Xeon系列没有Focus Processor的概念。

笔者:关于Focus Processor是尽量按spec的原话翻译,当然,E文水平有限,翻译的不好。不过大概就是这个意思。Focus Processor在哪儿设定?伪中断寄存器(见后面的伪中断相关内容)。spec说:“If a focus processor exists, it may accept the interrupt, regardless of its priority”spec用了一个may。这种不清不楚的用词太万恶了,让人完全搞不清楚它什么时候会may,什么时候又may not。不管怎样,Focus Processor给了我们这样一种暗示,即当系统中大量产生同一种中断时,该中断会被发送给同一个CPU处理。这样的好处是可以避免cache颠簸,缺点也十分明显:运行在该CPU上的进程可能饿死、中断处理过慢、系统中断负载不平衡 …… 我们又注意到,Xeon系列取消了这个功能,应该是顺应民心吧。既然已经有了PRT表,CPU就不应该再提供这种重定向中断的功能。

发了一堆牢骚,其实情况没那么糟糕。Focus Processor只对edge触发中断有效。而目前平台上大量使用的PCIlevel触发的。为什么?想想Focus Processor的定义,再去看看前面关于同类型中断pending两次的说明吧。

我们来举一个Pentium4Xeon系列优先级仲裁的例子,说明谁是Lowest Priority。假设有CPU1CPU2CPU3三个CPU,相应的TPR值为:TPR1=5TPR2=6TPR3=10IOAPIClowest priority模式发送一条中断消息,该中断对应的优先级级别为3。则CPU1具有最低优先级,接收该中断。此时,该中断被pendingIRR中,但不会交给CPU处理,因为其优先级级别低于TPR值。

至此,IOAPICLAPIC相互配合的中断机制已经大体介绍完了,其中提到了一部分寄存器和它们的功用。APIC的其它内容在后面分析Linux实现时补充,一次把硬件内容写完,你看着烦,我写着也累,而且逻辑容易乱。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值