ARMv8-A Exception Handling
Posted Loopers
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ARMv8-A Exception Handling相关的知识,希望对你有一定的参考价值。
本节来详细描述下ARMv8-A下的异常处理。
异常的概述:
当设备正在愉快的执行时候,此时发生了一个异常,处理器就必须暂停当前的任务,转而去处理发生的异常。当异常处理完毕后,处理就会发回到被打断的程序继续执行。
此图就是描述异常的处理流程。
异常的分类:
异常分为同步异常和异步异常,而这两种异常的区别是:
同步异常:如果异常的产生是通过执行指令,而且返回结果提供了产生异常的详细信息,则此类异常称为同步异常(Synchronous Exceprions)
异步异常:如果异常不是通过指令执行产生,而且返回结果不提供产线异常的详细信息,则此类异常为异步异常(asynchronous exceptions)
异步异常(Asynchronous Exceptions)
- 中断
- IRQ(normal priority interrupt)
- FIQ(Fast Interrupt)
- 其中FIQ的优先级比IRQ的优先级高。这两种中断类型都是通过pin脚连接到中断控制器(GIC),当外部触发一个中断的时候,中断控制器就会仲裁和转发此中断到相应的CPU
- SError(System Error)
同步异常(Synchronous Exceptions)
同步异常包含的类型很多,比如第一次申请内存,当去写或者读的时候就会触发一次page fault,此类异常就属于同步异常
- 从MMU发出的指令abort。 当cpu尝试去执行一块没有执行权限的内存区域,则会发生指令abort
- 从MMU发出的数据abort。 当cpu尝试去写一块只读的内存区域,则会发生data abort
- SP和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恢复到PC
PSTATE,SPSR已经在上一篇文章Process Status中做过描述了,此处不做说明了。
当一个异常发生时,如果确定异常的类型
当异常发生时,我们可以从ESR_ELn寄存器中获取对应的异常状态。
- Bits[31:26] 用来确定异常的类型,Exception class
- Bit[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
开发者涨薪指南 48位大咖的思考法则、工作方式、逻辑体系
以上是关于ARMv8-A Exception Handling的主要内容,如果未能解决你的问题,请参考以下文章