• MIPS32地址映射和TLB


    所有集成了MMU功能的CPU,使能MMU之后,程序地址就是虚拟地址,不能直接访问存储器,必须经过MMU转换成物理地址。

    MIPS32虚拟地址空间

    MIPS32将虚拟地址空间划分为4个区域:

    • kuseg 0x0000.0000 - 0x7FFF.FFFF(低2GB)

    这些地址是用户态可用的地址。对于有MMU的机器,这些地址需要经过MMU(TLB)的转换后才可以使用;对于没有MMU的机器,这些地址的行为与具体机器实现相关。

    • kseg0 0x8000.0000 - 0x9FFF.FFFF(512MB):

    这段地址只需将最高位清零即转换为物理地址,映射到连续的低端512MB物理地址上,因此在描述其属性时一般称为unmapped。另外该段地址访问时总是需要通过cache,因此描述其属性时称为cached。在一般应用上,这段地址映射到的物理地址用于存放程序和数据或者操作系统核心。

    • kseg1 0xA000.0000 - 0xBFFF.FFFF(512MB):

    与kseg0类似,这段地址同样映射到了低端512MB物理地址(将高3个bit清零),但其访问不经过cache,因此其属性可以称为 unmapped/uncached。由于unmaped/uncached特性,这段地址无需配置TLB和cache即可使用,是唯一的在系统重启时能 正常工作的地址空间,因此复位入口点(0xBFC0.0000)被放在这个区域,其物理地址为0x1FC0.0000。

    • kseg2 0xC000.0000 - 0xFFFF.FFFF(1GB):

    该段地址只能在核心态下使用且需要经过MMU(TLB)转换。

    综上,以BCM53003芯片为例,虚拟地址与物理地址的映射关系如下:

    其中,kseg3段只是对kseg2段进一步细分,没有本质的区别。

    kseg0和kseg1两个虚拟地址段为unmapped地址段,虚拟地址到物理地址的映射关系是固定的,这是因为它们不是通过TLB转换的,而是由MIPS CPU内部实现的Fix-Mapped MMU完成地址转换。这样设计的初衷,是因为CPU刚上电时,TLB未初始化,unmapped地址段可以将Flash Reset Vector(4MB)、DDR DMA(128MB)、CPU核心控制寄存器组以及关键外设寄存器组映射到CPU的虚拟地址空间。

    kuseg和kseg2两个虚拟地址段为mapped地址段,由TLB负责处理地址映射。

    MIPS CPU有四种工作模式——User/Supervisor/Kernel/Debug,每种工作模式下的访问权限不同,如下图所示:

    MIPS32 TLB描述

    TLB(Translation Lookside Buffer)介于CPU控制核心和Cache控制器之间,其作用是把程序地址(或称虚拟地址)转换成物理地址。

    TLB被称为相联存储器或者内容寻址存储器,因为它不是按照索引来寻址,而是根据内容来选择TLB表项进行寻址。其逻辑非常复杂,每一个TLB表项都有内建的比较器,复杂度和性能扩展性很差,因此,TLB的表项一般不是很多。

    典型的TLB包含16~64个TLB表项,每一个表项包含一个页的虚拟地址(VPN即虚拟页号)和一个物理页地址(PFN即物理页号),页大小是可以配置的。

    当程序访问一个虚拟地址时,该地址和所有TLB表项中的VPN进行比较,TLB返回匹配的TLB表项的PFN,完成地址转换;如果找不到,则触发TLB miss异常(Linux系统中,因为各进程虚拟地址空间独立且地址范围相同,因此会触发TLB refill重填异常,会涉及TLB表项的更新;但是VxWorks系统中,所有任务共享同一虚拟地址空间,所有TLB表项都是启动时配置,运行时不动态更新)。有一组标志位和每个PFN一起返回,标志位用来标识地址页是否缓存、缓存模式、属于某个ASID还是全局有效地址等。

    正所谓“知其然,然后知其所以然”,以BCM53003芯片(包含64个TLB表项)为例,将所有TLB表项导出如下:

    BCM5300X>tlb 0 63
     0 : 00 e0000000  64MB -> 0_40000000 C2DVG 0_44000000 C2DVG
     1 : 00 c0000000  64MB -> 0_40000000 C0DVG 0_44000000 C0DVG
     2 : 00 20000000 256MB -> 0_10000000 C0--- 0_20000000 C2DV-
     3 : 00 00000000 256MB -> 0_10000000 C0--- 0_20000000 C0DV-
     4 : 00 60000000 256MB -> 0_80000000 C2DVG 0_90000000 C2DVG
     5 : 00 40000000 256MB -> 0_80000000 C0DVG 0_90000000 C0DVG
     6 : 00 8000c000   4KB -> 0_00000000 C0--- 0_00000000 C0---
     7 : 00 8000e000   4KB -> 0_00000000 C0--- 0_00000000 C0---
     8 : 00 80010000   4KB -> 0_00000000 C0--- 0_00000000 C0---
     9 : 00 80012000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    10 : 00 80014000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    11 : 00 80016000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    12 : 00 80018000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    13 : 00 8001a000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    14 : 00 8001c000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    15 : 00 8001e000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    16 : 00 80020000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    17 : 00 80022000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    18 : 00 80024000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    19 : 00 80026000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    20 : 00 80028000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    21 : 00 8002a000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    22 : 00 8002c000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    23 : 00 8002e000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    24 : 00 80030000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    25 : 00 80032000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    26 : 00 80034000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    27 : 00 80036000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    28 : 00 80038000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    29 : 00 8003a000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    30 : 00 8003c000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    31 : 00 8003e000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    32 : 00 80040000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    33 : 00 80042000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    34 : 00 80044000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    35 : 00 80046000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    36 : 00 80048000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    37 : 00 8004a000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    38 : 00 8004c000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    39 : 00 8004e000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    40 : 00 80050000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    41 : 00 80052000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    42 : 00 80054000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    43 : 00 80056000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    44 : 00 80058000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    45 : 00 8005a000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    46 : 00 8005c000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    47 : 00 8005e000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    48 : 00 80060000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    49 : 00 80062000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    50 : 00 80064000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    51 : 00 80066000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    52 : 00 80068000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    53 : 00 8006a000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    54 : 00 8006c000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    55 : 00 8006e000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    56 : 00 80070000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    57 : 00 80072000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    58 : 00 80074000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    59 : 00 80076000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    60 : 00 80078000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    61 : 00 8007a000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    62 : 00 8007c000   4KB -> 0_00000000 C0--- 0_00000000 C0---
    63 : 00 8007e000   4KB -> 0_00000000 C0--- 0_00000000 C0---

    以TLB Entry 0为例说明:

     0 : 00 e0000000  64MB -> 0_40000000 C2DVG 0_44000000 C2DVG

    该表项表示将虚拟地址0xe000 0000开始的128MB虚拟地址空间,映射到从0x4000 0000开始的64MB物理地址空间,以及从0x4400 0000开始的64MB物理地址空间,每个物理地址段后面的标志位(C2DVG)表示映射模式。

    MIPS CPU一般采用双相相关联存储器实现TLB,即每个TLB表项包含一对相邻的虚拟地址页(虚拟地址空间上连续)对应两个单独的物理地址(物理地址空间上可以不连续)。

    接下来,就是“知其所以然”的阶段了,MIPS CPU提供了几个CP0协处理器寄存器和几条TLB相关的指令,用来实现TLB的配置。以一个TLB表项为例,它由CP0的EntryHi、PageMask、EntryLo0、EntryLo1四个寄存器的不同字段组成。每次程序代码访问mapped虚拟地址时,TLB都通过这几个寄存器返回TLB表项给CPU,整个地址转换的过程是CPU逻辑电路实现的,软件不感知;软件可以做的事情是配置TLB表项,建立虚拟地址和物理地址的映射表。

     VPN2表示虚拟页号,ASID用来唯一标识当前进程,如Linux系统中,每个进程的虚拟地址空间都是4GB大小,地址范围都是0x0000 0000 ~ 0xFFFF FFFF,相同的虚拟地址对不同的进程而言,是映射到不同的物理地址的,因此仅靠VPN2虚拟页号无法完成地址转换,还需要ASID。

    PageMask用来标识每个TLB表项的虚拟地址段大小,可配置范围如下:

    EntryLo0/1两个寄存器分别表示一个TLB表项的两个物理地址页,称为even page和odd page。

    PFN表示物理页号;C表示Cache一致性属性,即是cached还是uncached,是write-through还是write-back;D表示是否为Dirty页,V表示是否有效;G表示是否为全局地址,如果置1,则不关心ASID(ignore ASID),如果置0,则进行地址转换时要根据ASID进行地址转换。另外,一般情况下,EntryLo0和EntryLo1的G位需要配置为相同值,因为TLB的表项中的G属性是两位相与的逻辑。

    值得一提的是,kseg0和kseg1两个unmapped虚拟地址段的Cache一致性属性可以通过CP0相关寄存器配置:

    综上,一个完成的TLB地址映射如下:

    地址转换流程如下:

    MIPS32 TLB配置

    TLB配置还涉及其他CP0寄存器和TLB相关指令。

     Index表示TLB表项序号,从0~63。P表示Probe Failure标志位(只读),当发生TLB miss时,则置位。

    Random和Wired寄存器一起划定TLB refill重填的范围,即可以把64个TLB表项划分为静态表项和动态表项两个区域,当发生TLB refill异常时,则随机选取Wired~63之间的任意表项(Random随机数指向的表项)进行TLB表项更新。

    Context寄存器是辅助TLB refill重填的,当发生TLB miss异常需要refill时,在PTE Base指向的区域取匹配的表项进行快速回填。

    涉及TLB指令包括:

    TLBWI - 写CP0 Index寄存器设置TLB Entry ID

    TLBR - 读CP0 Index寄存器获取TLB Entry ID

    TLBWR - 写CP0 Random寄存器设置TLB Entry ID

    TLBP - 获取匹配的TLB Entry ID

    一个完整的TLB配置过程如下:

    Physical address 0x88000000 ~ 0x9FFFFFFF (384M) is mapped to virtual address 0xC8000000 ~ 0xDFFFFFFF.

    – 1 Set PageMask register to configure 16M page size. The value should be 0x01ffe000. 384/(16*2) = 12 entries needed.

    – 2 Set Index register to configure TLB entry index.

    – 3 Set EntryHi register to configure virtual address. ASID fields can be ignored.

    – 4 Set EntryLo0 and EntryLo1 registers to configure the even and the odd physical pages. The lower 6 bits, which are status bit, could be set to 0x1f. It means:

    • Cacheable, write back
    • Allow modify
    • The entry is valid.
    • Ignore ASID.
    – 5 Use TLBWI instruction to write one TLB entry by Index register.
    – 6 If more TLB entries needed, jump to 2 

  • 相关阅读:
    与图相关的一些算法
    累加出整个范围所有的数最少还需要几个数
    Java SE 19 新增特性
    Netty 学习(四):ChannelHandler 的事件传播和生命周期
    用递归函数和栈操作逆序栈
    二维数组的最小路径和问题
    Java SE 19 虚拟线程
    使用贪心来解决的一些问题
    Gatsby custom head & Google Analytics All In One
    2022 美国中期选举 All In One
  • 原文地址:https://www.cnblogs.com/justin-y-lin/p/13818045.html
Copyright © 2020-2023  润新知