IO端口和寻址(未完)

参考:

http://blog.****.net/vito_bin/article/details/60779404

基本概念

MMIO(Memory mapping I/O),即内存映射I/O,它是PCI规范的一部分,I/O设备被放置在内存空间而不是I/O空间。从处理器的角度看,内存映射I/O后系统设备访问起来和内存一样。这样访问AGP/PCI-E显卡上的帧缓存,BIOS,PCI设备就可以使用读写内存一样的汇编指令完成,简化了程序设计的难度和接口的复杂性。

I/O作为CPU和外设交流的一个渠道,主要分为两种,一种是Port I/O(也叫I/O映射方式,I/O mapped),一种是MMIO(Memory mapping I/O,即内存映射方式,memory mapped)。

Port I/O就是我们常说的I/O端口,它实际上的应该被称为I/O地址空间

x86为外设专门实现有单独的地址空间,可以称为“I/O地址空间”或“I/O端口空间”,这个是独立与CPU和RAM物理地址空间,它将所有外设的IO端口均在这一空间进行编址。I/O地址空间通过IN/OUT指令访问,这就是“I/O映射方式”(不是MMIO访问方式)。

与物理地址空间相比,I/O地址空间大小通常较小,X86架构一共有65536(2^16)个8bit的I/O端口,组成64K I/O地址空间,编号从0~0xFFFF。连续两个8bit的端口可以组成一个16bit的端口,连续4个组成一个32bit的端口。空间小是“I/O映射方式”的一个主要缺点,可以通过cat /proc/ioports查看,IO port空间的地址分配情况是以树状结构显示。这源于X86平台的设计思想,目前基本不用了,获取这些资源接口如request_region和ioremap。

I/O地址空间和CPU的物理地址空间是两个不同的概念,例如I/O地址空间为64K,一个32bit的CPU物理地址空间是4G。

MMIO占用CPU的物理地址空间,对它的访问可以使用CPU访问内存的指令进行。一个形象的比喻是把文件用mmap()后,可以像访问内存一样访问文件、同样,MMIO是用访问内存一样的方式访问I/O资源,如设备上的内存。MMIO不能被cache(有特殊情况,如VGA)。

32位操作系统,32bit的处理器,拥有32bit寻址能力,即可访问2^32=4G的物理地址,那么就具有4G内存的识别能力。

物理地址:并不是指物理内存的地址,而是指处理器和系统内存之间所用到的地址,可以理解为CPU最为方便访问的地址(有别于我们之前所知道的物理地址的定义:段地址*16+偏移地址<8086>),而这一个内存并不独属于物理内存,而被分成了很多部分,物理内存当然也能够占用其中的一部分。物理地址并不一定指向内存,它有可能指向一个芯片组的功能块,也可能指向外设,甚至什么也没有指到。

地址范围:0x0000 0000 -------->0xFFFF FFFF

我们所提到的4G物理地址和所安装的内存条没有任何关系,是相互独立的

即使安装的是2G内存,但计算机依然会分配4G的内存空间(线性地址空间??)

Linux设计了一个通用的数据结构resource来描述各种I/O资源(如:I/O端口、外设内存、DMA和IRQ等)。该结构定义在include/linux/ioport.h头文件中。Linux是以一种倒置的树形结构来管理每一类I/O资源。每一类I/O资源都对应有一颗倒置的资源树,树中的每一个节点都是个resource结构。基于上述这个思想,Linux将基于I/O映射方式的I/O端口和基于内存映射方式的I/O端口资源统称为“I/O区域”(I/O Region)。

/proc/iomem这个文件记录的是物理地址的分配情况,也是以树状结构显示,对其使用也是request_mem_region和ioremap,空间大小为16EB,远大于io port的64K。

ioport和iomem地址空间分别编制,均是从地址0开始,如果硬件支持MMIO,port地址也可以映射到memory空间去。

这里以pci设备为例,硬件的拓扑结构就决定了硬件在内存映射到CPU的物理地址,由于内存访问都是虚拟地址,所有就需要ioremap,此时物理内存是存在的,所以不用再分配内存,只需要做映射即可

应用总结:使用I/O内存首先要申请,然后才能映射,使用I/O端口首先要申请,对I/O端口的请求是让内核知道你要访问该端口,内核并让你独占该端口.

申请I/O端口的函数是request_region,申请I/O内存的函数是request_mem_region。request_mem_region函数并没有做实际性的映射工作,只是告诉内核要使用一块内存地址,声明占有,也方便内核管理这些资源。重要的还是ioremap函数,ioremap主要是检查传入地址的合法性,建立页表(包括访问权限),完成物理地址到虚拟地址的转换。

在intel的X86平台,GPIO资源也是类似应用,如果IO配置为SCI或者SMI中断,SCI可以产生GPE,然后经历acpi子系统,不过GPE中断号默认是0x10+GPIO端口号。

Port I/O和MMIO主要区别

  • 前者不占用CPU的物理地址空间,后者占有(这是对x86架构说的,一些架构,如IA64,port I/O占用物理地址空间)。

  • 前者是顺序访问。也就是说在一条I/O指令完成前,下一条指令不会执行。例如通过Port I/O对设备发起了操作,造成了设备寄存器状态变化,这个变化在下一条指令执行前生效。uncache的MMIO通过uncahce memory的特性保证顺序性。

  • 使用方式不同

由于port I/O有独立的64K I/O地址空间,但CPU的地址线只有一套,所以必须区分地址属于物理地址空间还是I/O地址空间。

映射地址空间

目前,大多数的CPU都支持36bit寻址,也就是说寻址范围达到了64G,但这只是从“系统”的视角来说,从“内存控制器”的视角来说,由于32bit的寻址能力的限制,只能访问4G空间。如果需要计算机正常工作,则所有必须的设备地址都需要存在这4G的空间当中,使计算机正常工作除了内存之外,也包括许多IO设备。图中展示了4Gb地址的大致分布,除去main memory之外,大多数都只占据极少的内存,一般为几M或者几十M,除了PCI ECAM。(PCI Memory range)

IO端口和寻址(未完)