ARM公司主要向客户提供处理器IP。通过这种独特的盈利模式,ARM软硬件生态变得越来越强大。表1.1展示了ARM公司重大的历史事件。
表1.1 ARM公司重大的历史事件
时 间 |
重 大 事 件 |
1978年 |
在英国剑桥创办了CPU(Cambridge Processing Unit)公司 |
1985年 |
第一款ARM处理器问世,它采用RISC架构,简称ARM(Acorn RISC Machine) |
1995年 |
发布ARM7处理器核心,它支持3级流水线和ARMv4指令集 |
1997年 |
发布了ARM9处理器核心,它支持5级流水线,支持ARMv4T指令集,支持MMU内存管理以及指令/数据高速缓存。兼容ARMv4T指令集的处理器核心有ARM920T,典型SoC芯片是三星S3C2410 |
2003年 |
发布ARM11处理器,它支持8级流水线和ARMv6指令集,典型的IP核心有ARM1176JZF |
2005年 |
发布Cortex-A8处理器核心,第一个引入超标量技术的ARM处理器 |
2007年 |
发布Cortex-A9处理器核心,它引入了乱序执行和猜测执行机制,并扩大了L2高速缓存的容量 |
2010年 |
发布Cortex-A15处理器核心,它的最高主频可以到2.5 GHz,最多可支持8个处理器内核,单个簇最多支持4个处理器内核 |
2012年 |
发布64位Cortex-A53和Cortex-A57处理器内核 |
2015年 |
发布Cortex-A72处理器内核。树莓派4B开发板采用Cortex-A72处理器内核 |
2019年 |
发布Neoverse系列处理器,它细分为E系列、N系列和V系列。V系列适用于性能优先的场景,例如高性能计算(HPC)。N系列适用于需要均衡的CPU设计优化的场景,例如网络应用、智能网卡、5G应用等,以提供出色的能耗比。E系列适用于高性能与低功耗的场景,例如网络数据平面处理器、5G低功耗网关等 |
2021年 |
发布ARMv9体系结构。Cortex-X2处理器支持ARMv9.0体系结构 |
ARM体系结构是一种硬件规范,主要是用来约定指令集、芯片内部体系结构(如内存管理、高速缓存管理)等。以指令集为例,ARM体系结构并没有约定每一条指令在硬件描述语言(Verilog或VHDL)中应该如何实现,它只约定每一条指令的格式、行为规范、参数等。为了降低客户基于ARM体系结构开发处理器的难度,ARM公司通常在发布新版本的体系结构之后,根据不同的应用需求开发出兼容体系结构的处理器IP,然后授权给客户。客户获得处理器IP之后,再用它来设计不同的SoC芯片。以ARMv8体系结构为例,ARM公司先后开发出Cortex-A53、Cortex-A55、Cortex-A72、Cortex-A73等多款处理器IP。
ARM公司一般有两种授权方式。
从最早的ARM处理器开始,ARM体系结构已经从v1版本发展到目前的v8版本。在每一个版本的体系结构里,指令集都有相应的变化,其主要变化如表1.2所示。
表1.2 ARM体系结构的变化
ARM体系结构版本 |
典型处理器核心 |
主 要 特 性 |
v1 |
— |
仅支持26位地址空间 |
v2 |
— |
新增乘法指令和乘加法指令、支持协处理器指令等 |
v3 |
— |
地址空间扩展到32位,新增SPSR和CPSR等 |
v4 |
ARM7TDMI/ARM920T |
新增Thumb指令集等 |
v5 |
ARM926EJ-S |
新增Jazelle和VFPv2扩展 |
v6 |
ARM11 MPCore |
新增SIMD、TrustZone以及Thumb-2扩展 |
v7 |
Cortex-A8/Cortex-A9 |
增强NEON和VFPv3/v4扩展 |
v8 |
Cortex-A72 |
同时支持32位以及64位指令集的处理器体系结构 |
v9 |
Cortex-X2 |
支持可伸缩矢量扩展计算、机密计算体系结构 |
ARM体系结构又根据不同的应用场景分成如下3种系列。
ARMv8是ARM公司发布的第一代支持64位处理器的指令集和体系结构。它在扩充64位寄存器的同时提供了对上一代体系结构指令集的兼容,因此它提供了运行32位和64位应用程序的环境。
ARMv8体系结构除了提高了处理能力,还引入了很多吸引人的新特性。
ARMv8体系结构一共有8个小版本,分别是ARMv8.0、ARMv8.1、ARMv8.2、ARMv8.3、ARMv8.4、ARMv8.5、ARMv8.6、ARMv8.7,每个小版本都对体系结构进行小幅度升级和优化,增加了一些新的特性。
下面介绍市面上常见的采用ARMv8体系结构的处理器(简称ARMv8处理器)内核。
ARM处理器实现的是精简指令集体系结构。在ARMv8体系结构中有如下一些基本概念和定义。
_Elx //最后一个字母 x 可以表示0、1、2、3
如SP_EL0表示在EL0下的SP寄存器,SP_EL1表示在EL1下的SP寄存器。
本书重点介绍ARMv8体系结构下的AArch64执行状态以及A64指令集,对AArch32执行状态、A32以及T32指令集不做过多介绍,感兴趣的读者可以阅读ARMv8相关技术手册。
指令集是处理器体系结构设计的重点之一。ARM公司定义与实现的指令集一直在变化和发展中。ARMv8体系结构最大的改变是增加了一个新的64位的指令集,这是早前ARM指令集的有益补充和增强。它可以处理64位宽的寄存器和数据并且使用64位的指针来访问内存。这个新的指令集称为A64指令集,运行在AArch64状态下。ARMv8兼容旧的32位指令集——A32指令集,它运行在AArch32状态下。
A64指令集和A32指令集是不兼容的,它们是两套完全不一样的指令集,它们的指令编码是不一样的。需要注意的是,A64指令集的指令宽度是32位,而不是64位。
ARMv8处理器支持两种执行状态——AArch64状态和AArch32状态。AArch64状态是ARMv8新增的64位执行状态,而AArch32是为了兼容ARMv7体系结构的32位执行状态。当处理器运行在AArch64状态下时,运行A64指令集;而当运行在AArch32状态下时,可以运行A32指令集或者T32指令集。
如图1.1所示,AArch64状态的异常等级(exception level)确定了处理器当前运行的特权级别,类似于ARMv7体系结构中的特权等级。
▲图1.1 AArch64状态的异常等级
ARMv8体系结构允许切换应用程序的运行模式。如在一个运行64位操作系统的ARMv8处理器中,我们可以同时运行A64指令集的应用程序和A32指令集的应用程序,但是在一个运行32位操作系统的ARMv8处理器中就不能运行A64指令集的应用程序了。当需要运行A32指令集的应用程序时,需要通过一条管理员调用(Supervisor Call,SVC)指令切换到EL1,操作系统会做任务的切换并且返回AArch32的EL0,从而为这个应用程序准备好AArch32状态的运行环境。
ARMv8支持如下几种数据宽度。
AArch64执行状态支持31个64位的通用寄存器,分别是X0~X30寄存器,而AArch32状态支持16个32位的通用寄存器。
除用于数据运算和存储之外,通用寄存器还可以在函数调用过程中起到特殊作用,ARM64体系结构的函数调用标准和规范对此有所约定,如图1.2所示。
在AArch64状态下,使用X(如X0、X30等)表示64位通用寄存器。另外,还可以使用W来表示低32位的数据,如W0表示X0寄存器的低32位数据,W1表示X1寄存器的低32位数据,如图1.3所示。
▲图1.2 AArch64状态的31个通用寄存器
▲图1.3 64位通用寄存器和低32位数据
AArch64体系结构使用PSTATE寄存器来表示当前处理器状态(processor state),如表1.3所示。
表1.3 PSTATE寄存器
分 类 |
字 段 |
描 述 |
条件标志位 |
N |
负数标志位。 |
Z |
0标志位。 |
|
C |
进位标志位。 |
|
V |
有符号数溢出标志位。 |
|
执行状态控制 |
SS |
软件单步。该位为1,说明在异常处理中使能了软件单步功能 |
IL |
不合法的异常状态 |
|
nRW |
当前执行状态。 |
|
执行状态控制 |
EL |
当前异常等级。 |
SP |
选择SP寄存器。当运行在EL0时,处理器选择EL0的SP寄存器,即SP_EL0;当处理器运行在其他异常等级时,处理器可以选择使用SP_EL0或者对应的SP_ELn寄存器 |
|
异常掩码标志位 |
D |
调试位。使能该位可以在异常处理过程中打开调试断点和软件单步等功能 |
A |
用来屏蔽系统错误(SError) |
|
I |
用来屏蔽IRQ |
|
F |
用来屏蔽FIQ |
|
访问权限 |
PAN |
特权模式禁止访问(Privileged Access Never)位是ARMv8.1的扩展特性。 |
UAO |
用户访问覆盖标志位,是ARMv8.2的扩展特性。 |
ARMv8体系结构除支持31个通用寄存器之外,还提供多个特殊的寄存器,如图1.4所示。
▲图1.4 特殊寄存器
ARMv8体系结构提供两个零寄存器(zero register),这些寄存器的内容全是0,可以用作源寄存器,也可以用作目标寄存器。WZR是32位的零寄存器,XZR是64位的零寄存器。
PC指针寄存器通常用来指向当前运行指令的下一条指令的地址,用于控制程序中指令的运行顺序,但是编程人员不能通过指令来直接访问它。
ARMv8体系结构支持4个异常等级,每一个异常等级都有一个专门的SP寄存器SP_ELn,如处理器运行在EL1时选择SP_EL1寄存器作为SP寄存器。
当处理器运行在比EL0高的异常等级时,处理器可以访问如下寄存器。
当处理器运行在EL0时,它只能访问SP_EL0,而不能访问其他高级的SP寄存器。
当我们运行一个异常处理程序时,处理器的备份程序会保存到备份程序状态寄存器(Saved Program Status Register,SPSR)里。当异常将要发生时,处理器会把PSTATE寄存器的值暂时保存到SPSR里;当异常处理完成并返回时,再把SPSR的值恢复到PSTATE寄存器。SPSR的格式如图1.5所示。SPSR的重要字段如表1.4所示。
▲图1.5 SPSR的格式
表1.4 SPSR的重要字段
字 段 |
描 述 |
N |
负数标志位 |
Z |
零标志位 |
C |
进位标志位 |
V |
有符号数溢出标志位 |
DIT |
与数据无关的指令时序(Data Independent Timing),ARMv8.4的扩展特性 |
UAO |
用户访问覆盖标志位,ARMv8.2的扩展特性 |
PAN |
特权模式禁止访问位,ARMv8.1的扩展特性 |
SS |
表示是否使能软件单步功能。若该位为1,说明在异常处理中使能了软件单步功能 |
IL |
不合法的异常状态 |
D |
调试位。使能该位可以在异常处理过程中打开调试断点和软件单步等功能 |
A |
用来屏蔽系统错误 |
I |
用来屏蔽IRQ |
F |
用来屏蔽FIQ |
M[4] |
用来表示异常处理过程中处于哪个执行状态,若为0,表示AArch64状态 |
M[3:0] |
异常模式 |
ELR存放了异常返回地址。
该寄存器表示PSTATE寄存器中的EL字段,其中保存了当前异常等级。使用MRS指令可以读取当前异常等级。
该寄存器表示PSTATE寄存器中的{D,A,I,F}字段。
该寄存器表示PSTATE寄存器中的SP字段,用于在SP_EL0和SP_ELn中选择SP寄存器。
PAN寄存器表示PSTATE寄存器中的PAN(Privileged Access Never,特权禁止访问)字段。可以通过MSR和MRS指令来设置PAN寄存器。当内核态拥有访问用户态内存或者执行用户态程序的能力时,攻击者就可以利用漏洞轻松地执行用户的恶意程序。为了修复这个漏洞,在ARMv8.1中新增了PAN特性,防止内核态恶意访问用户态内存。如果内核态需要访问用户态内存,那么需要主动调用内核提供的接口,例如copy_from_user()或者copy_from_user()函数。
PAN寄存器的值如下。
该寄存器表示PSTATE寄存器中的UAO(User Access Override,用户访问覆盖)字段。我们可以通过MSR和MRS指令设置UAO寄存器。UAO为1表示在EL1和EL2执行这非特权指令(例如LDTR、STTR)的效果与特权指令(例如LDR、STR)是一样的。
该寄存器表示PSTATE寄存器中的{N,Z,C,V}字段。
除上面介绍的通用寄存器和特殊寄存器之外,ARMv8体系结构还定义了很多的系统寄存器,通过访问和设置这些系统寄存器来完成对处理器不同的功能配置。在ARMv7体系结构中,我们需要通过访问CP15协处理器来间接访问这些系统寄存器,而在ARMv8体系结构中没有协处理器,可直接访问系统寄存器。ARMv8体系结构支持如下7类系统寄存器:
系统寄存器支持不同的异常等级的访问,通常系统寄存器会使用“Reg_ELn”的方式来表示。
程序可以通过MSR和MRS指令访问系统寄存器。
mrs X0, TTBR0_EL1 //把TTBR0_EL1的值复制到X0寄存器
msr TTBR0_EL1, X0 //把X0寄存器的值复制到TTBR0_EL1
基于ARMv8体系结构设计的处理器内核有很多,例如常见的Cortex-A53、Cortex-A55、Cortex-A72、Cortex-A77以及Cortex-A78等。本书的实验环境采用树莓派4B开发板,内置了4个Cortex-A72处理器内核,因此我们重点介绍Cortex-A72处理器内核。
Cortex-A72是2015年发布的一个高性能处理器内核。它最多可以支持4个内核,内置L1和L2高速缓存,如图1.6所示。
Cortex-A72处理器支持如下特性。
▲图1.6 Cortex-A72处理器内部体系结构
指令预取单元用来从L1指令高速缓存中获取指令,并在每个周期向指令译码单元最多发送3条指令。它支持动态和静态分支预测。指令预取单元包括如下功能。
指令译码单元对以下指令集进行译码:
指令译码单元会执行寄存器重命名,通过消除写后写(WAW)和读后写(WAR)的冲突来实现乱序执行。
指令分派单元控制译码后的指令何时被分派到执行管道以及返回的结果何时终止。它包括以下部分:
加载/存储单元(LSU)执行加载和存储指令,包含L1数据存储系统。另外,它还处理来自L2内存子系统的一致性等服务请求。加载/存储单元的特性如下。
L1内存子系统包括指令内存系统和数据内存系统。
L1指令内存系统包括如下特性。
L1数据内存系统包括如下特性。
MMU用来实现虚拟地址到物理地址的转换。在AArch64状态下支持长描述符的页表格式,支持不同的页面粒度,例如4 KB、16 KB以及64 KB页面。
MMU包括以下部分:
TLB不仅支持8位或者16位的ASID,还支持VMID(用于虚拟化)。
L2内存子系统不仅负责处理每个处理器内核的L1指令和数据高速缓存未命中的情况,还通过ACE或者CHI连接到内存系统。其特性如下。
2021年ARM公司发布ARMv9体系结构。ARMv9体系结构在兼容ARMv8体系结构的基础上加入了一些新的特性,其中:
ARMv9体系结构新加入的特性包括:
另外,ARMv9体系结构对AArch32执行环境的支持发生了变化。在EL0中,ARM64体系结构对AArch32状态的支持是可选的,取决于芯片设计;而在EL1/EL2/EL3中,ARM64体系结构将不再提供对AArch32状态的支持。
本文摘自:ARM64体系结构编程与实践
1.内容系统,突出动手实践
基于树莓派4B开发板,系统介绍ARM64体系结构,内容由浅入深,帮助读者开发运行小型的OS
2.以问题为导向,提高学习效率
深入浅出的问题导向式学习方法,各大公司高频面试题,提高读者阅读兴趣
3.趣味案例,常见陷阱总结
基于树莓派4B开发板和QEMU实验平台,总结了众多一线工程师在实际项目中遇到的陷阱与经验,让你不再害怕踩雷
4.海量资源随书赠送
本书赠送配套VMware开发环境,Linux软件包,QEMU+ARM64实验平台仓库,芯片资料,实验参考代码和配套资料以及配套教学视频供读者参考学习
本书旨在详细介绍ARM64体系结构的相关技术。本书首先介绍了ARM64体系结构的基础知识、搭建树莓派实验环境的方法,然后讲述了ARM64指令集中的加载与存储指令、算术与移位指令、比较与跳转等指令以及ARM64指令集中的陷阱,接着讨论了GNU汇编器、链接器、链接脚本、GCC内嵌汇编代码、异常处理、中断处理、GIC-V2,最后剖析了内存管理、高速缓存、缓存一致性、TLB管理、内存屏障指令、原子操作、操作系统等内容。
本书适合嵌入式开发人员阅读。