linux(arm架构)内存管理学习(1)

原创 2016年08月31日 11:11:26
        在研究内核hibernate实现的时候,由于需要对内存管理如MMU配置、内存分布和分配有相应了解,因此进行了专门的学习。最终结果是hibernate未研究出什么成果,反倒是内存管理的学习小有心得,就此予以总结。当然,按照一贯做法少上代码、多提思路和关键点。
        我所使用的平台是全志的平台T3(四核Cortex-A7、2G DDR),内核版本是3.10.65,硬件物理地址分布是:
SRAM    0x00000000---0x0000BFFF
IO      0x01000000---0x01EFFFFF
DRAM    0x40000000---0xBFFFFFFF
BROM    0xFFFF0000---0xFFFF8FFF
一、MMU
        关于MMU,一直以来都知其然而不知其所以然,因此利用这次机会做了一次亲密接触。文中提到的很多专业名词不会进行单独解释,引用的内容会附上相应的链接。
1、基础概念(具体参引用一)
其中第一级页表(L1)是由虚拟地址的高12bit(bits[31:20])组成,所以第一级页表有4096个item,每个item占4个字节,所以一级页表的大小为16KB,而在第一级页表中的每个entry的最低2bit可以用来区分具体是什么种类的页表项,2bit可以区分4种页表项,具体每种页表项的结构如下:
10b: Section entry
01b: Coarse page table
11b: Fine page table
00b: Fault 

简而言之L1页表的页表项主要有两大类:
第一大类是指向第二级页表(L2页表)的基地址
第二类直接指向1MB的物理内存

PGD(Page Global Directory):第一级页表(页目录)
PUD(Page Upper Directory):中间级页表(页目录),arm架构其实不需要
PMG(Page Mid-level Directory):第三级页表(页目录)
PTE(Page Table Entry):物理页表项

对于内核,不让3G-4G的空间都使用一一映射,而是将物理地址的[0x00,fix_addr](fix_addr<1GB)映射到内核空间虚拟地址[0x00+3G,fix_addr+3G],然后将[fix_addr+3G,4G]这段空间保留下来用于动态映射,这样我们可以通过这段虚拟地址来访问从fix_addr到4GB的物理内存空间。怎么做到的呢?

譬如我们想要访问物理地址[fix_addr,4GB]这段区间中的任何一段,我就用宝贵的内核虚拟地址[fix_addr+3G,4G]的一段去映射他,建立好mmu硬件使用的页表,访问完后,将映射清除,将内核的这段虚拟地址释放,以供下次访问其他的物理内存使用。这样就可以达到访问所有4GB的物理内存的目的。

二、代码片断
1、Bootloader:如果按照常用的两步启动法,Bootloader是由Boot0和Boot1组成:
1) Boot0:说法不一,从业以来见得到说法就还有IPL、SPL
Boot0由于功能不复杂,所以仅需要创建一级页表即可。由于没有找到T3的Boot0代码,用另一平台(Cortex-A8)的代替,但仍具有一定的代表性:
void mmu_system_init(__u32 dram_base, __u32 dram_size, __u32 mmu_base)
{
	__s32   *mmu_tlb_address = (__s32 *)mmu_base;
	__u32    i;

	//建立16k的段表,表项大小为1M
	for(i = 0; i < 4 * 1024; i++)
	{
		mmu_tlb_address[i] =
				  (i << 20)    |
				  (0 << 19)    |
				  (0 << 18)    |
				  (0 << 17)    |
				  (0 << 16)    |
				  (0 << 15)    |
				  (0 << 12)    |
				  (3 << 10)    |
				  (0 <<  9)    |
				  (15 << 5)    |
				  (0  << 4)    |
				  (0  << 3)    |
				  (0  << 2)    |
				  (2  << 0);
	}
	//cache sram
	mmu_tlb_address[0] = 
			 (0 << 20)    |         // 地址
			 (0 << 19)    |         // 安全区域
			 (0 << 18)    |         // 1M段表
			 (0 << 17)    |         // not global
			 (0 << 16)    |         // not shared
			 (0 << 15)    |         //
			 (0 << 12)    |         //
			 (3 << 10)    |         // 访问权限 特权
			 (0 <<  9)    |         //
			 (15 << 5)    |         // 域控制(arm特有)
			 (0  << 4)    |         //
			 (1  << 3)    |         // 有cache
			 (0  << 2)    |         // 无buffer
			 (2  << 0);             // 段表
	//cache dram
	for(i = 0; i < dram_size; i++)
	{
		mmu_tlb_address[i + (dram_base>>20)] =
						 (dram_base + (i << 20))  |
						 (0 << 19)    |
						 (0 << 18)    |
						 (0 << 17)    |
						 (0 << 16)    |
						 (0 << 15)    |
						 (0 << 12)    |
						 (3 << 10)    |
						 (0 <<  9)    |
						 (15 << 5)    |
						 (0  << 4)    |
						 (1  << 3)    |
						 (0  << 2)    |
						 (2  << 0);
	}
	//set ttb
	__asm{mcr p15, 0, mmu_base, c2, c0, 0}
	__asm{mcr p15, 0, mmu_base, c2, c0, 1}
	//clean i/d cache
	flush_icache();
	flush_dcache();
	//set domain controller
	mmu_set_domain_access();

	return ;
}
分析:从上面可以看到一级页表空间占用16KB,全部按段表方式创建表项,虚拟到物理的映射规则是一一对应的(即偏移为0)。

2) Boot1: 使用的是U-boot,也仅创建了一级页表,创建页表的宏是:
/* form a first-level section entry */
.macro FL_SECTION_ENTRY base,ap,d,c,b
.word (\base << 20) | (\ap << 10) | \
     (\d << 5) | (1<<4) | (\c << 3) | (\b << 2) | (1<<1)
.endm

2、Kerenl
内核会创建二级页表,具体代码就不做分析了(可参引用三),创建二级页表的接口是下面两个:
一级页表:__map_init_section
二级页表:alloc_init_pte
关于内核启动后,内核页表的分布会另写一文进行描述;

三、调试工具
1、proc文件系统
/proc/iomem
/proc/vmallocinfo
/proc/dma-mappings
/proc/meminfo
/proc/pidX/pagemap
2、系统工具
busybox devmem
procrank
showmap
pmap
3、自行开发工具
sw_mem
pagemap

四、引用
1、linux arm mmu基础
http://blog.csdn.net/xiaojsj111/article/details/11065717
2、linux arm的存储分布那些事之一
http://blog.csdn.net/xiaojsj111/article/details/11724081
3、Linux内核页表
http://blog.csdn.net/lieye_leaves/article/details/50809973

相关文章推荐

arm-linux内存管理学习笔记(1)-内存页表的硬件原理

学习内核的内存管理如果脱离了MMU的硬件原理,只去学习其软件逻辑,真的很难懂。说到底,软件代码的逻辑是为硬件服务,只是为了充分发挥硬件的各项功能,因此学习linux的内存管理机制,首先要学习下该处理器...

Arm-linux内存管理(3)

毛德操《嵌入式系统》读书笔记。 接着第二篇说 1、 与通用计算机系统相比,嵌入式系统中内存的组成与布局更加多样。因为长采用不同质的存储器件,如ROM/RAM等 外设接口的寄存器,按内存...

Linux内存管理:ARM Memory Layout以及mmu配置

转载:http://blog.csdn.net/hongzg1982/article/details/47341881 在内核进行page初始化以及mmu配置之前,首先需要知道整个memory ma...

Linux内存管理:ARM Memory Layout以及mmu配置

http://blog.csdn.net/hongzg1982/article/details/47341881 在内核进行page初始化以及mmu配置之前,首先需要知道整个memory...

ARM内存管理(MMU)详解

嵌入式系统中,存储系统差别很大,可包含多种类型的存储器件,如 FLASH , SRAM , SDRAM , ROM 等,这些不同类型的存储器件速度和宽度等各不相同;在访问存储单元时,可能采取平板式的地...
  • yimu13
  • yimu13
  • 2010年11月28日 10:46
  • 10430

ARMv8 内存管理架构.学习笔记

目 录 第1章 分级存储架构. 2 1.1基础认识... 2 1.1.1从数据通路描述. 2 1.1.2从数据交换单位描述. 2 1.1.3 Cache数据一致性拓扑结构. 3 1.2 系统层内存模...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

ARM学习之图解ARM

arm developer’s guide图:嵌入式arm的基本架构 图:应用软件运行在arm硬件上的抽象图 图:arm memory remap 图: arm内容数据流模型 图:arm...

给定A, B两个整数,不使用除法和取模运算,求A/B的商和余数

给定A, B两个整数,不使用除法和取模运算,求A/B的商和余数。 1.   最基本的算法是,从小到大遍历: for (i = 2 to A -1)          if (i * B > A)...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:linux(arm架构)内存管理学习(1)
举报原因:
原因补充:

(最多只允许输入30个字)