pci option rom 加载过程

在PCI 配置空间的0X30处有这么一个寄存器,叫Expansion ROM Base Address.

如图所示:


我们经常说的option rom 就放在这个位置, 注意前面有个option, 那就是说,并不是每个设备都带有 expansion rom.

原则上讲,一般比较高级的卡(add-in ) 都会有option rom. 从30h 这个位置开始,定义了option rom的基本信息,比如起始位置,

大小,即然是电脑上的东西,就得讲个规矩, layout 是固定的:

明白人,一眼就可以看出,它的高21bit 记录了expansion rom的base address.

另外,PCI SPEC 也说了,如果BIOS 想确定,一个device 需要多大的空间,只需要向这个寄存器写一个全0的值,然后读回来就行了。

如果不贴几行代码,大家可能不信,文章也就失去了专业性,失去了逼格:

现在大学跟着,打开PciOptionRomSupport.c 这个文件,然后看到269行:

  //
  // The bit0 is 0 to prevent the enabling of the Rom address decoder
  //
  AllOnes = 0xfffffffe;
  Address = EFI_PCI_ADDRESS (Bus, Device, Function, RomBarIndex);

  Status = PciRootBridgeIo->Pci.Write (
                                  PciRootBridgeIo,
                                  EfiPciWidthUint32,
                                  Address,
                                  1,
                                  &AllOnes
                                  );
  if (EFI_ERROR (Status)) {
    return EFI_NOT_FOUND;
  }

  //
  // Read back
  //
  Status = PciRootBridgeIo->Pci.Read(
                                  PciRootBridgeIo,
                                  EfiPciWidthUint32,
                                  Address,
                                  1,
                                  &AllOnes
                                  );

顺便提一下,pci bridge 设备也有这么一个寄存器,不过位置是放在 0x38的位置,图是这样子的:




所以,要得到option rom 的相关信息,一开始就得去这样的寄存器读一把:

</pre><pre code_snippet_id="1736156" snippet_file_name="blog_20160629_3_274882" name="code" class="cpp">  //
  // Offset is 0x30 if is not ppb
  //

  //
  // 0x30
  //
  RomBarIndex = PCI_EXPANSION_ROM_BASE;

  if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
    //
    // If is ppb, 0x38
    //
    RomBarIndex = PCI_BRIDGE_ROMBAR;
  }

我们要根据不同的device ,去设置 RomBarIndex , 如果用脚想一想, 这两个值必然是0x30, 0x38.

事实上呢,也是这样:

#define PCI_DEVICE_ROMBAR             0x30
#define PCI_BRIDGE_ROMBAR             0x38

如果读回来之后,没有得到一个有效值,那么我们就说,这个device 没有option rom .

  //
  // Bits [1, 10] are reserved
  //
  AllOnes &= 0xFFFFF800;
  if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) {
    return EFI_NOT_FOUND;
  }


最后,如果一节都还顺利,那么将得到的值取反加1, 即为option rom  的size;

PciIoDevice->RomSize = (UINT64) ((~AllOnes) + 1);


随着时代的进步 ,在21世纪初期 ,2006年1 月的最后一天,  EFI spec  横空出世,EFI SPEC 当然也会对option rom 给个标准, 这时也不叫rom了,改叫image 了。一方面,提高了逼格,一方面和它其他的函数名一致, 我们知道uefi 里面各种loadimage , startimage 函数。


UEFI SPEC 说了,所有的option rom , 必须以55AA 打头,细头的你,如果将55AA展开,那就是01010101 10101010, 刚好0和1 错着摆开,所以, 55AA还是有讲究的,不是一拍脑袋就定下来的,上图:


早在上个世纪, 我们著名的华罗庚就强调了数形结合的重要性,他说:数缺形时少知觉,形少数时难入微。 所以,光有这个图,我们还不能真正理解它到底是

怎么运作的,我们还得上几行代码:

  do {
    if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
      RomHeader = (PCI_EXPANSION_ROM_HEADER *) ((UINT8 *) RomHeader + 512);
      continue;
    }

简答跳转一下,就可以看到SIGNATURE 是啥,当然不出我们意料,它必须是55aa.

#define PCI_EXPANSION_ROM_HEADER_SIGNATURE              0xaa55


随着剧情的发展,这时候,我们已经确定了某个pci device 上面有option rom .那么我们就应该运行上面的代码:

btw , 写option rom 是有讲究的,跟应用程序不一样,它不能也无法调用os 或者标准C 库提供的接各种接口,它需要的只是内存。尽可能少的依赖其它模块。

还有, option rom 从来就不是在flash 上运行的,它必须先行copy 到RAM 上面,才能执行。





    //
    // Copy Rom image into memory
    //
    PciDevice->PciRootBridgeIo->Mem.Read (
                                      PciDevice->PciRootBridgeIo,
                                      EfiPciWidthUint8,
                                      RomBar,
                                      (UINT32) RomImageSize,
                                      Image
                                      );

将option rom 装载到内存,并且执行它,我们在一个函数里面就做完了,这个函数叫ProcessOpRomImage.

下面我们逐行分析这个函数:


传进来只有一个参数,一个指向pci device instance 的指针:

PCI_IO_DEVICE 描述了一个pci 设备所有自身的属性以及与其它兄弟姐妹爹妈的关系。比如  type, BusNumber, DeviceNumber, FunctionNumber. parent (挂在谁下面的)。

 ChildList (如果自己是桥设备)。


讲解各行代码之前,先做一个名词解释: DevicePath

在EFI 里面,我们用 device path 去描述一个设备的位置信息,可以是一个逻辑设备。 

然后device path 可以分为6类:

Hardware Device path:  这个device path 描述述了某个具体硬件属于哪个resource domain, resource 并不一个玄乎的概念,它是我们

天天见的,比如 内存, io, mmio.


ACPI Device path: 这一类地址空间只能用ACPI 独有的AML 语言去描述。


Messaging Device Paht: 这类device path 描述计算机本体之外的资源,比如一个SCSI ID, 或者ip 址址。


Media Device Path,  也就我们这篇文章要要提到的。  我们创建的 option rom device path ,类型即为MEDIA_DEVICE_PATH,


随后,根据创建的device path ,即load 之,执行之:








评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值