本文主要从内核实现的角度分析Linux 2.4.0内核IO子系统中对IO端口资源的管理的实现原理。本文是为那些想要深入分析Linux的IO子系统的读者和设备驱动程式研发人员而写的。

几乎每一种外设都是通过读写设备上的寄存器来进行的。外设寄存器也称为“I/O端口”,通常包括:控制寄存器、状态寄存器和数据寄存器三大类,而且一个外设的寄存器通常被连续地编址。CPU对外设IO端口物理地址的编址方式有两种:一种是I/O映射方式(I/O-mapped),另一种是内存映射方式(Memory-mapped)。而具体采用哪一种则取决于CPU的体系结构。

有些体系结构的CPU(如,PowerPC、m68k等)通常只实现一个物理地址空间(RAM)。在这种情况下,外设I/O端口的物理地址就被映射到CPU的单一物理地址空间中,而成为内存的一部分。此时,CPU可象访问一个内存单元那样访问外设I/O端口,而无需设立专门的外设I/O指令。这就是所谓的“内存映射方式”(Memory-mapped)。

而另外一些体系结构的CPU(典型地如X86)则为外设专门实现了一个单独地地址空间,称为“I/O地址空间”或“I/O端口空间”。这是个和CPU地RAM物理地址空间不同的地址空间,任何外设的I/O端口均在这一空间中进行编址。CPU通过设立专门的I/O指令(如X86的IN和OUT指令)来访问这一空间中的地址单元(也即I/O端口)。这就是所谓的“I/O映射方式”(I/O-mapped)。和RAM物理地址空间相比,I/O地址空间通常都比较小,如x86 CPU的I/O空间就只有64KB(0-0xffff)。这是“I/O映射方式”的一个主要缺点。

Linux将基于I/O映射方式的或内存映射方式的I/O端口通称为“I/O区域”(I/O region)。在讨论对I/O区域的管理之前,我们首先来分析一下Linux是如何实现“I/O资源”这一抽象概念的。

Linux对I/O资源的描述

Linux设计了一个通用的数据结构resource来描述各种I/O资源(如:I/O端口、外设内存、DMA和IRQ等)。该结构定义在include/linux/ioport.h头文档中:

  struct resource {

            const char *name;

            unsigned long start, end;

            unsigned long flags;

            struct resource *parent, *sibling, *child;

              };

各成员的含义如下:

1. name指针:指向此资源的名称。

2. start和end:表示资源的起始物理地址和终止物理地址。他们确定了资源的范围,也即是个闭区间[start,end]。

3. flags:描述此资源属性的标志(见下面)。

4. 指针parent、sibling和child:分别为指向父亲、兄弟和子资源的指针。

属性flags是个unsigned long类型的32位标志值,用以描述资源的属性。比如:资源的类型、是否只读、是否可缓存,连同是否已被占用等。下面是一部分常用属性标志位的定义(ioport.h):

/*

            * IO resources have these defined flags.

            */

            #define IORESOURCE_BITS		0x000000ff	/* Bus-specific bits */

            #define IORESOURCE_IO		0x00000100	/* Resource type */

            #define IORESOURCE_MEM		0x00000200

            #define IORESOURCE_IRQ		0x00000400

            #define IORESOURCE_DMA		0x00000800

            #define IORESOURCE_PREFETCH	0x00001000	/* No side effects */

            #define IORESOURCE_READONLY	0x00002000

            #define IORESOURCE_CACHEABLE	0x00004000

            #define IORESOURCE_RANGELENGTH	0x00008000

            #define IORESOURCE_SHADOWABLE	0x00010000

            #define IORESOURCE_BUS_HAS_VGA	0x00080000

            #define IORESOURCE_UNSET	0x20000000

            #define IORESOURCE_AUTO		0x40000000

            #define IORESOURCE_BUSY		0x80000000

            /* Driver has marked this resource busy */

指针parent、sibling和child的配置是为了以一种树的形式来管理各种I/O资源。

Linux对I/O资源的管理

Linux是以一种倒置的树形结构来管理每一类I/O资源(如:I/O端口、外设内存、DMA和IRQ)的。每一类I/O资源都对应有一颗倒置的资源树,树中的每一个节点都是个resource结构,而树的根结点root则描述了该类资源的整个资源空间。

基于上述这个思想,Linux在kernel/Resource.c文档中实现了对资源的申请、释放及查找等操作。

1 I/O资源的申请

文章整理:西部数码--专业提供域名注册虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!