字符设备驱动-Linux内核异常处理体系结构

Linux异常处理体系结构

以中断这种异常来举例分析:

当我们在裸机操作中断时候:
① 构建异常向量表
② cpu发生中断,跳到异常向量入口执行
③ 跳转到某函数
③-a 保存被中断的现场
③-b 执行中断处理函数
④-c 恢复现场

Linux驱动层面同样如此:
① 通过trap_init构造异常向量表
② cpu发生中断,跳到异常向量入口执行(b vector_irq + stubs_offset)
③ 跳转到vector_irq用宏实现保存、执行、恢复

 下面来分析一下内核怎样处理中断这种异常的:

内核在asmlinkage void __init start_kernel(void)(源码在init/main.c)中调用trap_init函数来设置异常的处理函数。

Ⅰ.trap_init函数(arch/arm/kernel/traps.c)

通过memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);来将异常向量表拷贝到ARM架构CPU的异常向量基址0xffff0000(还有一种0x00000000)

void __init trap_init(void)
{
#if   defined(CONFIG_KGDB)
    return;
}

void __init early_trap_init(void)
{
memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
    memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
    memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
}
Ⅱ. 搜索__vectors_start(arch\arm\kernel\entry-armv.S)查看异常向量表
.globl  __vectors_start
__vectors_start:
    swi SYS_ERROR0
    b   vector_und + stubs_offset
    ldr pc, .LCvswi + stubs_offset
    b   vector_pabt + stubs_offset
    b   vector_dabt + stubs_offset
    b   vector_addrexcptn + stubs_offset
    b   vector_irq + stubs_offset
    b   vector_fiq + stubs_offset

    .globl  __vectors_end
__vectors_end:

    .data

    .globl  cr_alignment
    .globl  cr_no_alignment
cr_alignment:
    .space  4
cr_no_alignment:
    .space  4
Ⅲ.以irq中断异常为例b vector_irq + stubs_offset,搜索整个文件找不到vector_irq,往上查询得知这是通过vector_stub宏(arch\arm\kernel\entry-armv.S)来定义的:
vector_stub irq, IRQ_MODE, 4

    .long   __irq_usr           @  0  (USR_26 / USR_32)
    .long   __irq_invalid           @  1  (FIQ_26 / FIQ_32)
    .long   __irq_invalid           @  2  (IRQ_26 / IRQ_32)
    .long   __irq_svc           @  3  (SVC_26 / SVC_32)
    .long   __irq_invalid           @  4
    .long   __irq_invalid           @  5
    .long   __irq_invalid           @  6
    .long   __irq_invalid           @  7
    .long   __irq_invalid           @  8
    .long   __irq_invalid           @  9
    .long   __irq_invalid           @  a
    .long   __irq_invalid           @  b
    .long   __irq_invalid           @  c
    .long   __irq_invalid           @  d
    .long   __irq_invalid           @  e
    .long   __irq_invalid           @  f
Ⅳ. 通过搜索vector_stub来查找宏定义
.macro  vector_stub, name, mode, correction=0
    .align  5

vector_\name:
    .if \correction
    sub lr, lr, #\correction
    .endif

    @
    @ Save r0, lr_<exception> (parent PC) and spsr_<exception>
    @ (parent CPSR)
    @
    stmia   sp, {r0, lr}        @ save r0, lr
    mrs lr, spsr
    str lr, [sp, #8]        @ save spsr

    @
    @ Prepare for SVC32 mode.  IRQs remain disabled.
    @
    mrs r0, cpsr
    eor r0, r0, #(\mode ^ SVC_MODE)
    msr spsr_cxsf, r0

    @
    @ the branch table must immediately follow this code
    @
    and lr, lr, #0x0f
    mov r0, sp
    ldr lr, [pc, lr, lsl #2]
    movs    pc, lr          @ branch to handler in SVC mode
    .endm
Ⅴ. 将vector_stub irq, IRQ_MODE, 4参数代入进去
.macro  vector_stub, name, mode, correction=0
    .align  5

vector_irq:
    sub lr, lr, #4
    .endif
    @
    @ Save r0, lr_<exception> (parent PC) and spsr_<exception>
    @ (parent CPSR)
    @
    stmia   sp, {r0, lr}        @ save r0, lr
    mrs lr, spsr
    str lr, [sp, #8]        @ save spsr

    @
    @ Prepare for SVC32 mode.  IRQs remain disabled.
    @
    mrs r0, cpsr
    eor r0, r0, #(\mode ^ SVC_MODE)
    msr spsr_cxsf, r0

    @
    @ the branch table must immediately follow this code
    @
    and lr, lr, #0x0f
    mov r0, sp
    ldr lr, [pc, lr, lsl #2]
    movs    pc, lr          @ branch to handler in SVC mode
    .endm

    .long   __irq_usr           @  0  (USR_26 / USR_32)
    .long   __irq_invalid           @  1  (FIQ_26 / FIQ_32)
    .long   __irq_invalid           @  2  (IRQ_26 / IRQ_32)
    .long   __irq_svc           @  3  (SVC_26 / SVC_32)
    .long   __irq_invalid           @  4
    .long   __irq_invalid           @  5
    .long   __irq_invalid           @  6
    .long   __irq_invalid           @  7
    .long   __irq_invalid           @  8
    .long   __irq_invalid           @  9
    .long   __irq_invalid           @  a
    .long   __irq_invalid           @  b
    .long   __irq_invalid           @  c
    .long   __irq_invalid           @  d
    .long   __irq_invalid           @  e
    .long   __irq_invalid           @  f
Ⅵ. 进入__irq_usr中断模式
__irq_usr:
    usr_entry

#ifdef CONFIG_TRACE_IRQFLAGS
    bl  trace_hardirqs_off
#endif
    get_thread_info tsk
#ifdef CONFIG_PREEMPT
    ldr r8, [tsk, #TI_PREEMPT]      @ get preempt count
    add r7, r8, #1          @ increment it
    str r7, [tsk, #TI_PREEMPT]
#endif

    irq_handler
#ifdef CONFIG_PREEMPT
    ldr r0, [tsk, #TI_PREEMPT]
    str r8, [tsk, #TI_PREEMPT]
    teq r0, r7
    strne   r0, [r0, -r0]
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
    bl  trace_hardirqs_on
#endif

    mov why, #0
    b   ret_to_user

    .ltorg

    .align  5
Ⅶ. 进入irq_handler来调用中断处理总入口函数asm_do_IRQ
.macro  irq_handler
    get_irqnr_preamble r5, lr
1:  get_irqnr_and_base r0, r6, r5, lr
    movne   r1, sp
    @
    @ routine called with r0 = irq number, r1 = struct pt_regs *
    @
    adrne   lr, 1b
    bne asm_do_IRQ

ARM架构Linux内核的异常处理体系结构

这里写图片描述
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

种瓜大爷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值