ARM64知识记录
armv8a分为aarch32与aarch64两种模式。因此在选择交叉编译链时一定要确定自己运行的arm设备是什么架构,什么模式。
从授权上,交叉编译链分为免费授权版和付费授权版。
免费版目前有三大主流工具商提供,第一是GNU(提供源码,自行编译制作),第二是 Codesourcery,第三是Linora。
收费版有ARM原厂提供的armcc、IAR提供的编译器等等,因为这些价格都比较昂贵,不适合学习用户使用,所以不做讲述。
arm-none-linux-gnueabi-gcc:是 Codesourcery 公司(目前已经被Mentor收购)基于GCC推出的的ARM交叉编译工具。可用于交叉编译ARM(32位)系统中所有环节的代码,包括裸机程序、u-boot、Linux kernel、filesystem和App应用程序。
arm-linux-gnueabihf-gcc:是由 Linaro 公司基于GCC推出的的ARM交叉编译工具。可用于交叉编译ARM(32位)系统中所有环节的代码,包括裸机程序、u-boot、Linux kernel、filesystem和App应用程序。
aarch64-linux-gnu-gcc:是由 Linaro 公司基于GCC推出的的ARM交叉编译工具。可用于交叉编译ARMv8 64位目标中的裸机程序、u-boot、Linux kernel、filesystem和App应用程序。
arm-none-elf-gcc:是 Codesourcery 公司(目前已经被Mentor收购)基于GCC推出的的ARM交叉编译工具。可用于交叉编译ARM MCU(32位)芯片,如ARM7、ARM9、Cortex-M/R芯片程序。
arm-none-eabi-gcc:是 GNU 推出的的ARM交叉编译工具。可用于交叉编译ARM MCU(32位)芯片,如ARM7、ARM9、Cortex-M/R芯片程序。
1. NEON 简介
SIMD,即 single instruction multiple data,单指令流多数据流,也就是说一次运算指令可以执行多个数据流,从而提高程序的运算速度。
NEON 是一种压缩的 SIMD 架构,由ARMv7引入,在ARMv8对其功能进行了扩展,支持包括加法、乘法、比较、移位、绝对值 、极大极小极值运算、保存和加载指令等运算。
ARMV7-A/R | ARMV8-A/R | ARMV8-A | |
AArch32 | AArch64 | ||
floating-point | 32-bit | 16-bit*/32-bit | 16-bit*/32-bit |
integer | 8-bit/16-bit/32-bit | 8-bit/16-bit/32-bit/64-bit | 8-bit/16-bit/32-bit/64-bit |
编译选项 LOCAL_CFLAGS += -mfpu=neon
头文件 #include <arm_neon.h>
ARM64包含4个异常等级:
EL0:非特权模式,常用来跑应用程序;
EL1:特权模式,常用来跑内核;
EL2:虚拟化监控程序,例如hypervisor;
EL3:安全模式,例如secure monitor;
2.同步异常和异步异常
同步异常是由正在运行的指令,或指令运行的结果,出错造成的异常;而异步异常则不必由运行的指令造成,可以在程序运行中的任意时刻(异步)发生。
同步异常包括:
1.系统调用,svc, hvc, SMC等;
2.MMU引发的异常;
3.SP和PC对齐检查;
4.未分配的指令;
异步异常:
IRQ中断;
FIQ中断;
SError
注:在官方手册D1.12有详细列出那些是同步异常;
1.选择异常级别:
当异常发生时,PC可以有三个基地址VBAR_EL1、VBAR_EL3、VBAR_EL1(secure)供选择;路由规则如下:
举两例来说明下:
第一个红色框的内容表示:在此种配置(安全模式)下,EL0和EL1状态下产生的异步异常,会导致CPU进入EL1。
第一个红色框的内容表示:在此种配置(非安全模式)下,EL0和EL1状态下产生的异步异常,会导致CPU进入EL1,而EL2状态下产生的异常,不会导致exception level切换。
Linux内核只支持EL0和EL1,EL0对应用户态,EL1对应内核态,当CPU运行在用户态时,产生的异步异常会导致CPU切换到EL1,当CPU运行在内核态时,产生的异步异常不会导致exception level的切换。
这里配置为非安全模式vbar_el1:
2.选择异常级别相关的偏移:
配置好基地址后,再根据下表配置异常向量表的偏移地址
说明:
(1)实际上有四张表,每张表有四个异常入口,分别对应同步异常,IRQ,FIQ和出错异常。
(2)每一个异常入口占用0x80 bytes(不同于ARMv7之前的4bytes)空间,也就是说,每一个异常入口可以放置多条指令,而不仅仅是一条跳转指令。
四张表类型:
(1)如果发生异常并不会导致exception level切换,并且使用的栈指针是SP_EL0,那么使用第一张异常向量表。
(2)如果发生异常并不会导致exception level切换,并且使用的栈指针是SP_EL1/2/3,那么使用第二张异常向量表。
(3)如果发生异常会导致exception level切换,并且比目的exception level低一级的exception level运行在AARCH64模式,那么使用第三张异常向量表。
(4)如果发生异常会导致exception level切换,并且比目的exception level低一级的exception level运行在AARCH32模式,那么使用第四张异常向量表。
在Linux中,用户态EL0, 内核态EL1, 结合上面路由规则,可得到如下结论:
(1)第一章异常向量表,用不到; 因为EL0使用SP_EL0,但发生EL0异常会routing到EL1;
(2)第二张表,用于CPU运行在EL1即内核态,发生异常时,exception level不发生切换;
(3)第三张表用于CPU运行在EL0即用户态的AARCH32模式时,发生异常;
(4)第四张表,用于CPU运行在EL0即用户态的AARCH64时,发生异常;