pci option rom 加载过程

在PCI 配置空间的0X30处有这么一个寄存器,叫Expansion ROM Base Address.
如图所示:https://blog.csdn.net/robinsongsog/article/details/51785335

pci option rom 加载过程_第1张图片

我们经常说的option rom 就放在这个位置, 注意前面有个option, 那就是说,并不是每个设备都带有 expansion rom.
原则上讲,一般比较高级的卡(add-in ) 都会有option rom. 从30h 这个位置开始,定义了option rom的基本信息,比如起始位置,
大小,即然是电脑上的东西,就得讲个规矩, layout 是固定的:

pci option rom 加载过程_第2张图片

明白人,一眼就可以看出,它的高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的位置,图是这样子的:

pci option rom 加载过程_第3张图片

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

  //  // 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还是有讲究的,不是一拍脑袋就定下来的,上图:

pci option rom 加载过程_第4张图片

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

  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 option rom 加载过程_第5张图片

传进来只有一个参数,一个指向pci device instance 的指针:
PCI_IO_DEVICE 描述了一个pci 设备所有自身的属性以及与其它兄弟姐妹爹妈的关系。比如  type, BusNumber, DeviceNumber, FunctionNumber. parent (挂在谁下面的)。
 ChildList (如果自己是桥设备)。

pci option rom 加载过程_第6张图片

讲解各行代码之前,先做一个名词解释: 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 之,执行之:

pci option rom 加载过程_第7张图片
--------------------- 
作者:uefi_artisan 
来源:CSDN 
原文:https://blog.csdn.net/robinsongsog/article/details/51785335 
版权声明:本文为博主原创文章,转载请附上博文链接!

 

你可能感兴趣的:(UEFI基础知识)