第5章 ARM处理器的Cache和Write Buffer
Cache是位于CPU与主存储器即DRAM(Dynamic RAM,动态存储器)之间的少量超高速静态存储器SRAM(Static RAM),它是为了解决CPU与主存之间速度匹配问题而设置的,不能由用户直接寻址访问。随着科技的发展和生产工艺水平的提高,高性能处理器中Cache的容量将越来越大,而且级数将越来越多,从而大大提高系统的性能。
5.1 Cache和Write Buffer一般性介绍
本节我们摘录一些网上介绍Cache和Write Buffer的文章,以期读者能对Cache和Write Buffer有一个比较深刻的认识。按照先一般性后个性的顺序,我们后面章节再介绍ARM处理器中的Cache和Write Buffer时就会比较容易理解。
5.1.1 Cache工作原理
具有Cache的计算机,当CPU需要进行存储器存取时,首先检查所需数据是否在Cache中。如果存在,则可以直接存取其中的数据而不必插入任何等待状态,这是最佳情况,称为高速命中;当CPU所需信息不在Cache中时,则需切换存取主储器,由于速度较慢,需要插入等待,这种情况称高速未命中;在CPU存取主存储器的时候,按照最优化原则将存储信息同时写入到Cache中以保证下次可能的高速缓存命中。因此,同一数据可能同时存储在主存储器和Cache中。同样,按照优化算法,可以淘汰Cache中一些不常使用的数据。
传统的Socket架构通常采用两级缓冲结构,即在CPU中集成了一级缓存(L1 Cache),在主板上装二级缓存(L2 Cache),而SlotⅠ架构下的L2 Cache则与CPU做在同一块电路板上,以内核速度或者内核速度的一半运行,速度比Socket下的以系统外频运行的L2 Cache更快,能够更大限度发挥高主频的优势,当然对Cache工艺要求也更高。CPU首先在L1 Cache中查找数据,如找不到,则在L2 Cache中寻找。若数据在L2 Cache中,控制器在传输数据的同时,修改L1 Cache;若数据既不在L1 Cache中,又不在L2 Cache中,Cache控制器则从主存中获取数据,将数据提供给CPU的同时修改两级Cache。K6-Ⅲ则比较特殊,64KB L1 Cache,256KB Full Core Speed L2 Cache,原先主板上的缓存实际上就成了L3 Cache。根据有关测试表明:当512K~2MB的三级缓存发挥作用时,系统性能还可以有2%~10%的提高;Tri-level成为PC系统出现以来提出的解决高速CPU与低速内存之间瓶颈最为细致复杂的方案;而且,今后Cache的发展方向也是大容量、超高速。
在主存-Cache存储体系中,所有的指令和数据都存在主存中,Cache只是存放主存中的一部分程序块和数据块的副本,只是一种以块为单位的存储方式。Cache和主存被分为块,每块由多个字节组成。由上述的程序局部性原理可知,Cache中的程序块和数据块会使CPU要访问的内容在大多数情况下已经在Cache中,CPU的读写操作主要在CPU和Cache之间进行。CPU访问存储器时,送出访问单元的地址,由地址总线传送到Cache控制器中的主存地址寄存器MA,主存-Cache地址转换机构从MA获取地址并判断该单元内容是否已在Cache中存有副本,如果副本已存在于Cache中,即命中。当命中时,立即把访问地址变换成它在Cache中的地址,然后访问Cache。
如果CPU要访问的内容不在Cache中,即不命中,则CPU转去直接访问主存,并将包含此存储单元的整个数据块(包括该块数据的地址信息)传到Cache中,使得以后的若干次对内存的访问可转化为对Cache的访问。若Cache存储器已满,则需在替换控制部件的控制下,根据某种替换算法/策略,用此块信息替换掉Cache中原来的某块信息。
所以,要想提高系统效率,必须提高Cache命中率,而Cache命中率的提高则取决于Cache的映像方式和Cache刷新算法等一系列因素,同时Cache中内容应与主存中的部分保持一致,也就是说,如果主存中的内容在调入Cache之后发生了变化,那么它在Cache中的映像也应该随之发生相应改变,反之,当CPU修改了Cache中的内容后,主存中的相应内容也应作修改。
5.1.2 地址映像方式
所谓地址映像方式是指如何确定Cache中的内容是主存中的哪一部分的副本,即必须应用某种函数把主存地址映像到Cache中定位。当信息按某种方式装入Cache中后,执行程序时,应将主存地址变换为Cache地址,这个变换过程叫作地址变换。地址映像方式通常采用直接映像、全相联映像、组相联映像三种:
直接映像
每个主存地址映像到Cache中的一个指定地址的方式,称为直接映像方式。在直接映像方式下,主存中存储单元的数据只可调入Cache中的一个位置,如果主存中另一个存储单元的数据也要调入该位置则将发生冲突。地址映像的方法一般是将主存空间按Cache的尺寸分区,每区内相同的块号映像到Cache中相同的块位置。一般地,Cache被分为2N块,主存被分为大小为2MB的块,主存与Cache中块的对应关系可用如下映像函数表示:j = i mod 2N。式中,j是Cache中的块号;i是主存中的块号。
直接映像是一种最简单的地址映像方式,它的地址变换速度快,而且不涉及其他两种映像方式中的替换策略问题。但是这种方式的块冲突概率较高,当程序往返访问两个相互冲突的块中的数据时,Cache的命中率将急剧下降,因为这时即使Cache中有其他空闲块,也因为固定的地址映像关系而无法应用。
全相联映像
主存中的每一个字块可映像到Cache任何一个字块位置上,这种方式称为全相联映像。这种方式只有当Cache中的块全部装满后才会出现块冲突,所以块冲突的概率低,可达到很高的Cache命中率,但它实现很复杂。当访问一个块中的数据时,块地址要与Cache块表中的所有地址标记进行比较已确定是否命中。在数据块调入时存在着一个比较复杂的替换问题,即决定将数据块调入Cache中什么位置,将Cache中哪一块数据调出主存。为了达到较高的速度,全部比较和替换都要用硬件实现。
组相联映像
组相联映像方式是直接映像和全相联映像的一种折中方案。这种方法将存储空间分为若干组,各组之间是直接映像,而组内各块之间则是全相联映像。它是上述两种映像方式的一般形式,如果组的大小为1,即Cache空间分为2N组,就变为直接映像;如果组的大小为Cache整个的尺寸,就变为全相联映像。组相联方式在判断块命中及替换算法上都要比全相联方式简单,块冲突的概率比直接映像低,其命中率也介于直接映像和全相联映像方式之间。
5.1.3 Cache写入方式原理简介
提高高速缓存命中率的最好方法是尽量使Cache存放CPU最近一直在使用的指令与数据,当Cache装满后,可将相对长期不用的数据删除,提高Cache的使用效率。为保持Cache中数据与主存储器中数据的一致性,避免CPU在读写过程中将Cache中的新数据遗失,造成错误地读数据,确保Cache中更新过程的数据不会因覆盖而消失,必须将Cache中的数据更新及时准确地反映到主存储器中,这是一个Cache写入过程,Cache写入的方式通常采用直写式、缓冲直写式与回写式三种,下面比较介绍这三种Cache写入方式。
■ 直写式(Write Through)系统
CPU对Cache写入时,将数据同时写入到主存储器中,这样可保证Cache中的内容与主存储器的内容完全一致。这种方式比较直观,而且简单、可靠,但由于每次对Cache更新时都要对主存储器进行写操作,而这必须通过系统总线来完成,因此总线工作频繁,系统运行速度就会受到影响。
■ 缓冲直写式(Post Wirte)系统
为解决直写式系统对总线速度的影响问题,在主存储器的数据写入时增加缓冲器区。当要写入主存储器的数据被缓冲器锁存后,CPU便可执行下一个周期的操作,不必等待数据写入主存储器。这相对于给主存储器增加了一个单向单次高速缓存。比如,在写入周期之后可以紧接着一个数据已存在于Cache中的读取周期,这样就可避免直写式系统造成的操作延时,但这个缓冲器只能存储一次写入的数据,当连续两次写操作发生时,CPU仍需等待。
■ 回写式(Write Back)系统
前面两种写入方式系统,都是在写Cache的同时对主存储器进行写操作。实际上这不仅是对总线带宽的占用,浪费了宝贵的执行时间,而且在有些情况下是不必要的,可以通过增加额外的标准来判断是否有必要更新数据。回写式系统就是通过在Cache中的每一数据块的标志字段中加入一更新位,解决主存储器不必要的写操作。比如,若Cache中的数据曾被CPU更新过但还未更新主存储器,则该更新位被置1。每次CPU将一块新内容写入Cache时,首先检查Cache中该数据块的更新位,若更新位为0,则将数据直接写入Cache;反之,若更新位为1,则先将Cache中的该项内容写入到主存储器中相应的位置,再将新数据写回Cache中。
与直写式系统相比,回写式系统可省下一些不必要的立即回写操作,而在许多情况下这是很频繁出现的。即使一个Cache被更新,若未被新的数据所取代,则没有必要立刻进行主存储器的写操作。也就是说,实际写入主存储器的次数,可能少于CPU实际所执行写入周期的次数,但回写式系统的结构较复杂,Cache也必须用额外的容量来存储标志。由于回写系统的高效率,现代的Cache大多采取这种方式进行操作。
5.1.4 关于Write-through和Write-back
■ 对于磁盘操作来说
write-through的意思是写操作根本不使用缓存,数据总是直接写入磁盘,关闭写缓存,可释放缓存用于读操作(缓存被读写操作共用)。
write-back的意思是数据不直接被写入磁盘,而是先写入缓存,再由控制器将缓存内未写入磁盘的数据写入磁盘,从应用程序的角度看,比等待完成磁盘写入操作要快得多,因此可以提高写性能。
但是write-back(write cache)方式通常在磁盘负荷较轻时速度更快。负荷重时,每当数据被写入缓存后,就要马上再写入磁盘以释放缓存来保存将要写入的新数据,这时如果数据直接写入磁盘,控制器会以更快的速度运行。因此,负荷重时,将数据先写入缓存反而会降低吞吐量。
■ 对于CPU内部的cache缓冲模式来说
Write-Through和Write-Back,前者是按顺序来一个写一个,而后者则是先将资料按一定数量保存在缓冲区中,然后将相同位置的数据一次性写出。举例说明:有一部电梯,如果按先入先出的原则,即write through模式,第一个人去3楼,第二个去2楼,第三个也去3楼,那么这电梯就得先到3楼,然后到2楼,再去3楼。但如果在write back模式下,电梯先到2楼把第二个人送出去,然后再到3楼把第一个人和第三个人送出去,效率显然高多了。早期的cache只有write through模式,但现在的cache都使用write back模式了。
■ 其他的解释
Write-Through:在write的时候,同步更新cache和memory中的数据。
Write-Back:在write的时候更新cache,但是memory中的数据不一定同步更新,只有当cache到一定程度才会把cache中的数据刷到memory中,或者通过cache指令刷新,不会同步自动刷新。
cache line的意思是假设你那条指令只要从memory中读4个字节,但是一般来说你接下来的指令很有可能要读这4个字节后面的数据,所以一般硬件会多读一些数据进入cache,比如64字节,那么这64字节就是一个cache line。而如果你这个cache line里的数据长时间不被CPU访问,那么这个cache line可能会被选中换出,这时候就必须把cache里被改过的信息写回memory了。
5.1.5 Cache替换策略
Cache和存储器一样具有两种基本操作,即读操作和写操作。当CPU发出读操作命令时,根据它产生的主存地址分为两种情形:一种是需要的数据已在Cache中,那么只需要直接访问Cache,从对应单元中读取信息到数据总线即可;另一种是需要的数据尚未装入Cache,CPU需要从主存中读取信息的同时,Cache替换部件把该地址所在的那块存储内容从主存复制到Cache中。若Cache中相应位置已被字块占满,就必须去掉旧的字块。常见的替换策略有以下两种:
先进先出策略(FIFO)
FIFO(First In First Out)策略总是把最先调入的Cache字块替换出去,它不需要随时记录各个字块的使用情况,较容易实现。缺点是经常使用的块,如一个包含循环程序的块也可能由于它是最早的块而被替换掉。
最近最少使用策略(LRU)
LRU(Least Recently Used)策略是把当前近期Cache中使用次数最少的信息块替换出去,这种替换算法需要随时记录Cache中字块的使用情况。LRU的平均命中率比FIFO高,在组相联映像方式中,当分组容量加大时,LRU的命中率也会提高。
5.1.6 使用Cache的必要性
所谓Cache即高速缓冲存储器,它位于CPU与主存即DRAM之间,是通常由SRAM构成的规模较小但存取速度很快的存储器。目前计算机主要使用的内存为DRAM,它具有价格低、容量大等特点,但由于使用电容存储信息,存取速度难以提高,而CPU每执行一条指令都要访问一次或多次主存,DRAM的读写速度远低于CPU速度,因此为了实现速度上的匹配,只能在CPU指令周期中插入wait状态,高速CPU处于等待状态将大大降低系统的执行效率。由于SRAM采用了与CPU相同的制作工艺,因此与DRAM相比,它的存取速度快,但体积大、功耗大、价格高,不可能也不必要将所有的内存都采用SRAM。因此为了解决速度与成本的矛盾就产生了一种分级处理的方法,即在主存和CPU之间加装一个容量相对较小的SRAM作为高速缓冲存储器。当采用Cache后,在Cache中保存着主存中部分内容的副本(称为存储器映像),CPU在读写数据时,首先访问Cache(由于Cache的速度与CPU相当,所以CPU可以在零等待状态下完成指令的执行),只有当Cache中无CPU所需的数据时(这称之“未命中”,否则称为“命中”),CPU才去访问主存。而目前大容量Cache能使CPU访问Cache命中率高达90%~98%,从而大大提高了CPU访问数据的速度,提高了系统的性能。
5.1.7 使用Cache的可行性
对大量的典型程序的运行情况分析结果表明,在一个较短的时间内,由程序产生的地址往往集中在存储器逻辑地址空间的很小范围内。在多数情况下,指令是顺序执行的,因此指令地址的分布就是连续的,再加上循环程序段和子程序段要重复执行多次,因此对这些地址的访问就自然具有时间上集中分布的趋向。数据的这种集中倾向不如指令明显,但对数组的访问以及工作单元的选择都可以使存储器地址相对集中。这种对局部范围的存储器地址的频繁访问,而对此范围以外的地址则访问甚少的现象称为程序访问的局部性。根据程序的局部性原理,在主存和CPU之间设置Cache,把正在执行的指令地址附近的一部分指令或数据从主存装入Cache中,供CPU在一段时间内使用,是完全可行的。
5.2 ARM处理器中的Cache和Write Buffer
5.2.1 基本概念
5.2.2 Cache工作原理
在cache存储系统中,把cache和主存储器都划分成相同大小的块。主存地址由块号B和块内地址W两部分组成,cache地址由块号b和块内地址w组成。当CPU访问cache时,CPU送来主存地址,放到主存地址寄存器中,通过地址变换部件把主存地址中的块号B变换成cache的块号b,并放到cache地址寄存器中,同时将主存地址中的块内地址W直接作为cache的块内地址w装入cache地址寄存器中,如果变换成功(又叫cache命中),就用得到的cache地址去访问cache,从cache中取出数据送到CPU中;如果变换不成功(cache不命中),则产生cache失效信息,并且用主存地址访问主存储器,从主存储器中读出一个字送往CPU,同时把包含该字在内的一整块数据都从主存储器读出来装入cache,这时,如果cache已经满了,则要采用某种cache替换策略把不常用的块先调出到主存储中相应的块中,以便腾出空间来存放新调入的块。由于程序具有局部性特点,每次块失效时都把一块(由多个字组成)调入到cache中,能够提高cache的命中率。
5.2.3 Cache地址映射和变换方法
地址的映射和变换是密切相关的,采用什么样的地址映射方法就必然有与这种映射方法相对应的地址变换方法。无论采用什么样的地址映射方式和地址变换方式,都要把主存和cache划分成同样大小的存储单位,每个存储单位成为“块”,在进行地址映射和变换时,都是以块为单位进行的。常用的映射方式和变换方式有以下3种:
■ 全相联映射方式
主存中任意一块可以映射到cache中的任意一块上。
■ 直接映射方式
主存中一块只能映射到cache中的一个特定块上,假定主存的块号为B,cache的块号为b,cache的总块数为Cb,则它们之间的映射关系可以用下面的公式表示:
b = B mode Cb
■ 组相连映射方式
在这种相联的地址映射和变换方式中,把主存和cache按同样大小划分成组(set),每个组都由相同块数组成。从主存的组到cache的组之间采用直接映射方式,在主存中的组与cache中的组之间建立好映射关系之后,在两个对应的组内部采用全相联的映射方式。
在ARM处理器中,主存与cache采用组相联地址映射和变换方式,如果cache的块大小为2L,则同一块中各地址的bit[31:L]是相同的。如果cache中组的大小(每组中包含的块数)为2S,则虚拟地址的bit[L+S-1:L]用于选择cache中的某个组,而虚拟地址中其他位[31:L+S]包含了一些标志。
将cache每组中的块数称为组容量(set-associativity),当组容量等于cache中的总块数时,对应的映射方式为全相联映射方式;当组容量等于1时,对应的映射方式为直接映射方式;当组容量为其他值时,称为组相联映射方式。
在组相联映射方式中,cache的大小CACHE_SIZE(字节数)可以通过下面的公式来计算:
CACHE_SIZE = LINELEN*ASSOCIATIVITY*NSETS
其中,LINELEN为cache块(line)大小;ASSOCIATIVITY为组容量;NSETS为cache的组数。
5.2.4 Cache分类
根据不同的分类标准可以按以下3种方法对Cache进行分类。
1)数据cache和指令cache
● 指令cache:指令预取时使用的cache。
● 数据cache:数据读写时使用的cache。
如果一个存储系统中指令cache和数据cache是同一个cache,称系统使用了统一的cache。反之,如果是分开的,那么称系统使用了独立的cache;如果系统中只包含指令cache或者数据cache,那么在配制系统时可以作为独立的cache使用了。
使用独立的数据cache和指令cache,可以在同一个时钟周期中读取指令和数据,而不需要双端口的cache,但这时候要注意保证指令和数据的一致性。
2)写通(write-through)cache和写回(write-back)cache
● 写回cache
CPU在执行写操作时,被写的数据只写入cache,不写入主存,仅当需要替换时,才把已经修改的cache块写回到主存中,在采用这种更新算法的cache快表中,一般有一个修改位,当一块中的任何一个单元被修改时,这一块的修改位被设置为1,否则这一块的修改位仍保持为0;在需要替换这一块时,如果对应的修改位为1,则必须先把这一块写到主存中去之后,才能调入新的块,否则,只要用新调入的块覆盖该块即可。
● 写通cache
CPU在执行写操作时,必须把数据同时写入cache和主存,这样,在cache的快表中就不需要“修改位”,当某一块需要替换时,也不必把这一块写回到主存中,新调入的块可以立即把这一块覆盖掉。
写回cache和写通cache的优缺点比较如表5-1所示。
表5-1写回cache与写通cache比较
3)读时分配(read-allocate)cache和写时分配(write-allocate)cache
● 读时分配cache
当进行数据写操作时,如果cache没命中,只是简单地将数据写入主存中,主要在数据读取时,才进行cache内容预取。
● 写时分配cache
当进行数据写操作时,如果cache未命中,cache系统将会进行cache内容预取,从主存中将相应的块读取到cache中相应的位置,并执行写操作,把数据写入到cache中。对于写通类型的cache,数据将会同时写入到主存中,对于写回类型的cache,数据将在合适的时候写回到主存中。
由于写操作分配cache增加了cache内容预取的次数,增加了写操作的开销,但同时可能提高cache的命中率,因此这种技术对于系统整体性能的影响与程序中读操作和写操作的数量有关。
5.2.5 Cache替换算法
随机替换算法
通过一个伪随机数发生器产生一个伪随机数,用新块编号为该伪随机数的cache块替换掉。这种算法很简单且容易实现,但没有考虑程序的局部性特点,也没有利用历史上块地址流的分布情况,因而效果较差,同时这种算法不易预测最坏情况下cache的性能。
轮转替换算法
维护一个逻辑的计数器,利用该计数器依次选择将要被替换出去的cache块。这种算法容易预测在最坏情况下cache的性能。但在程序发生很小的变化时,可能造成cache平均性能的急剧变化,这是它的一个明显缺点。
5.2.6 Cache内容锁定
“锁定”在cache中的块在常规的cache替换操作中不会被替换,但当通过C7控制cache中特定的块时,比如使某特定的块无效时,这些被“锁定”在cache中的块也将受到相应的影响。
用LINELEN表示cache的块大小,用ASSOCIATIVITY表示每个cache组中的块数,用NSETS表示cache中的组数。cache的“锁定”是以锁定块(lockdown block)为单位进行的。每个锁定块中包括cache中每个组中各一个块,这样cache中最多可有ASSOCIATIVITY个锁定块,编号为0~ASSOCIATIVITY-1。其中编号为0的锁定块中包含cache组0中的0号块、组1中的0号块,一直到ASSOCIATIVITY-1中的0号块。
“N锁定块被锁定”是指编号为0~N-1的锁定块被锁定在cache中,编号为N~ASSOCIATIVITY-1的锁定块可用于正常的cache替换操作。
实现N锁定块被锁定的操作步骤说明如下:
1)确保在整个锁定过程中不会发生异常中断,否则必须保证与该异常中断相关的代码和数据位于非缓冲(uncachable)的存储区域。
2)如果锁定的是指令cache或者统一的cache,必须保证锁定过程所执行的代码位于非缓冲的存储区域。
3)如果锁定的是数据cache或者统一的cache,必须保证锁定过程所涉及的数据位于非缓冲的存储区域。
4)确保将要被锁定的代码和数据位于缓冲(cachable)的存储区域。
5)确保将要被锁定的代码和数据尚未在cache中,可以通过使无效相应cache中的块达到这一目的。
6)对于I=0到N-1,重复执行下面的操作:
a)Index=I写入CP15的C9寄存器,当使用B格式的锁定寄存器时,令L=1;
b)在锁定块I中的各cache块内容从主存中预取到cache中,对于数据cache和统一cache可以使用LDR指令读取一个位于该块中的数据,将块预取到cache中;对于指令cache,通过操作CP15的C7寄存器,将相应的块预取到指令cache中。
7)将index=N写入CP15的C9寄存器,当使用B格式的锁定寄存器时,令L=0。
解除N锁定块被锁定只须执行以下操作:
将index=0写入CP15的C9寄存器,当使用B格式的锁定寄存器时,令L=0。
5.2.7 MMU映射描述符中B位和C位的含义
见表5-2。
表5-2 存储空间缓冲特性的控制位
5.2.8 Cache和Writer Buffer编程接口
ARM处理器中的Cache和Write Buffer操作是通过写CP15的C7寄存器来实现的。访问CP15的C7寄存器的指令格式如下所示:
mcr p15, 0, <rd>, <c7>, crm, <opcode_2>
ARM处理器中的Cache和Write Buffer操作指令如表5-3所示。
表5-3 ARM处理器Cache和Write Buffer操作指令
5.3 ARM处理器的快速上下文切换技术
5.3.1 FCSE概述
FCSE(Fast Context Switch Extension,快速上下文切换)位于CPU和MMU之间,如果两个进程使用了同样的虚拟地址空间,则对CPU而言,两个进程使用了同样的虚拟地址空间。快速上下文切换机构对各进程的虚拟地址进行变换,这样系统中除了CPU之外的部分看到的是经过快速上下文切换机构变换的虚拟地址。快速上下文切换机构将各进程的虚拟空间变换成不同的虚拟空间,这样在进行进程间切换时就不需要进行虚拟地址到物理地址的重映射。
快速上下文切换(FCSE)通过修改系统中不同进程的虚拟地址,避免在进行进程间切换时造成的虚拟地址到物理地址的重映射,这样就减少了重建MMU、使cache和TLB无效、重建cache和TLB内容等操作的巨大开销,从而提高系统的性能。
5.3.2 FCSE原理
在ARM系统中,4GB的虚拟空间被分成128个进程空间块,每个进程空间块大小为32MB。每个进程空间块中可以包含一个进程,该进程可以使用虚拟地址空间0x00000000~0x01ffffff,这个地址范围也就是CPU看到的进程的虚拟空间。系统128个进程空间块的编号为0~127,编号为 I的进程空间块中的进程实际使用的虚拟地址空间为 I*0x02000000到 I*0x02000000+0x01ffffff,这个地址空间是系统中除了CPU之外的其他部分看到的该进程所占用的虚拟地址空间。
快速上下文切换机构将CPU发出的每个虚拟地址按照上述的规则进行变换,然后发送到系统中的其他部分,变换过程如图5-1所示。
图5-1 FCSE原理框图
图5-1中地址VA到MVA的变换算法如下:
if (VA[31:25] == 0b0000000) then MVA = VA | (PID <<25) else MVA = VA
如果VA[31:25]不等于0,说明地址VA是本进程用于访问其他进程中的数据和指令的虚拟地址,此时被访问进程的PID不能为0。相反如果VA[31:25]等于0,说明要访问的地址VA在该进程自身地址空间内,所以要进行进程上下文切换,将VA转换成MVA,其中上面公式中的PID是该进程的PID号。
5.3.3 FCSE编程接口
ARM处理器用CP15协处理器的C13寄存器来实现FCSE功能,C13寄存器的介绍详见第4.1.2节“CP15寄存器介绍”。当要进行进程切换时,首先清空写缓存,再把新进程的页表地址写入CP15的C2寄存器,然后把新进程的PID号写入CP15的C13寄存器的最高7位即可。如果处理器不支持FCSE功能,那么使cache和TLBs无效,然后系统要重建cache和TLBs。下面我们比较一下XScale处理器以及ARMv6处理器中进程切换中的内存切换操作函数的区别:
XScale处理器进程切换中的内存切换操作函数如下所示:
.align 5 ENTRY(cpu_xscale_switch_mm) clean_d_cache r1, r2;使r1所指地址到r2所指地址之间数据cache无效 mcr p15, 0, ip, c7, c5, 0;使系统全部指令cache无效 mcr p15, 0, ip, c7, c10, 4;清空写缓存Write Buffer mcr p15, 0, r0, c2, c0, 0;装入新的页表地址 mcr p15, 0, ip, c8, c7, 0;使系统全部数据和指令TLBs cache无效 cpwait_ret lr, ip;返回
ARMv6处理器进程切换中的内存切换操作函数如下所示:
ENTRY(cpu_v6_switch_mm) mov r2, #0 ldr r1, [r1, #MM_CONTEXT_ID];获取新进程的PID号,该PID号其实就是新进程的 struct mm_struct结构中的mm_context_t成员结构context的id mcr p15, 0, r2, c7, c10, 4;清空写缓存Write Buffer mcr p15, 0, r0, c2, c0, 0 ;装入新的页表地址 mcr p15, 0, r1, c13, c0, 1;设置上下文PID号 mov pc, lr;返回
在ARM处理器中只有ARMv6以上版本的处理器才支持FCSE功能。