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