嵌入式系统Linux内核开发实战指南(ARM平台)
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

第4章 ARM处理器内存管理单元(MMU)

4.1 ARM处理器中CP15协处理器的寄存器

本章和第5章的内容都与ARM处理器中CP15协处理器的寄存器有密切关系,所以我们这里先介绍一下CP15寄存器以及访问CP15寄存器的汇编指令。

4.1.1 访问CP15寄存器的指令

访问CP15寄存器指令的编码格式及语法说明如下:

说明:

<opcode_1>:协处理器行为操作码,对于CP15来说,<opcode_1>永远为0b000,否则结果未知。

<rd>:不能是r15/pc,否则,结果未知。

<crn>:作为目标寄存器的协处理器寄存器,编号为C0~C15。

<crm>:附加的目标寄存器或源操作数寄存器,如果不需要设置附加信息,将crm设置为c0,否则结果未知。

<opcode_2>:提供附加信息比如寄存器的版本号或者访问类型,用于区分同一个编号的不同物理寄存器,可以省略<opcode_2>或者将其设置为0,否则结果未知。

4.1.2 CP15寄存器介绍

CP15的寄存器列表如表4-1所示。

表4-1 ARM处理器中CP15协处理器的寄存器

CP15中寄存器C0对应两个标识符寄存器,由访问CP15中的寄存器指令中的<opcode_2>指定要访问哪个具体物理寄存器,<opcode_2>与两个标识符寄存器的对应关系如下所示:

● CP15的寄存器C0

1)主标识符寄存器

访问主标识符寄存器的指令格式如下所示:

        mrc p15, 0, r0, c0, c0, 0      ;将主标识符寄存器C0,0的值读到r0中

ARM不同版本体系处理器中主标识符寄存器的编码格式说明如下。

ARM7之后处理器的主标识符寄存器编码格式如下所示:

ARM7处理器的主标识符寄存器编码格式如下所示:

ARM7之前处理器的主标识符寄存器编码格式如下所示:

2)cache类型标识符寄存器

访问cache类型标识符寄存器的指令格式如下所示:

        mrc p15, 0, r0, c0, c0, 1      ;将cache类型标识符寄存器C0,1的值读到r0中

ARM处理器中cache类型标识符寄存器的编码格式如下所示:

其中控制字段位[28:25]的含义说明如下:

表4-2 cache类型标识符寄存器的控制字段位[28:25]

控制字段位[23:12]和控制字段位[11:0]的编码格式相同,含义如下所示:

cache容量字段bits[8: 6]的含义如下所示:

cache相联特性字段bits[5: 3]的含义如下所示:

cache块大小字段bits[1: 0]的含义如下所示:

● CP15的寄存器C1

访问主标识符寄存器的指令格式如下所示:

        mrc p15, 0, r0, c1, c0{, 0}    ;将CP15的寄存器C1的值读到r0中
        mcr p15, 0, r0, c1, c0{, 0}    ;将r0的值写到CP15的寄存器C1中

CP15中的寄存器C1的编码格式及含义说明如下:

CP15中的寄存器C2保存的是页表的基地址,即一级映射描述符表的基地址。其编码格如下所示:

● CP15的寄存器C2

● CP15的寄存器C3

CP15中的寄存器C3定义了ARM处理器的16个域的访问权限。

● CP15的寄存器C5

CP15中的寄存器C5是失效状态寄存器,编码格式如下所示:

其中,域标识bit[7:4]表示存放引起存储访问失效的存储访问所属的域。

状态标识bit[3:0]表示放引起存储访问失效的存储访问类型,该字段含义如表4-3所示(优先级由上到下递减)。

表4-3 状态标识字段含义

● CP15中的寄存器C6

CP15中的寄存器C5是失效地址寄存器,编码格式如下所示:

● CP15中的寄存器C7

CP15的C7寄存器用来控制cache和写缓存,它是一个只写寄存器,读操作将产生不可预知的后果。

访问CP15的C7寄存器的指令格式如下所示:

        mcr p15, 0, <rd>, <c7>, crm, <opcode_2>;<rd>、<crm>和<opcode_2>的不同取值
    组合 实现不同功能

● CP15中的寄存器C8

CP15的C8寄存器用来控制清除TLB的内容,是只写寄存器,读操作将产生不可预知的后果。

访问CP15的C8寄存器的指令格式如下所示:

        mcr p15, 0, <rd>, <c8>, crm, <opcode_2>;<rd>、<crm>和<opcode_2>的不同取值
    组合实现不同功能,见第4.2节

● CP15中的寄存器C9

CP15的C9寄存器用于控制cache内容锁定。

访问CP15的C9寄存器的指令格式如下所示:

        mcr p15, 0, <rd>, <c9>, c0, <opcode_2>
        mrc p15, 0, <rd>, <c9>, c0, <opcode_2>

如果系统中包含独立的指令cache和数据cache,那么对应于数据cache和指令cache分别有一个独立的cache内容锁定寄存器,<opcode_2>用来选择其中的某个寄存器:

<opcode_2>=1选择指令cache的内容锁定寄存器;

<opcode_2>=0选择数据cache的内容锁定寄存器。

CP15的C9寄存器有A、B两种编码格式。编码格式A如下所示:

其中index表示当下一次发生cache未命中时,将预取的存储块存入cache中该块对应的组中序号为index的cache块中。此时序号为0~index-1的cache块被锁定,当发生cache替换时,从序号为index到ASSOCIATIVITY的块中选择被替换的块。

编码格式B如下所示:

● CP15的寄存器C10

CP15的C10寄存器用于控制TLB内容锁定。

访问CP15的C10寄存器的指令格式如下所示:

        mcr p15, 0, <rd>, <c10>, c0, <opcode_2>
        mrc p15, 0, <rd>, <c10>, c0, <opcode_2>

如果系统中包含独立的指令TLB和数据TLB,那么对应于数据TLB和指令TLB分别有一个独立的TLB内容锁定寄存器,<opcode_2>用来选择其中的某个寄存器:

<opcode_2>=1选择指令TLB的内容锁定寄存器;

<opcode_2>=0选择数据TLB的内容锁定寄存器。

C10寄存器的编码格式如下:

● CP15的寄存器C13

C13寄存器用于快速上下文切换FCSE。

访问CP15的C13寄存器的指令格式如下所示:

        mcr p15, 0, <rd>, <c13>, c0, 0
        mrc p15, 0, <rd>, <c13>, c0, 0

C13寄存器的编码格式如下所示:

其中,PID表示当前进程的所在的进程空间块的编号,即当前进程的进程标识符,取值为0~127。

0:MVA(变换后的虚拟地址)= VA(虚拟地址),禁止FCSE(快速上下文切换技术),系统复位后PID=0;

非0:使能FCSE。

4.2 MMU简介

MMU是Memory Manage Unit的缩写,即存储管理单元的意思。MMU实现以下功能:

1)虚拟存储地址到物理存储地址的映射;

2)控制存储空间访问权限;

3)设置存储空间的缓冲特性。

与MMU相关的一些基本概念介绍如下:

■ 页表(Translate Table)

页表又叫翻译表,用来将虚拟地址翻译成对应的物理地址,它位于内存中,是实现MMU功能的重要组成部分,处理器通过查找页表中的描述符来获取虚拟地址对应的物理地址。ARM处理器是按两级分页来管理内存的,所以页表包括一级页表和二级页表。一级页表中的每一项(1个字,4字节)对应于虚拟存储空间的一段(section),一段的大小为1MB(0x100000字节),该项包含了该虚拟存储段对应的物理存储段的基地址或者一段存储空间内每页的二级页表描述符组成的表的基地址、所属的内存域编号、缓冲特性等,一级页表的基地址保存在ARM处理器中CP15协处理器的C2寄存器中,该寄存器中保存的是一级页表的物理基地址,而不是虚拟地址。二级页表中的每一项(1word,4bytes)对应于虚拟存储空间的一页,一页的大小可以是4KB或1KB,该项包含了该虚拟存储页对应的物理存储页的基地址、该页的访问权限和该页的缓冲特性等。我们将页表中的每一项叫做一个地址变换条目(entry),也可以叫一个页表项。

■ 翻译援助缓冲区(Translation Lookaside Buffer,TLB)

TLB在硬件上和cache一样,是处理器内部的一小块高速SRAM内存,用于缓存,与cache不同的是,它专门缓存存放在内存中的页表,容量相对比较小,而cache则用于缓存普通内存,容量相对比较大。TLB也分为数据TLB和指令TLB,指令TLB用于取指令时的指令地址翻译,而数据TLB用于其他存储访问操作时的地址翻译。有的处理器中数据TLB和指令TLB是分开的,有的处理器中这两者是统一的。TLB是为了提高处理器查询页表的速度而设计的,所以TLB又叫快表。当处理器要查询页表时首先在TLB中查找,如果要查找的页表项不在TLB中,那么CPU从位于内存中的页表中查询,并把相应的结果添加到TLB中,这样CPU下次查找该页表项时就可以从TLB中直接获取。

4.3 系统访问存储空间的过程

系统访问存储空间的过程对于使能MMU和禁止MMU两种情况是不一样的。ARM处理器中控制MMU功能的开关位是CP15协处理器的C1寄存器的bit[0],当该位为0时禁止MMU功能,当该位为1时使能MMU功能。

4.3.1 使能MMU时的情况

当CPU请求存储访问时,首先在TLB中查找虚拟地址,如果该虚拟地址对应的地址变换条目(页表项)不在TLB中,CPU从位于内存中的页表中查询对应于该虚拟地址的页表项,并把相应的结果添加到TLB中,这样CPU下次再访问该页表项时就可以直接从TLB中获取。如果TLB已经装满,还应该根据一定的淘汰算法进行替换。

在得到了需要的页表项后,将进行以下操作:

1)得到该虚拟地址对应的物理地址;

2)根据页表项中的缓冲特性控制位C(Cachable)和B(Bufferable)的值决定是否缓存该存储访问的结果;

3)根据存取权限控制位和所属存储域的权限设置情况确定该存储访问是否被允许;

4)对于不允许缓存(uncached)的存储访问,使用上面步骤1)中得到的物理地址访问存储空间。对于允许缓存(cached)的存储访问,如果cache命中,则忽略物理地址;如果cache没有命中,则使用上面步骤1)中得到的物理地址访问存储空间,并把该数据块读到cache中。

4.3.2 禁止MMU时的情况

如果系统禁止MMU功能,那么CPU的存储访问规则如下:

1)当禁止MMU时,是否支持cache和Write Buffer由各具体芯片确定。如果芯片规定当禁止MMU的同时也禁止cache和Write Buffer,则存储访问不考虑缓冲特性控制位C和B的设置情况;如果芯片规定当禁止MMU时可以使能cache和Write Buffer,则数据访问时,C=0,B=0,指令读取时,如果使用数据和指令分开的TLB,则C=1,如果使用统一的TLB,则C=0。

2)存储访问不进行权限控制,MMU也不会产生存储访问中止信号。

3)所有的物理地址和虚拟地址相同,也就是使用所谓的平板存储模式。

4.3.3 使能/禁止MMU时应注意的问题

在使能和禁止MMU时要注意以下几点:

1)在使能MMU前,要在内存中建立好页表,同时CP15中的各相关寄存器必须完成初始化。

2)如果使用的不是平板存储模式(物理地址和对应虚拟地址相等),在禁止/使能MMU时,虚拟地址和物理地址的对应关系会发生改变,此时应该清除cache中的当前地址变换条目(TLB)。

3)如果完成禁止/使能MMU的代码的物理地址和虚拟地址不同,禁止/使能MMU时将造成很大麻烦,因此强烈建议完成禁止/使能MMU的代码的物理地址和虚拟地址相同(或者与地址无关)。

4.4 ARM处理器地址变换过程

虚拟存储空间到物理存储空间的映射是以内存块为单位进行的,虚拟存储空间中的一块连续存储空间被映射成物理存储空间中同样大小的一块连续存储空间。每一个地址变换条目(页表项)记录了一个虚拟存储空间的存储块的基地址与物理存储空间相应的一个存储块的基地址的对应关系。根据存储块大小不同,可以有多种地址变换。

ARM处理器支持的存储块大小有以下几种:

1)段(section):大小为1MB的存储块。

2)大页(Large Page):大小为64KB的存储块。

3)小页(Small Page):大小为4KB的存储块。

4)极小页(Tiny Page):大小为1KB的存储块。

通过采用适当的访问控制机制,还可以将大页分成大小为16KB的子页,也可将小页分成大小为1KB的子页,但极小页不能再细分,只能以1KB大小的整页为单位。

ARM处理器采用两级页表实现地址映射:

1)一级页表中包含以段为单位的地址变换条目或者指向二级页表的指针,一级页表实现的地址映射粒度较大。

2)二级页表中包含以大页、小页和极小页为单位的地址变换条目。

当以二级分页管理某段存储空间时,要同时设置一级页表项和二级页表项,一个一级页表项对应一段(1section=1MB)虚拟存储空间的映射关系,一个一级页表项对应一张二级页表,这张二级页表中的所有页表项合在一起对应了前面一级页表项所对应的一段虚拟存储空间的映射关系。ARM处理器的二级页表分为粗粒度二级页表和细粒度二级页表,一张粗粒度二级页表的最大容量为1KB,一张细粒度二级页表的最大容量为4KB,不管是粗粒度还是细粒度页表,每张页表都对应一段虚拟存储空间的映射关系。所以粗粒度二级页表的页表项(页描述符)最小只能描述4KB大小(小页)虚拟存储空间的映射关系,如果再小就没有足够的页表空间来存放一段虚拟存储空间的全部页表项(因为粗粒度二级页表的最大容量为1KB),而细粒度二级页表的页描述符最小可以描述1KB大小(极小页)的虚拟存储空间的映射关系。

综上所述,我们可以归纳出以下6种ARM处理器的地址变换方法:

1)分段地址变换,这种变换只需要一级地址变换,而下面5种都需要两级地址变换;

2)粗粒度大页地址变换;

3)粗粒度小页地址变换(Linux通常使用的地址变换方法);

4)细粒度大页地址变换;

5)细粒度小页地址变换;

6)细粒度极小页地址变换。

在讲解以上各种地址变换方法之前我们先介绍一下一级映射描述符和二级映射描述符的定义。

4.4.1 MMU的一级映射描述符

ARM处理器MMU的一级映射描述符编码格式如下所示:

表4-4 一级描述符对应的存储空间的cache和write buffer特性控制位

4.4.2 MMU的二级映射描述符

ARM处理器MMU的二级映射描述符编码格式如下所示:

表4-5 二级描述符对应的存储空间的cache和write buffer特性控制位

4.4.3 基于段的地址变换过程(见图4-1)

图4-1 分段地址变换过程

4.4.4 粗粒度大页地址变换过程(见图4-2)

图4-2 粗粒度大页地址变换过程

4.4.5 粗粒度小页地址变换过程(见图4-3)

图4-3 粗粒度小页地址变换过程

4.4.6 细粒度大页地址变换过程(见图4-4)

图4-4 细粒度大页地址变换过程

4.4.7 细粒度小页地址变换过程(见图4-5)

图4-5 细粒度小页地址变换过程

4.4.8 细粒度极小页地址变换过程(见图4-6)

图4-6 细粒度极小页地址变换过程

4.5 ARM存储空间访问权限控制

在ARM处理器中,MMU将整个存储空间分成最多16个域,记作D0~D15,每个域对应一定的存储区域,该区域具有相同的访问控制属性。

在ARM处理器中,MMU中的每个域的访问权限分别由CP15的C3寄存器中的两位来设定,C3寄存器刚好可以设置16个域的访问权限。C3寄存器的域定义如表4-6所示。

表4-6 CP15的C3寄存器的域定义

C3寄存器的D0~D15各占两位,它们分别控制D0~D15共16域的访问类型,具体说明如表4-7所示。

表4-7 域的访问控制字段编码及含义

当域访问权限控制位设置为上面的0b01即客户类型权限时,用户模式以及特权模式的访问权限则由CP15的C1控制寄存器中的R和S位以及页表中地址变换条目中的访问权限控制位AP两位来确定,具体说明如表4-8所示。

表4-8 MMU中存储访问权限控制

4.6 TLB操作

对TLB的操作是通过访问CP15的C8和C10寄存器来完成的,写CP15的C8/C10寄存器的指令格式如下所示:

        mcr p15, 0, <rd>, <c8>, crm, <opcode_2>
        mcr p15, 0, <rd>, <c10>, crm, <opcode_2>

4.6.1 使TLB内容无效

使TLB中的内容无效是通过写CP15的寄存器C8来实现的,指令如表4-9所示。

表4-9 使TLB内容无效操作指令

4.6.2 锁定TLB内容

锁定TLB是通过写CP15的寄存器C10来实现的。

锁定TLB中N条地址变换条目的操作步骤说明如下:

1)确保在整个锁定过程中不会产生异常中断,可以通过禁止中断等方法实现;

2)如果锁定的是指令TLB或者统一的TLB,将base=N、victim=N、P=0写入C10;

3)使整个将要锁定的TLB无效;

4)如果想要锁定的是指令TLB,确保与锁定过程所涉及的指令相关的地址变换条目已经加载到指令TLB中;如果想要锁定的是数据TLB,确保与锁定过程所涉及的数据相关的地址变换条目已经加载到指令TLB中;如果系统使用的是统一的数据TLB和指令TLB,上述两条都要保证;

5)对于I=0到N-1,重复执行下面操作:

将base=i、victim=i、P=1写入寄存器C10,将每一条想要锁定到快表中的地址变换条目读取到快表中。对于数据TLB和统一TLB可以使用ldr指令读取一个涉及该地址变换条目的数据,将该地址变换条目读取到TLB中。对于指令TLB,通过操作寄存器C7,将相应的地址变换条目读取到指令TLB中;

6)将base=N、victim=N、P=0写入寄存器C10。

4.6.3 解除TLB中被锁定的地址变换条目

解除TLB中被锁定的地址变换条目,可以使用以下操作步骤:

1)通过操作寄存器C8,使无效TLB中被锁定的地址变换条目;

2)将base=0、victim=0、P=0写入C10寄存器。

4.7 存储访问失效

ARM处理器通过以下两种机制来检测存储访问失效,进而中止CPU的运行:

1)MMU硬件模块检测与内存管理相关的存储访问失效,一旦MMU检测到存储访问失效,它向CPU发出通知,并将存储访问失效的相关信息保存到寄存器中,具体说就是将失效状态保存在CP15的C5寄存器中,将导致失效的地址保存在CP15的C6寄存器中,详见前面CP15的C5、C6寄存器说明。这种存储访问失效叫做MMU失效(MMU Fault)。

2)外部存储系统向CPU报告存储访问失效,这种机制叫做外部存储访问中止(External Abort)。

以上两种访问失效统称为存储访问中止(Abort)。如果存储访问中止发生在数据访问周期,CPU将产生数据访问中止异常中断,即Data Abort;如果存储访问中止发生在指令预取周期,那么CPU产生指令预取中止异常中断,即Prefetch Abort。

4.7.1 MMU失效(MMU Fault)

MMU可以产生以下4大类存储访问失效:

1)地址对齐失效:地址对齐失效指挥发生在数据访问周期,比如访问字单元(4字节)时地址的bit[1:0]不全是0或者访问半字(双字节)单元时地址的bit[0]不等于0;访问字节单元不会产生地址对齐失效,指令预取周期也不会产生地址对齐失效。

2)地址变换失效:当一级地址变换条目的bit[1:0]为0b00时,表示产生了基于段的地址变换失效;当二级地址变换条目的bit[1:0]为0b00时,表示产生了基于页的地址变换失效。

3)域控制失效:如果所访问的存储地址对应的一级地址变换条目中bit[8:5]的值所指的存储域的两位控制位被设置为0,就说明产生了域控制失效,域控制失效可能是基于段的也可能是基于页的。

4)访问权限控制失效:参见第4.5节“ARM存储空间访问权限控制”,如果出现了访问权限冲突就产生访问权限控制失效。

以上4大类存储访问失效又可细分为15种类型,见前面CP15的C5寄存器说明。

当发生存储访问失效时,存储系统可以中止3种存储访问:cache内容预取、非缓冲的存储器访问和页表访问。

4.7.2 外部存储访问失效(External Abort)

由外部存储系统向CPU报告存储访问失效。

外部存储访问失效通过一个外部存储访问失效引脚实现,下面的存储访问操作可以通过这种机制中止和重启动:

1)读操作;

2)非缓冲的写操作;

3)一级描述符的获取;

4)二级描述符的获取;

5)非缓冲的存储区域中的信号量操作。

注意:在系统中标记为可外部终止的存储区域不要进行可缓存的写操作。