字符设备驱动-Linux内核异常处理体系结构
2017-08-30 15:27
459 查看
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内核的异常处理体系结构
相关文章推荐
- 第12课第4.1节 字符设备驱动程序之中断方式的按键驱动_Linux异常处理结构
- 字符设备驱动笔记——中断方式按键驱动之linux异常处理结构(四)
- 第12课第4.2节 字符设备驱动程序之中断方式的按键驱动_Linux中断处理结构
- 字符设备驱动笔记——中断方式按键驱动之linux中断处理结构(五)
- Linux内核代码笔记5----I/O体系结构和设备驱动模型
- Linux异常处理体系结构
- 【linux驱动笔记】字符设备驱动相关数据结构与算法
- Linux内核分析(五)----字符设备驱动实现
- LCD设备驱动的体系结构
- java中从Spring、Hibernate和Struts框架的action、service和dao三层结构异常处理体系设计
- 【linux驱动笔记】字符设备驱动相关数据结构与算法
- 一种面向服务体系结构中消息层异常处理方法
- Linux 字符设备驱动结构(四)—— file_operations 结构体知识解析
- Linux 字符设备驱动结构(一)—— cdev 结构体、设备号相关知识解析
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】深入剖析Linux中断机制之三--Linux对异常和中断的处理
- 简单的LINUX字符设备驱动及编译进Linux内核
- Linux内核分析(五)----字符设备驱动实现
- Linux内核之字符设备驱动
- 2-1、2-2字符设备驱动基本结构
- 字符设备驱动结构