RISCV内存管理单元
MMU(内存管理单元)
虚拟内存
在用户的视角里,每个进程都有自己独立的地址空间,A进程的4GB和B进程4GB是完全独立不相关的,他们看到的都是操作系统虚拟出来的地址空间。但是呢,虚拟地址最终还是要落在实际内存的物理地址上进行操作的。操作系统就会通过页表的机制来实现进程的虚拟地址到物理地址的翻译工作。其中每一页的大小都是固定的。页表管理有两个关键点,分别是页面大小和页表级数。
页表级数
页表级数越少,虚拟地址到物理地址的映射就会越快,但是需要管理的页表项会越多,能支持的地址空间也有限,相反页表的级数越多,需要的存储的页表数据就会越少,而且能支持到比较大的地址空间,但是虚拟地址到物理地址的映射就会越慢。
PGD:Page Global Directory,页全局目录,它是多级页表的顶层,包含指向下一级页表的基地址。
PUD:Page Upper Directory, 页上级目录,位于PGD之下,包含了指向PMD的基地址。
PMD:Page Middle Directory,页中级目录,位于PUD之下,包含了指向PTE的及地址。
PTE:Page Table Entry,页表项,位于PMD之下,包含了虚拟地址到物理地址的具体映射信息。
RISCV内存管理机制
RV32(32 位地址空间):主要用于嵌入式系统和资源受限的设备。虚拟和物理地址都限制为 32 位,通常采用两级页表,支持的页大小为 4KB、2MB 或 1GB。RV32 并没有 39 位地址管理。
RV39(39 位虚拟地址空间):主要用于中小型系统,比如一般的操作系统环境。虚拟地址为 39 位,物理地址宽度则可以根据硬件实际支持的位宽(通常在 36-40 位之间)进行设置。RV39 使用三级页表,支持的页大小同样是 4KB、2MB 或 1GB。
RV48(48 位虚拟地址空间):适合高性能计算或服务器系统。虚拟地址为 48 位,物理地址宽度可以支持 44-52 位,具体取决于硬件配置。RV48 使用四级页表,允许更大的虚拟地址空间,支持的页大小为 4KB、2MB 和 1GB。
RV64(64 位虚拟地址空间):理论上支持 64 位虚拟地址,但实际上限制在 RV48,适合未来超大规模系统。不过在目前的 RISC-V 实现中,64 位的地址空间通常没有完全实现,因为绝大多数系统的虚拟地址需求并未达到如此高的级别。
Riscv使用satp寄存器来保存MMU的映射表的根地址。
MODE(位 63 到位 60):
- 用于表示虚拟内存的模式。不同的模式代表不同的页表格式,RISC-V 支持多个页表层级。常见的模式如下:
0b0000
:禁用虚拟地址翻译。0b0001
:SV32(2级页表)。0b0010
:SV39(3级页表)。0b0011
:SV48(4级页表)。0b0100
:SV57(5级页表)。0b0101
:SV64(6级页表)。ASID(位 59 到位 38):
- 地址空间标识符(Address Space Identifier),用于区分不同进程的虚拟地址空间。ASID 的作用是避免进程间的虚拟地址映射冲突。
PPN(位 37 到位 0):
- 页表的物理页号(Physical Page Number),指示当前页表的物理地址基址。页表基址会用该值来进行虚拟地址到物理地址的映射。它以4KB的页面大小为单位。
页表是一个很庞大的数据结构且储存在内存中,直接由MMU访问内存中的页表从而得到物理地址会产生非常大的开销,进而影响CPU的运行效率。为了解决这一问题,利用局域性原理,通常会在内存与MMU之间增加一级缓存,该缓存有一个特殊的名称,即TLB(Translation Look-aside Buffer),用于缓存近期经常使用的页表项(Page Table Entry)。为了减小TLB的缺失率,通常TLB为全相联的结构。
在玄铁C910中TLB被分为了两级,第一级称为UTLB,且UTLB被分为了ITLB与DTLB,ITLB储存由IFU请求的指令虚拟地址(即指令PC)对应的虚实地址转换的页表项,DTLB储存由LSU中Load/Store指令访存的虚拟地址对应的虚实地址转换的页表项。ITLB和DTLB均为全相联结构。第二级TLB称为JTLB,为四路组相联结构,页表项信息储存在SRAM中,访问JTLB需要一个周期得到结构。
当IFU或LSU发送请求虚实地址转换的请求时,会首先访问ITLB或DTLB,若命中UTLB,经过物理内存保护单元(Physical Memory Protection)检查相应地址范围的权限后,若检查未通过,将产生访问异常(Access Error Exception)。若检查通过,经过转换得到的物理地址将根据需要发送到指令缓存或者数据缓存用于缓存命中的判断。若第一级TLB访问缺失,将会访问第二级的JTLB,若JTLB进一步失配,则MMU会启动Hardware Page Table Walk,访问内存得到最终的地址转换结果。在UTLB、JTLB或从PTW模块中找到虚拟地址对应的页表项后,还需判断该页的属性,比如该页是否为可执行,可读,可写,是否有效(在内存中是否存在)等等,若访存操作违反页面属性的规定,会产生缺页异常(Page Fault Exception),代表CPU无法获取该页的数据。由于CPU没有数据就无法进行计算,CPU罢工了用户进程也就出现了缺页中断,进程会从用户态切换到内核态,并将缺页中断交给内核的Page Fault Handler处理。
若命中JTLB或内存中的页表且未产生缺页异常,MMU会根据请求JTLB重新填充的来源选择更新ITLB还是DTLB,或者以请求PTW模块的虚拟内存信息为索引更新JTLB。命中JTLB或内存中的页表后物理地址同样要通过物理内存保护单元(PMP)进行检查权限后,才能发送给请求虚实地址转换缓存。
在多核系统中,当操作系统(OS)修改了页表后,通常需要确保所有核上的 TLB(Translation Lookaside Buffer) 都反映了最新的页表内容。否则,不同核心可能会依然使用旧的页表映射,导致地址转换错误和数据不一致。
SV39分页机制
使用64位虚拟地址的低39位,高25位未使用,每一页占用4KB内存,页内使用虚拟地址低12位寻址,虚拟地址高27位分为三级页号,每一级都有512个可用页号。
如果每级页表项8字节,且每个4KB页面只能容纳4096/512=512个页表项,所以每级页表的寻址范围是9位。
SV39页表项(PTE)
每个PTE包含一个44位的物理页(PPN)和一些标志位,分页硬件使用39位虚拟地址中的高27位作为索引,在页表中周到对应的PTE,然后PTE中的44位地址作为高位(物理页号),虚拟地址中的低12位作为低位(页内偏移量),构造出一个56位的物理地址。
- v位决定了该页表项的其余部分是否有效(V = 1时有效)。若V=0,则任何遍历到此页表项的虚拟转换操作都会导致页错误。
- R、W、X位分别表示此页是否可以读取、写入、执行。如果都是0,那么这个页表是指向下一级页表的指针,否则它是也表述的一个叶节点。
VMA
VMA(Virtual Memory Area,虚拟内存区域) 是操作系统中用于管理和描述进程虚拟地址空间的一种结构。在现代操作系统(如 Linux)中,VMA 是虚拟地址空间的基本组成单元,用于划分进程的不同内存区域,且每个 VMA 描述一个连续的虚拟地址范围。
- VMA的基本作用
- 管理进程虚拟地址空间:VMA 用来表示进程虚拟地址空间中的一个区域,这个区域通常具有相同的属性,比如是否可读、可写、可执行等。
- 内存区域的划分:操作系统通过 VMA 划分出不同的内存区域,例如代码段、数据段、堆、栈以及共享库等。
- 内存映射的管理:VMA 在进程地址空间内表示的是一块虚拟内存,它可能会映射到物理内存、交换空间,或是磁盘上的文件(例如通过
mmap
系统调用映射的文件)。
- VMA的组成部分
每个 VMA 通常包含以下信息:
- 虚拟地址范围:每个 VMA 具有一个起始虚拟地址和一个结束虚拟地址,表示该内存区域的大小和范围。
- 内存权限:描述该区域的访问权限,包括是否可读(
PROT_READ
)、可写(PROT_WRITE
)、可执行(PROT_EXEC
)等。- 映射类型:包括该区域是否映射到文件(如共享库),或者是否是匿名映射(如堆和栈)。
- 标志:标志可以包括是否该区域是共享的(
MAP_SHARED
)或私有的(MAP_PRIVATE
),是否是堆栈区域等。- 偏移量:对于文件映射,VMA 还可能记录文件在虚拟地址空间中的偏移量,指明文件在内存中的位置。
- VMA的作用和管理
VMA 主要用于管理进程的内存区域,它在进程的内存映射和内存管理中扮演了关键角色。具体来说:
- 虚拟地址空间的划分:每个 VMA 对应进程虚拟地址空间的一个逻辑区域(如代码、数据、堆栈等)。操作系统通过维护 VMA 来确保这些区域的内存管理。
- 内存分配与回收:在进程创建、加载程序或执行时,操作系统会使用 VMA 来管理和分配虚拟内存区域,并在进程退出时回收这些内存区域。
- 进程上下文切换:操作系统在进行进程上下文切换时,会利用 VMA 结构来恢复或切换不同的虚拟内存映射。
- VMA 与其他内存管理结构的关系
- 页表(Page Tables):VMA 管理虚拟地址的逻辑划分,而页表则负责将这些虚拟地址映射到物理内存。每个 VMA 中的虚拟地址段在页表中都有相应的映射关系。
- 内存映射文件(mmap):通过
mmap
系统调用,操作系统可以将文件内容映射到进程的虚拟内存中,这个映射关系通常由 VMA 来描述。- 内核虚拟内存(Kernel VMA):操作系统内核通常也会维护自己的虚拟地址空间,用于管理内核的代码、数据、堆栈等区域。内核的 VMA 不同于用户空间的 VMA,且不通过用户页表进行管理。
- VMA 的典型使用场景
- 堆和栈:进程的堆和栈分别是动态分配和管理内存的区域,它们通常是由操作系统通过 VMA 来管理的。例如,堆和栈的增长和收缩是由 VMA 的边界和映射方式来控制的。
- 共享内存和文件映射:通过
mmap
,操作系统可以将文件或共享内存区域映射到进程的虚拟地址空间,形成一个 VMA 区域。该 VMA 描述了文件与进程内存之间的映射关系。
- VMA的例子
假设一个进程需要加载一个程序,它的虚拟地址空间可能会被划分成以下几个 VMA 区域:
- 代码段(Text Segment):包含可执行的代码,通常是只读且可执行的区域。
- 数据段(Data Segment):包含程序的静态数据,通常是可读写的。
- 堆(Heap):动态分配内存的区域,通常从低地址增长至高地址。
- 栈(Stack):用于存储函数调用信息的区域,通常从高地址向低地址增长。
- 共享库映射:通过
mmap
映射到虚拟内存中的共享库或文件映射。
VMA(虚拟内存区域)是操作系统用于管理进程虚拟地址空间的基本数据结构之一。它帮助操作系统在进程的虚拟内存中划分不同的区域,并描述这些区域的属性和映射关系。VMA 是现代操作系统内存管理的重要组成部分,尤其在虚拟内存管理、内存保护和文件映射等方面发挥着关键作用。
换页
换页基本思想
- 用磁盘作为物理内存的补充,且对上层应用透明
- 应用对虚拟内存的使用,不受物理内存大小限制
如何实现
- 磁盘上划分专门的Swap分区,或专门的Swap文件
- 在处理缺页异常时,触发物理内存页的换入换出