MPIC 与 PowerPC Linux 中断处理(1)
- UID
- 1066743
|
MPIC 与 PowerPC Linux 中断处理(1)
PowerPC 异常类型与异常向量将处理器内部产生的异常和外部中断信号统一称为异常 (Exception)。异常发生时,PowerPC 处理器根据异常的类型,分别跳转到不同的异常向量地址,执行异常处理程序。异常类型到异常向量的映射,经典 PowerPC 和 Book E 有所不同。
经典 PowerPC异常类型异常向量偏移 (0X)说明 System Reset 00100
Machine Check 00200
DSI 00300 Data Storage Exception ISI 00400 Instruction Storage Exception External Interrupt00500所有外部中断信号 Alignment 00600
…
本文只关注外部中断,完整内容请看处理器手册
根据异常类型得到偏移 offset, 异常向量的物理地址为 :
MSR[IP]=0 时,Vector = offset ;
MSR[IP]=1 时,Vector = offset | 0xFFF00000;
其中 MSR[IP] 代表 Machine State Register 的 Interrupt Prefix 比特,该比特用来选择中断向量的地址前缀。
Book E异常类型异常向量偏移寄存器说明 Critical Input IVOR0 来自 #cint 引脚的外部中断信号 Machine Check IVOR1
DSI IVOR2 Data Storage Exception ISI IVOR3 Instruction Storage Exception External InputIVOR4来自 #int 引脚的外部中断信号 Alignment IVOR5
…
本文只关注外部中断,完整内容请看处理器手册
从异常类型对应的 IVOR(Interrupt Vector Offset Register) 得到偏移 ( 只取低 16 比特 , 最低 4 比特清零 ),加上 IVPR(Interrupt Prefix Register) 的高 16 比特,构成中断向量的地址:
Vector = (IVORn & 0xFFF0) | (IVPR & 0xFFFF0000);
值得注意的是,跟经典 PowerPC 不同,Book E 的中断向量是 Effective Address, 对应 Linux 内核的虚拟地址。
Linux 对 Book E 中断向量寄存器的设置以 Freescale E500 处理器为例,在 arch/powerpc/kernel/head_xxx.S(xxx 为处理器子类型 ) 中,定义了标签 interrupt_base,紧接着就是
各中断向量的处理代码:1
2
3
| interrupt_base:
...
EXCEPTION(0x0500, ExternalInput, do_IRQ, EXC_XFER_LITE)
|
EXCEPTION 这句展开后如下:1
2
3
4
5
| .align 5; //32 bytes aligned
ExternalInput:
NORMAL_EXCEPTION_PROLOG;
addi r3,r1,STACK_FRAME_OVERHEAD;
xfer(0x0500, do_IRQ);
|
这些宏继续展开就是中断处理的代码。后面”中断处理程序”一章有更详细介绍。
在 __early_start 函数中,使用以上代码段的地址设置 IVOR4 和 IVPR:1
2
3
4
5
| li r26, ExternalInput@l; /*IVOR only uses the low 16-bits*/
mtspr SPRN_IVOR4, r26;
......
lis r4, interrupt_base@h /*IVPR only uses the high 16-bits*/
mtspr SPRN_IVPR, r4
|
以上代码把 IVOR4 和 IVPR 分别设置为 ExternalInput 地址的低 16 位和 interrupt_base 的高 16 位。由于 head_xxx.S 编译出来的目标文件链接在内核镜像的最前面,而内核加载地址对齐在比较大的内存块边界上,所以可以保证 interrupt_base 的高 16 位,跟 ExternalInput 的高 16 位,是相同的。
PowerPC 外部中断的屏蔽MSR(Machine Status Register) 的 EE 位 (MSR 的第 16 比特,记为 MSR[EE]) 为 0 时将屏蔽来自 #int 引脚的外部中断,为 1 时使能。
mfmsr 和 mtmsr 指令用来读写 MSR 的内容。格式为:"mfmsr rD", "mtmsr rS"。另外 Book E 还提供专门的指令来写 MSR[EE] 位:wrtee 和 wrteei,格式为"wrtee rS","wrteei E"。其中 E 是立即数 0 或 1。
Linux kernel 中屏蔽和使能外部中断的接口有:
1
2
| local_irq_disable()/local_irq_enable()
local_irq_save()/local_irq_restore()
|
另外,spin_lock_irq, spin_lock_irqsave 也包含以上屏蔽操作。
在 Linux Powerpc 中,以上屏蔽外部中断的操作,都是由内联函数 arch_local_irq_disable 或者 arch_local_irq_save 实现。
arch_local_irq_disable 的代码展开如下:1
2
3
4
5
6
7
8
| #ifdef CONFIG_BOOKE
asm volatile("wrteei 0" : : : "memory");
#else
register unsigned long rval;
asm volatile("mfmsr %0\n" : "=r" (rval));
rval &= ~MSR_EE; /*MSR_EE = 1<<16*/
asm volatile("mtmsr %0" : : "r" (rval) : "memory");
#endif
|
PowerPC 中断的硬件处理流程- 把正在执行的指令序列下一条指令地址保存到 SRR0(Save/Restore Regiser 0)。
- 把当前 MSR 的内容保存到 SRR1。
- 把 MSR 某些比特置为 0,如 PR, EE。
注:PowerPC 有两种执行模式,分别为用户模式 (User Mode) 和特权模式 (Supervisor Mode), MSR[PR]=0 表示特权模式。Linux 内核运行在特权模式,而普通程序运行在用户模式。
- 在新的 MSR 状态下,从中断向量偏移处开始指令读取和执行。
- 外部中断处理结束时,必须通过 rfi 指令返回。rfi 的执行,会把 SRR1 的内容恢复到 MSR, 并从 SRR0 所保存的地址处继续执行。
PowerPC Linux 中断处理程序异常向量 ExternalInput 处的处理程序主要分为以下几个步骤:
- NORMAL_EXCEPTION_PROLOG 宏 建立用户中断处理程序的栈帧,并把一些寄存器的值保存在栈帧中,它们在栈帧中布局由 struct pt_regs 定义。
- 执行 do_IRQ 在 irq_enter() 函数中更新 preempt_count。 读 MPIC 的 IACK 寄存器,通知 MPIC 开始处理该中断,同时获取 MPIC 中断号 , 映射为软件中断号,找到并运行注册在该软件中断号上的用户中断处理程序,最后写 MPIC 的 EOI 寄存器,通知 MPIC 中断处理结束。
在 irq_exit() 中更新 preempt_count, 调用 invoke_softirq() 处理 pending 的软中断。
- ret_from_except 某些条件满足时,进行进程调度和信号处理,最后调用 rfi 指令返回。
中断控制器在什么情况下把外设的中断信号发送给处理器?读 IACK 寄存器得到的是什么?硬件中断号怎么来的?为什么要写 EOI ?中断嵌套?这些问题的答案并不存在于代码中,需要了解 MPIC 的内部逻辑和编程接口才能回答。
|
|
|
|
|
|