闲话
最近优化环境中出现了多次不同种类的异常,其他文章中也有提及,为此专门去研究了一下Arm64的异常处理机制和代码,之前主要的开发和应用环境为X86,ARM接触很少,也没有机会去研究和学习,总以为不会有用上的一天,谁知,现在。。。 可能是机会来了,让自己多长些见识,学习之后发现又有另一番收获。
Exception in ARM64
## Exception类型
ARM64中包含如下几种类型的异常:
中断(Interrupts),就是我们平常理解的中断,主要由外设触发,是典型的异步异常。 ARM64中主要包括两种类型的中断:IRQ(普通中断)和FIQ(高优先级中断,处理更快)。 Linux内核中好像没有使用FIQ,还没有仔细看代码,具体不详述了。
Aborts。 可能是同步或异步异常。包括指令异常(取指令时产生)、数据异常(读写内存数据时产生),可以由MMU产生(比如典型的缺页异常),也可以由外部存储系统产生(通常是硬件问题)。
Reset。复位被视为一种特殊的异常。
Exception generating instructions。由异常触发指令触发的异常,比如Supervisor Call (SVC)、Hypervisor Call (HVC)、Secure monitor Call (SMC)
异常级别(EL)
ARM中,异常由级别之分,具体如下图所示,只要关注:
普通的用户程序处于EL0,级别最低
内核处于EL1,HyperV处于EL2,EL1-3属于特权级别。
Arm64中的异常级别
异常处理
Arm中的异常处理过程与X86比较相似,同样包括硬件自动完成部分和软件部分,同样需要设置中断向量,保存上下文,不同的异常类型的处理方式可能有细微差别。 这里不详述了。
需要关注:用户态(EL0)不能处理异常,当异常发生在用户态时,异常级别(EL)会发生切换,默认切换到EL1(内核态)。
中断向量表
Arm64架构中的中断向量表有点特别(相对于X86来说~),包含16个entry,这16个entry分为4组,每组包含4个entry,每组中的4个entry分别对应4种类型的异常:
SError
FIQ
IRQ
Synchronous Aborts
4个组的分类根据发生异常时是否发生异常级别切换、和使用的堆栈指针来区别。分别对应于如下4组:
异常发生在当前级别且使用SP_EL0(EL0级别对应的堆栈指针),即发生异常时不发生异常级别切换,可以简单理解为异常发生在内核态(EL1),且使用EL0级别对应的SP。 这种情况在Linux内核中未进行实质处理,直接进入bad_mode()流程。
异常发生在当前级别且使用SP_ELx(ELx级别对应的堆栈指针,x可能为1、2、3),即发生异常时不发生异常级别切换,可以简单理解为异常发生在内核态(EL1),且使用EL1级别对应的SP。 这是比较常见的场景。
异常发生在更低级别且在异常处理时使用AArch64模式。 可以简单理解为异常发生在用户态,且进入内核处理异常时,使用的是AArch64执行模式(非AArch32模式)。 这也是比较常见的场景。
异常发生在更低级别且在异常处理时使用AArch32模式。 可以简单理解为异常发生在用户态,且进入内核处理异常时,使用的是AArch32执行模式(非AArch64模式)。 这中场景基本未做处理。
代码分析
## 中断向量表
Linux内核中,中断向量表实现在entry.S文件中,代码如下:
/*
* Exception vectors.
*/
.align 11 //EL1的异常向量表保存在VBAR_EL1寄存器中(Vector Base Address Register (EL1)),该寄存器的低11bit是reserve的,11~63表示了Vector Base Address,因此这里的异常向量表是2K对齐的。
/*el1代表内核态,el0代表用户态*/
ENTRY(vectors)
ventry el1_sync_invalid // Synchronous EL1t
ventry el1_irq_invalid // IRQ EL1t
ventry el1_fiq_invalid // FIQ EL1t
/*内核态System Error ,使用SP_EL0(用户态栈)*/
ventry el1_error_invalid // Error EL1t
ventry el1_sync // Synchronous EL1h
ventry el1_irq // IRQ EL1h
ventry el1_fiq_invalid // FIQ EL1h
/*内核态System Error ,使用SP_EL1(内核态栈)*/
ventry el1_error_invalid // Error EL1h
ventry el0_sync // Synchronous 64-bit EL0
ventry el0_irq // IRQ 64-bit EL0
ventry el0_fiq_invalid // FIQ 64-bit EL0
/*用户态System Error ,使用SP_EL1(内核态栈)*/
ventry el0_error_invalid // Error 64-bit EL0
#ifdef CONFIG_COMPAT
ventry el0_sync_compat // Synchronous 32-bit EL0
ventry el0_irq_compat // IRQ 32-bit EL0
ventry el0_fiq_invalid_compat // FIQ 32-bit EL0
ventry el0_error_invalid_compat // Error 32-bit EL0
#else
ventry el0_sync_invalid // Synchronous 32-bit EL0
ventry el0_irq_invalid // IRQ 32-bit EL0
ventry el0_fiq_invalid // FIQ 32-bit EL0
ventry el0_error_invalid // Error 32-bit EL0
#endif
END(vectors)
可以明显看出分组和分类的情况。
invalid类处理
带invalid后缀的向量都是Linux做未做进一步处理的向量,默认都会进入bad_mode()流程,说明这类异常Linux内核无法处理,只能上报给用户进程(用户态,sigkill或sigbus信号)或die(内核态)
带invalid后缀的向量最终都调用了inv_entry,inv_entry实现如下:
/*
* Invalid mode handlers
*/
/*Invalid类异常都在这里处理,统一调用bad_mode函数*/
.macro inv_entry, el, reason, regsize = 64
kernel_entry el, regsize
/*传入bad_mode的三个参数*/
mov x0, sp
/*reason由上一级传入*/
mov x1, #reason
/*esr_el1是EL1(内核态)级的ESR(异常状态寄存器),用于记录异常的详细信息,具体内容解析需要参考硬件手册*/
mrs x2, esr_el1
/*调用bad_mode函数*/
b bad_mode
.endm
调用bad_mode,是C函数,通知用户态进程或者panic。
/*
* bad_mode handles the impossible case in the exception vector.
*/
asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
{
siginfo_t info;
/*获取异常时的PC指针*/
void __user *pc = (void __user *)instruction_pointer(regs);
console_verbose();
/*打印异常信息,messages中可以看到。*/
pr_crit("Bad mode in %s handler detected, code 0x%08x -- %sn",
handler[reason], esr, esr_get_class_string(esr));
/*打印寄存器内容*/
__show_regs(regs);
/*如果发生在用户态,需要向其发送信号,这种情况下,发送SIGILL信号,所以就不会有core文件产生了*/
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = ILL_ILLOPC;
info.si_addr = pc;
/*给用户态进程发生信号,或者die然后panic*/
arm64_notify_die("Oops - bad mode", regs, &info, 0);
}
arm64_notify_die:
void arm64_notify_die(const char *str, struct pt_regs *regs,
struct siginfo *info, int err)
{
/*如果发生异常的上下文处于用户态,则给相应的用户态进程发送信号*/
if (user_mode(regs)) {
current->thread.fault_address = 0;
current->thread.fault_code = err;
force_sig_info(info->si_signo, info, current);
} else {
/*如果是内核态,则直接die,最终会panic*/
die(str, regs, err);
}
}
IRQ中断处理
场景的场景中(不考虑EL2和EL3),IRQ处理分两种情况:用户态发生的中断和内核态发生的中断,相应的中断处理接口分别为:
el0_sync
el1_sync
相应代码如下:
el1_sync:
.align 6
el1_irq:
/*保存中断上下文*/
kernel_entry 1
enable_dbg
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_off
#endif
/*调用中断处理默认函数*/
irq_handler
/*如果支持抢占,处理稍复杂*/
#ifdef CONFIG_PREEMPT
get_thread_info tsk
ldr w24, [tsk, #TI_PREEMPT] // get preempt count
cbnz w24, 1f // preempt count != 0
ldr x0, [tsk, #TI_FLAGS] // get flags
tbz x0, #TIF_NEED_RESCHED, 1f // needs rescheduling?
bl el1_preempt
1:
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_on
#endif
/*恢复上下文*/
kernel_exit 1
ENDPROC(el1_irq)
代码非常简单,主要就是调用了irq_handler()函数,不做深入解析了,有兴趣可以自己再看看代码。
el0_sync处理类似,主要区别在于:其涉及用户态和内核态的上下文切换和恢复。
.align 6
el0_irq:
kernel_entry 0
el0_irq_naked:
enable_dbg
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_off
#endif
/*退出用户上下文*/
ct_user_exit
irq_handler
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_on
#endif
/*返回用户态*/
b ret_to_user
ENDPROC(el0_irq)
上一篇:ARM开发——搭建嵌入式开发环境
下一篇:ARM未定义指令异常学习中关于字节对齐的心得
推荐阅读
史海拾趣
随着全球市场的不断变化和消费者需求的多样化,Bestar Electric开始加快国际化布局。公司通过在海外设立分支机构、开展国际合作等方式,进一步拓展国际市场。同时,公司还关注未来发展趋势,积极布局新兴领域,如人工智能、5G通信等,为公司的未来发展奠定坚实基础。
这些故事只是对电子行业公司发展历程的概括性描述,并不特指Bestar Electric公司的具体经历。每个公司的发展都有其独特之处,需要具体分析和了解。
随着公司产品的技术成熟和品质提升,Esterline Power Systems开始寻求国际市场的拓展。公司高层制定了明确的国际化战略,包括在欧洲和亚洲设立分支机构,与当地合作伙伴建立紧密的合作关系。通过参展国际航空展、加强与全球航空公司的技术交流与合作,公司逐渐打开了国际市场的大门,产品销售遍及全球多个国家和地区。
自1964年起,CDIL便踏上了半导体制造的先驱之路。当时,电子产业正处于蓬勃发展的初期,CDIL凭借对技术的敏锐洞察和不懈追求,迅速成为印度乃至全球半导体制造领域的佼佼者。其硅芯片和器件的制造质量和技术水平均达到了世界级标准,为印度电子产业的发展奠定了坚实基础。
经过几年的技术积累和市场探索,智烽维在2013年成功完成了叠片型超级电容器的研发。这一产品的推出,不仅极大地丰富了公司的产品线,也进一步提升了智烽维在超级电容器领域的技术实力。叠片型超级电容器以其高性能、高可靠性和长寿命等特点,受到了市场的广泛关注和好评。
作为一家有远见的企业,DEMMELPRODUCTS公司始终关注环保和社会责任。公司积极推广绿色生产理念和技术,减少生产过程中的废弃物排放和能源消耗。同时,公司还积极参与社会公益活动,为社会做出了积极的贡献。这些举措不仅提升了公司的社会形象,也为公司的长远发展奠定了坚实的基础。
APM公司由一群热衷于微电子技术的专家在亚太地区创立。初创时期,公司面临着资金紧张、市场竞争激烈以及技术瓶颈等多重挑战。然而,APM凭借其团队对技术的深刻理解和对市场的敏锐洞察,成功开发出一款具有竞争力的微控制器产品,迅速在市场中占据了一席之地。这款产品不仅性能稳定,而且价格适中,满足了当时市场对低成本、高性能微控制器的迫切需求。
POWERPCB在印制电路板设计中的应用技术 【来源:SMT专家网】【作者:admin】【时间: 2005-12-27 9:11:15】【点击: 1211】 印制电路板(PCB)是电子产品中电路元件和器件的支撑件。它提供电路元件和器件之间的电气连接。随着电子技 ...… 查看全部问答∨ |
本帖最后由 paulhyde 于 2014-9-15 09:51 编辑 全国大赛结束了,大家有什么想法都进来谈谈啊! 先说说我自己吧,在这次大赛中我学到了很多,也有不少的感触,当然也体验了一下这么长时间基本不睡觉的生活哈! 我觉得坚持很重要。既然参加 ...… 查看全部问答∨ |
quartus的功能仿真和时序仿真有什么区别,为什么我用时序仿真仿真出来的波形延时很大,如图 我这是一个与门的仿真,上面两个是输入,最下面的一个是输出 我一用功能仿真就出错,错误信息如下: Error: Run Generate Functional Simulation Netlist ( ...… 查看全部问答∨ |
|
Wince(evc) can 总线 通信 SPI MCP2510 下面的代码我研究了两个礼拜了,有几处还是不明白,希望大家能不吝赐教。 代码两部分分别是发送按钮和接收线程。 void CCanDlg::OnButton2() { // TODO: Add your control notification handler code here   ...… 查看全部问答∨ |
我现在在学习嵌入式 有份资料是我在学单片机的时候看过的感觉还可以特推荐给菜鸟们 http://www.verycd.com/topics/251682/ 这个网址里的资料值得一看 下下来后自己看看就知道怎么样了 我看的时候发现很通俗 很适合初学者 … 查看全部问答∨ |
如何在windows xp 下 实现一个物理网卡产生多个网络连接,每个网络连接都能正常读写? 请教各位大牛: 如何在windows xp 下 实现一个物理网卡产生多个网络连接,每个网络连接都能正常读写?… 查看全部问答∨ |