您的位置:首页 > 其它

[TZ]内存与IO访问(1)--地址,MMU、内存管理相关概念

2015-11-23 09:33 393 查看
说在前面(只关注概念的看官可以跳过):笔者正好买了s5pv210的板子,所以非X86部分尽量会以s5pv210(ARMv7 - CortexA8)的设定、参数为例来说明。顺便自己学习一下。非特指的其他内内容以 X86体系结构的32位版本(
IA_32
)描述。如果使用网络资料还可能用到s3c2410等芯片。

由于ARM不同版本内核体系结构不同,而很多资料没加区分全部以ARM代替还是带来不少麻烦。



(image source: http://www.arm.com/zh/products/processors/instruction-set-architectures/index.php)

ARMv7有三个系列: ARMv7-A, ARMv7-R, ARMv7-M

ARMv7-A: Application profile, 支持ARM和Thumb指令集, 支持MMU(Memory Management Unit) - s5pv210属于这一类

ARMv7-R: Real-time profile, 支持ARM和Thumb指令集, 支持MPU(Memory Protection Unit), 无MMU

ARMv7-M: Micro-controller profile, 只支持Thumb指令集, 支持MPU, 无MMU

更多ARMv7架构资料

转载请注明原文地址:http://blog.csdn.net/ts_dchs/article/details/49991053

1.1 地址、地址空间

虚拟地址、物理地址、总线地址

虚拟地址:CPU核角度看到的地址(线性地址)

物理地址:CPU通过MMU控制器看到的内存地址。

总线地址:从设备角度看到的内存地址。

物理空间、虚拟空间

支持MMU的32bit 平台,物理存储和虚拟存储空间的地址分布都是0x00000000到0xFFFFFFFF,共4GB。

Linux运行在虚拟空间,负责将物理内存、设备空间(设备的寄存器,设备内存)根据不同需求映射到4G虚拟空间。

物理空间布局

Linux的物理空间布局和处理器相关,查看s5pv210芯片手册,Memory Map一节说明。



(image source: s5pv210 Manuals)

NR_BANKS表示系统中支持的最大内存bank数,一般等于处理器的RAM片选数。

mem_init()函数会将所有节点的页帧位码表所占空间、孔洞页描述符空间及空闲内存页都释放掉。

虚拟空间布局

在支持MMU的系统中,当系统做完硬件初始化后就使能MMU功能,这样整个系统就运行在虚拟存储空间中。MMU实现虚拟存储空间到物理存储空间映射功能,而虚拟存储空间与物理存储空间的映射关系则是由Linux内核来管理的。

32bit内核将虚拟空间布局划分为3G User space和1G的Kernel space,如图:



用户进程只能访问User space虚拟地址,不能访问Kernel space。

高端内存的出现

如果之用这样的划分Kernel如果用线性地址一一映射,满打满算只能支配1G的物理空间,显然是不科学的。所以不能完全用线性映射的方法。Linux将1G的Kernel space大致分为三个区域:

0-16MB,ZONE_DMA(0xC000 0000 ~ 0xC00F FFFF) 线性映射DMA

16-896MB,ZONE_NORMAL(0xC010 0000 ~ 0x7FF FFFF) 线性映射物理内存空间

896-1024MB,ZONE_HIGHMEM(0xF800 0000 ~ 0xFFFF FFFF) 非线性映射

tip:这里是linux逻辑设定的区域划分,如果真实的内存只有1G,实际线性对应在常规内存的物理内存就可能没有896MB。



(image source: http://blog.chinaunix.net/uid-20528014-id-314322.html )

以这样的方式使用Kernel space内存来映射到整个物理空间。

比如要访问被线性映射之后的物理内存,也就是DRAM 896MB(假设线性映射了896MB)后的区域。那么就借用高端内存的一块空闲地址,建立访问相应物理内存的映射,通过建立好的映射来访问实际的物理内存中的数据。也就是通过MMU(后面有简单介绍)的机制来访问。之后这段被借用的地址还可以释放掉用作对其他地址的映射。

具体来说:

1G的Kernel space的高端内存又划分为:

vmalloc分配器区(前后有隔离带,地址VMALLOC_START ~ VMALLOC_END)

高端内存映射区(高端内存只能以映射在这里)(PKMAP_BASE ~ FIXADDR_START)

专用页面映射区(实际中FIXADDR_START ~ FIXADDR_TOP)这部分需要配置,下图未显示。

保留区域(实际中FIXADDR_TOP ~ 4G区域)

如图:



(image source: http://ilinuxkernel.com/?p=1013 )

注意:高端内存的概念只在Kernel space中有,Kernel可以访问所有物理内存,进程能访问的还是虚拟空间中的3G用户空间。

x86 IO空间

Intel X86存在IO空间的概念(IO Space),相对于内存空间(笔者理解就是前面的虚拟空间)而言,通过特定的IN OUT指令访问。大多数ARM PowerPC仅有内存空间。内存空间通过地址,指针访问。程序,程序运行中使用的变量都在内存空间。

tip: X86的IO空间现在相对拥挤,我们自己设计的电路外设可以只挂接在内存空间。

PC的ISA和PCI,其总线地址就是物理地址,但是并非每个平台都是这样。有时候总线通过桥接电路连接,电路会将IO地址映射为不同的物理地址。

内存地址/线性地址/逻辑地址

常说的内存地址是内存空间的地址,线性地址,程序中可以通过指针来访问。程序中出现的地址是逻辑地址(x86下是段地址+偏移量 不直接等于线性地址,需要段机制转化)。

unsigned char *p = (unsigned char*) 0xF000FF00;
*p = 1;


0xF000FF00这个地址对于x86是16bit段地址+16bit偏移地址,即,0xF000 * 16 + 0xFF00 = 0xF0000 + 0xFF00 = 0xFFF00

地址对于ARM等为采用段地址的处理器,就是内存空间0xF000FF00。

x86处理器用实际地址做第一步跳转(软重启):

typedef void (*lpFunction) ();//define a function pointer type
lpFunction lpReset = (lpFunction)0xF000FFF0; //get a pointer that point to the addr
lpRest(); //go to the function at addr


小结一下:

物理空间 - 物理地址 - 总线地址 - 硬件相关

虚拟空间 - 虚拟地址 - 32bitCPU可寻址的 线性地址 - 内存地址 - 内存空间 ~ 程序逻辑地址(每个程序都有自己的4G空间 x86靠段机制完成程序逻辑地址到线性地址的转化)

IO空间(x86) - 相对于内存空间对外设的访问空间

有了虚拟空间的概念,就可以利用一定的机制使得逻辑空间的总和大于物理内存的空间,将当前用的部分保存在物理内存使用,将不用的置换在硬盘中。所以一个物理存储块(之后会提到的Page Frame)可以映射多个逻辑存储单位(Page)。想要完成这样的地址转化就需要有相应的映射机制。

1.2 地址映射

这里简单了解,详细说明见之后《Linux地址映射》一节

x86
IA_32
启用保护模式+开启分页机制后)逻辑地址(VA)段转化(segment translation)后得到线性地址,页转化(page translation)后得到物理地址(PA)。也就是说程序给入一个逻辑地址,CPU拿到后经过两个映射得到数据总线的地址(物理地址)。

借用前辈的图描述
IA_32
段页式地址转化的过程:



(image source: http://ilinuxkernel.com/?p=1276 )

RISC

大多数RISC没有分段,进行一次线性到物理的转化。

ARM没有段地址的概念,没有段寄存器。VA被先转化为MVA(Modified Virtual Address),供Cache和MMU使用,它们再将MVA转为PA访问设备。

1.3 内存管理(
IA_32
)

物理内存管理:用Page为单位划分,通常4KB为大小。包括设备的地址,也用Page管理。

Linux为了架构无关性,才用了三级架构(node,zone,page),如图:



(image source: http://blog.csdn.net/myarrow/article/details/8624687 )

[node]

是对物理内存的一种描述,总线主设备访问一个node中的单元代价相同。任意两个节点的访问代价不同。两种内存的架构:

UMA,Uniform Memory Architecture。一致存储结构,只有一个节点。

NUMA,非一致性存储,有多个节点。所以CPU访问不同node代价不同,尽量在代价小的node中进行以便提高效率。

ARM架构使用UMA,Intel有双路架构有使用NUMA。

三种内存模型

Linux支持三种内存模型:

Flat Memory,默认采用内存模型。

Discontigous Memory,用于内存地址不连续,有空洞,也用于支持NUMA的内存模型。

Sparse Memory,对内存热插拔的支持

[zone]

位于同一node中,用途不同的划分。

记录自己zone的page frame的情况。

[page]

物理页框,内存管理基本单位。

物理内存在初始化的时候就生成了page。其他地址空间需要重新生成page - ioremap。

进程虚拟内存管理:Linux进程通过VMA(Virtual Memory Area)管理。每个进程由一个
task_structure
,进程控制块,维护,其中有一个VMA的链表,每个VMA对应一段连续的进程内存(逻辑连续)。

正是应为有虚拟内存管理的需要,就有了MMU,让CPU看到的VA转化为需要的PA。

1.4 MMU

Memory Management Unit,内存管理单元。辅助内存管理

在没有MMU的机器,”虚拟地址”被直接送到数据总线,具有相同地址的物理存储器被读写,也就是说大家使用的都是物理地址。使用虚拟地址和MMU之后,虚拟地址先送到MMU,再映射为物理地址。另外MMU可以实现不同权限的访问、分隔程序的空间则增加了安全性。

TLB:Translation Lookaside Buffer,转换旁路缓存。是MMU的核心部件,缓存少量的虚拟–物理关系,是转换表的Cache,也称为“快表”。

TTW:Translation Table walk,转换表漫游操作。当TLB没有需要的转换对,通过内存中的转换表(常常是多级页表,从页表记地址寄存器找到页表,一层一层直到代码页。)访问得到虚拟–物理关系,TTW成功就写入TLB。

写入之后如果权限正确将访问Cache或者内存找到相应的数据。如果不允许,MMU会向ARM发送一个存储器异常。

处理器架构不同、管理方式不同的时候,会用到不同层次的页表。比如:在s3c2410中MMU是由协处理器(cp15)控制的,s3c2410/s3c2440最多会用到两级页表:以段(Section,1MB)的方式进行转换时只用到一级页表,以页(page)的方式进行转换时用到两级页表。

问题:

物理设备的地址是不是也通过MMU用上述机制映射?

注:Linux 2.6支持不带MMU的处理器。其为了兼容嵌入式系统,融合了uClinux,来支持MMU-Less系统。

notification

source: 《Linux设备驱动开发详解》(第二版),内容为读书笔记和网络资料,有些资料原始来源不详,分享为了方便自己和他人查阅。如有侵权请及时告知,对于带来的不便非常抱歉。转载请注明来源。个人所学有限,若有错误和不足还请不吝赐教,我会及时更正。Terrence Zhou.

http://blog.csdn.net/ts_dchs

reference

[1] Linux线性,http://blog.chinaunix.net/uid-20528014-id-314322.html

[2] 物理地址和虚拟地址,http://blog.csdn.net/sunacmer/article/details/6833418

[3] Linux内核高端内存,http://ilinuxkernel.com/?p=1013 (好贴)

[4] Linux内存管理,http://blog.csdn.net/myarrow/article/details/8624687

[5] 关于MMU,http://blog.csdn.net/liangkaiming/article/details/6310098
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  arm 内存管理