Linux内存空间

        对于一个系统来讲,会有很多的外设,那么这些外设的管理都是通过CPU完成。那么CPU在这个过程中是如何找到外设的呢?尽管在一个系统中会有诸多的外设,在每个外设的接口电路中会有多个端口。但是如果系统能够每个端口都被赋予一个具体的地址值,那么在系统中就能轻易的找到任何一个外设。系统在管理的时候,不管是内存还是外设都需要分配一个内存地址。对于一个32bit的系统来讲,可寻址的范围为2^32=4G的地址空间。

       既然说到地址空间,就要明确地址空间的种类:物理地址、总线地址、虚拟地址。

(1)物理地址

CPU地址总线传来的地址,由硬件电路控制其具体含义。物理地址中很大一部分是留给内存条中内存的,但也常被映射到其他存储器上(如显存、bios等)。在程序指令中的虚拟地址经过段映射和页面映射后,就生成了物理地址,这个物理地址被放到CPU的地址线上。

(2)总线地址

总线的地址线或在地址周期上产生的信号。外设使用的是地址总线,cpu使用的是物理地址。

物理地址和总线地址之间的关系有系统设计决定的。在X86平台上,物理地址就是总线地址,这是因为它们共享相同的地址空间。在其他平台上,可能需要转换/映射。

(3)虚拟地址

现代操作系统普遍采用虚拟内存管理(virtual memory management)机制,这需要MMU的支持。MMU通常是CPU的一部分,如果处理器没有MMU,或者有MMU但没有启用,CPU执行单元发出的内存地址将直接传到芯片引脚上,被内存芯片(物理内存)接收,这成为物理地址,如果处理器启用了MMU,CPU执行单元发出的内存地址将被MMU截获,从CPU到MMU的地址称为虚拟地址,而MMU将这个地址翻译成另一个地址发到CPU芯片的外部地址引脚上,也就是讲虚拟地址映射成物理地址。

      linux中,进程的4GB内存分为用户空间和内核空间。用户空间分布为1~3GB。剩下的1GB为内核空间。程序员只能使用虚拟地址。系统中每个进程有各自的私有用户空间(0~3GB),这个空间对系统中的其他进程是不可见的。

编址方式

  外设都是通过读写设备上的寄存器来进行工作的,外设寄存器也称为“IO端口”,而IO端口的编址方式有两种,独立编址和统一编址。

统一编址:外设接口中的IO寄存器(即IO端口)与主存单元一样看待,每个端口占用一个存储单元的地址,将主存的一部分划出来用作IO地址空间。 统一编址的原理是将IO的端口地址存储器寻址的地址空间范围之内,此方法也成为存储器映像编址。CPU访问一个端口的操作与访问内存的操作相同,也使用访问内存的指令。独立编址是为端口地址单独开辟一部分地址空间,其访问指令也需要使用单独的指令(不同于内存访问指令)。

   根据CPU体系结构的不同,CPU对IO端口的编址方式有两种:

  (1)I/O映射方式(I/O-mapped)
  典型地,如X86处理器为外设专门实现了一个单独的地址空间,称为"I/O地址空间"或者"I/O端口空间",CPU通过专门的I/O指令(如X86的IN和OUT指令)来访问这一空间中的地址单元。
  (2)内存映射方式(Memory-mapped)
  RISC指令系统的CPU(如ARM、PowerPC等)通常只实现一个物理地址空间,外设I/O端口成为内存的一部分。此时,CPU可以象访问一个内存单元那样访问外设I/O端口,而不需要设立专门的外设I/O指令。
  但是,这两者在硬件实现上的差异对于软件来说是完全透明的,驱动程序开发人员可以将内存映射方式的I/O端口和外设内存统一看作是"I/O内存"资源。
 一般来说,在系统运行时,外设的I/O内存资源的物理地址是已知的,由硬件的设计决定。但是CPU通常并没有为这些已知的外设I/O内存资源的物理地址预定义虚拟地址范围,驱动程序并不能直接通过物理地址访问I/O内存资源,而必须将它们映射到核心虚地址空间内(通过页表),然后才能根据映射所得到的核心虚地址范围,通过访内指令访问这些I/O内存资源。

ioremap() 函数

   Linux在io.h头文件中声明了函数ioremap(),用来将I/O内存资源的物理地址映射到核心虚地址空间(3GB-4GB)中(这里是内核空间),原型如下:

1、ioremap函数

     ioremap宏定义在asm/io.h内:

  #define ioremap(cookie,size)           __ioremap(cookie,size,0)

  __ioremap函数原型为(arm/mm/ioremap.c):

  void __iomem * __ioremap(unsigned long phys_addr, size_t size, unsigned long flags);

  • 参数:
  • phys_addr:要映射的起始的IO地址
  • size:要映射的空间的大小
  • flags:要映射的IO空间和权限有关的标志

  该函数返回映射后的内核虚拟地址(3G-4G). 接着便可以通过读写该返回的内核虚拟地址去访问之这段I/O内存资源。

2、iounmap函数

    iounmap函数用于取消ioremap()所做的映射,原型如下:

    void iounmap(void * addr);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值