ARMv8中的异常向量介绍
历经一年多时间的系统整理合补充,《手机安全和可信应用开发指南:TrustZone与OP-TEE技术详解 》一书得以出版,书中详细介绍了TEE以及系统安全中的所有内容,全书按照从硬件到软件,从用户空间到内核空间的顺序对TEE技术详细阐述,读者可从用户空间到TEE内核一步一步了解系统安全的所有内容,同时书中也提供了相关的示例代码,读者可根据自身实际需求开发TA。目前该书已在天猫、京东、当当同步上线,链接如下:
非常感谢在此期间大家的支持以及各位友人的支持和帮助!!!。
在ARMV8架构中使用execption level来表示AArch64的执行等级,而在ARMV7架构中则使用PL的方式来进行定义。在ARMv8中ARM核的执行等级划分如下图所示。
而在ARMv7架构中,因为是使用PL的方式来定义ARM核的执行等级,ARM核中各种运行模式与PL的对应关系如下表所示:
在ARMv8架构的AArch64时,每种EL都具有独立的16个entires,这16个entires分为四类异常, 分别为:IRQ, FIQ,SError, Synchronous。而根据触发一种异常时是否会产生EL级别的迁移和使用产生迁移时使用的是AArch64还是AArch32的指令集又具有四种不同的区域。整个16个entires的分类和在向量表中的偏移关系如下表所示:
Address | Execption type | Description |
VBAR_Eln+0x000 | Synchronous | Current EL wit SP0 |
0x080 | IRQ/vIRQ | |
0x100 | FIQ/vFIQ | |
0x180 | Serror/vSError | |
0x200 | Synchronous | Current EL wit SPx |
0x280 | IRQ/vIRQ | |
0x300 | FIQ/vFIQ | |
0x380 | Serror/vSError | |
0x400 | Synchronous | Lower EL using AArch64 |
0x480 | IRQ/vIRQ | |
0x500 | FIQ/vFIQ | |
0x580 | Serror/vSError | |
0x600 | Synchronous | Lower EL using AArch32 |
0x680 | IRQ/vIRQ | |
0x700 | FIQ/vFIQ | |
0x780 | Serror/vSError |
当在EL0产生异常而位产生EL的迁移时,使用的是SP0保存的栈空间地址。而在除EL0之外的ELx产生异常而未导致EL的迁移时使用的是对应的SPx保存的栈空间地址。在AArch64中,EL的迁移只能是从低EL向高EL进行迁移,如果使用AArch64指令集和AArch32指令集时产生了异常并且也发生了EL的迁移时,则使用的是将迁移到的EL对应的SPx。
为方便理解在ARMv8 AArch64中异常向量表的定义,以下以ATF中bl31为例进行说明, 在ATF的bl31中,其异常向量表的定义如下:
/* 用于处理EL0产生异常时的entire */
vector_entry sync_exception_sp_el0
b report_unhandled_exception
check_vector_size sync_exception_sp_el0
vector_entry irq_sp_el0
b report_unhandled_interrupt
check_vector_size irq_sp_el0
vector_entry fiq_sp_el0
b report_unhandled_interrupt
check_vector_size fiq_sp_el0
vector_entry serror_sp_el0
b report_unhandled_exception
check_vector_size serror_sp_el0
/* 用于处理当前ELx产生异常时的entire */
vector_entry sync_exception_sp_elx
b report_unhandled_exception
check_vector_size sync_exception_sp_elx
vector_entry irq_sp_elx
b report_unhandled_interrupt
check_vector_size irq_sp_elx
vector_entry fiq_sp_elx
b report_unhandled_interrupt
check_vector_size fiq_sp_elx
vector_entry serror_sp_elx
b report_unhandled_exception
check_vector_size serror_sp_elx
/* 用于处理AArch64指令产生的异常,且发生了EL的迁移的entire */
vector_entry sync_exception_aarch64
handle_sync_exception
check_vector_size sync_exception_aarch64
vector_entry irq_aarch64
handle_interrupt_exception irq_aarch64
check_vector_size irq_aarch64
vector_entry fiq_aarch64
handle_interrupt_exception fiq_aarch64
check_vector_size fiq_aarch64
vector_entry serror_aarch64
b report_unhandled_exception
check_vector_size serror_aarch64
/* 用于处理AArch32指令产生的异常,且发生了EL的迁移的entire */
vector_entry sync_exception_aarch32
handle_sync_exception
check_vector_size sync_exception_aarch32
vector_entry irq_aarch32
handle_interrupt_exception irq_aarch32
check_vector_size irq_aarch32
vector_entry fiq_aarch32
handle_interrupt_exception fiq_aarch32
check_vector_size fiq_aarch32
vector_entry serror_aarch32
b report_unhandled_exception
check_vector_size serror_aarch32
在支持Trustzone的ARRMv8中,当在non-secure world或者secure world中触发了smc或者hvc指令时都属于产生sync类型的异常。根据产生该异常是否会导致EL的迁移从异常向量表中确定最终用于处理该异常的handle。
ARMv8中,EL1,EL2,EL3都具有独立的VBAR寄存器,该寄存器就是用于存放各ELx的异常向量表的基地址。当发生异常时,如果该异常产生了EL的迁移,那么完成迁移操作之后会到迁移到的EL中的VBAR寄存器中找到向量表的基地址,然后命中对应的handl。值得注意的是,EL的迁移都是只能由低往高进行迁移,EL0不能直接迁移到EL3。