linux 内核空间内存分布

发布时间 2023-05-07 22:23:49作者: 流水灯

虚拟地址空间划分

linux通过宏“PAGE_OFFSET”将4GB的虚拟地址空间(32bit平台)划分成内核地址空间和进程地址空间两部分。“PAGE_OFFSET”的值支持通过Kconfig配置,其默认的值是“0xC0000000”。下面以经典的“PAGE_OFFSET=0xC0000000”来看下linux对虚拟地址空间的详细划分。

Linux将虚拟地址空间划分为:0~3G为用户空间,3~4G为内核空间。下面是一个经典划分图:

下面简要介绍下各个部分意义:

【1】Process address space

0x0000 0000 ~ PAGE_OFFSET - 1 :用户进程虚拟地址空间,用于用户空间地址映射。每个进程独有,进程通过mmap()系统调用建立的映射都在这个区域内(其实这个区间高地址还包含内核模块区域,范围为MODULES_VADDR ~ MODULES_END-1)。

【2】Physical memory mapping

PAGE_OFFSET ~ high_memory - 1 :物理内存映射区,又名“Kernel direct-mapped RAM region”,即内核直接物理内存映射区域。这个区域用于将内核空间前896M和物理空间的前896M进行直接映射。

high_memory是指超过能直接映射的物理内存部分,超过“high_memory”的虚拟地址属于高端内存区域,“高端”是相应直接映射区的“low memory”而定的。引入高端内存映射这样一个概念的主要原因就是我们所安装的内存大于1G时,内核的1G线性地址空间无法建立一个完全的直接映射来触及整个物理内存空间,而对于80x86开

启PAE的情况下,允许的最大物理内存可达到64G,因此内核将自己的最后128M的线性地址空间腾出来,用以完成对高端内存的暂时性映射。而在64位的系统上就不存在这样的问题了,因为可用的线性地址空间远大于可安装的内存。

用于映射高端物理内存的虚拟地址空间划分,因平台而异,上图给出的是x86中一种经典划分,下面分析下高端内存映射区域是如何使用的。

【3】Vmalloc area

VMALLOC_START ~ VMALLOC_END :区域由vmalloc ioremap使用,物理不连续,是内核动态映射区域,用于动态映射物理内存。此区域由vmalloc函数执行动态地址分配,虚拟地址连续但物理地址不连续的内存。物理地址一般是HIGH_MEM区域,但也可以是其他物理地址,比如外设寄存器地址。Vmalloc 区域和直接映射区有一个8MB的隔离区,另外每个独立的Vmalloc area中间都有4KB的隔离区,主要是为了“捕获”对内存的越界访问(因为空洞未映射,访问会报错,以达到捕捉越界行为的目的)。

【4】persistent kernel map

PKMAP_START ~ FIXADDR_START:区域是kmap 内核永久映射空间。这里的永久并不是指调用kmap()建立的映射关系会一直持续下去无法解除,而是指在调用kunmap()解除映射之前这种映射会一直存在,这是相对于临时内核映射机制而言的。另外kmap申请不到会导致阻塞。

【5】fix-map area

FIXADDR_START ~ end :区域是kmap_atomic 使用的内核固定映射空间,又称临时映射区,固定映射区不是线性转换,而是强制指定的任意映射,每个固定的线性地址都映射到一块物理内存页。以任意方式映射任意物理地址。(ARM中有3MB空间)。临时是因为会强制映射,覆盖以前已经有的映射,所以这种映射不会阻塞,可以用在中断处理流程中。主要用于使用线性地址常量代替指针变量,提高内存访问效率。

 

 

IMX6ULL 配置如下

CONFIG_VMSPLIT_2G=y

 

所以 PAGE_OFFSET 是 0x80000000,即内核空间的起始虚拟地址是 0x80000000。

PAGE_OFFSET: the virtual address of the start of the kernel image // 内核固件存储的起始地址是 PAGE_OFFSET

 

由于 IMX6ULL DDR 内存所在的物理地址是 0x80000000,内核固件存储在 DDR 首地址,所以内核空间的物理地址等于虚拟地址。

链接脚本设置的起始链接地址就是 0x80008000,因为在内核启动时执行自解压完成后,会跳转到解压后的地址处 0x80008000 运行