Linux--高端内存的映射方式
高端内存是指物理地址大于 896M 的内存。
对于这样的内存,无法在“内核直接映射空间”进行映射。 为什么? 因为“内核直接映射空间”最多只能从 3G 到 4G,只能直接映射 1G 物理内存,对于大于 1G 的物理内存,无能为力。 实际上,“内核直接映射空间”也达不到 1G, 还得留点线性空间给“内核动态映射空间” 呢。 因此,Linux 规定“内核直接映射空间” 最多映射 896M 物理内存。 对于高端内存,可以通过 alloc_page() 或者其它函数获得对应的 page,但是要想访问实际物理内存,还得把 page 转为线性地址才行(为什么?想想 MMU 是如何访问物理内存的),也就是说,我们需要为高端内存对应的 page 找一个线性空间,这个过程称为高端内存映射。 高端内存映射有三种方式: 1、映射到“内核动态映射空间” 这种方式很简单,因为通过 vmalloc() ,在”内核动态映射空间“申请内存的时候,就可能从高端内存获得页面(参看 vmalloc 的实现),因此说高端内存有可能映射到”内核动态映射空间“ 中。 2、永久内核映射 如果是通过 alloc_page() 获得了高端内存对应的 page,如何给它找个线性空间? 内核专门为此 留出一块线性空间,从 PKMAP_BASE 到 FIXADDR_START ,用于映射高端内存。在 2.4 内核上,这个地址范围是 4G-8M 到 4G-4M 之间。这个空间起叫“内核永久映射空间”或者“永久内核映射空间” <!--[endif]--> 这个空间和其它空间使用同样的页目录表,对于内核来说,就是 swapper_pg_dir,对普通进程来说,通过 CR3 寄存器指向。 通常情况下,这个空间是 4M 大小,因此仅仅需要一个页表即可,内核通过来 pkmap_page_table 寻找这个页表。 通过 kmap(), 可以把一个 page 映射到这个空间来 <!--[endif]--> 由于这个空间是 4M 大小,最多能同时映射 1024 个 page 。因此,对于不使用的的 page ,及应该时从这个空间释放掉(也就是解除映射关系),通过 kunmap() ,可以把一个 page 对应的线性地址从这个空间释放出来。 3、临时映射 内核在 FIXADDR_START 到 FIXADDR_TOP 之间保留了一些线性空间用于特殊需求。这个空间称为“固定映射空间” 在这个空间中,有一部分用于高端内存的临时映射。 这块空间具有如下特点: <!--[if !supportLists]-->1、 <!--[endif]-->每个 CPU 占用一块空间 <!--[if !supportLists]-->2、 <!--[endif]-->在每个 CPU 占用的那块空间中,又分为多个小空间,每个小空间大小是 1 个 page,每个小空间用于一个目的,这些目的定义在 kmap_types.h 中的 km_type 中。 当要进行一次临时映射的时候,需要指定映射的目的,根据映射目的,可以找到对应的小空间,然后把这个空间的地址作为映射地址。这意味着一次临时映射会导致以前的映射被覆盖。 通过 kmap_atomic() 可实现临时映射。
下图简单简单表达如何对高端内存进行映射
|
Linux--高端内存的映射方式
最新推荐文章于 2021-05-11 21:30:30 发布