linux忽略abort信号,ARM Linux Data Abort 异常处理流程
// 本文部分内容来自网络
//基于内核版本3.4
发生Data Abort异常后,ARM处理器首先根据向量表找到对应异常入口,向量表位于arch/arm/kernel/entry-armv.S:
.globl__vectors_start
__vectors_start:
ARM(swiSYS_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
对于data abort,对应的跳转地址是vector_dabt + stubs_offset。这个地址的指令定义也在entry-armv.S
/*
* Data abort dispatcher
* Enter in ABT mode, spsr = USR CPSR, lr = USR PC
*/
vector_stubdabt, 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
怎么将vector_dabt + stubs_offset和上述代码对应起来呢?将vector_stub的宏定义展开就能看出:
/*
* Vector stubs.
*
* This code is copied to 0xffff0200 so we can use branches in the
* vectors, rather than ldr's. Note that this code must not
* exceed 0x300 bytes.
*
* Common stub entry macro:
* Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
*
* SP points to a minimal amount of processor-private memory, the address
* of which is copied into r0 for the mode specific abort handler.
*/
.macro vector_stub, name, mode, correction=0
.align 5
vector_\name:
.if \correction
sub lr, lr, #\correction
.endif
@
@ Save r0, lr_ (parent PC) and spsr_
@ (parent CPSR)
@
stmia sp, {r0, lr} @ save r0, lr
mrs lr, spsr @保存跳转之前的CPSR到lr寄存器
str lr, [sp, #8] @ save spsr
@
@ Prepare for SVC32 mode. IRQs remain disabled.
@
mrs r0, cpsr
eor r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
msr spsr_cxsf, r0 @准备进入svc模式
@
@ the branch table must immediately follow this code
@
and lr, lr, #0x0f @得到跳转前所处的模式(usr、svr等)
THUMB( adr r0, 1f )
THUMB( ldr lr, [r0, lr, lsl #2] )
mov r0, sp
ARM( ldr lr, [pc, lr, lsl #2] ) @根据模式跳转到相应的data abort指令,并进入svc模式
movs pc, lr @ branch to handler in SVC mode
ENDPROC(vector_\name)
.align 2
@ handler addresses follow this label
1:
.endm
对于同一个异常,根据进入异常之前所处的模式,会跳转到不同的指令分支,这些指令分支紧跟在vector_stub宏定义的后面。如果进入data abort之前处于usr模式,那么跳转到__dabt_usr;如果处于svc模式,那么跳转到__dabt_svc;否则跳转到__dabt_invalid。 实际上,进入异常向量前Linux只能处于usr或者svc两种模式之一。这时因为irq等异常在跳转表中都要经过vector_stub宏,而不管之前是哪种状态,这个宏都会将CPU状态改为svc模式。 usr模式即Linux中的用户态模式,svc即内核模式。
__dabt_svc流程,调用dabt_helper继续:
__dabt_svc:
svc_entry
mov r2, sp
dabt_helper
@
@ IRQs off again before pulling preserved data off the stack
@
disable_irq_notrace
#ifdef CONFIG_TRACE_IRQFLAGS
tst r5, #PSR_I_BIT
bleq trace_hardirqs_on
tst r5, #PSR_I_BIT
blne trace_hardirqs_off
#endif
svc_exit r5 @ return from exception
UNWIND(.fnend )
ENDPROC(__dabt_svc)
dabt_helper流程,调用CPU_DABORT_HANDLER继续:
.macro dabt_helper
@
@ Call the processor-specific abort handler:
@
@ r2 - pt_regs
@ r4 - aborted context pc
@ r5 - aborted context psr
@
@ The abort handler must return the aborted address in r0, and
@ the fault status register in r1. r9 must be preserved.
@
#ifdef MULTI_DABORT
ldr ip, .LCprocfns
mov lr, pc
ldr pc, [ip, #PROCESSOR_DABT_FUNC]
#else
bl CPU_DABORT_HANDLER
#endif
.endm
#ifdef CONFIG_KPROBES
.section .kprobes.text,"ax",%progbits
#else
.text
#endif
CPU_DABORT_HANDLER是一个宏定义,以armv6架构为例,最终函数为v6_early_abort
# define CPU_DABORT_HANDLER v6_early_abort
v6_early_abort:
首先读取DFSR和DFAR两个协处理寄存器,保存在R1和R0中,然后调用do_DataAbort进入C语言环境:
ENTRY(v6_early_abort)
mrcp15, 0, r1, c5, c0, 0@ get FSR
mrcp15, 0, r0, c6, c0, 0@ get FAR
bdo_DataAbort
DFSR:失效状态寄存器,Data Fault Status Register -> R1: fsr
DFAR:失效地址寄存器,Data Fault Address Register ->R0:addr
do_DataAbort:
asmlinkage void __exception
do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
const struct fsr_info *inf = fsr_info + fsr_fs(fsr);
struct siginfo info;
if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs))
return;
printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n",
inf->name, fsr, addr);
info.si_signo = inf->sig;
info.si_errno = 0;
info.si_code = inf->code;
info.si_addr = (void __user *)addr;
arm_notify_die("", regs, &info, fsr, 0);
}
const struct fsr_info *inf = fsr_info + fsr_fs(fsr):
根据FSR的状态值,查询fsr_info表,得到相应处理函数与信号值。
struct fsr_info {
int(*fn)(unsigned long addr, unsigned int fsr, struct pt_regs *regs);
intsig;
intcode;
const char *name;
};
static struct fsr_info fsr_info[] = {
{ do_bad,SIGBUS, 0,"unknown 0"},
{ do_bad,SIGBUS, 0,"unknown 1"},
{ do_bad,SIGBUS, 0,"unknown 2"},
{ do_bad,SIGBUS, 0,"unknown 3"},
{ do_bad,SIGBUS, 0,"reserved translation fault"},
{ do_translation_fault,SIGSEGV, SEGV_MAPERR,"level 1 translation fault"},
{ do_translation_fault,SIGSEGV, SEGV_MAPERR,"level 2 translation fault"},
{ do_page_fault,SIGSEGV, SEGV_MAPERR,"level 3 translation fault"},
{ do_bad,SIGBUS, 0,"reserved access flag fault"},
{ do_bad,SIGSEGV, SEGV_ACCERR,"level 1 access flag fault"},
{ do_bad,SIGSEGV, SEGV_ACCERR,"level 2 access flag fault"},
{ do_page_fault,SIGSEGV, SEGV_ACCERR,"level 3 access flag fault"},
......
fsr_info数组列出了常见的地址失效处理方案,例如do_page_fault处理缺页中断,do_translation_fault处理转换错误,其他不能处理的默认为do_bad:
static int
do_bad(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
return 1;
}
do_bad不做任何处理,返回1后再调用arm_notify_die后处理:
void arm_notify_die(const char *str, struct pt_regs *regs,
struct siginfo *info, unsigned long err, unsigned long trap)
{
if (user_mode(regs)) {
current->thread.error_code = err;
current->thread.trap_no = trap;
force_sig_info(info->si_signo, info, current);
} else {
die(str, regs, err);
}
}
arm_notify_die函数判断当前处于Kernel模式还是User模式,如果是Kernel模式直接die,如果是User模式,调用force_sig_info向进程强制发送fsr_info表中对应信号,强制发送信号可以忽略信号处理的SIG_IGN标记,和stask_struct的blocked域。进程收到信号后,接着进行coredump等流程。
linux忽略abort信号,ARM Linux Data Abort 异常处理流程相关推荐
- linux忽略的信号可以被子进程继承,linux – 可以忽略(丢失)信号吗?
我有一个通过信号与工人沟通的应用程序(特别是SIGUSR1 / SIGUSR2 / SIGSTOP). 我能相信无论发生什么,每个信号都将由处理程序传递和处理吗? 如果信号的发送速度快于应用程序处理信 ...
- arm linux 2.6下载,ARM+LINUX(montavista2.6.x)环境下SIMCOM5218使用
ARM+LINUX(montavista2.6.x)环境下 SIMCOM5218使用 http://blog.sina.com.cn/s/blog_4c796ed20100hpxg.html 一. 系 ...
- linux中swi指令,Arm Linux系统调用流程详细解析SWI
Unix系统通过向内核发出系统调用(system call)实现了用户态进程和硬件设备之间的大部分接口.系统调用是操作系统提供的服务,用户程序通过各种系统调用,来引用内核提供的各种服务,系统调用的执行 ...
- arm linux 指纹识别,基于ARM—Linux指纹识别系统的设计.pdf
基于ARM-Linux指纹识别系统的设计.pdf 第 20卷 第 l5期 电子设计工程 2012年 8月 Vo1.20 No.15 ElectronicDesienEn~inee Aug.2012 基 ...
- linux进程被信号杀死,Linux 命令 - kill: 向进程发送信号
kill 命令通常用来 "杀死"(终止)进程,它可以用来终止运行不正常的程序或者反过来拒绝终止的程序.kill 命令准确地说并不是 "杀死" 进程,而是给进程发 ...
- linux进程被信号杀死,linux杀死进程以及发送或响应信号
摘要 腾兴网为您分享:linux杀死进程以及发送或响应信号,真还赚,邮币在线,优美图,小t智联等软件知识,以及idevice,cdr条码生成器,二手车闪卖,卡卡日语,微帮手,arpr,萤石云监控,nf ...
- 最新linux伺服控制,基于ARM Linux的三轴伺服控制系统人机界面设计 毕设
基于ARM Linux的三轴伺服控制系统人机界面设计 毕设 洛阳理工学院毕业设计(论文) 基于ARM+Linux的三轴伺服控制系统人机界面设计 摘要 现代计算机技术的产业革命,将世界经济从资本经济带入 ...
- arm linux 进程调度,详解ARM Linux 2.4.x进程调度
Linux2.4.x是一个基于非抢占式的多任务的分时操作系统,虽然在用户进程的调度上采用抢占式策略,但是而在内核还是采用了轮转的方法,如果有个内核态的线程恶性占有CPU不释放,那系统无法从中解脱出来, ...
- linux指定内核位置,ARM linux内核启动时几个关键地址
1. 内核启动地址 ZTEXTADDR 解压代码运行的开始地址.没有物理地址和虚拟地址之分,因为此时MMU处于关闭状态.这个地址不一定时RAM的地址,可以是支持读写寻址的flash等存储中 ...
最新文章
- Linux(CentOS 7_x64位)系统下安装GaussView5
- linux学习笔记(11)df命令
- VMware ESX的性能如何与Hyper-V的价格进行竞争?
- Windows上优质精选的最佳应用程序及工具列表(附下载链接)
- QT实现电子表digitalclock
- 车联网登录显示连接不上服务器,车联网,如何解决连接的问题?
- 寻宝游戏设定_Excel寻宝游戏
- 团队管理21--梯队培养
- 【补丁】YYC松鼠短视频系统补丁,增加视频点赞数据管理功能,可修改点赞数量,V2.8的功能
- 数学上的表示“任意”和“存在”的符号
- vue2 qrcodejs2链接生成二维码
- 我的世界服务器货币充值系统,《我的世界》中国版正式开启了充值功能
- VBA向单元格输入双引号
- LSSVM分类和回归
- 【物联网+区块链=?】展锐、蚂蚁链、广和通联合发布可信上链模组
- xxxxxxxxxxxxx
- iOS 应用退到管理后台 左上角图片未更新(或不显示)
- H3C的RRPP配置注意祥解
- 有一种执行力叫做“海娃”
- 前端使用国密sm2和sm4进行加解密