没有合适的资源?快使用搜索试试~ 我知道了~
Linux_的异常处理 很强大的分析
5星 · 超过95%的资源 需积分: 30 277 下载量 144 浏览量
2012-09-04
12:59:31
上传
评论 5
收藏 1.25MB PDF 举报
温馨提示
试读
28页
Linux的驱动机制及实现.pdf 很详细 Linux的虚拟文件系统.pdf Linux_的异常处理.pdf 三部
资源推荐
资源详情
资源评论
Linux 的异常处理
---------------by gyj
导语
导语导语
导语:
::
:
Linux 内核作为一个完整的镜像,被 Bootloader 从外存储器(如 NandFlash)中复制到
RAM 指定区域(S3C6410 平台为 0xC0008000 的虚拟地址,物理地址为 0x50008000),所以
可以将 linux 内核看成一个完整的程序。该程序首先在 disable 中断的情况下,完成硬件以及
各种内核功能软件的初始化,之后初始化 init 进程(SWAP 进程)和某些内核线程,enable
中断之后,开始按照既定策略进行调度。
Linux 由此进入正常的运行状态,之后一段程序(用户空间的或者内核空间的)将一直
在 CPU 上执行,直到程序执行结束或发生任何 Exception。发生 Exception 时,CPU 自动进入
内核态(ARM 的 SVC 态),根据发生的 Exception 类型的不同,linux 内核将可能处理外设 IO、
切换进程、管理内存分配、提供系统服务等一系列操作。所以 Linux 的动态运行可以认为完
全是由 Exception 事件驱动的。
本文介绍了 linux 2.6.28 内核的 Exception 处理机制,并具体分析了基于 ARM1176JZS
(ARMv6)的 S3C6410 处理器的 Exception 处理的实现过程。
一、 ARM 处理器的异常结构
1.1 异常与中断
在大多数体系的 CPU 架构(x86,ARM,PowerPC 等)中,都支持异常(Exception)
事件,而通常与外设相关中断(Interrupt)则作为 Exception 的一种类型来处理。
因此,无论是发生中断还是其他类型的 Exception,软件都通过统一的入口进行处
理,这个统一的入口被称为 Exception 向量,将在下节介绍。
1.2 ARM 的 Exception 类型和 Exception 向量
当任何类型的 Exception(包括 interrupt)发生时,CPU 将会自动跳转到某个固
定地址开始执行那里的指令。ARM 架构的 CPU,会根据 Exception 的类型,跳转到
类型对应的地址。ARMv6 支持如下几种类型的 Exception:
图中显示,所有 7 种类型的 Exception 的跳转地址按顺序从基地址开始排列,被称
为 Exception 向 量 。 ARMv6 支 持 两 种 基 地 址 ( Normal:0x00000000,High
vector:0xFFFF0000),具体使用哪个基地址,由 ARMv6 内部的 Control Register 的
bit13(V bit)设定。Linux 使用 High vector,需要注意的是,Exception 向量地址也是
虚拟地址(如果使用了虚拟地址机制)。
1.3 ARMException 向量的代码(for Linux)
向量中每种 Exception 对应的代码仅 4Byte,刚够一个 32 位指令,因此 Exception
向量由跳转指令组成。代码在 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:
其中.globl __vectors_start 和.globl __vectors_end 用于标示 向量的首尾 地
址,在 linux 初始化时会利用这两个标示将 Exception 向量复制到对应的基地址
(0xFFFF0000)。
Vector_xxx+stubs_offset 表明了 xxx 类型的 exception 发生时将要跳转到的地址。
Stubs_offset 是 Linux 对处理代码重定位时产生的地址偏移。
Vector_xxx 由 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
ENDPROC(vector_\name)
.endm
name:要生成的 vector_xxx 中的 xxx,比如 vector_stub irq, IRQ_MODE, 4,生成 vector_irq,
即 Exception 向量中 IRQ 对应的跳转地址。
mode:设定 CPU 模式位(CPSR 的 M[4:0]),从而可以操作对应模式的特殊寄存器。
correction:用以修正 Exception 返回后的地址。由于 ARM 采用流水线技术,执行到产生 Exception
的指令 n 时,PC 实际上已经又向下取了若干条指令 n+x,因此返回地址必须退回到发生 Exception
的指令接下来的第一条指令 n+1。根据 Exception 类型的不同,X 取值不同。
该宏产生的 vector_xxx 程序段,首先修正 LR 寄存器,用于 Exception 返回时能跳到正确地
址,然后保存了一些状态寄存器等,最后取出 Exception 之前的 SPSR(保存了发生 Exception 时
的 CPSR),通过其中的 M[3:0]作为 index,跳转到紧跟在 vector_xxx 后面的例程数组地址。以
Data Abort Exception 为例:
vector_stub dabt, ABT_MODE, 8
.long __dabt_usr @ 0 (USR_26 / USR_32)
.long __dabt_invalid @ 1 (FIQ_26 / FIQ_32)
.long __dabt_invalid @ 2 (IRQ_26 / IRQ_32)
.long __dabt_svc @ 3 (SVC_26 / SVC_32)
.long __dabt_invalid @ 4
.long __dabt_invalid @ 5
.long __dabt_invalid @ 6
.long __dabt_invalid @ 7
.long __dabt_invalid @ 8
.long __dabt_invalid @ 9
.long __dabt_invalid @ a
.long __dabt_invalid @ b
.long __dabt_invalid @ c
.long __dabt_invalid @ d
.long __dabt_invalid @ e
.long __dabt_invalid @ f
由于 linux 仅使用 usr/svc 两种状态,所以处理例程的数组中,除了 index=0/3 之外,都认为
无效。
1.4 ARM 异常的处理例程及异常返回
vector_xxx 程序执行到最后,即跳转到对应的例程地址,该例程将完成对应 Exception 处理
的所有工作,并且最终返回到异常发生前的地址。
以在用户状态下,发生 irq 异常为例进行分析,这是应用程序运行时遇到外设中断的情况,也是
linux 运行时遇到的最常见的 Exception 情况。
__irq_usr:
usr_entry @保存 usr 空间各寄存器的宏
kuser_cmpxchg_check
#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 @irq 的处理例程
#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 @返回到 usr 空间
ENDPROC(__irq_usr)
1.4.1 usr_entry
将 user 空间内(即发生 Exception 前)的 r0~r12,SP(r13),LR(r14)保存在栈内,
同时也将发生 Exception 的返回 LR(LR_e),发生 Exception 的 SPSR(SPSR_e)
保存在栈内。
1.4.2 kuser_cmpxchg_check
ARMv6 以下版本使用的原子访问检查。
1.4.3 irq_handler
获取 IRQ 号,并且将 IRQ 号保存在 r0 中,将 Exception 之前的所有寄存器
的值保存在栈内,并且把栈地址保存在 r1 中,然后跳转至 C 语言函数
asm_do_IRQ(unsigned int irq, struct pt_regs *regs),该函数利用 r0,r1 内的值
作为参数。
1.4.4 ret_to_user
当 asm_do_IRQ()返回后,退出 Exception,恢复 Exception 发生前的状态。
二、 Linux 需要处理的异常
Linux 内核包含内存管理、进程调度、设备驱动、系统调用等多个功能模块。在用
户态的应用程序执行时,一旦发生某种异常,Linux 进入异常处理之后,通常会使用相
关的一个或者几个功能模块进行管理和服务。ARM 体系的 CPU 所包含的各种异常类型
与 Linux 的功能模块之间对应关系大致如下:
Reset 系统热重启,CPU 各寄存器状态为运行时的状态。Exception 引起
(SYS_ERROR0 号)系统调用。
Undefined 出现未知异常,linux 可以将发生异常时相关的寄存器信息打印至控
制台。
Software interrupt Linux 通过此 Exception 对应用程序提供系统调用功能。
Prefetch Abort 取指异常,Linux 内存管理模块在发生该异常时进行处理,可能执行
分配内存、换入内存等操作。
Data Abort 访问虚拟地址时发生的异常,Linux 的内存管理、设备驱动、进程调
度等模块可能处理该异常。进行内存分配、换入内存、进程休眠、调
度等操作。
IRQ 异步中断异常,通常与设备驱动有关,也可能引起进程调度模块进行
切换进程等工作。
FIQ 快速异步中断异常,Linux 通常不使用这种 Exception。
三
三三
三、
、、
、
Linux 对
对对
对 IRQ 异常的处理
异常的处理异常的处理
异常的处理
Linux 对 IRQ 异常处理的第一个 C 函数为 asm_do_IRQ(unsigned int irq, struct pt_regs *regs),
该函数与 CPU 体系相关,两个参数分别为 IRQ 号及保存了 IRQ 发生前各寄存器的栈指针。
本节首先说明 S3C6410 平台下如何获取 IRQ 号,然后详细说明 linux 内部获得 IRQ 号之后进
行的所有处理。
3.1 S3C6410 获取 IRQ 号
Irq_handler 的宏定义如下:
.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 *
@
剩余27页未读,继续阅读
zhanglu231123
- 粉丝: 235
- 资源: 100
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
- 1
- 2
前往页