03IO端口寻址和访问控制方式
1. I/O端口和寻址
CPU 为了访问 I/O 接口控制器或者控制卡上的数据和状态信息,需要首先指定他们的地址。这种地址就称为I/O端口地址或简称端口。通常一个 I/O 控制器包含访问数据的数据端口、输出命令的命令端口和访问控制器执行状态的状态端口。端口地址的设置方法一般有两种:统一编址和独立编址。
端口统一编址的原理是把 I/O 控制器中的端口地址归入存储器寻址地址空间范围内。因此这种编址方式也称为存储器映射编址。CPU 访问一个端口的操作与访问内存的操作一样,也使用访问内存的指令。
端口独立编址的方法是把 I/O 控制器和控制卡的寻址空间单独作为一个独立的地址空间对待,称为 I/O 地址空间。每个端口有一个 I/O 地址与之对应,并且使用专门的 I/O 指令来访问端口。
IBM PC 及其兼容微机主要使用独立编址方式,采用了一个独立的 I/O 地址空间对控制设备中的寄存器进行寻址和访问。使用 ISA 总线结构的传统 PC 机及其 I/O 地址空间范围是 0x000 -- 0x3FF,有1024 个 I/O 端口地址可供使用。各个控制器和控制卡所默认分配使用的端口地址范围见下表。
另外,IBM PC 机也部分地使用了统一编址方式。例如, CGA 显示卡上显示内存的地址就直接占用了存储器地址空间 0xB800 -- 0xBC00 范围。因此若要让一个字符显示在屏幕上,可以直接使用内存操作指令往这个内存区域执行写操作。
对于使用 EISA 或 PCI 等总线结构的现代 PC 机,有 64KB 的 I/O 地址空间可供使用。在普通 Linux 系统下通过查看 /proc/ioports 文件可以得到相关控制器或设置使用的 I/O 地址范围,如下所示。
[root@rockman ~]# cat /proc/ioports
0000-0cf7 : PCI Bus 0000:00
0000-001f : dma1
0020-0021 : pic1
0040-0043 : timer0
0050-0053 : timer1
0060-0060 : keyboard
0064-0064 : keyboard
0070-0071 : rtc0
0080-008f : dma page reg
00a0-00a1 : pic2
00c0-00df : dma2
00f0-00ff : fpu
0170-0177 : 0000:00:07.1
0170-0177 : ata_piix
01f0-01f7 : 0000:00:07.1
01f0-01f7 : ata_piix
0376-0376 : 0000:00:07.1
0376-0376 : ata_piix
03c0-03df : vga+
03f6-03f6 : 0000:00:07.1
03f6-03f6 : ata_piix
0cf0-0cf1 : pnp 00:00
0cf8-0cff : PCI conf1
0d00-feff : PCI Bus 0000:00
1000-103f : 0000:00:07.3
1000-1003 : ACPI PM1a_EVT_BLK
1004-1005 : ACPI PM1a_CNT_BLK
1008-100b : ACPI PM_TMR
100c-100f : ACPI GPE0_BLK
1010-1015 : ACPI CPU throttle
1040-104f : 0000:00:07.3
1040-104f : pnp 00:00
1060-106f : 0000:00:07.1
1060-106f : ata_piix
1070-107f : 0000:00:0f.0
1070-107f : vmwgfx probe
1080-10bf : 0000:00:07.7
1080-10bf : vmw_vmci
1400-14ff : 0000:00:10.0
2000-3fff : PCI Bus 0000:02
2000-203f : 0000:02:01.0
2000-203f : e1000
2040-205f : 0000:02:00.0
2040-205f : uhci_hcd
4000-4fff : PCI Bus 0000:03
5000-5fff : PCI Bus 0000:0b
6000-6fff : PCI Bus 0000:13
7000-7fff : PCI Bus 0000:1b
8000-8fff : PCI Bus 0000:04
9000-9fff : PCI Bus 0000:0c
a000-afff : PCI Bus 0000:14
b000-bfff : PCI Bus 0000:1c
c000-cfff : PCI Bus 0000:05
d000-dfff : PCI Bus 0000:0d
e000-efff : PCI Bus 0000:15
fce0-fcff : pnp 00:05
2. 接口访问控制
PC 机 I/O 接口数据传输控制方式一般可采用程序循环查询方式、中断方式和 DMA 传输方式。顾名思义,循环查询方式是指 CPU 通过在程序中循环查询指定设备控制器中的状态来判断是否可以与设备进行数据交换。这种方式不需要过多硬件支持。使用和编程都比较简单,但是特别耗费 CPU 宝贵时间。因此在多任务操作系统中除非等待时间极短或必须,否则就不应该使用这种方式。在 Linux 操作系统中,只有在设备或控制器能够立刻返回信息时才会在很少的几个地方采用这种方式。
中断处理控制方式 需要有中断控制器的支持。在这种控制方式下,只有当 I/O 设备通过通过中断向 CPU 提出处理请求时,CPU 才会暂时中断当前执行的程序转而去执行相应的 I/O 中断处理服务过程。当执行完该中断处理服务过程后,CPU 又会执行刚才被中断的程序。在 I/O 控制器或设备发出中断请求时,CPU 通过使用中断向量表(或中断描述符表)来寻址相应的中断处理服务过程的入口地址。因此采用中断控制方式时需要首先设置好中断向量表,并编制好相应的中断处理服务过程。Linux 操作系统中大多数设备 I/O 控制都采用中断处理方式。
直接存储器访问 DMA (Direct Memory Access)方式 用于 I/O 设备与系统内存之间进行批量数据传送,整个操作过程需要使用专门的 DMA 控制器来进行而无需 CPU 插手。由于在传输过程中无须软件介入,因此操作效率很高。在 Linux 操作系统中,软盘驱动程序使用中断和 DMA 方式配合来实现数据的传输工作。
3. 寻址空间(补充)
寻址空间一般指的是 CPU 对于内存寻址的能力。通俗的说,就是能最多用到多少内存的一个问题。数据在存储器(RAM)中存放是有规律的,CPU 在运算的时候需要把数据提取出来就需要知道数据在哪里,这时候就需要挨家挨户的找,这就叫做寻址。但如果地址太多超出了 CPU的能力范围,CPU 就无法找到数据了。 CPU 最大能查找多大范围的地址叫做寻址能力,CPU的寻址能力以字节为单位。
通常人们认为,内存容量越大,处理数据的能力也就越强,但内存容量不能无限的大,它要受到系统结构、硬件设计、制造成本等多方面因素的制约,一个最直接的因素取决于系统的地址总线的地址寄存器的宽度(位数)。
计算机的寻址范围是由总线宽度(处理器的地址总线的位数)决定的,也可以理解为 CPU 寄存器位数,这二者一般是匹配的。
Intel 公司早期的 CPU 产品的地址总线和地址寄存器的宽度为 20 位,即 CPU 的寻址能力为 2^20 = 1024*1024 = 1M 字节。386及386以上的地址总线和地址寄存器的宽度为 32 位,CPU 的寻址能力为 2^32 = 4096M字节 = 4G字节。
由此推出:地址总线为 N 位 (N通常都是 8 的整数倍,也说 N根数据总线)的 CPU 寻址范围是 2 的N次方字节,即2^N(Byte)。