PCI扩展ROM
1. ROM映像
在PCI规范中提供了一种机制,使PCI设备可以带一个扩展ROM。通过执行ROM中存放的代码来完成与设备有关的初始化,同时也有可能完成系统的引导功能。该机制允许扩展ROM包含有几种为不同系统和处理器结构而设计的映像(如图16)。
图16 ROM中可包含不通类型的映像
每个映像必须开始于一个512字节边界并含有PCI扩展ROM头标,每个映像的开始位置取决于前一个映像的长度。ROM的最后一个映像的头标中要有一个特殊的编码以表示它是最后一个。
每个ROM映像中所要求的信息分为两个不同的区域:一个区域是ROM头标,应该放在ROM映像的开始处;另一个区域是PCI数据结构,必须放置在映像的第一个64KB处。图17表示了扩展ROM中一个映像的典型布局。
图17 ROM映像的典型布局
下面来详细说说它的各个结构。
2. ROM头标
ROM头标格式如下:
偏移 | 值 | 字节大小 | 说明 |
+0 | 55 AA | 2 | ROM标识 |
+2 | 66 | 1 | 初始化长度: 512字节为单位 |
+3 | EB xxxx | 3 | Jmp near xxxx, POST 代码会直接远程调用此位置。所以返回需要RETF |
+6 | 0 | 18 | 保留 |
+18H |
| 2 | 指向PCI数据结构的指针。以本rom image开始为起始值。一般为1AH。 |
ROM标识为55H 0AAH,POST程序在检测ROM开头两个字节,只要检测到55 AA就知道知道有扩展ROM了。加电自检程序(POST)当检测到合适的ROM后,会直接调用偏移+3处的指令,故在此位置上(偏移+3处)总是放置一个跳转指令。
3. PCI数据结构
PCI数据结构格式如下:
偏移 | 值 | 字节大小 | 说明 |
+1A | ‘PCIR’ | 4 | 标识:50H 43H 49H 52H |
+1E |
| 2 | 供应商识别码 |
+20 |
| 2 | 设备识别码 |
+22 |
| 2 | VPD |
+24 |
| 2 | 本PCI数据结构长度,一般为:18h |
+26 |
| 1 | 本PCI数据结构的版本号,一般为0 |
+27 |
| 3 | 设备分类代码 |
+2A |
| 2 | IMAGE LENGTH,也是以512字节为单位。一般和上面的初始化长度一样。 |
+2C |
| 2 | 代码版本 |
+2E |
| 1 | 代码类型。在PC机上该值为0。当有多个ROM映像时,POST会检测本字段,直到找到合适的映像。 |
+2F |
| 1 | 标识。最后一个IMAGE,该值为80H,否则为0。 |
+30 |
| 2 | 保留。 |
供应商识别码和设备识别码必须和PCI配置空间中的相应字段一样,否则也不会执行映像中指令的。设备分类代码虽然也要和PCI配置空间中数据一致,但是POST不会进行强行检测,也就是说:这不是ROM映像是否执行的必须条件。POST主要根据该字段来判断设备类型,以进行一些特别处理,比如,当为VGA设备时,POST就会将ROM 中的BIOS拷贝至RAM的0C0000H处。
4. POST代码处理ROM流程
在大多数情况下,系统的上电自测试(POST)代码对插接的PCI设备的处理与对那些焊接在母板上的设备的处理相同。但对扩展ROM的处理是不同的。POST代码分两步检测一个选项ROM是否存在:其中第一步确定设备是否在配置空间中实现了一个扩展ROM基址寄存器,如果该寄存器存在,POST就必须将ROM映射到地址空间中未用的部分并将使能位置1;第二步是检查前两个字节是否为标签值AA55H,如果是,就表示存在一个ROM,否则就说明该设备上没有ROM。
如果检测到设备上有一个ROM,POST就必须在该ROM中寻找一个具有合适的代码类型的映象,同时该映象中的供应商识别和设备识别字段也要与设备配置空间的相应字段吻合。当这个合适的映象找到之后,POST就从ROM中拷贝适当数量的数据到RAM中,然后执行该设备的初时化代码。至于拷贝多少数据量,以及怎样执行设备初始化代码,要由代码类型来决定。
系统中的POST代码根据初始化长度字段所指定的字节数,将数据从ROM拷贝到RAM中,然后以03H处的值作为入口点调用INIT功能。在INIT返回之前,POST代码应将上述拷贝过来的RAM区保持为可写状态,以使INIT代码能在该区存放一些静态数据,并调整运行存储分配,使得系统在运行时耗费较少的空间。
当涉及到扩展ROM是,在系统POST代码中有一套为PC兼容而设的特别步骤,它们是:
1. 映象并使能扩展ROM到存储器地址空间的一个空区域。
2. 在ROM中寻找一个适当的映像区,并根据初始化长度指定的字节数从ROM中拷贝数据到RAM兼容区。
3. 使扩展ROM基址寄存器实效。
4. 保持RAM区为可写状态并远程调用(FAR CALL)INIT功能。
5. 从INIT返回之后,利用偏移地址02H处的的值决定运行是需要多少存储器空间。
在系统引导之前,POST代码必须把含有扩展ROM代码的RAM区变为只读区。
POST代码必须用特殊的方法去处理带有扩展ROM的VGA设备,VGA设备的扩展BIOS必须拷贝到0C0000H处。VGA设备的识别是通过检查设备配置空间中的分类代码字段来实现的。
5. ROM的初始化(INIT)代码
在PC兼容的扩展ROM中,含有一个INIT功能,用来负责I/O设备的初始化以及为运行操作做准备。由于在执行INIT功能时代码所驻留的RAM区被保持为可写状态,因此,允许PCI扩展ROM中的INIT功能具有某种扩展能力。
在INIT功能执行期间,INIT功能可以在它的RAM区中存放静态参数。运行BIOS或设备驱动程序便可以调用这些参数。但是该RAM区在运行期间是不能写入的。
INIT功能还可以调整它在运行期间所消耗的RAM总量,具体方法是修改映象中位于偏移地址02H处的长度字段,从而能够保持扩展ROM区(0C0000H~0DFFFFH)占用有限的存储器资源。例如,一个设备的扩展ROM为其初始化和运行代码要求24KB的存储空间,但运行代码只要求8KB。ROM中的映象所表现出的长度是24KB。所以,POST代码将全部数据拷贝到RAM中。然后,当运行到INIT功能时,它可以调整长度字段使其减为8KB。当退出INIT功能时,POST代码看到的运行长度为8KB并且可以将下一个扩展BIOS拷贝到最佳位置。
INIT功能负责保证整个映象长度的检查的校验和是正确的。如果它以任何方式修改了RAM区,就必须计算出新的校验和并存入映象中。INIT功能不能以任何方式修改系统存储器(除RAM区域的INIT功能),除非它对配置存储器采用适当的协议或BIOS服务。
如果要将INIT功能从扩展ROM中移去,只要向初始化长度字段(便宜地址02H)写入0即可。在这种情况下,不产生检查和。
INIT从入口处可以得到三个参数:设备的总线编号、设备编号和功能编号。这些参数可以用来访问正在被初始化的设备。它们被传送到X86的寄存器AX中,其中AH包含总线编号,AL的高5位为设备编号,AL的低3位是功能编号。
6. 映像结构的三个长度
一个PC兼容的映像有三个长度与映像结构有关:映像长度、初始化长度和运行长度。
映像长度是映像的总长度,它必须大于或等于初始化长度。
初始化长度表示映像中所含的初始化代码和运行代码两部分的总和,这也是在执行初始化例行程序之前,POST代码要拷贝到RAM区中的数据总量。初始化长度必须大于或等于运行长度。拷贝到RAM区中的初始化数据的检查和必须为0。
运行长度是指映像中所包含运行代码的总量。这也是系统运行时POST代码保留在RAM区中的数据量。这部分映像的检查和必须为0.
PCI数据结构必须包含与映像的运行分配部分中,否则他必须包含于初始化部分。