首页 >> 大全

ARM32内存空间分配

2023-10-11 大全 36 作者:考证青年

Linux内核一般将处理器的虚拟地址空间分成两部分,在32系统上,地址空间在用户进程和内核之间划分的典型比例为3:1,在给出的4GB的虚拟地址空间中,0 ~ 3GB将用于用户空间而3GB ~ 4GB将用于内核空间,内核提供了相关的配置项来修改该比例,也就是说最多寻址1GB的虚拟地址空间。

当CPU启动MMU后,CPU访问的时虚拟地址空间,然后由MMU根据页表转换成物理地址,页表是由维护的,所以可以决定1GB的虚拟地址空间具体映射到什么物理地址。但是不管怎么映射,最多也只能映射1G的物理内存,所以如果一个系统有超过1G的物理内存,在某一时刻,必然有一部分空间是内核无法访问到的,对于该问题内核借助于高端内存()方法来管理多余的内存,本章的主要讲解以下内容

什么是高端内存及其作用

ARM32 Linux的内存布局

1. 什么是高端内存

对于32系统,内核使用3G ~ 4G的虚拟地址空间,那么只有1G的地址空间可以用来映射物理空间。但是,如果我们使用的内存大于1G的情况,是不是超过1G的内存就无法使用了呢?为此内核引入了一个高端内存的概念,把1G的虚拟地址空间分成两部分

低端内存空间:小于的物理地址空间,这部分的内存物理地址和3G开始的线性地址是一一映射的,也就是说内核使用的线性地址空间3G ~ (3G + )和物

理地址空间0 ~ 一一映射

高端内存空间:剩下的128M的线性空间用来映射剩下的大于的物理地址空间

对于以上,我们可以知道以下问题

对于高端内存,现在一般是896M,当我们只有512M的内存的时候,就没有高端内存一说了,因为512MB的物理内存已经被直接映射

64位系统下不会有high ,因为64位虚拟地址空间非常大(分给的也很大),完全能够直接映射全部物理内存。

在32位系统上,没有任何进程能够有效地使用超过3GB的内存。这意味着购买超过4GB的从理论上是发挥不出其优势

对于我们使用的IMX6U,由于使用了CMA,所以其高端内存的地址空间范围为 0000 ~ FFFF(512 MB ~ )。那么内核如何借助512M高端内存地址空间实现访问访问所有4GB的物理内存。比如当内核项访问高于的物理地址时,可以从( 0000 + ) ~ FFFF地址空间范围内找一段相应大小的空闲虚拟地址,建立映射到想访问的那段物理内存,用完后归还。这样就所有的人都可以借用这段地址空间访问物理地址,访问所有物理内容如下图所示:

我们可以知道高端内存的最基本思想:借一段地址空间,建立临时地址映射,用完后释放,达到这段地址空间可以循环使用,访问所有物理内存。万一有内核进程或模块一直占用某段逻辑地址空间不释放,怎么办?若真的出现的这种情况,则内核的高端内存地址空间越来越紧张,若都被占用不释放,则没有建立映射到物理内存都无法访问了。

2. Linux内核高端内存的划分

对于高端内存,一般划分如下:

动态内存映射区:虚拟内存中连续,但物理内存不连续的内存,可以在区域分配。该机制通常用于用户空间,内核自身会试图尽力避免非连续的物理内存。

永久内存映射区:该区域可访问高端内存,访问方法是使用()分配高端内存页或使用kmap函数将分配到高端内存映射到该区域

固定映射区:固定映射是与物理内存空间中的固定页关联的虚拟地址空间项,该区域和4GB的顶端只有4K的隔离带,其每个地址项都服务于特定的用途。

对于高端内存的划分,其中fixed 主要用在boot阶段用来永久性映射一些物理地址固定的数据结构或者硬件地址(比如ACPI表,APIC地址,等等)。kmap area是用来临时建立映射来访问物理页用的,可用的地址空间也比较小。绝大部分了给 area,和返回的都是这个空间里的地址。

3. ARM32内存分布图

了解完低端内存和高端内存的概念,我们来看看我们实际上内存布局是怎么样的?Linux内核在启动时,会打印出内核内存空间的布局图,下面是ARM IMX6平台打印出来的内存空间布局图

:

: - ( 4 kB)

: - (3072 kB)

: - ( 496 MB)

: - ( 512 MB)

pkmap : - ( 2 MB)

: - ( 14 MB)

.text : - (10208 kB)

.init : - (2048 kB)

.data : - ( 467 kB)

.bss : - ( 460 kB)

10

11

这部分信息是的打印是在()函数中实现的

(" :\n"

" : 0xlx - 0xlx (%4ld kB)\n"

#ifdef

" DTCM : 0xlx - 0xlx (%4ld kB)\n"

" ITCM : 0xlx - 0xlx (%4ld kB)\n"

#endif

" : 0xlx - 0xlx (%4ld kB)\n"

" : 0xlx - 0xlx (%4ld MB)\n"

" : 0xlx - 0xlx (%4ld MB)\n"

#ifdef

" pkmap : 0xlx - 0xlx (%4ld MB)\n"

#endif

#ifdef

" : 0xlx - 0xlx (%4ld MB)\n"

#endif

" .text : 0x%p" " - 0x%p" " (%4td kB)\n"

" .init : 0x%p" " - 0x%p" " (%4td kB)\n"

" .data : 0x%p" " - 0x%p" " (%4td kB)\n"

" .bss : 0x%p" " - 0x%p" " (%4td kB)\n",

MLK(UL(), UL() +

()),

#ifdef

MLK(, ( long) ),

MLK(, ( long) ),

#endif

MLK(, ),

MLM(, ),

MLM(, ( long)),

#ifdef

MLM(, () + () *

()),

#endif

#ifdef

MLM(, ),

#endif

(_text, ),

(, ),

(, ),

(, ));

10

11

12

13

14

15

16

17

18

分配内存空间的函数__分配内存空间

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

内核image本身占据的内存空间从_text段到 _end段,并且分为如下几段

代码段:_text和 为代码段的起始和结束地址,包含了编译后的内核代码

init 段: 和 为init段的起始和结束地址,包含了大部分模块初始化的数据

数据段:和 数据段的起始和结束地址,保存大部分内核的变量

BSS段:和 为BSS段的开始和结束地址,包含了初始化为0的所有的静态全局变量

那么高端内存的起始地址是如何确定的呢?在内核初始化内存时候,在函数中确定低端内存和高端内存的起始地址

= (u64)() - + ;

= ;

= __va( - 1) + 1;

计算出来内核线性映射512M地址空间,剩下的保留给,和高端向量表使用,内核很多驱动使用来分配连续虚拟地址内存,因为有的驱动不需要连续物理地址内存;除此之外,还可以用于高端内存的临时映射。对于内核空间配置如下

# (8*1024*1024)

# ((( long) + ) & ~(-1))

#

区域在ARM32内核中,从开始到结束,即从 - ,大小为512MB,在开始之前有一个8MB的空间,用于捕获越界访问。

4. 总结

对于高端内存,首先我们需要明确这是一个物理内存的概念,它仅仅是内核中的内存管理模块看待物理内存的时候的概念。在内核中,除了内存管理模块直接操作物理地址之外,其他的模块,都需要操作虚拟地址,而虚拟地址是需要内存管理模块分配和映射的。例如,我们有一个2G的内存,现在内核模块如果想要访问物理内存1.5G的地方,应该怎么办呢?

首先,我们不能使用物理地址,你需要使用内存管理模块给你分配虚拟地址,但是虚拟地址0 ~ 3G已经被用户态进程占用去了,作为内核不能使用。

其次,对于1.5G的地方就算映射了,也不是你真正要访问的物理内存地址,所以对于内核,能够使用虚拟内存地址,只剩下高端内存这块了。

内核通常把物理内存低于的地址成为线性映射地址,而高于以上的成为高端内存。由于32位系统寻址能力只有4GB,对于物理内存高于而低于4GB的情况,我们就需要从虚拟地址空间中画出一部分来用于动态映射高端内存,这样就可以访问到全部的4GB的内存。而对于映射高端内存的虚拟地址空间,可以划分位固定映射区和临时映射区,后面章节中单独来讲解每个的功能。对于我们现在使用的IMX6U的内核空间的内存分布图如下所示,对于途中的高端内存每个平台可能都不一样,主要是通过客户实际需要来配置

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了