摘要:在ARM体系结构中,硬件产生的外部中断( IRQ) 具有单一的程序入口。为了识别中断源,进而运行对应的中断服务例程( ISR) ,程序需读取中断悬挂寄存器,获得中断号。在这种方式中,程序必须通过软件方法对中断悬挂寄存器的每一位进行比较,直到找到中断源为止,效率较低。本文移植了基于2.6.11 内核的uClinux ,在此基础上设计了一套向量中断机制,并基于ARM7TDMI 架构的S3C44B0X处理器,实现了这套向量中断机制。结果表明,这套机制可以大规模地减少外部中断的响应时间。 1简介 近年来,基于ARM 架构的处理器凭借其强大的处理能力,较低的功耗以及低廉的价格在嵌入式领域得到广泛应用。Linux 由于其免费,开源的特点,受到越来越多用户的欢迎。在基于ARM 体系结构的Linux 版本中,有两个分支,ARM-Linux 及uClinux ,目前两者都已并入Linux 主流开发树。ARM-Linux 是针对通用的ARM处理器而设计的,具有同普通Linux 完全一样的功能。而uClinux 是针对没有内存管理单元(MMU) 的处理器而设计的。由于没有MMU 的保护等。但是在某些领域,如工控、汽车电子等,存在着大量32 位的低端应用,这些处理器没有MMU 的支持。在这些领域,使用uClinux能充分享有Linux 的几乎所有的优点,同时能降代系统的成本。 在ARM体系中,通常有3 种方法控制指令的流程。程序顺序执行,程序跳转和出现异常。异常有复位(Reset) 、未定义指令(Undefined Instruction) 、软件中断(Software Interrupt SWI) 、指令预取终止(Prefetch Abort) 、数据访问终止(Data Abort) 、外部中断请求( IRQ) 和快速中断请求( FIQ) 七种。这七种异常的处理代码入口,称为异常向量表。本文关注的重点,是其中的外部中断请求IRQ。 ARM核拥有一根外部中断请求信号线nIRQ。每当出现处部中断请求,ARM中断控制器的仲裁机制会根据中断源的优先级确保最高优先级的中断产生IRQ 请求。此时,硬件自动把程序计数器PC 指向0x18 地址,0x18 地址正是在异常向量表中的外部中断请求对应的跳转指令,该指令跳转到内核的特定代码段,读取中断悬挂寄存器,确定中断源,为asm-do-IRQ这个Linux 中断管理函数准备参数并调用该函数。asm-do-IRQ 函数根据中断号调用相应用中断服务例程( ISR) 。这个过程可以由图1 表示。 图1 传统的处部中断处理流程 2 向量中断机制 向量中断并不是一个新的概念,是指在中断产生同时,处理器已经获知产生中断的原因。它与非向量中断主要区别在于:是否需要查询中断号。在Intel 的IA-32 架构中,在实模式下,最低端的1K内存存入的就是中断向量表,它是由BIOS进行初始化的。在保护模式下,中断向量表被称为中断描述符表(Interrupt Description Table -IDT) , IDT 的首地址存储在IDTR硬件寄存器中。两种模式都采用向量中断机制。 在ARM中实现向量中断,第一种方式是设置一个专用的可编程的硬件寄存器,由系统软件负责填充中断向量表,并把该硬件寄存器的内容设置成中断向量表的首地址。第二种方式无需专用的硬件寄存器,外部中断产生后处理器根据中断源产生一个固定的偏移,在特定的地址写入特定的处理代码,不如第一种方式灵活但设计简单。在第二种方式下,每当外部中断产生时,处理流程如图2 所示。 图2 向量中断处理流程 从图1 和图2 可以看出,向量中断省去了查询中断号的时间。 3 实现 实现向量中断需要硬件提供相关的机制,在基于ARM核的处理器中,S3C44B0X处理器具有相应的功能。尽管该处理器的硬件向量中断机制并不十分适合Linux ,但是经过详尽的设计,可以找到变通的方法。如果开启了向量中断机制,在产生外部中断,程序计数器指向0x18 地址的同时,S3C44B0X 处理器的中断控制器在地址总线上根据中断源的类型装载一个跳转指令,该跳转指令的目的地址根据中断号的不同而有所不同。因此,可以事先得到中断号,而无需循环判断中断悬挂寄存器。
3. 1 在uClinux 的一级中断向量表中添加转跳代码 uClinux 的一级中断向理表由表1 所示的指令序列组成,它在trap-init 函数中被拷贝到内存的起始地址0x0c000000 处。为向量中断增加一个入口,它是从Flash 中的Bootloader 跳转到内核的入口,该入口是一条跳转指令,将被trap-init 复制到0x0c000000 地址处。
表1 uClinux 的一级中断向量表 .LCvectors : swi SYS- ERROR0 b - real- stubs- start + (vector-und - - stubs- start) 1dr pc ,- real- stubs- start + (.LCvswi - - stubs- start) b - real- stubs- start + (vector-pabt - - stubs- start) b - real- stubs- start + (vector-dabt - - stubs- start) b - real- stubs- start + (vector-addrexcptn - - stubs- start) b - real- stubs- start + (vector-irq - - stubs- start) b - real- stubs- start + (vector-fiq - - stubs- start) b - real- stubs- start + (vector- s3c44b0x - - stubs- start) @< = 添加的代码
| 3.2 在Bootloader 中安装跳转代码 由于S3C44B0X系统的0x18 地址处于Flash 中,而uClinux 在SDRAM中运行,位于地址0X0C000000 处。因此,要完成向量中断的跳转,首先必须在Flash 中的Bootloader 程序里安装相应的处理代码,获得中断号之后再从Flash 中跳转到uClinux 的一级中断向量表处。Bootloader 中的相关代码片断(使用ADS 编译器) 如表2 所示。
表2 Bootloader 中的代码片断 MACRO VECTOR- ENTRY $VectorIRQNumber 1dr r13 , = 0x0c000014 ;0x0c000014 地址是保留的异常向量, 利用该地址保存临时值 str r14 ,[ r13 ] ;临时存放r14 ,r14 是返回地址+ 4 mov r14 , $VectorIRQNumber str r14 ,[ r13 ,4 ] ;把中断号临时存入0x0c000018 地址 1dr r14 ,[ r13 ] ;恢复r14 b JumpToKernel MEND ;中断向量表,地址固定 VECTOR-BRANCH …… b HandlerTIMER5 ;Timer5 向量中断的地址为0x74 , 由s3c44b0x 硬件决定 …… HandlerTIMER5 Verctor- ENTRY# 8 ;Timer5 对应的中断号为8 JumpToKernel 1dr pc ,VectoIRQKenelAddress VectorIRQKernelAddress DCD 0x0c000020 ; uClinux 的一级中断表的向量中断的入口
| 程序进入HandlerTIMER5 代码段时,处于IRQ 模式,uClinux 没有实现中断栈,无法用堆栈保留中断号,也无法用寄存器保留中断号,否则会破坏程序上下文,因此,本文利用了保留的异常向量(0x0c000014) 保存临时变量,非向量中断模式的内核入口(0x0c00018) 保存中断号。在Timer5 产生中断的情况下,程序的运行轨迹是:
- PC 指向0x18 地址
- 硬件根据Timer5 中断的特点,使PC 指向0x74 地址
- 运行0x74 处( Flash 中,Bootloader 程序) 写入的代码bHandlerTIMER5
- 运行HandlerTIMER5 标号处的代码,把中断号存储在0x0c000018 地址
- 跳转至内核的0x0c000020 处执行b- real- start + (vectors3c44b0x- - stubs- start) 指令
- 进入vector- s3c44b0x 函数,后续处理
3. 3 实现程序上下文保护及处理器模式切换 这一任务由vector- s3c44b0x 及其他一些函数完成。uClinux 内核中断管理模块维护一个全局数组,struct irqdesc irq-desc[NR-IRQS] ;每个中断尖对尖数组中的一个元素, uClinux的驱动程序开发者通过request-irq 或者setup-irq 注册中断服务例程( ISR) 。增加向量中断机制,不能破坏uClinux 的驱动编程的接口,它的实现对驱动程序必须是透明的,否则跟原有的方式不兼容,将毫无意义。因此,在新添加的向量中断方式中, 必须使用跟非向量中断一致的上下文保护机制和寄存器栈定义方式。假设中断在处理器的用户模式(正常程序执行的模式) 下产生,则处理器模式切换的过程如图3 所示。 图3 处理器模式切换示意图 3. 4 设置硬件寄存器,开启向量中断模式 uClinux 初始化中断系统的函数init- IRQ 会调用init-archirq函数,它是一个指向特定平台中断系统初始化函数的指针,在该函数中,设置S3C44B0X处理器中的中断控制寄存器,第2 位置0 ,开启向量中断模式。 4 性能分析与评估 通常,中断响应时间定义为产生硬件中断到开始执行ISR的时间: 中断响应时间tIR = 硬件延迟时间tHL + 中断指派时间tID + 其它时间To 其中硬件延迟时间tHL由硬件特性决定,间隔极短,可以忽略不计。中断指派的时间tID即获得中断号,找到对应中断处理例程( ISR) 的时间,是本文致力于改进的焦点。其它时间To 包括保存程序上下文切换的时间,uClinux 的中断管理函数asm-do-IRQ 中调用ISR 之前的时间。 由于内核的计时系统依赖于时钟中断,而时钟中断本身也是一个外部中断源,所以通过判断jiffies 值,修改HZ值等内核计时方法,是很不准确的。因此,常见的性能测试工具如dhrystone ,1mbench , unixbench 等均无法测试外部中断响应时间。 ARM体系结构使用RISC 指令集,处理器执行的时间和执行的指令数呈近似线性关系 ,评估中断响应时间可以归结为计算执行的指令数。 在非向量中断情况下,假设系统共支持N 个外部中断源,中断悬挂寄存器的每一位表示一个中断源,1 表示该位对应的中断源产生了中断,0 表示该中断源未产生中断。每查找一次中断号,执行mb 条基本指令,如果没查到,将执行一次循环操作,多运行me 条指令。为了简化推理的过程,假设每个外部中断源产生中断的概率是均等的,并且不允许中断嵌套,即中断悬挂寄存器中,有且令有一位为1。设 1 中断悬挂寄存器出现中断 X={ 0 中断悬挂寄存器没有中断 1 中断悬挂寄存器出现中断 Xi ={ 0 中断悬挂寄存器没有中断(0≤i≤N - 1) 假设期望值E(x) 表示产生外部中断后中断指派阶段平均执行的指令数,则E(xi) 表示中断悬挂寄存器第i 位出现中断时中断指派阶段执行的指令数。由于中断悬挂寄存器中每一位出现1 的概率是均等的,所以有: 这样,得到公式(1) : E(xi) = p (xi = 1) ×mb + p (xi = 0) ×(mb + i×me) 公式(1) 把相关变量代入、化简得: 所以有公式(3) : 在向量中断方式中,从产生外部中断到获得中断号,整个过程中执行的指令数由实现方式决定,由于无需查询中断悬挂寄存器,该值是常量。为了使用向量中断而必须做一些额外的工作,假设额外执行的指令数为mv 。设ms 为除中断指派之外所有共他的批令数,μ为向量中断比非向量中断少执行的指令数的比例,则得到公式(4) : 在S3C44B0X非向量中断的实现中,查找中断号的伪代码如下所示: base =中断悬挂寄存器的映射地址; base =中断悬挂寄存器的值; irq-number = 0 ; LOOP: base 最低位是否为1 ; 为1 ,找到中断号,跳转到END irq-number = irq-number+1 base = base 右移1 位; irq-number 与最大的中断号; 如小于,跳转到LOOP END: 可见,基于的指令数mb 等于5 ,每执行一次循环,多执行的指令数me 等于6。 在本文实现的向量中断机制中,额外执行的指令数mv 为7。除中断指派之处所有其他的脂令数ms 与C 语言代码asmdoIRQ有关,计算相对复杂,根据反汇编的结果,按照每次访问3 个单位指令数来计算,ms 大约为600。 根据公式(4) 得到,在S3C44B0X处理器下,采用向量中断比非向量中断效率提升η, 图4 η- N 曲线图 ms ,mv ,mb ,me 的值由软件设计决定,在不同的平台上基本固定。不同的是N 值。因此,η是N 的单元函数,如图4 所示。N 值越大,η也越大,性能提升越多。提升幅度随着N 的增大越来越缓慢。 S3C44B0X处理器支持26 个中断源,计算得到η等于76.7 % ! 由于充分利用了S3C44BOX硬件提供的向量中断机制,向量中断方式使得中断响应时间大幅度降低。 5 末来的工作 在实际系统中,中断产生的概率并不是均等的。时钟中断产生的频率非常高,在网络应用中,网络中断产生的频率远比其他外设产生中断的频率高,因此需修正本文提出数字模型。同时,本文也没有考虑中嵌套的情况,对ms 值的测试出不够精确,需要在未来的工来中加以改进。 6 结论 针对ARM体系结构通常不支持向量中断的情况,本文提出了一种向量中断机制,并基于S3C44B0X处理器的硬件功能,在uClinux 2.6 内核上,实现了这种机制。由于uClinux 和ARM- Linux 的外部中断管理部分差别不大,本文实现的向量中断机制完全可以应用在ARM-Linux 系统中。分析结果表明,采用上向量中断方式,能大幅度地降低中断响应时间,提升系统的实时性能。处理器支持的外设越多,性能提升也越多。在对中断响应时间要求苛刻的实时系统中,本文提出的向量中断机制具有广阔的应用前景。
|