linux内存从0到1学习笔记(二,arm64物理内存)

高桐@BILL 高桐@BILL     2022-12-01     345

关键词:

写在前面

我们先通过一张图来里哦啊接下ARM处理器的内存管理架构;

2.1 ARM处理器的内存管理架构

ARM处理器内核:是指ARM架构的CPU中间的核心芯片,由单晶硅制成,用来完成所有的计算、接受/存储命令、处理数据等,是数字处理核心。

MMU:Memory Mangerment  Unit (内存管理单元),有时称作分页内存管理单元。它是一种负责处理CPU内存访问请求的计算机硬件。用于完成虚拟内存和物理内存的映射,位于CPU内部;MMU将虚拟内存映射到物理内存,以及设置修改CPU的访问级别,如printf函数,要调用系统函数write,要进入内核空间,此时CPU的访问级别由3级用户空间转换到0级内核空间。

TLB:Translation Lookaside Buffer (页表缓存)。作为CPU的一种缓存,由存储器管理单元用于改进虚拟地址到物理地址的转译速度。

高速缓存:Cache。其原始意义是指存取速度比一般随机存取记忆体(RAM)来得快的一种RAM,一般而言它不像系统主记忆体那样使用DRAM技术,而使用昂贵但较快速的SRAM技术,也有快取记忆体的名称。

页表或分页表:(Page Table),一种特殊的数据结构,用于存储虚拟地址到物理地址间的映射。

页表项:(PTE, Page Table Entry),用来描述一个虚拟页号如何映射到物理页号的。

一、ARM内存管理简介

ARM处理器内核的MMU包括TLB和页表遍历单元(Table Walk Unit)两个部件;TLB是一个高速缓存,用于缓存页表转换的结果,从而减少页表查询的时间。当TLB未命中时,MMU才会查询页表,从而得到翻译后的物理地址。页表通常存储在主存储器中,也就是内存中,在kernel初始化的时候创建。

那么进程地址空间如何映射到物理地址空间呢?这就需要处理器MMU提供页表映射和管理的功能。如下图:

2.2进程地址空间和物理地址空间的映射关系

二、页表及页表映射

在AArch64中MMU支持单一页表转化(VA to PA),也支持虚拟化扩展的两阶段页表转化(VA to IPA to PA)。

在ARrch64架构中,地址总线位宽最多支持48位,所以VA(Virtual Address)被划分为两个空间,每个空间最多支持256TB。在此架构下的页表最多支持4级页表,翻译的页面粒度可以是4KB,16KB或64KB。默认为4KB。

2.1查表或地址翻译

处理器查表过程,我们称之为Translation Table Walk,这个过程是由MMU硬件完成的,如下:

  1. 处理器根据页表基地址控制寄存器(页表基地址寄存器(PTBR):CPU有一个专门的页表基地址寄存器,指向当前页表的基地址,也就是起始地址.)和虚拟地址来判断使用哪个页表基地址寄存器。在页表基地址寄存器中存放着一级页表(L0页表)的基地址(起始地址)。
  2. 处理器将[47:39]作为L0索引,L0页表的页表项中存放着L1页表的物理基地址,L0页表有512个页表项。
  3. 处理器将[38:30]作为L1索引,L1页表的页表项中存放着L2页表的物理基地址。L1页表有512个页表项。
  4. 处理器将[29:31]作为L2索引,L2页表的页表项中存放着L3页表的物理基地址。L2页表有512个页表项。
  5. 处理器将[20:12]作为L3索引,L3页表有512个页表项,每个页表项存放着4KB页面的物理基地址,然后再加上[11:0],就构成了新的物理地址。

至此,处理器就完成了也表的查询和翻译工作。那么一次查表寻址的过程需要访问5次物理内存。这个过程实际上是很耗时的。TLB的存在可以大大加快查表或者地址翻译的速度。这里先剧透下,后面会详细介绍TLB的工作原理。TLB会把虚拟地址到物理地址的翻译结果或者查表结果保存到TLB表项中,这样当处理器需要访问内存时就会首先从TLB中查询是否有相应的表项,如果TLB命中就不需要去MMU中查表了。因此TLB也被称之为快表。

2.2 页表描述符

在AArch64架构中的4级页表都有512页表项。每个页表项我们又称之为页表描述符,其占8个字节。

L0~L2的页表项共有3类,第一类是无效页表项,第二类是块类型的页表项,第三类是页表类型的页表项。

L3的页表项共有5类,分别是无效类,保留的页表项,4KB粒度,16KB粒度和64KB粒度的页表项。

2.3 Linux内核中的页表

ARM64的Linux内核中采用了4级分页模型,包括页全局目录(PGD,Page Global Directory),页上级目录(PUD,Page Upper Directory)、页中间目录(PMD,Page Middle Directory),页表(PT,Page Table)。那么前面说的4级分页模型在64位虚拟地址的划分如下图:

  2.3 4级分页模型在64位虚拟地址的划分

页表的作用就是通过VPN找到PFN,那么页表最基本的组成部分需要包含如下内容:

  • PFN物理页帧号;
  • 有效位(valid),用于标记页面是否有效;
  • 存在位(present),指示该页是否存在于物理内存,用于页面换入换出(swap);
  • 特权标记,指示页面访问的特权等级;
  • Dirty位,写操作时设置该位,表示页面被写过,页面交换时使用;

最后一张图来总结下MMU的寻址映射过程,如下:

 

2.4 基于ARM64的页表映射过程内核源码解读

参考源码:mmu.c « mm « arm64 « arch - kernel/git/stable/linux.git - Linux kernel stable tree

由于在head.S文件中,已经对内核映像文件做了块映射,那么在内核架构初始化的时候,paging_init函数会对内核空间的页表进行重新映射。

pgd_set_fixmap():主要负责固定映射,全局变量swapper_pg_dir即内页页表的PGD页表基地址。该函数会将swapper_pg_dir页表重新映射到固定映射区域,并返回PGD页表的虚拟地址。

map_kernel(pgdp):主要负责内核映像文件各个块的重新映射;

map_mem(pgdp):主要负责物理内存的线性映射;

pgd_clear_fixmap():解除固定映射;

写在最后:

参考资料:

《奔跑吧Linux内核 第二版》

《深入Linux内核架构》

linux内存从0到1学习笔记(6.8,物理内存初始化之buddy伙伴系统)

写在前面在linux启动的那一刻,内存管理就已经开始了。在内核中,实现物理内存管理的allocator包括:初始化阶段物理内存管理memblock连续物理内存管理buddy非连续物理内存管理vmallocallocator小块物理内存管理slaballocator在系统初始... 查看详情

linux内存从0到1学习笔记(四,tlb)

...、TLB简介        Kernel初始化的时候,会在初始化内存中创建页表;而处理器读取指令和数据的时候需要首先通过MMU查表得到物理地址,然后在访问物理地址读取指令或数据。MMU查表过程汇中需要4次访问内存,... 查看详情

linux内存从0到1学习笔记(五,内存分类)

一、内存类型ARMv8架构处理器定义了两种类型的内存类型,分别是普通内存(NormalMemory)和设备内存(DeviceMemory)。二、普通内存        普通内存对应MT_NORMAL属性;        普通内存由于其弱一致... 查看详情

linux内存从0到1学习笔记(九,内存优化调试之三-内存拆解)---持续更新(代码片段)

写在前面我们在日常的工作当中需要各种手段来调试内存,尤其是在内存泄漏的情况下,我们需要一种手段来统计内存的使用去向,以确定内存使用不合理的方向。或者物理内存有限的情况下,需要对内存进行优... 查看详情

linux内存从0到1学习笔记(七,用户空间虚拟内存之三-内存映射)(代码片段)

...通常C标准库只提供了一个函数,由应用程序用来创建内存映射,接下来该函数调用在内部转换为适合于体系结构的系统调用mmap和mmap2。可使用munmap系统调用删除映射。一、内存映射简介        mmap完成的是将物理内... 查看详情

linux内存从0到1学习笔记(8.14dma-buf内存调试二bufinfo介绍)--更新中(代码片段)

bufinfo是我们调试dmabuf使用的一个非常有效的debug信息。因此我们需要了解下它的由来以及记录的关键信息。并且根据场景需要来对跟踪的信息进行调整和完善,以满足我们的调试需要。一,bufinfo的生成首先在内核初始化子系统... 查看详情

linux内存从0到1学习笔记(8.14dma-buf内存调试二bufinfo介绍)--更新中(代码片段)

bufinfo是我们调试dmabuf使用的一个非常有效的debug信息。因此我们需要了解下它的由来以及记录的关键信息。并且根据场景需要来对跟踪的信息进行调整和完善,以满足我们的调试需要。一,bufinfo的生成首先在内核初始化子系统... 查看详情

linux内存从0到1学习笔记(8.11dma-buf导出器和导入器使用示例二)(代码片段)

    除了前面介绍的非常重要的导出器操作管理结构体dma_buf_ops,我们再来了解下设备缓冲区的附着数据(attachmentdata)的结构体以及共享缓冲区对象的构成结构体dma_buf。一,dma_buf_attachment解读dma_buf_attachment结构体... 查看详情

linux内存从0到1学习笔记(8.11dma-buf导出器和导入器使用示例二)(代码片段)

    除了前面介绍的非常重要的导出器操作管理结构体dma_buf_ops,我们再来了解下设备缓冲区的附着数据(attachmentdata)的结构体以及共享缓冲区对象的构成结构体dma_buf。一,dma_buf_attachment解读dma_buf_attachment结构体... 查看详情

linux内存从0到1学习笔记(8.7dma-buf代码解读)

一,基本操作与设备DMA访问drivers/dma-buf/dma-buf.c二,CPU访问DMA缓冲区对象drivers/dma-buf/dma-buf.c三,隐式Fence轮询支持drivers/dma-buf/dma-buf.c四,DMA-BUF统计drivers/dma-buf/dma-buf-sysfs-stats.c五,DMA缓冲区ioctls操作include/uapi/linux/ 查看详情

linux内存从0到1学习笔记(8.7dma-buf代码解读)

一,基本操作与设备DMA访问drivers/dma-buf/dma-buf.c二,CPU访问DMA缓冲区对象drivers/dma-buf/dma-buf.c三,隐式Fence轮询支持drivers/dma-buf/dma-buf.c四,DMA-BUF统计drivers/dma-buf/dma-buf-sysfs-stats.c五,DMA缓冲区ioctls操作include/uapi/linux/ 查看详情

linux内存从0到1学习笔记(七,用户空间虚拟内存之二-内存空间的建立)(代码片段)

在使用load_elf_binary装在一个ELF二进制文件时,将创建进程的地址空间。Linux下的exec系统调用该函数来加载ELF文件。linux_mainline-5.17.0/fs/binfmt_elf.c823staticintload_elf_binary(structlinux_binprm*bprm)824825 structfile*interpreter= 查看详情

linux内存从0到1学习笔记(8.8无限dmafence)

在不同时间,结构体dma_fence具有无限期的时间,直到dma_fence_wait()执行完成。例如:FutureFence(未来围栏),在HWC1中使用的,用于在显示器不再使用缓冲区时发出信号,并在屏幕更新时创建,以使得缓冲区可见。此围栏完成的时... 查看详情

linux内存从0到1学习笔记(8.8无限dmafence)

在不同时间,结构体dma_fence具有无限期的时间,直到dma_fence_wait()执行完成。例如:FutureFence(未来围栏),在HWC1中使用的,用于在显示器不再使用缓冲区时发出信号,并在屏幕更新时创建,以使得缓冲区可见。此围栏完成的时... 查看详情

linux内存从0到1学习笔记(8.13dma内存调试一)

...常使用过程中常常会遇到哪些问题呢?当然,dma-buf也是内存使用大法的一部分,那就免不了遇到这几大件:1.dma不足(合理使用),这部分的优化慎之又慎,要么从系统内存的大锅里多盛一点,要么自己节衣缩食;2.dma-buf泄漏(... 查看详情

linux内存从0到1学习笔记(8.13dma内存调试一)

...常使用过程中常常会遇到哪些问题呢?当然,dma-buf也是内存使用大法的一部分,那就免不了遇到这几大件:1.dma不足(合理使用),这部分的优化慎之又慎,要么从系统内存的大锅里多盛一点,要么自己节衣缩食;2.dma-buf泄漏(... 查看详情

linux内存从0到1学习笔记(10.1bugsshooter之cma配置过小导致页迁移繁忙而内存申请失败)

...程tombstone中的CALLSTACK,确认为_M_allocate_bucket进行bucket内存分配时发生异常;2.2kernel或串口日志alloc_congit_range:(xxx,xxx)PFNsbusy;cm 查看详情

linux内存从0到1学习笔记(8.9可恢复硬件页面错误的含义)

...起的页面错误显然会阻碍加速器上运行的任务,通常需要内存分配来解决错误。但是,不允许内存分配来控制DMA围栏的完成,这意味着使用可恢复页面错误的任何工作负载都不能使用DMA围栏进行同步,而必须改用由用户空间控制... 查看详情