由于L1 MMU只是一个L2MMU的一个子集,硬件负责自动更新,因此我们可以就可以通过编程控制L2 MMU中的TLB就能达到操作TLB的目的。
通过对L2 MMU的TLB编程,我们可以进行根据虚拟地址查找匹配的TLB entry,建立虚拟页<—>物理页映射,修改TLB entry中的属性,无效TLB等等操作,这样的方式让powerpc e500的MMU更加灵活。
1. 根据一个虚拟地址找到对应的TLB Entry
说明:我们用程序控制找到的entry指的是L2 MMU 中Tlb中的entry index。
指令:tlbsx RA,RB
准备:
(1) 首先配置MAS6寄存器:SPID0域和SAS域;
(2) 把我们需要寻找的虚拟地址放到RA+RB中(一般直接放到RB中,RA置0);
(3) 执行tlbsx RA,RB指令;
执行:
指令tlbsx会根据MAS6、RA+RB的值,进行如下匹配:对L2 MMU中TLB0和TLB1的每一个entry进行查询:
(1)entry中的V域是否有效;
(2)MAS6、RA+RB与entry对应的字段进行匹配:SPID0 == TID,SAS == TS, EPN == (RA+RB) (上面的“==”表示匹配,不一定是相等,例如:ENP == (RA+RB) ,这里需要根据entry的size域来确定EPN的位数。EPN总共20位,所以对应的最小页大小是4k,即这20位都作为虚拟页号;如果size指示页大小为4M ,即一页占22位,那么EPN只有10位有效,这时秩序匹配RA+RB的高10位就可以了)
(3)若MAS6、RA+RB匹配到某一个entry,并且V域有效,则说明我们匹配成功,也就是命中,否则没有匹配到任何entry表示不命中。
输出:
(1)若tlbsx命中:将命中的entry,包括entry index输出到如下寄存器的相应字段中。MAS0 ~ MAS3:MAS1[V] = 1,MAS0[TLBSEL] = 命中的是TLB0/TLB1, MAS0[ESEL]命中的entry的index或者TLB0的哪一路。
(2)若没有命中,则MAS1[V] = 0,MAS2[RPN] 为 0
举例:
/* Find the index of the entry we're executing in */
bl invstr /* Find our address */
invstr: mflr r6 /* Make it accessible :r6存放的便是当前正在执行代码的虚拟地址 */
mfmsr r7
rlwinm r4,r7,27,31,31 /* extract MSR[IS] :提取当前的[IS]地址空间 */
mfspr r7, SPRN_PID0
slwi r7,r7,16
or r7,r7,r4
mtspr SPRN_MAS6,r7 /* 设置MAS6的SAS */
tlbsx 0,r6 /* search MSR[IS], SPID=PID0 */
上面的代码表示将我们正在执行的 标号invstr处的地址放到r6中,并在Tlb的当前(IS)地址空间中查找r6这个地址对应的entry。
2. 读Tlb
如果我们想了解某个entry的内容,比如它的RPN(物理页号),就将这个entry的值读出到MAS寄存器中,然后再从MAS寄存器取出到普通寄存器就可以了。
指令:tlbre
准备:
(1) 通过MAS0选择我们要读取的entry。
配置MAS0[TLBSEL]指定读TLB0还是TLB1;
配置MAS0[ESEL]指定命中是哪一个entry,若选择的是TLB0,还需要先借助EPN[45:51]来进行索引组,然后通过ESEL则来路选确定具体的entry项。
(2) 执行tlbre,根据上面的信息读取指定的tlb entry。
过程:
tlbre指令根据MAS0中TLBSEL和ESEL域来定位某个entry,并把entry中内容读出到各个MAS寄存器的相关域中。
举例:
li r6,0 /* Set Entry counter to 0 */
lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */
rlwimi r7,r6,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r6) */
mtspr SPRN_MAS0,r7
tlbre
上述代码的目的是读取tlb1中的entry0
3. 写TlB
和读Tlb类似,要写某个Tlb entry首先要定位这个entry,然后将各个MAS0中的对应的各个域写入到这个entry。
指令:tlbwe
准备:
(1) 通过MAS0选择我们要读取的entry。
配置MAS0[TLBSEL]指定读TLB0还是TLB1;
配置MAS0[ESEL]指定命中是哪一个entry,若选择的是TLB0,还需要先借助EPN[45:51]来进行索引组,然后通过ESEL则来路选确定具体的entry项。
(2) 准备好我们需要写到entry中内容。填写好各个MAS寄存器中与entry对应的各个域,如MAS2[EPN],MAS3[RPN]等。
(3) 执行tlbwe,根据上面的信息找到指定的tlb entry,并将这个entry的信息写到各个MAS寄存器中。
过程:
tlbwe指令根据MAS0中TLBSEL和ESEL域来定位某个entry,并把entry中内容读出到各个MAS寄存器的相关域中。
举例:
li r6,0 /* Set Entry counter to 0 */
lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */
rlwimi r7,r6,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r6) */
mtspr SPRN_MAS0,r7 /* 找到TLB1的entry0 */
mfspr r7,SPRN_MAS1
rlwinm r7,r7,0,2,31 /* Clear MAS1 Valid and IPROT */
mtspr SPRN_MAS1,r7
tlbwe /* 写TLB */
上述代码修改(清除)TLB1中entry0的Valid和IPOROT域。
4. invalid TLB项
指令:tlbivax RA + RB
准备:EA = RA + RB 为虚拟地址
过程:
(1) EA[32:51] 用于匹配 TLB 项 (组选 + EPN 匹配),其不进行 PID 和 AS 的比较,则若同一组内有相同的 EPN,皆会将其置无效。
(2) EA[60] 用于选择操作的对象是 TLB0 还是 TLB1,类似 MAS0[TLBSEL];
(3) EA[61] 为 1 则置无效 TLB0 或 TLB1 的所有项
(4) 若 HID1[ABE] = 1 则该无效操作亦广播给其它 Core,置无效相应的项。
注意:若TLB1的某项entry 的IPROT域为1,可以不受tlbivax的影响。
举例:
/* 当前进程的data地址空间中,寻找虚拟地址为0xc0000000的TLB entry */
lis r6 , 0xc0000000@h
ori r6 , r6 , 0xc0000000@l
mfmsr r7
rlwinm r4,r7,27,31,31 /* extract MSR[DS] */
mfspr r7, SPRN_PID0
slwi r7,r7,16
or r7,r7,r4
mtspr SPRN_MAS6,r7
tlbsx 0,r6 /* search MSR[DS], SPID=PID0 */
/* 设置这个entry的IPROT域,保证后面的tlbivax指令不会让自己无效 */
mfspr r7,SPRN_MAS0
rlwinm r3,r7,16,20,31 /* Extract MAS0(Entry) */
mfspr r7,SPRN_MAS1 /* Insure IPROT set */
oris r7,r7,MAS1_IPROT@h
mtspr SPRN_MAS1,r7
tlbwe
/* 除了我们设置的0xc0000000对应的entry,TLB0和TLB1中的其他的entry全部置无效(除非某个其他的entry中也设置了IPROT位) */
/* Invalidate TLB0 */
li r6,0x04
tlbivax 0,r6
TLBSYNC
/* Invalidate TLB1 */
li r6,0x0c
tlbivax 0,r6
TLBSYNC