0%

ARM64架构基础

原图

ARM64架构介绍

ARMv8-A架构介绍

ARMv8-A是ARM公司发布的第一代支持64位处理器的指令集和架构。ARMv8-A架构除了提高了处理能力外,还引入了很多吸引人的新特性。

  • 具有64位宽的虚拟地址空间
  • 提供31个64位宽的通用寄存器,可以减少对栈的访问,从而提高性能
  • 提供16KB和64KB的页面,有助于降低TLB的未命中率(miss rate)
  • 具有全新的异常处理模型,有助于降低操作系统和虚拟化的实现复杂度
  • 具有全新的加载-获取、存储-释放指令(load-acquire,store-release instruction),专为C++11以及Java内存模型而设计

ARM64的基本概念

ARM处理器实现的是精简指令集计算机(Reduced Instruction Set Computer,RISC)架构。本节介绍ARMv8-A架构中的一些基本概念。

  • 处理单元 ARM公司的官方技术手册中提到了一个概念,可以把处理器处理事务的过程抽象为处理单元(Processing Element,(PE)

  • 执行状态 执行状态(execution state)是处理器运行时的环境,包括寄存器的位宽、支持的指令集异常模型、内存管理以及编程模型等。ARMv8架构定义了两种执行模式

    • AArch64:64位的执行状态。提供31个64位的通用寄存器、提供64位的程序计数(PC)寄存器、栈指针(SP)寄存器以及异常链接寄存器(ELR)。提供A64指令集、定义ARMv8异常模型,支持4个异常等级ELO~EL3
    • AArch32:32位的执行状态。提供13个32位的通用寄存器,再加上PC寄存器、SP寄存器、链接寄存器(LR)。支持两套指令集,分别是A32和T32指令集(Thumb指令集)
  • ARMv8指令集

    • A64指令集:运行在AArch64状态,提供64位指令集支持
    • A32指令集:运行在AArch32状态,提供32位指令集支持
    • T32指令集:运行在AArch32状态,提供16和32位指令集支持
  • 系统寄存器命名 在AArch64状态下,很多系统寄存器会根据不同的异常等级提供不同的变种寄存器

    _ELx, where x is 0,1, 2, or 3

比如,SP_ELO表示ELO下的栈指针寄存器,SP_EL1表示EL1下的栈指针寄存器。

ARMv8处理器的运行状态

ARMv8处理器支持两种运行状态--AArch64状态和AArch32状态。AArch64架构的异常等级(exception level)确定了处理器当前运行的特权级别,类似于ARMv7架构中的特权等级.

  • EL0:用户特权,用于运行普通用户程序
  • EL1:系统特权,通常用于运行操作系统
  • EL2:运行虚拟化扩展的虚拟监控程序(hypervisor)
  • EL3:运行安全世界中的安全监控器(secure monitor)

在ARMv8架构里允许切换应用程序的运行模式。比如,在运行64位操作系统的ARMv8处理器中,我们可以同时运行A64指令集的应用程序和A32指令集的应用程序。当需要执行 A32指令集的应用程序时,需要通过管理员调用(Supervisor Call, SVC)指令切换到EL1操作系统会执行任务的切换并且返回到AArch32的ELO,这时候系统便为这个应用程序备好了AArch32的运行环境。

不对齐访问

对齐访问有两种情况。一种是指令对齐,另一种是数据对齐。

  • A64指令集要求指令存放的位置必须以字(word,32位宽)为单位对齐。访问存储位置不是以字为单位对齐的指令会导致PC对齐异常(PCaligment fault)
  • 对于数据访问,需要区分不同的内存类型
    • 对内存类型是设备内存的不对齐访问会触发对齐异常(alignment fault)
    • 对于访问普通内存,除了使用独占、加载/独占-存储(load-exclusive/store-exclusive)指令或加载-获取/存储-释放(load-acquire/store-release)指令外,还可使用其他的用于加载或存储单个或多个寄存器的所有指令。如果访问地址和要访问的数据元素大小不对齐,那么可以根据以下两种情况进行处理:
      • 若对应的异常等级中的SCTLR_ELx寄存器的A域设置为1,则说明打开了地址对齐检查功能,因而会触发对齐异常
      • 若对应的异常等级中的SCTLRELx寄存器的A域设置为0,则说明处理器支持不对齐访问

当然,处理器支持的不对齐访问也有一些限制。

  • 不能保证单次访问原子地完成,有可能复制多次
  • 不对齐访问比对齐访问需要更多的处理时间
  • 不对齐的地址访问可能会引发中止(abort)

ARMv8寄存器

通用寄存器

AArch64运行状态支持31个64位的通用寄存器,分别是x0~x30寄存器,而AArch32运行状态支持16个32位的通用寄存器。通用寄存器除了用于数据运算和存储之外,还可以在函数调用过程中起到特殊作用,ARM64架构的函数调用标准和规范对此有所约定。

  • 传递参数和结果: x0 - x7
  • 间接结果寄存器: x8
  • 临时寄存器(调用的函数需要保存): x8 - x15
  • 平台寄存器: x16(IP0) x17(IP1) x18(PR)
  • 被调用函数需要保存: x19 - x28
  • 栈帧寄存器: x29(FP)
  • 链接寄存器: x30(LR)

在AArch64运行状态下,使用X来表示64位通用寄存器,比如X0、X30等。另外,还可以使用W来表示低32位的寄存器,比如W0表示X0寄存器的低32位数据。

特殊寄存器

ARMv8架构除了支持31个通用寄存器之外,还提供各个特殊的寄存器,如下图所示:

零寄存器

ARMv8架构提供两个零寄存器(zero register),这两个零寄存器的内容全是0,可以用作源寄存器,也可以当作目标寄存器。WZR是32位的零寄存器,XZR是64位的零寄存器。

栈指针寄存器

ARMv8架构支持4个异常等级,每一个异常等级都有专门的SP_ELn寄存器,比如当处理器运行在EL1时就选择SP_EL1寄存器作为栈指针(Stack Pointer,SP)寄仔器。

  • SP EL0:EL0下的栈指针寄存器
  • SP EL1:EL1下的栈指针寄存器
  • SP EL2:EL2下的栈指针寄存器
  • SP EL3:EL3下的栈指针寄存器

当处理器运行在比EL0高的异常等级时:

  • 处理器可以访问当前异常等级对应的栈指针寄存器SP_ELn
  • EL0对应的栈指针寄存器SP_ELO可以当作临时寄存器,比如Linux内核就使用这种临时寄存器存放进程的task struct数据结构的指针
  • 当运行在ELO时,处理器只能访问SP_EL0寄存器,而不能访问其他高等级的SP寄存器

PC寄存器

PC (Program Counter)寄存器通常用来指向当前运行指令的下一条指令的地址,用于控制程序中指令的执行顺序,但是编程人员不能通过指令来直接访问。

异常链接寄存器

异常链接寄存器(Exception Link Register,ELR)用来存放异常返回地址。

保存处理状态寄存器

当我们进行异常处理时,处理器的处理状态会保存到保存处理状态寄存器(SavedProcess Status Register,(SPSR)里,这种寄存器非常类似于ARMv7架构中的CPSR。当异常将要发生时,处理器会把处理状态寄存器(PSTATE)的值暂时保存到SPSR里;当异常处理完成并返回时,再把SPSR中的值恢复到处理器状态寄存器。SPSR的布局如图所示:

  • CurrentEL寄存器
    PSTATE寄存器中的EL字段保存了当前异常等级。使用MRS指令可以读取当前异等级。
    • 0:表示ELO
    • 1:表示EL1
    • 2:表示EL2
    • 3:表示EL3
  • DAIF寄存器
    表示PSTATE寄存器中的{D,A,I,F}字段
    • D Debug exceptions mask
    • A SError interrupt Process state mask, for example, asynchronous external abort
    • I IRQ interrupt Process state mask
    • F FIQ interrupt Process state mask
  • SPSel寄存器 表示PSTATE寄存器中的SP字段,用来在SP_EL0和SP_ELn中选择栈指针寄存器

系统寄存器

除了上面介绍的通用寄存器和特殊寄存器之外,ARMv8架构还定义了很多系统寄存器,可通过访问和设置这些系统寄存器来完成对处理器不同功能的配置。在ARMv7架构里,我们需要通过访问CP15协处理器来间接访问这些系统寄存器:而在ARMv8架构中没有协处理器,可直接访问系统寄存器。ARMv8架构支持如下7大类的系统寄存器:

  • 通用系统控制寄存器
  • 调试寄存器
  • 性能监控寄存器
  • 活动监控寄存器
  • 统计扩展寄存器
  • RAS寄存器
  • 通用定时器寄存器

系统寄存器支持不同异常等级下的访问,通常系统寄存器可使用“Reg_ELn”的方式来表示,示例如下。

  • Reg_EL1:处理器处于EL1、EL2以及EL3时可以访问该寄存器
  • Reg_EL2:处理器处于EL2和EL3时可以访问该寄存器

当处于EL0时,大部分系统寄存器不支持处理器访问,但也有一些例外,比如CTR_ELO。可以通过MSR和MRS指令来访问系统寄存器,比如:

1
2
mrs x0, TTBRO_EL1 //把TTBR0_EL1的值复制到x0寄存器
msr TTBROEL1, xO //把x0寄存器的值复制到TTBR0_EL1

A64指令集

指令集架构(ISA)是处理器架构设计的重点之一。ARM公司定义和实现的指令集架构一直在不断变化和发展。ARMv8架构最大的改变是增加了一种新的64位的指令集,这是对早前ARM指令集的有益补充和增强,称为A64指令集。这种指令集可以处理64位宽的寄存器,并且使用64位的指针来访问内存,运行在AArch64状态下。ARMv8兼容老的32位指令集,又称为A32指令集,运行在AArch32状态下。 A64指令集和A32指令集是不兼容的,它们是两套完全不一样的指令集架构,它们的指令编码也不一样。需要注意的是,A64指令集的指令为32位宽,而不是64位宽

aarch64架构图

指令集概览:

详细可以查看原文点击

ARM64异常处理

在arm64架构里,中断属于异常的一种。中断是外部设备通知处理器的一种方式,他会打断处理器正在执行的指令流。在前面的描述中断的文章中已经介绍了关于异常的处理,这里不再细说。

ARM64内存管理

如图所示,ARM处理器的内存管理单元(Memory Management Unit,MMU)包括TLB和页表遍历单元(Table Walk Unit)两个部件。TLB是一块高速缓存,用于缓存页表转换结果,从而减少页表查询的时间。完整的页表翻译和查找的过程叫作页表查询(TranslatonTable Walk),页表查询的过程由硬件自动完成,但是页表的维护需要由软件完成。

对于多任务操作系统,每个进程都拥有独立的进程地址空间。这些进程地址空间在虚地址范围内是相互隔离的,但是在物理地址空间内有可能映射到同一个物理页面,那么这些进程地址空间是如何和物理地址空间发生映射关系的呢?这就需要处理器的内存管理单元提供页表映射和管理的功能。

页表

AArch64架构中的MMU不仅支持单一阶段的地址页表转换,还支持虚拟化扩展中的两阶段页表转换

  • 单一阶段页表:虚拟地址(VA)被翻译成物理地址(PA)
  • 两阶段页表(虚拟化扩展) 阶段1虚拟地址被翻译成中间物理地址(Intermediate Physical Adress,IPA) 阶段2中间物理地址被翻译成最终物理地址

页表映射

在AArch64架构中,因为地址总线位宽最多支持48位,所以虚拟地址被划分为两个空间,每个空间最多支持256TB。

  • 低位的虚拟地址空间位于0x00000000000000~0x0000FFFFFFFFF。如果虚拟地址的最高位等于0,那就使用这个虚拟地址空间,并且使用TTBRO_ELx (TranslationTable Base Register)来存放页表的基地址
  • 高位的虚拟地址空间介于0xFFFF00000000000~0xFFFFFFFFFFFFF。如果虚拟地址的最高位等于1,那就使用这个虚拟地址空间,并且使用TTBR1_ELx来存放页表的基地址

AArch64架构中的页表支持如下特性。

  • 最多可以支持4级页表
  • 输入地址的最大有效位宽为48位
  • 输出地址的最大有效位宽为48位
  • 翻译的页面粒度可以是4KB、16KB或64KB

当TLB未命中时,处理器查询页表的过程如下。

  • 处理器根据TTBRx和虚拟地址来判断使用哪个页表基地址寄存器,是使用TTBR0还是TTBR1。当虚拟地址的第63位(简称VA[63])为1时选择TTBR1当VA[63]为0时选择TTBR0。页表基地址寄存器中存放着一级页表的基地址
  • 处理器将虚拟地址的VA[47:39]作为L0索引,在一级页表(L0页表)中找到页表项,一级页表一共有512个页表项
  • 一级页表的页表项中存放有二级页表(L1页表)的物理基地址。处理器将虚拟地址的VA[38:30]作为L1索引,在二级页表中找到相应的页表项,二级页表有512个页表项
  • 二级页表的页表项中存放有三级页表(L2页表)的物理基地址。处理器将虚拟地址的VA[29:21]作为L2索引,在三级页表(L2页表)中找到相应的页表项,三级页表有512个页表项
  • 三级页表的页表项中存放有四级页表(L3页表)的物理基地址。处理器将虚拟地址的VA[20:12]作为L3索引,在四级页表(L3页表)中找到相应的页表项,四级页表有512个页表项
  • 四级页表的页表项里存放有4KB页的物理基地址,然后加上虚拟地址的VA[11:0]就构成了新的物理地址,于是处理器就完成了页表的查询和翻译工作

参考文献

https://blog.51cto.com/u_15278218/2930963
https://courses.cs.washington.edu/courses/cse469/19wi/arm64.pdf
《ARM-Architecture Reference Manual,for ARMv8-A Architecture Profile,v8.4》
《奔跑吧Linux内核-入门篇》