Linux硬件原理和分页管理

内存管理相对复杂,涉及到硬件和软件,从微机原理到应用程序到内核。比如,硬件上的cache,CPU如何去寻址内存,页表, DMA,IOMMU。 软件上,要知道底层怎么分配内存,怎么管理内存,应用程序怎么申请内存。

常见的误解包括:

对free命令 cache和buffer的理解。
1、应用程序申请10M内存,申请成功其实并没有分配。内存其实是边写边拿。代码段有10M,并不是真的内存里占了10M。
2、内存管理学习难,一是网上的资料不准确,二是学习时执行代码,具有欺骗性。看到的东西不一定真实,要想理解必须陷入Linux本身。

学习时,不要过快陷入太多细节,而要先对整个流程整个框架理解。

先理清楚脉络和主干,从硬件到最底层内存的分配算法,–>到内核的内存分配算法,–>应用程序与内核的交互,–>到内存如何做磁盘的缓存, –> 内存如何和磁盘替换。

再动手实践demo。

硬件原理 和 分页管理

本文主要让大家理解内存管理最底层的buddy算法,内存为什么要分成多个Zone?

  • CPU寻址内存,虚拟地址、物理地址
  • MMU 以及RWX权限、kernel和user模式权限
  • 内存的zone: DMA、Normal和HIGHMEM
  • Linux内存管理Buddy算法
  • 连续内存分配器(CMA)

内存分页

Linux硬件原理和分页管理

CPU 一旦开启MMU,MMU是个硬件。CPU就只知道虚拟地址了。如果地址是32位,0x12345670 。

假设MMU的管理是把每一页的内存分成4K,那么其中的670是页内偏移,作为d;0x12345 是页号,作为p。通过虚拟地址去查对应的物理地址,用0x12345去查一张页表,页表(Page table)本身在内存。

硬件里有寄存器,记录页表的基地址,每次进程切换时,寄存器就会更新一次,因为每个进程的页表不同。

CPU一旦访问虚拟地址,通过页表查到页表项,页表项记录对应的物理地址。

总结:一旦开启MMU,CPU只能看到虚拟地址,MMU才能看到物理地址。
虚拟地址是指针,物理地址是个整数。内存中的一切均通过虚拟地址来访问。

typedef u64 phys_addr_t;

去内存里读取页表会比较慢,CPU里有个高速单元tlb,它是页表的高速缓存。CPU就不需要在内存里读页表,直接在tlb中读取,从虚拟地址到物理地址的映射。如果tlb中读取不到,才回到内存里读取页表映射,并且在tlb中命中。

虚拟地址:0x12345 670 –> 1M

物理地址:1M+670 MMU去访问这个物理地址。

内存的映射以页为单位。

页表(Page table)记录的页权限

cpu虚拟地址,mmu根据cpu请求的虚拟地址,访问页表,查得物理地址。

每个MMU中的页表项,除了有虚拟地址到物理地址的映射之外,还可以标注这个页的 RWX权限和 kernel和user模式权限(用户空间,内核空间读取地址的权限),它们是内存管理两个的非常重要的权限。

一是,这一页地址的RWX权限 ,标记这4k地址的权限。一般用来做保护。

Pagefault,是CPU提供的功能。两种情况会出现Pagefault,一是,CPU通过虚拟地址没有查到对应的物理地址。二是,MMU没有访问物理地址的权限。

MPU,memory protection unit.

二是,MMU的页表项中,还可以标注这一页的地址:可以在内核态访问,还是只能在用户态访问。用户一般映射到0~3G,只有当CPU陷入到内核模式,才可以访问3G以上地址。

程序在用户态运行,处于CPU非特权模式,不能访问特权模式才能访问的内存。内核运行在CPU的特权模式,从用户态陷入到内核态,发送 软中断指令,CPU进行切环,x86从3环切到0环,到一个固定的地址去执行。软件就从非特权模式,跳到特权模式去执行。

MMU,能把某一段地址指定为只有特权模式才能够访问,会把内核空间3G以上的页表项里的每一行,指定为只有CPU 0环才能访问。应用程序没有陷入到内核态,是无法访问内核态的东西。

intel的漏洞meltdown,就是让用户可以在用户态读到内核态的东西。

meltdown 攻击原理: 基于时间的 旁路攻击 side-channel

李小璐买汉堡的故事 –> 安全的基于时间的旁路攻击技巧。

比如试探用户名,密码。比如一个软件比较傻,每次第一个字母就不对,就不对比第2个字母了。那我每次26个字母实验换一次,看哪个字母反弹地最慢,就证明是这个字母的密码。

密码是abc, 我敲了d,那么第一个字母就不对,软件这个时候如果快速的返回出错,我知道首字母不是d,我可以实验出来首字母是a,然后接着一个个字母实,就可以把密码试探出来了。类似地原理。。

下面的这个例子,演示 page table记录的RWX权限的作用

Linux硬件原理和分页管理

页表的权限,RWX权限,和 用户空间,内核空间读取的权限。

内存分Zone

下面解释内存为什么分Zone? DMA zone.

Linux硬件原理和分页管理

内存的分Zone,全都是物理地址的概念。内存条,被分为三个Zone。

分DMA Zone的原因,是DMA引擎的缺陷。DMA引擎 可以直接访问内存空间的地址,但不一定能够访问到所有的内存,访问内存时会存在一定的限制。

当CPU 和DMA同时访问内存时,硬件上会有仲裁器,选择优先级高的去访问内存。

为什么要切DMA zone?
DMA Zone的大小,是由硬件决定的。访问不到更高的内存。

什么叫做 normal zone? highmem zone?

highmem和lowmem 都是指的内存条,在虚拟地址空间,只能称为highmem,lowmem映射区。

如上图,内存虚拟地址空间0~4G,3~4G是内核空间的虚拟地址,0-3G 是用户空间的虚拟地址。

内核空间,访问任何一片内存都要虚拟地址。Linux为了简化内存访问,开机就把lowmem的物理地址一一映射到虚拟地址。highmem 地址包括了 normal + DMA。

Linux硬件原理和分页管理

lowmem是开机就直接映射好的内存,CPU访问这片内存,也是通过3G以上的虚拟地址。这段地址的虚拟地址和物理地址是直接线性映射,通过linux的两个api (phys_to_virt / virt_to_phys)在虚拟和物理之间进行映射, highmem 不能直接用。

内核空间一般不使用highmem,内核一般使用kmalloc在lowmem申请内存,使用 kmmap在highmem 申请内存。lowmem 映射了,并不代表被内核使用掉了,只是不需要重建页表。内核使用lowmem内存,同样是要申请。 应用程序一样可以申请 lowmem 和highmem。

总结:
内存分highmem zone的原因,地址空间整体不够。
DMA zone产生的原因,硬件DMA引擎的访问缺陷。

Linux硬件原理和分页管理

硬件层的内存管理- buddy算法

每个zone都会使用buddy算法,把所有的空闲页面变成2的n次方进行管理。

/proc/buddyinfo

通过/proc/buddyinfo,可以看出空闲内存的情况

Linux硬件原理和分页管理

CPU寻址内存的方法:通过MMU提供的虚拟地址到物理地址的映射访问。

如何处理内存碎片

Linux硬件原理和分页管理

X86 linux 内核有一个线程 compaction, 会进行内存碎片整理,会尽量移出大内存。

CMA:continuous memory allocation

内核把虚拟地址 指向新的物理地址,让应用程序毫无知觉情况,把64M内存腾出来给DMA。当用DMA的api申请内存,会走到CMA。在dts中指定哪块区域做CMA。

Documentation/devicetree/bindings

reserved-memory/reserved-memory.txt

dma_alloc_coherent

CMA, iommu

CMA主要是给需要连续内存的DMA用的。但是为了避免DMA不用的时候浪费,才在DMA不用的时候给可移动的页面用。不能移动的页面,不能从CMA里面拿。所以主要是APP和文件的page cache的内存,才可以在CMA区域拿。

这样当DMA想拿CMA区域的时候,要么移走,要么抛弃。总之,必须保证DMA需要这片CMA区域的时候,之前占着CMA的统统滚蛋。

不具备滚蛋能力的内存,不能从CMA区域申请。你申请也滚蛋不了,待会DMA上来用的时候,DMA就完蛋了。

要搞清楚CMA的真正房东是那些需要连续内存的DMA,其他的人都只是租客。DMA要住的时候,租客必须走。哪个房东会把房子租给一辈子都不准备走的人?内核绝大多数情况下的内存申请,都是无法走的。应用走起来很容易,改下页面就行了。

CMA和不可移动之间,没有任何交集。CMA唯一的好处是,房东不住的时候,免得房子空置。

酷客网相关文章:

赞(0)

评论 抢沙发

评论前必须登录!