做人呢,最紧要就系开心啦

Linux内核之内存1: CPU寻址原理和分页管理

851次阅读
没有评论

1 CPU 寻址内存,虚拟地址、物理地址

(1)寻址内存:

CPU 访问外设,有两种类型,一个是内存空间,一个是 IO 空间;

IO 空间,X86 通过 in/out 指令访问外设,IO 空间只存在 X86 架构,在 RISC 架构不存在;

内存空间 ,CPU 通过指针访问所有内存空间,内存空间分为两类, 普通内存 位于内存空间的寄存器。其他设备的寄存器,比如通过 I2C 总线访问触摸屏的寄存器,与 CPU 内存空间无关。

Linux 内核之内存 1: CPU 寻址原理和分页管理

(2) MMU 原理

对于一个支持 MMU 的 CPU,只要开启 MMU,CPU 跟程序员视角一致,看到的永远是虚拟地址;

在访问内存空间时,CPU 发一个虚拟地址(指针),MMU 把虚拟地址映射为物理地址。

其他硬件设备,比如 DMA/IVE(硬件模块不带 mmu)访问也是物理地址;

(3)虚拟地址和物理地址:

比如在两个不同的进程 QQ/WECHAT 里,可以分别定义一个变量,虚拟地址相同(都为 1G);真正访问的时候,经过 MMU 映射到实际不同的物理地址。

Linux 内核之内存 1: CPU 寻址原理和分页管理

每个进程都维护自己的页表,相同的虚拟地址可以映射到不同的物理地址;

当 CPU 访问 0x1234560 时,先查询页地址 0x1234 对应的物理地址(比如 1M),560 为页内偏移

patch

int *p=1m; // 对指针赋值物理地址,是错误的

(4) 物理地址的本质

在 Linux 内核,物理地址定义为一个无符号 64/32 位整数;

32 处理器虚拟地址最大 4G,物理地址不一定 32 位,可以大于 4G;

物理地址位数可以大于虚拟地址位数;

2.MMU 以及 RWX 权限、kernel 和 user 模式权限

32 位处理器,页表有 32 位,但实际维护页表只用到高 20 位,低 12 位用来存放其他信息比如权限

Linux 内核之内存 1: CPU 寻址原理和分页管理

CPU 访问一个地址,不仅要做虚拟 / 物理地址页表地址查询,还要检查页表权限,出现非法操作时,MMU 拦截 CPU 访问请求,并报 page fault,CPU 收到 MMU pagefault 中断时,报段错误,发信号 11,进程默认信号处理方式是挂掉。
Linux 内核之内存 1: CPU 寻址原理和分页管理

找不到物理地址,或者权限不对,发生段错误;

tips:
gdb layout src

meltdown 漏洞,利用时间旁路攻击原理,从用户空间获取内核空间数据;

3.MMU 作用总结:

(1). 内存隔离:防止应用程序访问不属于自己的空间,隔离应用对其它应用空间、内核空间的访问。因为它们只能访问自己的虚拟空间,每个进程的虚拟空间都是独立的。
(2). 权限管理:不同地址段拥有不同的访问权限,不能越权访问。
(3). 地址映射:将不连续的物理地址映射为连续的虚拟地址,并可以通过 swap 机制可以获得比实际内存大得多的使用空间。
前两者实现数据安全,第三条为程序提供空间便利。

该部分由网友 Aero Learning 补充, 感谢。

再补充两点:
1. 直接使用物理内存,当即将运行的程序内存不足时,需要选择一个进程整体换出,这导致有大量数据的换出与换入,效率低下;即MMU 可以解决内存使用效率问题

2. 有效解决碎片化问题;

3. 内存的 zone: DMA、Normal 和 HIGHMEM

32 位 Linux 内核空间物理地址映射在 3G~4G,分三个区域,
ZONE_DMA(0~16M):DMA 内存分配区;
ZONE_NORMAL(16MB~896MB): 普通映射的内存区域;
ZONE_HIGHMEM(896MB\~): 高端内存区域,其中的页不能永久映射到内核地址空间;内核一般不使用,如果要使用,通过 kmap 做动态映射;

存在高端内存的原因是,当物理内存大于虚拟内存寻址范围 (1G) 时,需要做 非线性映射,才能在访问所有物理内存空间范围。32 系统一般都划分 896M 以上物理地址为高端内存。

在目前流行的 64 位 CPU 中,由于虚拟寻址位数足够,就不存在高端内存概念了。

Linux 内核之内存 1: CPU 寻址原理和分页管理

896M 以下,开机直接映射好(通过 virt_to_phys/phys_to_virt 简单线性映射),896MB 以上动态分配,可以被内核和用户空间访问;

对于 64 位 CPU 有足够寻址能力,就不存在 869MB 问题了,64 位处理器,一般没有 HGIHMEM ZONE;;

对于一个嵌入式设备,内存太小,也不存在 HIGHMEM 区域;

DMAzone 存在的根本原因是 DMA 硬件有缺陷,比如一个典型 32 位系统 ISA 设备的 DMA 只有 24 位寻址能力,也就是只能访问内存的前 16M 内存,而整个系统的最大物理内存寻址甚至可以大于 1G,超过内核的虚拟空间;

DMA 没有 MMU,所以只能访问连续物理内存;少数最新的 DMA 具有 MMU,也可以访问物理不连续的内存,MMU 页表映射即可。

当为一个 DMA 有缺陷设备申请内存时,传入标记 GFP_DMA,在 DMA ZONE 区域分配内存,如果 DMA 可以访问所有内存空间,则不用受限于 DMA_ZONE。而其他普通设备,也可以申请 DMA_ZONE.

申请 DMA 内存,会填入设备访问范围,根据范围确定申请的内存区域;

DMA 内存不一定来自于 DMA ZONE,DMA ZONE 也不一定用于 DMA

如果系统所有 DMA 都没有缺陷,则不存在 dma_zone;

DMA 直接访问内存,不会让外设访问速度更快,DMA 最大好处是解放 CPU 资源,速度受限外设总线及访问频率;

4.Linux 内存管理 Buddy 算法

Buddy 算法直面物理内存;

Buddy 算法把内存中的所有页面按照 2 的幂次进行分块管理,分配的时候如果没有相应大小块,就把大的块二分成小块;释放的时候,回收的块跟相邻的空闲伙伴块又能合并成大块;

BUDDY 页面的分配和使用情况可以通过 proc 接口 /proc/buddyinfo 来查看;

Linux 内核之内存 1: CPU 寻址原理和分页管理

Buddy 有个缺陷,会造成许多内存碎片,比如总和还剩余很大,但是没有足够连续的空余内存可用。

早期采用预留分配方法,给予显卡,摄像头等预留内存,即使设备不使用,也会预留。

5. 连续内存分配器(CMA)

Linux 内核之内存 1: CPU 寻址原理和分页管理

分配专门的 CMA 区域,用于 DMA 设备的内存申请,比如摄像头,

当摄像头设备不用时,该区域可以用于其他内存分配;

当使用摄像头时,将该区域内的所有已申请内存,拷贝到其他分散的页,并且修改对应页表。

Linux 内核之内存 1: CPU 寻址原理和分页管理

这样 CMA 大块连续内存,就不会被浪费掉,也保持了大块连续内存的访问需求;

把不同的 DMA 设备,放在不同的 CMA,就不会导致内存碎片化;

其他参考文章:

宋宝华《DMA 若干误解的彻底澄清》;

内核文档:Doccumentation/devicetree/binding/reserved-memory/reserved-meory.txt

正文完
 1
admin
版权声明:本站原创文章,由 admin 2022-01-04发表,共计2574字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)