Linux系统开发专栏

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

“小王,今天咱们开始讲有关内存和I/O访问的内容,心里先要有点低,这部分内容还是有点烦,有点难的哦”说着话,我心里都没底,怕吓着小王,不瞒你说,当时看这部分,我可是没少费劲。

“哦,那咋办,不能不学是不?没事,有小涛哥在,俺就不怕”小王信心十足的说。

“哦!看不出来,还让你来安慰我了”看着小王这充满信心的样子,我也没啥顾虑了。好了,深吸一口气,开始今天的课程。

   我们知道,在X86中,有I/O空间的概念,I/O空间是相对于内存空间的概念,它通过特定的指令in,out来访问。端口号标识了外设的寄存器地址。而巧的是Arm等嵌入式控制器中并不提供I/O空间,所以我们就不考虑了,我们重点放在内存空间。

   内存空间可以通过地址,指针来访问,在C语言中的表现就是通过指针来操作,如在186处理器中:

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

   *P=11;

   这段代码的意思就是:在绝对地址0xF000+0xFF00(186处理器使用16位段地址和16位偏移地址)写入11。在ARM, PPC等未采用段地址的处理器中,P指向的内存

空间就是0xF000FF00,而*p=11就是在该地址写入11。

   说完内存空间,就不得不说说MMU(内存管理单元),它辅助操作系统进行内存管理,提供虚拟地址和物理地址的映射,内存访问权限保护和Cache缓存控制等硬件支持,操作系统内核借助MMU,可以让用户感觉好像程序可以使用非常大的内存空间,从而使得编程人员在写程序时不用考虑计算机中物理内存的实际容量。

   为了理解基本的MMU操作原理,先介绍几个概念:

   1)TLB:Translation Lookaside Buffer,即转换旁路缓存。也称快表,是转换表的cache,缓存少量的虚拟地址与物理地址的对应关系。

   2)TTW:Translation Table walk,即转换表漫游。当TLB中没有缓冲对应的地址转换关系时,需要通过对内存中转换表的访问来获得虚拟地址和物理地址的对应关系。TTW成功后,结果应写入TLB.

   为了说明MMU在访问内存中的使用,我特意画了一个流程图。如下:

   123

   说了MMU,现在就来和linux联系一下,对于包含MMU的处理而言,Linux系统提供了复杂的存储管理系统,使得进程所能访问的内存达到4GB,这4GB是分为2个部

分---用户空间和内核空间,前者一般分布为0~3GB(即PAGE_OFFSET,在0x86中等于0xC0000000),剩下的3~4GB是内核空间。通常情况下,用户进程只有通过系统调用等方式才可以访问到内核空间。

   小王你学过C语言,知道在用户空间动态申请内存用malloc()函数,释放用free,这在各种操作系统上的使用是一致的。这方面的内容,比如内存泄漏啦,具体使用等就不细讲了,我们的重点放在内核空间,内核空间怎么做呢?

   前边有个知识点没说,后面要用到,就提一下:linux内核空间3~4GB是还可以在分的,从低到高依次是:物理内存映射区->隔离带->vmalloc虚拟内存分配器->隔

离带->高端内存映射区->专用页面影视区->保留区

   在Linux内核空间中申请内存涉及的函数主要包括kmalloc(),__get_free_pages()【这两个申请的内存位于物理内存映射区在物理内存上也是连续的,和物理内存有简单的转换关系】和vmalloc【它是在虚拟内存空间给出一块连续的内存区,在物理内存中不一定是联系的,和物理内存也没有简单的换算关系】等。有关这三个函数的使用网上一大堆,我就我细说了,小王,你的我都给你打印好了,你直接看就行了。

  我们说虚拟地址和物理地址是有一定的转换关系,具体是使用virt_to_phys()可以实现虚拟地址转换为物理地址,代码清单如下:

  #define _ _pa(x)  ((unsigned long)(x)-PAGE_OFFSET)
  extern inline unsigned long virt_to_phys(volatile void * address)
  {
    return _ _pa(address);
  }

   与之对应的函数是phys_to_virt(),用于将物理地址转化为虚拟地址。具体代码如下:

   #define  _ _pa(x)      ((unsigned long)(x)+PAGE_OFFSET)

   extern inline unsigned long virt_to_phys(volatile void * address)

   {

        return _ _pa (address);

   } 

   值得说明的是上述方法仅适用与常规内存,高端内存的虚拟地址与物理地址之间不存在这样简单的换算关系。

“小王不知道,你听的怎么样,我说的时候心里都没底啊,这一章确实很难,挺那个的..”

“小涛哥,没事,你放心讲吧,经过那么多,我觉得自己应该有一定能力了,理解起来应该能跟上,如果跟不上再找你哈”小王又给了我继续讲下去的信心。

posted on 2010-10-25 20:16  ☆&寒 烟☆  阅读(6802)  评论(0编辑  收藏  举报