本节来详细描述下ARMv8-A下的异常处理。
异常的概述:当设备正在愉快的执行时候,此时发生了一个异常,处理器就必须暂停当前的任务,转而去处理发生的异常。当异常处理完毕后,处理就会发回到被打断的程序继续执行。
此图就是描述异常的处理流程。
异常的分类:异常分为同步异常和异步异常,而这两种异常的区别是:
同步异常:如果异常的产生是通过执行指令,而且返回结果提供了产生异常的详细信息,则此类异常称为同步异常(Synchronous Exceprions)
异步异常:如果异常不是通过指令执行产生,而且返回结果不提供产线异常的详细信息,则此类异常为异步异常(asynchronous exceptions)
异步异常(Asynchronous Exceptions)中断 IRQ(normal priority interrupt)FIQ(Fast Interrupt)其中FIQ的优先级比IRQ的优先级高。这两种中断类型都是通过pin脚连接到中断控制器(GIC),当外部触发一个中断的时候,中断控制器就会仲裁和转发此中断到相应的CPUSError(System Error)同步异常(Synchronous Exceptions)同步异常包含的类型很多,比如第一次申请内存,当去写或者读的时候就会触发一次page fault,此类异常就属于同步异常
从MMU发出的指令abort。 当cpu尝试去执行一块没有执行权限的内存区域,则会发生指令abort从MMU发出的数据abort。 当cpu尝试去写一块只读的内存区域,则会发生data abortSP和PC的对齐检查同步外部异常未分配的异常:当第一次访问申请内存时,cpu会通过mmu去寻找虚拟地址对应的物理地址,而此时因为此虚拟地址没有对应的物理地址,则会发生未分配的异常debug时发生的异常Services Calls(SVC,SMC,HVC)SVC,HVC,SMC指令SVC(Supervisor Call) 当用户空间通过系统调用陷入到内核空间的时候,则最终会通过SVC指令进入到内核空间HVC(Hypervisor Call) 当在ARMv8-A架构下,normal world, EL1尝试去访问EL2的时候,则会陷入到虚拟化层的,其中是通过HVC指令SMC(Secure Moniter Call) 用于切换noramal world 和 secure world使用。异常处理涉及到的寄存器我们先来看下异常处理的整个过程
当异常发生时,硬件会自动做如下几个步骤:
将PSTATE的状态保存到SPSR_ELn寄存器中,根据当前所在的EL级别来保存到对应的SPSR寄存器中。如果当前的异常发生在EL1,则将PSTATE的状态保存到SPSR_EL1中将PC的值存储在ELR_ELn寄存器中,也是根据当前所处的EL级别。以上两个步骤是硬件自动保存的,不需要软件的干涉假设当前是一个IRQ中断,软件上也会保存一些现场的。当异常处理完毕后,则会将之前保存的值恢复SPSR_ELn的值恢复到PSTATE中,ELR_ELn恢复到PCPSTATE,SPSR已经在上一篇文章Process Status中做过描述了,此处不做说明了。
当一个异常发生时,如果确定异常的类型当异常发生时,我们可以从ESR_ELn寄存器中获取对应的异常状态。
Bits[31:26] 用来确定异常的类型,Exception classBit[25]: 用来确定异常指令的长度,0代表16位异常指令,1代表32位异常Bits[24:0]: 用来确定具体的异常,每种异常类型独立定义此字段比如:
ARM64 异常向量表这四组在EL1的实现为,也就是linux内核的实现为:
424/* 425 * Exception vectors. 426 */ 427 .pushsection ".entry.text", "ax" 428 429 .align 11 430ENTRY(vectors) 431 kernel_ventry 1, sync_invalid // Synchronous EL1t 432 kernel_ventry 1, irq_invalid // IRQ EL1t 433 kernel_ventry 1, fiq_invalid // FIQ EL1t 434 kernel_ventry 1, error_invalid // Error EL1t 435 436 kernel_ventry 1, sync // Synchronous EL1h 437 kernel_ventry 1, irq // IRQ EL1h 438 kernel_ventry 1, fiq_invalid // FIQ EL1h 439 kernel_ventry 1, error // Error EL1h 440 441 kernel_ventry 0, sync // Synchronous 64-bit EL0 442 kernel_ventry 0, irq // IRQ 64-bit EL0 443 kernel_ventry 0, fiq_invalid // FIQ 64-bit EL0 444 kernel_ventry 0, error // Error 64-bit EL0 445 446#ifdef CONFIG_COMPAT 447 kernel_ventry 0, sync_compat, 32 // Synchronous 32-bit EL0 448 kernel_ventry 0, irq_compat, 32 // IRQ 32-bit EL0 449 kernel_ventry 0, fiq_invalid_compat, 32 // FIQ 32-bit EL0 450 kernel_ventry 0, error_compat, 32 // Error 32-bit EL0 451#else 452 kernel_ventry 0, sync_invalid, 32 // Synchronous 32-bit EL0 453 kernel_ventry 0, irq_invalid, 32 // IRQ 32-bit EL0 454 kernel_ventry 0, fiq_invalid, 32 // FIQ 32-bit EL0 455 kernel_ventry 0, error_invalid, 32 // Error 32-bit EL0 456#endif 457END(vectors)分为四组,其中第一组是invaild的。
如果异常级别是EL1,也就是Current EL,则偏移地址为0x200如果异常类型是64位应用程序,异常级别是EL0发生,则偏移地址为0x400如果异常类型是32位应用程序,异常级别是EL0发生,则偏移地址为0x600 ---来自腾讯云社区的---DragonKingZhu
微信扫一扫打赏
支付宝扫一扫打赏