arm64 linux 学习笔记一

写在前面的一些杂七杂八的东西

  1. ARM从ARMv8开始支持64位架构,当前的ARMv8只有A系列,ARMv8-A架构。
  2. 新增一套arm64位指令集称为A64,之前的32位arm指令集称为A32, thumb指令集称为T32。
  3. 定义AArch64/AArch32两套运行环境(称作Execution state)分别执行64/32位指令集。
  4. A64和A32指令集的每个指令都是固定4字节的。
  5. ARMv8的异常与以前的架构做了较大改动,以前的ARM,处理器可以处在多种工作模式(process mode),如 User,FIQ, IRQ, Abort, Undefined,System等,每个模式都是由1/2中相应的中断触发的。实际上粗略分只是两种特权模式(User属于非特权模式,其他的都是特权模式)。

    在ARMv8中User,FIQ, IRQ, Abort, Undefined,System这些模式统统取消,被EL0,EL1,EL2,EL3四种特权特权模式取代(跟之前的特权模式/非特权模式相比,实际上特权级还是增加了的)。与x86的ring0-ring3刚好相反,在这四种模式中EL0是最低权限,一般给用户态程序用的。EL1稍高,一般给内核用的。EL2/EL3分别是Hypervisor(虚拟化相关)和secure monitor(安全相关)的模式,一般linux中是可以不用的。

    因为需要兼容ARMv7,所以User,FIQ, IRQ, Abort, Undefined,System这些中断模式还是需要支持的,在ARMv8中就全部直接映射到EL1模式了(TODO: 应该是有个寄存器记录当前具体哪个模式)。

    ARMv8异常模式如下图(摘自[1])。
    arm64 linux 学习笔记一_第1张图片

  6. 不同EL级别之间的转换规则:

    1. EL转换只会发生在 异常发生 或者 异常返回 的时候。
    2. 异常发生时EL级别只能提升或不变。
    3. 异常返回时EL级别只能降低或不变。
    4. EL转换的目标级别称为”目标异常级别”,只能由异常自身特征,或配置系统控制寄存器决定。
    5. 目标异常级别不能使EL0。
    6. 不同的EL级别有些寄存器是不同的,如图(摘自[2])。
      arm64 linux 学习笔记一_第2张图片
  7. Execution state的变化(这个词…意会吧)
    1. AArch64提供31个(x0 - x30)64-bit的通用寄存器
    2. 提供64位的pc/lr/sp
    3. A32/T32的切换通过BX即可,但A32/A64的切换必须通过异常。
    4. EL0,EL1,EL2,El3之前的切换,分别通过指令svc,hvc,smc。
    5. 若下层系统为32bit(如EL1),则上层只能为32bit(如EL0),反之若下层位64bits,则上层可以为32/64bits。
  8. 8.

虚拟内存体系结构(Vritual Memory System Architecture, VMSA)

  1. 在AArch64模式下(所有转换机制都包括),地址用64位表示,但其中最多只有后48位是有效的地址位,2^48 = 256TB。
  2. AArch64支持多种地址转换机制,如图:
    arm64 linux 学习笔记一_第3张图片
    看着比较蛋疼,其中主要有两点需要注意,一个是是不是secure,一个是是不是两个stage。 个人理解,是不是secure跟开没开器EL3有关(secure monitor),是不是两个stage跟用没用上EL2有关(Hypervisor),两个stage的意思就是在通常的地址转换上又加了一层地址转换。其中arm linux kernel用的是VMSAv8-64 EL1&0这一种,没用到EL2,也就是说只有stage1(我用到的是这样,目前看到的只用了这一种,后面默认以这个为例)。
    这个只有stage1的不是说页表只需要一次转换了,这个只有stage1的和我们arm32理解的正常有mmu的地址转换是一样的。如果有stage2,还要在mmu转换后再多一次转换。
  3. mmu地址转换中最关键的两个寄存器就是TTBR(Translation Table Base Register)和TCR(Translation Control Register),TCR就是mmu的控制寄存器,TTBR是mmu的页表物理基址寄存器。注意这两个寄存器都是统称,不是具体的某个寄存机,在不同地址转换机制下,这两个寄存器的名字还不太一样,如下图。
    arm64 linux 学习笔记一_第4张图片
    我们这里只关注EL1&0的模式。
  4. VMSAv8-64 EL1&0模式下的虚拟地址的第55位(VA[55]),代表了应该基于哪个页表查表(TCR_EL1.TBIx应该是使能位),arm手册中有一下描述:
    1. 如果VA[55] = 0 &&TCR_EL1.TBI0 = 1,则基于TTBR0查表。
    2. 如果VA[55] = 1 &&TCR_EL1.TBI1 = 1,则基于TTBR1查表。
    3. 在上述模式中,VA[64-56]为VA[55]的符号扩展(1635页)。
    4. EL1&0模式下,有两个虚拟子地址空间,0x0000_XXXX_XXXX_XXXX和 0xFFFF_XXXX_XXXX_XXXX,这两个地址空间都是256TB大小。
      综上所述: EL1&0模式下有两个虚拟地址空间:
      1. 0x0000_XXXX_XXXX_XXXX,mmu转换基于TTBR0。
      2. 0xFFFF_XXXX_XXXX_XXXX,mmu转换基于TTBR1。
  5. AArch64最多可支持4级页表,分别为level0 - level3,但也可以支持3,2级页表(4KB页只能4,3级页表,64KB页只能3,2级页表),使用几级页表是由TCR.TxSZ来标记的(这个x分别代表TTBR0/TTBR1是几级页表),使用多大页是由TCR.TGx来决定的,以4KB页为例:
    1. 如果使用4级页表,则地址转换方式如下:
      arm64 linux 学习笔记一_第5张图片
    2. 如果使用3级页表,则地址转换方式如下:
      arm64 linux 学习笔记一_第6张图片
      在我用到的arm linux中,使用的就4KB页 + 3级页表的方式。
  6. 3级页表则代表虚拟地址只有[38:0]是有效位,可代表的地址范围为512G。所以在我目前测试的arm linux中,地址空间一共分为两段:
    1. 0x0000000000000000 - 0x0000007FFFFFFFFF(512GB), 通过TTBR0寻址,从level1开始做地址转换。
    2. 0xFFFFFF8000000000 - 0xFFFFFFFFFFFFFFFF(512GB),通过TTBR1寻址,从level1开始做地址转换。
    ps:[64:56]位任何值都不影响地址解析,[55-39]位会有问题,看手册中的伪代码,感觉[54-48]位应该也不影响,但实际上没试验成功。

参考资料

[1]. http://www.wowotech.net/armv8a_arch/armv8-a_overview.html
[2]. http://blog.chinaunix.net/uid-29955651-id-4855990.html
[3]. http://www.xuebuyuan.com/879030.html
[4]. http://loda.hala01.com/
[5]. http://wiki.csie.ncku.edu.tw/embedded/ARMv8

你可能感兴趣的:(嵌入式系统,linux-kernel)