linux中的异常体系

基于s5pv210cpu在linux2.6.35.6中的异常体系介绍:

 

start_kernel:
    setup_arch:
        early_trap_init:构建异常向量表(一些固有的跳转程序)

异常向量表如下所示
异常向量表:
__vectors_start:
 ARM(    swi    SYS_ERROR0    )
 THUMB(    svc    #0        )
 THUMB(    nop            )
    W(b)    vector_und + stubs_offset
    W(ldr)    pc, .LCvswi + stubs_offset
    W(b)    vector_pabt + stubs_offset
    W(b)    vector_dabt + stubs_offset
    W(b)    vector_addrexcptn + stubs_offset
    W(b)    vector_irq + stubs_offset
    W(b)    vector_fiq + stubs_offset

    .globl    __vectors_end
__vectors_end:

vector_irq使用#+name宏来定义(在linux内核中使用广泛):
    .macro    vector_stub, name, mode, correction=0
    .align    5
vector_\name:
    .if \correction
    sub    lr, lr, #\correction
    .endif

    mrs    r0, cpsr
    eor    r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
    msr    spsr_cxsf, r0

    and    lr, lr, #0x0f
 THUMB(    adr    r0, 1f            )
 THUMB(    ldr    lr, [r0, lr, lsl #2]    )
    mov    r0, sp
 ARM(    ldr    lr, [pc, lr, lsl #2]    )
    movs    pc, lr            @ branch to handler in SVC mode
ENDPROC(vector_\name)

    .align    2
    @ handler addresses follow this label
1:
    .endm


下面以中断这个异常向量为例进行中断处理的分析:
W(b)    vector_irq + stubs_offset  执行vector_irq处的代码,stubs_offset用来重新定位跳转的位置
该段代码主要将中断返回地址保存在栈中,进入管理SVC模式

__irq_usr:
    usr_entry  宏,保存现场
    irq_handler  进行中断处理的宏
        asm_do_IRQ  进行中断处理的c函数
            generic_handle_irq
                generic_handle_irq_desc 
                    desc->handle_irq(irq, desc);   每一个中断号对应一个中断描述符,通过中段描述符中的处理函数进行中断处理

                   或者__do_IRQ(irq)    可以配置使用中断线程,是否使用中断线程由action->handler函数的返回值决定

在 Linux 中,中断具有最高的优先级。不论在任何时刻,只要产生中断事件,内核将立即执行相应的中断处理程序,等到所有挂起的中断和软中断处理完毕后才能执行正常的任务,因此有可能造成实时任务得不到及时的处理。中断线程化之后,中断将作为内核线程运行而且被赋予不同的实时优先级,实时任务可以有比中断线程更高的优先级。这样,具有最高优先级的实时任务就能得到优先处理,即使在严重负载下仍有实时性保证。但是,并不是所有的中断都可以被线程化,比如时钟中断,主要用来维护系统时间以及定时器等,其中定时器是操作系统的脉搏,一旦被线程化,就有可能被挂起,这样后果将不堪设想,所以不应当被线程化。 
        

for (irq = IRQ_EINT(0); irq <= IRQ_EINT(15); irq++)
        set_irq_chip(irq, &s5p_irq_vic_eint);

    for (irq = IRQ_EINT(16); irq <= IRQ_EINT(31); irq++) {
        set_irq_chip(irq, &s5p_irq_eint);
        set_irq_handler(irq, handle_level_irq);
        set_irq_flags(irq, IRQF_VALID);
    }

可见IRQ_EINT(0)到IRQ_EINT(15)没有设置set_irq_handler(irq, handle_level_irq)。由下面代码:

if (likely(desc->handle_irq))
        desc->handle_irq(irq, desc);
    else
        __do_IRQ(irq);

可知IRQ_EINT(0)到IRQ_EINT(15)可以进行配置中断线程

 

上面追述到了使用中断描述符中的中断处理函数进行中断处理,在什么地方将这个描述符的成员进行填充呢?

上面那个问题的入口从init_IRQ函数开始
init_IRQ:
    init_arch_irq() 函数指针  真正调用的是s5pv210_init_irq,在开发板machine_desc结构体中定义
        s5p_init_irq
            vic_init   填充四组中断的irq_dsc
            s3c_init_vic_timer_irq   填充定时器中断的irq_desc
            s3c_init_uart_irqs  填充串口中断的irq_desc
            
上面主要初始化的是内部中断
            
arch_initcall(s5p_init_irq_eint)    
#define arch_initcall(fn)        __define_initcall("3",fn,3)
#define __define_initcall(level,fn,id) \
    static initcall_t __initcall_##fn##id __used \
    __attribute__((__section__(".initcall" level ".init"))) = fn
    上面这段代码在段.initcall3.init中定义了函数s5p_init_irq_eint
    
    
思考:定义这个函数在什么地方进行调用呢?
start_kernel
    rest_init
        kernel_init   进程1
            do_basic_setup
                do_initcalls   该函数中调用了所有在initcall段中的函数
                    
思考:s5p_init_irq_eint该函数做了什么呢?
这个函数主要初始化了外部中断:
s5p_init_irq_eint
    set_irq_chip   设置chip进行底层的硬件相关处理
    set_irq_handler    设置irq_desc中的中断处理函数
                
        
irq_handle处理中断函数handle_level_irq,最终调用的是action->handler

下面就是action这个结构是什么时候构造的呢?
request_threaded_irq   构造action
    __setup_irq    链入action   综合考虑中断的触发方式、是否共享等
        irq_chip_set_defaults  使用默认填充irq_desc中的chip成员
            __irq_set_trigger
                chip->set_type  设置外部中断触发类型
        desc->chip->startup  开启中断使能中断
                
        
构造的action怎样释放呢?
free_irq(unsigned int irq, void *dev_id)
    kfree(__free_irq(irq, dev_id))
        __free_irq(unsigned int irq, void *dev_id)
上面代码主要是从链表中释放action对象,如果释放后链表中再也没有action对象则关闭中断

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值