您好、欢迎来到现金彩票网!
当前位置:彩之网 > 中断机制 >

ARM Linux中断机制分析

发布时间:2019-06-16 18:23 来源:未知 编辑:admin

  发生中断时的处理流程,以在usr态发生IRQ为例,即usr>

  发生中断时的处理流程,以在usr态发生IRQ为例,即usr

  异常向量表的建立过程就是拷贝过程,为了将内核代码写成位置无关的,有很多地方需要注意。

  在ARM V4及V4T以后的大部分处理器中,中断向量表的位置可以有两个位置:一个是0x00000000,另一个是0xffff0000。可以通过CP15协处理器c1寄存器中V位(bit[13])控制。V和中断向量表的对应关系如下:

  内核代码编译生成后,需要将异常向量表拷贝到指定位置(0x00000000 or 0xffff0000),这就需要将内核中的异常向量表设计成与位置无关的。

  .align5//将异常入口强制进行2^5字节对齐,即一个cache line大小对齐,出于性能考虑

  sublr, lr, 4//需要调整pc返回值,对于irq异常,将lr减去4,对于其他异常需要作出不同调整

  图一说明:上面两条有方向的横线,横线方向代表地址生长方向,下面那个是Code/Load视图,是搬移前的代码在生成的二进制内核中的组织情况,上面的Exec view是代码在内存中开始执行后的分配情况。

  SPSR_irq = CPSR /*保存处理器当前状态、中断屏蔽位以及各条件标志位*/

  PC=0xFFFF0018 /*将程序计数器(PC)值设置成该异常中断的中断向量地址,从

  *而跳转到相应的异常中断处理程序处执行,对于ARMv7向量表普遍是0xFFFF0018

  sp是SVC32模式下的堆栈指针,这里将它移到r0中,就可以作为C函数的第一个参数,即C函数中的pt_regs参数。

  pc是当前地址+8,也就是本段代码后面紧跟的跳转表的基地址,lr用于在跳转表中索引,lr左移两位等同于*4,因为每个条目是4字节。从usr模式进入irq模式,则lr=pc+4*0,若从svc模式进入irq,则lr=pc+4*3,即__irq_svc的地址,其他地址进入__irq_invalid出错处理,因为不能从其他模式进入irq异常。

  假设这里是从usr进入irq,则执行跳转表中的第一条指令。跳转的基准地址为当前pc,因为ARMv4是三级流水线结构的,它总是指向当前指令的下两条指令的地址,尽管以后版本的指令流水线级,但是这一特性一直被兼容处理,也即pc(excute)=pc(fetch) + 8,其中:pc(fetch)是当前正在执行的指令,就是之前取该指令时候的PC的值;pc(execute):当前指令执行的,计算中如果用到pc,是指此时pc的值。

  当mov指令的目标寄存器是PC,且指令以S结束,则它会把spsr的值恢复给cpsr,上面说到当前的spsr中保存的是r0的值,即svc模式。所以本条指令是跳转到__irq_usr的同时将处理器模式转为svc模式。异常处理一定要进入svc模式的原因是:异常处理一定要进入PL1特权级;另一个原因是使能嵌套中断。具体原因在问题4中解释。关于__irq_svc和__irq_invalid暂时不讨论。

  注意,以下操作都是在svc模式中,因为要借用SVC模式进行ISP处理,所以需要保存所有SVC模式下的寄存器到SVC堆栈中,最后才去调用中断服务例程(ISP)irq_handler。

  usr_entry //用于用户模式下发生中断时初始化中断处理堆栈,同时保存所有SVC态寄存器到堆栈。

  kuser_cmpxchg_check //对低版本的ARM核来说,用户态无法实现原子比较交换。如果用户态在处理原

  get_thread_info宏用来根据当前的sp值,通过lsr和lsl分别右移左移13位,相当于对sp向下圆整到8K对齐。这里也就是thread_info所在的地址。

  如果配置了该选项,平台代码可以修改全局变量:handle_arch_irq,这里只讨论默认实现.

  //会返回到get_irqnr_and_base处,直到所有中断都已经处理完毕才退出循环。

  adrne lr, BSYM(1b)//同理,这里也是将返回地址设置为ALT_SMP的第二条指令,构造成一个循环

  get_irqnr_preamble用于获得中断状态寄存器基地址,特定于CPU,这里CPU用的是tegra,其定义如下

  get_irqnr_preamble和get_irqnr_and_base两个宏由machine级的代码定义,目的就是从中断控制器中获得IRQ编号,紧接着就调用asm_do_IRQ,从这个函数开始,中断程序进入C代码中,传入的参数是IRQ编号和寄存器结构指针,

  asm_do_IRQ是ARM处理硬件中断的核心函数,第一个参数指定了硬中断的中断号,第二个参数是寄存器备份组成的一个结构体,保存了中断发生时的模式对应的寄存器的值,在中断返回时使用。

  irq_enter是更新一些系统的统计信息,同时在__irq_enter宏中禁止了进程的抢占。虽然在产生IRQ时,ARM会自动把CPSR中的I位置位,禁止新的IRQ请求,直到中断控制转到相应的流控层后才通过local_irq_enable()打开。那为何还要禁止抢占?这是因为要考虑中断嵌套的问题,一旦流控层或驱动程序主动通过local_irq_enable打开了IRQ,而此时该中断还没处理完成,新的irq请求到达,这时代码会再次进入irq_enter,在本次嵌套中断返回时,内核不希望进行抢占调度,而是要等到最外层的中断处理完成后才做出调度动作,所以才有了禁止抢占这一处理。

  }// handle_irq是个函数指针,它用来实现中断处理器的电流处理。电流处理分为边

  no_work_pending: //没有抢占或者信号需要处理,或者已经处理完毕,开始退回用户态

  答:(1)内核刚启动时(head.S文件)通过设置CP15的c1寄存器已经确定了异常向量表的起始地址(例如0xffff0000),因此需要把已经写好的内核代码中的异常向量表考到0xffff0000处,只有这样在发生异常时内核才能正确的处理异常。

  (2)从上面代码看出向量表和stubs(中断处理函数)都发生了搬移,如果还用bvector_irq,那么实际执行的时候就无法跳转到搬移后的vector_irq处,因为指令码里写的是原来的偏移量,所以需要把指令码中的偏移量写成搬移后的。至于为什么搬移后的地址是vector_irq+stubs_offset,如图一所示。下图是搬移示意图更加清晰说明了搬移过程。。

  因为b跳转指令只能在+/-32MB之内跳转,所以必须拷贝到0xffff0000附近。

  b指令是相对于当前PC的跳转,当汇编器看到 B 指令后会把要跳转的标签转化为相对于当前PC的偏移量写入指令码。

  答:内核源代码顶层目录下的Makefile制定了vmlinux生成规则:

  如果一个中断模式(例如从usr进入irq模式,在irq模式中)中重新允许了中断,并且在这个中断例程中使用了BL指令调用子程序,BL指令会自动将子程序返回地址保存到当前模式的lr(即r14_irq)中,这个地址随后会被在当前模式下产生的中断所破坏,因为产生中断时CPU会将当前模式的PC保存到r14_irq,这样就把刚刚保存的子程序返回地址冲掉。为了避免这种情况,中断例程应该切换到SVC或者系统模式,这样的线_svc来保存子程序的返回地址。

  由于系统调用异常的代码编译在其他文件中,其入口地址与异常向量相隔较远,使用b指令无法跳转过去(b指令只能相对当前pc跳转32M范围)。因此将其地址存放到LCvswi中,并从内存地址中加载其入口地址,原理与其他调用是一样的。这也就是为什么系统调用的速度稍微慢一点的原因。

  因为ARM架构的CPU有一个机制,只要中断产生了,CPU就会根据中断类型自动跳转到某个特定的地址(即中断向量表中的某个地址)。如下表所示,既是中断向量表。

  A:Uboot执行结束后会把Linux内核拷贝到内存中开始执行,linux内核执行的第一条指令是linux/arch/arm/kernel/head.S,此文件中执行一些参数设置等操作后跳入linux/init/main.c文件的start_kernel函数,此函数调用一系列初始化函数,其中trip_init()函数实现向量表的设定操作。

http://ando2.com/zhongduanjizhi/92.html
锟斤拷锟斤拷锟斤拷QQ微锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷微锟斤拷
关于我们|联系我们|版权声明|网站地图|
Copyright © 2002-2019 现金彩票 版权所有