将操作系统移植到Aarch64

Aarch64是ARM的64位体系结构(有时称为arm64)。 在本文中,我将告诉您它与“常规”(32位)ARM有何不同,以及将系统移植到它上有多困难。


本文不是详细的指南,而是概述了必须重做的那些系统模块,以及整个体系结构与普通的32位ARM有多少不同。 所有这些都是从我将Embox移植到此架构的个人经验得出的 。 对于特定系统的直接移植,您将不得不使用一种或另一种方式来处理文档,在本文结尾处,我留下了一些可能有用的文档的链接。


实际上,差异比相似之处更多,并且Aarch64更像是新架构,而不是熟悉的ARM的64位扩展。 Aarch64的前身主要是Aarch32(这是通常的32位ARM的扩展),但是由于我没有使用它的经验,所以我不会写它:)


在本文的进一步内容中,如果我写的是“旧”或“旧” ARM,我的意思是32位ARM(带有一组ARM命令)。


我将简要介绍与32位ARM相比的更改列表,然后将更详细地分析它们。


  • 通用寄存器的宽度增加了2倍(现在每个寄存器为64位),并且其数量增加了一倍(也就是说,现在没有16个,而是32个)。
  • 拒绝协处理器寄存器的概念,现在可以简单地通过名称来访问它们,例如msr vbar_el1, x0 (与之前的mcr p15, 0, %0, c1, c1, 2 msr vbar_el1, x0 mcr p15, 0, %0, c1, c1, 2 msr vbar_el1, x0相对)
  • 新的MMU模型(它与旧模型没有任何关系,您必须重新编写)。
  • 以前,有两种特权级别:用户(对应于USR处理器模式)和系统(对应于SYS,IRQ,FIQ,ABT等)模式,现在所有东西同时变得更加简单和复杂-现在有4种模式。
  • AdvSIMD替换为NEON,浮点操作通过它完成。

现在更多的是重点。


寄存器和指令集


通用寄存器为r0-r30,您可以将其作为64位(x0-x30)或32位(w0-w30,访问低32位)进行访问。


Aarch64的指令集称为A64。 在此处阅读说明的说明。 汇编语言中的基本算术和其他一些命令保持不变:


  mov w0, w1 /*    w1  w0 */ add x0, x1, 13 /*   x0  x1   13 */ b label /* ""   "label" bl label /* ""   "label",     x30 */ ldr x3, [x1, 0] /*   x3 ,    x1 */ str x3, [x0, 0] /*   x3  ,    x0 */ 

现在介绍一下差异:


  • 出现了一个特殊的“零” rzr/xzr/wzr ,在读取时为零(可以对寄存器使用写操作,但计算结果不会写到任何地方)。

 subs xzr, x1, x2 /*  x1  x2    NZCV,       */ 

  • 您不能一次将许多寄存器( stmfd sp!, {r0-r3} )堆叠到堆栈中,而必须成对进行:

  stp x0, x1, [sp, 16]! stp x2, x3, [sp, 16]! 

  • PC寄存器(程序计数器,指向当前执行指令的指针)现在不再是通用寄存器(以前是R15),因此无法使用普通命令( movldr )只能通过retbl等进行访问。


  • 程序状态现在不显示CPSR(此寄存器根本不存在),而是显示DAIF寄存器(包含IRQ,FIQ掩码等,AIF-CPSR中的A,I,F位相同),NZCV(负,零,进位) ,oVerflow-突然之间,来自CPSR的相同NZCV)和系统控制寄存器(SCTLR,以启用缓存,MMU,字节序等)。



这些命令似乎足以编写一个简单的引导加载程序,可以将控制权转移到与平台无关的代码:)


性能模式以及它们之间的切换


性能模式在ARMv8-A的基础知识中写得很好,在此我将简要介绍一下本文档的实质。


Aarch64具有4个特权级别(执行级别,以下简称EL)。


  • EL3-安全监视器(假定固件正在此级别上运行)
  • EL2-虚拟机监控程序
  • EL1-操作系统
  • EL0-应用

在64位OS上,您可以同时运行32位和64位应用程序。 在32位OS上,只能运行32位应用程序。



EL之间的转换既可以借助异常(系统调用,中断,内存访问错误)来实现,也可以借助异常返回( ereteret


每个EL都有自己的寄存器SPSR,ELR,SP(即它是“存储寄存器”)。


EL还划分了许多系统寄存器-例如,MMU上下文寄存器ttbr0ttbr0_el2ttbr0_el1 ,您需要访问相应EL上的寄存器。 程序状态寄存器-DAIF,NZCV,SCTLR,SPSR,ELR ...


MMU


Armv8-A支持MMU ARMv8.2 LPA,有关此内容的更多信息,请参见《 ARM体系结构参考手册》(ARMv8)的D5章Armv8-A


简而言之,此MMU支持4KiB页(4级虚拟内存表),16KiB(4级)和64KiB(3级)。 在任何中间级别上,您都可以指定一个内存块,从而不指示表的下一级,而是指示下一级表应“覆盖”的整个内存。 我有一篇关于虚拟内存的长期文章 ,您可以在其中阅读有关表,翻译级别等信息。


在较小的更改中,他们拒绝了域,但添加了诸如脏位之类的标志。


通常,除了“块”而不是中间转换表外,没有发现特殊的概念更改,MMU为MMU。


高级SIMD


在使用浮点运算和矢量运算(SIMD)时,旧的NEON中存在明显的AdvSIMD差异。 例如,如果较早的D0由S0和S1组成,而D0和D1由Q0-组成,则现在不是这样:对于Q1-D1和S0,Q0对应于D0和S0,依此类推。 同时,对VFP / SIMD的支持是强制性的,通过调用协议,现在不存在编程参数传递(在GCC中以前称为“ soft float ABI”-标志-mfloat-abi=softfp ),因此您必须实现对浮点的硬件支持。


有16个128位寄存器:



一共有32个128位的寄存器:



您可以在本文中阅读有关NEON的更多信息;可以在此处找到Aarch64可用命令的列表。


浮点寄存器的基本操作:


  fadd s0, s1, s2 /* s0 = s1 + s2 */ fmul d0, d1, d2 /* d0 = d1 * d2 */ 

SIMD基本操作:


  /*  , : NEON,    */ /* q0 = q1 + q2,   --   4     */ vadd.s32 q0, q1, q2 /* : AdvSIMD,    */ /* v0 = v1 + v2,   --   4     */ add v0.4s, v1.4s, v2.4s /*   v1 (  2 64- )    d1 */ addv d1, v1.ds /*     4   0 */ movi v1.4s, 0x0 

平台类


量化宽松


QEMU支持Aarch64。 其中一个平台是virt ,因此它以64位模式启动,您需要另外传递-cpu cortex-a53 ,如下所示:


 qemu-system-aarch64 -M virt -cpu cortex-a53 -kernel ./embox -m 1024 -nographic # ./embox -- ELF-  

很好,此平台使用了许多外围设备,其驱动程序已在Embox中使用-例如,用于控制台的PL011,ARM通用中断控制器等。当然,这些设备具有不同的基寄存器地址和其他中断号,但主要是驱动程序代码在新体系结构上保持不变。 系统启动时,控件位于EL1中。


i.MX8


由于这块铁,开始移植到Aarch64-i.MX8MQ Nitrogen8M。



与QEMU不同,u-boot将控制转移到EL2中的映像,而且由于某种原因,它包括MMU(所有内存都映射为1到1),这在初始化期间会产生一些其他问题。


Embox已经支持i.MX6,并且在i.MX8中,外围部分是相同的-例如,UART和以太网也可以工作(我必须修复几个紧密绑定到32位地址的地方)。 另一方面,中断控制器在那里有所不同-ARM GICv3,它与第一个版本完全不同。


结论


目前,Embox对Aarch64的支持还不完整,但是功能已经很少了-中断,MMU,通过UART的输入输出。 还有很多工作有待完成,但第一步比一开始看起来就容易做。 与ARM相比,文档和文章要少得多,但是有足够的信息来处理所有问题。


通常,如果您具有ARM的经验,则移植到Aarch64是可行的任务。 尽管像往常一样,您可能会偶然发现一些小问题:)


如果您有任何问题,可以从我们的资源库中下载该项目以在QEMU中戳它-在评论中,在新闻通讯中或在Telegram的聊天室中聊天 (也有一个频道 )。


有用的链接



聚苯乙烯


8月24日至25日,我们将在TechTrain上演讲,听我们的表演大约两到 三遍 ,来到展台-我们将回答您的问题:)

Source: https://habr.com/ru/post/zh-CN463417/


All Articles