arm内存管理单元学习

2024-07-05

arm内存管理单元学习(共6篇)

1.arm内存管理单元学习 篇一

高端内存是指物理地址大于 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 之间。这个空间起叫“内核永久映射空间”或者“永久内核映射空间”

通常情况下,这个空间是 4M 大小,因此仅仅需要一个页表即可,内核通过来 pkmap_page_table 寻找这个页表。

通过 kmap(), 可以把一个 page 映射到这个空间来

3、临时映射

内核在 FIXADDR_START 到 FIXADDR_TOP 之间保留了一些线性空间用于特殊需求。这个空间称为“固定映射空间”

在这个空间中,有一部分用于高端内存的临时映射。

这块空间具有如下特点:

当要进行一次临时映射的时候,需要指定映射的目的,根据映射目的,可以找到对应的小空间,然后把这个空间的地址作为映射地址。这意味着一次临时映射会导致以前的映射被覆盖。

通过 kmap_atomic() 可实现临时映射。

下图简单简单表达如何对高端内存进行映射

2.ARM学习心得 篇二

2008-08-13 13:55

由于很多人总问这个问题,所以这里做一个总结文档供大家参考。

这里必须先说明,以下的步骤都是针对Linux系统的,并不面向WinCE。也许你会注意到,现在做嵌入式的人中,做linux研究的人远比做WinCE的人多,很多产家提供的资料也是以linux为主。我一直很难理解,其实WinCE的界面比linux的界面好看多了,使用起来也很方便,更为重要的是,WinCE的开发和Windows下的开发基本一样,学起来简单得多,但是学linux或者使用linux做嵌入式的人就是远比WinCE多。在和很多工作的人交流时我了解到,他们公司从没考虑使用WinCE,因为成本高,都是使用linux进行开发。我读研究生的的实验室中也没有使用WinCE的,大都研究linux,也有少部分项目使用vxwork,但是就没有听说过使用WinCE的,原因就是开源!当然现在WinCE6.0听说也开源,不过在成本和资源上linux已经有了无人能挡的优势。与此相对应的是,越来越多的电子厂商已经开始使用linux开发产品。举个例子,Google近期开发的智能手机操作系统Android其实就是使用linux-2.6.23内核进行改进得到的。

第一,学习基本的裸机编程。

对于学硬件的人而言,必须先对硬件的基本使用方法有感性的认识,更必须深刻认识该硬件的控制方式,如果一开始就学linux系统、学移植那么只会马上就陷入一个很深的漩涡。我在刚刚开始学ARM的时候是选择ARM7(主意是当时ARM9还很贵),学ARM7的时候还是保持着学51单片机的思维,使用ADS去编程,第一个实验就是控制led。学过一段时间ARM的人都会笑这样很笨,实际上也不是,我倒是觉得有这个过程会好很多,因为无论做多复杂的系统最终都会落实到这些最底层的硬件控制,因此对这些硬件的控制有了感性的认识就好很多了

学习裸机的编程的同时要好好理解这个硬件的构架、控制原理,这些我称他为理解硬件。所谓的理解硬件就是说,理解这个硬件是怎么组织这么多资源的,这些资源又是怎么由cpu、由编程进行控制的。比如说,s3c2410中有AD转换器,有GPIO(通用IO口),还有nandflash控制器,这些东西都有一些寄存器来控制,这些寄存器都有一个地址,那么这些地址是什么意思?又怎么通过寄存器来控制这些外围设备的运转?还有,norflash内部的每一个单元在这个芯片的内存中都有一个相应的地址单元,那么这些地址与刚刚说的寄存器地址又有什么关系?他们是一样的吗?而与norflash相对应的nandflash内部的储存单元并不是线性排放的,那么s3c2410怎么将nandflash的地址映射在内存空间上进行使用?或者简单地说应该怎么用nandflash?再有,使用ADS进对ARM9行编程时都需要使用到一个初始化的汇编文件,这个文件究竟有什么用?他里面的代码是什么意思?不要这个可以吗?

诸如此类都是对硬件的理解,理解了这些东西就对硬件有很深的理解了,这对以后更深一步的学习将有很大的帮助,如果跳过这一步,我相信越往后学越会

觉得迷茫,越觉得这写东西深不可测。因为,你的根基没打好。

不过先声明一下,本人并没有使用ADS对ARM9进行编程,我是学完ARM7后直接就使用ARM9学linux系统的,因此涉及使用ADS对ARM9进行编程的问题我很难回答^_^,自己去研究研究吧。

对于这部分不久将提供一份教程,这个教程中的例程并不是我为我们所代理的板子写的,是我在我们学院实验室拿的,英培特为他们自己的实验箱写的,不过很有借鉴意义,可以作为一份有价值的参考。

第二,使用linux系统进行一些基本的实验。

在买一套板子的时候一般会提供一些linux的试验例程,好好做一段时间这个吧,这个过程也是很有意义的,也是为进一步的学习积累感性认识,你能想象一个从没有使用过linux系统的人能学好linux的编程吗?好好按照手册上的例程做一做里面的实验,虽然有点娃娃学走路,有点弱智,但是我想很多高手都会经历这个过程。

在这方面我们深蓝科技目前没有计划提供相应的例程,主要是开发板的提供商会提供很丰富的例程,我们不做重复工作,只提供他们没有的、最有价值的东西给大家。

第三,研究完整的linux系统的的运行过程。

所谓完整的linux系统包括哪些部分呢?

三部分:bootloader、linux kernel(linux内核)、rootfile(根文件系统)。那么这3部分是怎么相互协作来构成这个系统的呢?各自有什么用呢?三者有什么联系?怎么联系?系统的执行流程又是怎么样的呢?搞清楚这个问题你对整个系统的运行就很清楚了,对于下一步制作这个linux系统就打下了另一个重要的根基。介绍这方面的资料网上可以挖掘到几吨,自己好好研究吧。第四,开始做系统移植。

上面说到完整的linux有3部分,而且你也知道了他们之间的关系和作用,那么现在你要做的便是自己动手学会制作这些东西。

当然我不可能叫你编写这些代码,这不实现。事实上这个3者都能在网下载到相应的源代码,但是这个源代码不可能下载编译后就能在你的系统上运行,需要很多的修改,直到他能运行在你的板子上,这个修改的过程就叫移植。在进行移植的过程中你要学的东西很多,要懂的相关知识也很多,等你完成了这个过程你会发现你已经算是一个初出茅庐的高手了。

在这个过程中如果你很有研究精神的话你必然会想到看源代码。很多书介绍你

怎么阅读linux源代码,我不提倡无目的地去看linux源代码,用许三多的话说,这没有意义。等你在做移植的时候你觉得你必须去看源代码时再去找基本好书看看,这里我推荐一本好书倪继利的《linux内核的分析与编程》,这是一本针对linux-2.6.11内核的书,说得很深,建议先提高自己的C语言编程水平再去看。

至于每个部分的移植网上也可以找到好多吨的资料,自己研究研究吧,不过要提醒的是,很多介绍自己经验的东西都或多或少有所保留,你按照他说的去做总有一些问题,但是他不会告诉你怎么解决,这时就要靠自己,如果自己都靠不住就找我一起研究研究吧,我也不能保证能解决你的问题,因为我未必遇到过你的问题,不过我相信能给你一点建议,也许有助你解决问题。

这一步的最终目的是,从源代码的官方主页上(都是外国的,悲哀)下载标准的源代码包,然后进行修改,最终运行在板子上。

盗用阿基米德的一句话:“给我一根网线,我能将linux搞定”。

第五,研究linux驱动程序的编写。

移植系统并不是最终的目的,最终的目的是开发产品,做项目,这些都要进行驱动程序的开发。

Linux的驱动程序可以说是五花八门,linux2.4和linux2.6的编写有相当大的区别,就是同为linux2.6但是不同版本间的驱动程序也有区别,因此编写linux的驱动程序变都不是那么容易的事情,对于最新版本的驱动程序的编写甚至还没有足够的参考资料。那么我的建议就是使用、移植一个不算很新的版本内核,这样到时学驱动的编程就有足够的资料了。

这部分的推荐书籍可以参考另一篇文章《推荐几本学习嵌入式linux的书籍》。第六,研究应用程序的编写。

做作品做项目除了编写驱动程序,最后还要编写应用程序。现在的趋势是图形应用程序的开发,而图形应用程序中用得最多的还是qt/e函数库。我一直就使用这个函数库来开发自己的应用程序,不过我希望你能使用国产的MiniGUI函数库。盗用周杰伦的广告词就是“支持国产,支持MiniGUI”。MiniGUI的编程比较相似Windows下的VC编程,比较容易上手,效果应该说是相当不错的,我曾使用过来开发ARM7的程序。不过MiniGUI最大的不好就是没有像qtopia这样的图形操作平台,这大大限制了他的推广,我曾经幻想过与北京飞漫公司(就是MiniGUI的版权拥有者)合作使用MiniGUI函数库开发像qtopia这样的图形操作平台,不过由于水平有限这只能是幻想了,呵呵。

完成这一步你基本就学完了嵌入式linux的全部内容了。

还有一个小小的经验想和大家分享。我在学习嵌入式linux的过程中很少问人,客观原因是身边的老师、同学师兄都没有这方面的高手,主观原因是我不喜欢问人,喜欢自己研究解决问题。这样做有个好处,就是可以提高自己解决问题的能力,因为做这些东西总有很多问题你难以理解,别人也没有这方面的经验,也不是所有问题都有人给你答案,这时必须要自己解决问题,这样,个人的解决问题能力就显得非常关键了。因此我的建议就是一般的问题到网上搜索一下,确实找不到答案了就问问高手,还是不行了就自己去研究,不要一味去等别人帮你解决问题。

3.linux的内存管理机制 篇三

前面我们介绍了386保护模式.从今天起我们将在此基础上,分析linux的虚拟存储管理,对每个程序员来说.他们都希望有无穷大的快速的内存,然而,现阶段是不可能的,况且,无穷大与快速本身就可能矛盾

为了解决无穷大.linux 引入了虚拟存储系统,为了解决快速,linux 引入了cache ,交换机制等等,以使的存储系统,在容量上接近硬盘,速度上接近cache.(当然,我认为这是存储系统的实际目的).

Linux 的内存管理采取的是分页机制.它的设计目的是分时多任务.linux 可同时处理256个任务(这应该与某个变量来定义,一时想不起来).同时它采用了两级饱和机制来分别内核进程与用户进程.

在386 保护模式的0-4G 的线性虚拟地址中,3-4G 是留给内核进程的.而0-3G分给用户进程.内核在内核空间的寻址不同于用户进程在用户空间的寻址.因为内核是在启动时装入内存的.说以它可以直接吧地址映射到3G 以上.用户若想访问内核就不许通过swapper_pg_div 中的指针来得到页表.

相反,用户进程,在用户空间的寻址是通过所用户页目录中的指针得到用户的页表.并通过页表的指针直接指向相应的物理内存.

Linux虚拟内存的实现,需要几种不同的机制来实现:

地址映射机制

内存的分配与回收

请页机制

交换机制

内存共享机制

在具体的读源码之前.我们先根据我们以前学过的操作系统知识.和C语言等知识.来考虑一下,这几个机制如何实现.现自己设计一下.在看别人是怎样实现的.找到自己想不到.或者对效率空间有损的地方.这样才有进步.我不止一次的说.操作系统的某一部分,就起实现来说,非常简单.它的难点是如何将大量的功能集成出一个kernerl.

地址映射机制,说白了,就是在虚拟内存与物理内存上的一个桥梁.它要做的事情可能就是通过几个不同的表.把虚拟地址转换成物理地址,把物理地址转化虚拟地址.

我们以前说过.因为有系统与用户之分,它必须也要有不同的数据结构.为了解决速度等问题.它会有一个硬件的缓冲区

对于它的数据结构.我们可以先想一下.如虚拟地址的信息,虚拟地址在那个区域等等

至于请页机制,更好理解.因为linux是页式存储的.因此必然会存在空白页和使用页.既然是页.就必然会存在页溢出.页无效(是不是在win98 下经常出现类似错误,当然linux的内存管理不可能和windows一样,可基本道理相同).因此.在每一个页出错.或者该页存不下多余的数据时.就要要求内核分配新的页面

同时.当时用fork 产生一个新的进程时.也需要分配新的叶面.这一部分大概讲的就是进程如何向内和描述自己需要怎么样的和多少页

在我们学习<<数据结构>>是我们学了,很多内存分配方式,如首次拟和.最佳拟和,最差拟和等等.但是我们可以想象.linux 大概不会用他们.那就一定是伙伴系统了.因此我们可以对于伙伴系统的分配,回收的基本算法.回想一下.这样在读者一部分源码时,回有意象不到的收获.

至于交换机制.我们也可以现想一想.内存中总与很多使用者的页.如果这些也已经把所有的页都用完了.再分配时必须把其中的某些页释放.释放那些页,需要考虑.如最近不用页.近期少用页,等等都可以在考虑之中.

这个算法,大概就是计算内存中使用的页,什么时候可以换处.说白了就是为所有的使用页计算一个”权”,而这个”权”就决定了他什么时候被释放以换如它的内容.需要想的是对于经常使用的页.可以把它放入cahe.(尽管这一部分对程序员是透明的,但我们应该理解他的原理).

最后的一部分共享内存,我想和我门初学linux编程时,进程通讯里面的共享内存没有区别.大概也就是在它的数据结构中加入可以允许不同进程访问的tag 就行了.

以上,只是我们对linux的内存管理机制的猜测,需要我们做的工作就是具体的读源码.更正不正确的猜想.同时学习别人的实际思路.

从下篇日记开始.我们将分别讲解这几部分的实现

4.iOS内存管理就这么简单2 篇四

MemoryManager[633:14446] obj1 retainCount=1 obj2 retainCount=1

strong和retain修饰的属性效果一样都使引用计数加一:

copy修饰的属性对象的类型必须实现NSCopying协议,否则会出错,

5.惯有嵌入式系统内存管理方案研究 篇五

摘要:嵌入式系统的内存管理机制必须满足实时性和可靠性的要求,嵌入式系统内存管理方案研究。本文以开源的的操作系统RTEMS为例,介绍嵌入式系统中内存管理的要求、存在的问题以及解决的策略。

引言

内存管理机制是嵌入式系统研究中的一个重点和难点的问题,它必须满足以下几个特性:

①实时性。从实时性的角度出发,要求内存分配过程要尽可能地快。因此,在嵌入式系统中,不可能采用通用操作系统的一些复杂而完善的内存分配策略,一般没有段页式的虚存管理机制;而是采用简单、快速的内存分配方案,其分配方案也因程序对实时性的要求而异。例如,VxWorks系统采用简单的“首次适应,立即聚合”方法;VRTX中采用多个固定尺寸存储块的binning方案。

②可靠性。嵌入式系统应用的环境千变万化,在有些特定情况下,对系统的可靠性要求极高,内存分配的.请求必须得到满足,如果分配失败则可能会带来灾难性的后果。比如,飞机的燃油检测系统。在飞机飞行过程中,如果燃料发生泄漏,系统应该立即检测到,并发出相应的警报等待飞行员及时处理。如果因为内存分配失败而不能相应地操作,就可能发生机毁人亡的事故。

③高效性。内存分配要尽可能地减少浪费。不可能为了保证满足所有的内存分配请求而将内存配置得很大。一方面,嵌入式系统对成本的要求使得内存在其中只是一种很有限的资源;另一方面,即使不考虑成本的因素,系统硬件环境有限的空间和有限的板面积决定了可配置的内存容量是很有限的。

针对以上三个约束条件,市场上主流的嵌入式操作系统,如VxWorks、嵌入式Linux等均提出了一套有效的解决方案;但是,这些系统只提供了应用开发的接口,其底层的实现方案不可见。本文以开源的嵌入式操作系统RTEMS为例,分析了嵌入式系统内存管理所面临的问题,研究了其底层实现的解决方案。

6.arm内存管理单元学习 篇六

#include//数据流输入/输出

#include//字符串处理

#include//参数化输入/输出

const int MJ=10;//假定系统允许的最大作业数量为10

typedef struct node{

int address;

int length;

char tag[10];

}job;

job frees[MJ];

int free_quantity;

job occupys[MJ];

int occupy_quantity;

int read()

{

FILE *fp;

char fn[10];

cout<<“请输入初始空闲表文件名:”;

cin>>fn;

if((fp=fopen(fn,“r”))==NULL){ 其意义是在当前目录下打开文件file a,只允许进行“读”操作,并使fp指向该文件

cout<<“错误,文件打不开,请检查文件名”<

}

else{

while(!feof(fp)){

fscanf(fp,“%d,%d”,&frees[free_quantity].address,&frees[free_quantity].length);free_quantity++;fscanf(文件指针,格式字符串,输入表列);

}

return 1;

}

return 0;

}

void sort()

{

int i,j,p;

for(i=0;i

p=i;

for(j=i+1;j

if(frees[j].address

p=j;

}

}

if(p!=i){

frees[free_quantity]=frees[i];

frees[i]=frees[p];

frees[p]=frees[free_quantity];

}

}

}

void view()

{

int i;

cout<

cout<<“输出空闲区表:n起始地址 分区长度状态n”<

for(i=0;i

cout.setf(2);

cout.width(12);

cout<

cout.width(10);

cout<

cout.width(8);

cout<

}

cout<

cout<<“输出已分分区表:n起始地址 分区长度 占用作业名n”<

for(i=0;i

cout.setf(2);

cout.width(12);

cout<

cout.width(10);

cout<

cout.width(8);

cout<

}

}

void ear()

{

char job_name[10];

int job_length;

int i,j,flag,t;

cout<<“请输入分配内存的作业名和空间大小:”;

cin>>job_name;

cin>>job_length;

flag=0;

for(i=0;i

if(frees[i].length>=job_length){

flag=1;

}

}

if(flag==0){//未找到空闲区,返回

cout<

}

else{

t=0;

i=0;

while(t==0){

if(frees[i].length>=job_length){//找到可用空闲区,开始分配

t=1;

}

i++;

}

i--;

occupys[occupy_quantity].address=frees[i].address;//修改已分配区表

strcpy(occupys[occupy_quantity].tag,job_name);

occupys[occupy_quantity].length=job_length;

occupy_quantity++;

if(frees[i].length>job_length){

frees[i].address+=job_length;

frees[i].length-=job_length;

}

else{

for(j=i;j

frees[j]=frees[j+1];

}

free_quantity--;

cout<<“内存空间成功:)”<

}

}

}

void reclaim()//回收作业所占的内存空间

{

char job_name[20];

int i,j,flag,p=0;

int address;

int length;//寻找已分分区表中对应的登记项

cout<<“输入要回收分区的作业名:”;

cin>>job_name;

flag=-1;

for(i=0;i

if(!strcmp(occupys[i].tag,job_name)){

flag=i;

address=occupys[i].address;

length=occupys[i].length;

}

}

if(flag==-1){ //在已分分区表中找不到作业

cout<<“没有这个作业名”<

}

else{//修改空闲区表,加入空闲表

for(i=0;i

if((frees[i].address+frees[i].length)==address){

if(((i+1)

for(j=i+1;j

frees[j]=frees[j+1];

}

free_quantity--;

p=1;

}

else{

frees[i].length+=length;

p=1;

}

}

if(frees[i].address==(address+length)){

frees[i].address=address;

frees[i].length+=length;

p=1;

}

}

if(p==0){

frees[free_quantity].address=address;

frees[free_quantity].length=length;

free_quantity++;

}//删除分配表中的该作业

for(i=flag;i

occupys[i]=occupys[i+1];

}

occupy_quantity--;

}

}

void main()

{

int flag=0;

int t=1;

int chioce=0;

int i;

for(i=0;i

frees[i].address=-1;//空闲区表初始化

frees[i].length=0;

strcpy(frees[i].tag,“free”);

occupys[i].address=-1;//已分分区表初始化

occupys[i].length=0;

strcpy(occupys[i].tag,“");

}

free_quantity=0;

occupy_quantity=0;

flag=read();

while(flag==1){

sort();

cout<<”选择功能项:(0-退出,1-分配内存,2-回收内存,3-显示内存)n“<

cin>>chioce;

switch(chioce){

case 0:

flag=0;

break;

case 1:

ear();

break;

case 2:

reclaim();

break;

case 3:

view();

break;

default:

cout<<”没有该选项n"<

}

}

上一篇:合伙创业要注意哪些问题下一篇:关于世界地球日祝福句子