Cstyle的UEFI导读之PCI Driver Stack

来源:互联网 发布:vnr翻译软件 编辑:程序博客网 时间:2024/06/10 18:47
     N久没更新了,简单说下PCI driver,应该可以说pci是整个PC的核心和灵魂,目前来说所有的PC架构基本上都是用的PCI来作为板端链接的,所以这个还是很复杂,这里只是先简单说下理论,在之后再专门针对code做一个比较系统的详细的解读。
 
一.Driver的种类:
1.PCI  root bridge driver
    Produces one or more instances of the PCI Root Bridge I/OProtocol.管理pci root bridge对root bridge直接操作硬,件进行软件抽象。(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL/EFI_DEVICE_PATH_PROTOCOL)

2.pci bus driver
    Consumes the PCI Root Bridge I/O Protocol, produces a child handle for each PCI controller, and installs the Device Path Protocol and the PCI I/O Protocol onto each child handle,扫描并初始化所有的pci设备,分配设备资源。如果uefi FW需要移植到新的硬件平台的话,pci bus driver一般是不需要修改的,应为他是按照pci的spc标准来做的,我们需要修改的一般是pci root bridge driver以及pci device driver。pre-boot环境下pci bus driver 在EDK当中的默认实现是不支持热插拔的。(EFI_PCI_IO_PROTOCOL/EFI_DEVICE_PATH_PROTOCOL).

3.pci driver
    Consumes the PCI I/O Protocol and produces an I/O abstraction providing services for the console and boot devices required to boot an EFI-conformant operating system.follow the UEFI driver model so they may be any of the following:
  1. Device drivers(graphics controllers/USB host controllers)
  2. Bus drivers(PCI drivers for disk controllers)
  3. Hybrid drivers(PCI drivers for disk controllers)
Notes:PCI drivers for disk controllers既可能是bus driver也可能是混合driver

下图是有一个pci host bridge管理一个PCI disk controller,一个graphics controller,一个usb controller,资源的情况下,产生和消费protocol的示意图。当pci设备扫描并完成资源分配及初始化完成之后会有以下的protocol和handels产生:
EFI_BLOCK_IO_PROTOCOL/EFI_DEVICE_PATH_PROTOCOL;
EFI_GRAPHICS_OUTPUT_PROTOCOL/EFI_DEVICE_PATH_PROTOCOL;
EFI_USB_HOST_CONTROLLER_PROTOCOL/EFI_DEVICE_PATH_PROTOCOL;

 
二.PCI driver的实现(UEFI driver modle)
    由于PCI driver是遵循UEFI driver module的所以它必须实现EFI_DRIVER_BINDING_PROTOCOL,并实例化Supported(), Start(), and Stop() 这三个服务。
    
1. Supported() 
        服务主要的任务是评估传递给driver的device handle(ControllerHandle)所表示的pci controller能否被driver所驱动。最常用的做法是去检索 pci controller 的配置空间,根据其Vendor ID、Device ID,Class Code是否和pci driver所能驱动的设备,同时要注意不能随意写和改变设备的register,应为可能还有别的pci driver也可能会去驱动设备。下面是一个例子,红色的部分先使用 EFI_OPEN_PROTOCOL_BY_DRIVER作为参数来open protocol看该controller handle是否有被install了pci i/o protocol 如果没有就表示该driver不能被pcidriver所驱动。若返回EFI_SUCCESS那就表示可以pci driver可以驱动该设备,然后继续判断vendor id,device id,class code等

// Open the PCI I/O Protocol on ControllerHandle
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiPciIoProtocolGuid,
(VOID **)&PciIo,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
return Status;
}

// Read 16-bit Vendor ID from the PCI configuration header at offset 0x00

Status = PciIo->Pci.Read (
PciIo, // This
EfiPciIoWidthUint16, // Width
PCI_VENDOR_ID_OFFSET, // Offset
sizeof (VendorId), // Count
&VendorId // Buffer
);
if (EFI_ERROR (Status))

2.Start()
    如下图所示,support()服务会为设备定义并初始化一个私有数据结构,open PCI I/O protocol并使用PCI I/O protocol提供的Attributes()服务去初始化PCI设备配置空间里的Command 寄存来enable,I/O, memory以及 bus master bits。并保存其原始值到设备的私有数据结构的OriginalPciAttributes的64bit空间中,在stop()服务里面会回填这些值。
PCI bus driver则不关心这些bit的设置。
 
2.Stop()
        执行于start()相反的动作。

Attributes()服务使用到的各种属性:
  
  

访问PCI资源:
    PCI driver只允许间接使用PCI I/O Protocol使用访问PCI控制器管理的I/O和memory-mapped I/O资源,而不能访问其他控制器或者是chipset/Motherboard资源如下图,同时还需要注意的是这里提到的资源的地址都是pci空间的地址,需要使用Map()/Unmap()服务把处理器地址空间的地址映射到pci配置空间。
• PciIo->PollMem()
• PciIo->PollIo()
• PciIo->Mem.Read()
• PciIo->Mem.Write()--需要考虑在写完之后,读一次同一个地址,使memery写事务周期完成。
• PciIo->Io.Read()
• PciIo->Io.Write()
• PciIo->Pci.Read()
• PciIo->Pci.Write()
• PciIo->CopyMem()
• PciIo->AllocateBuffer()
• PciIo->FreeBuffer()
• PciIo->Map()
• PciIo->Unmap()
• PciIo->Flush()

    当我们的uefi driver设计完成后我们需要使用一定的工具去把生成的efi或者是和leagcy rom一起打包烧到板卡的存储芯片中,这样在pci bus driver枚举pci设备的时候就会自动的读取并执行这些rom。efirom.exe 是我们最常见的工具例如:
EfiRom -o Compressed.rom -f 0xABCD -i 0x1234 -ec File1.efi File2.efi -b Legacy.bin这样就能把两个efi rom和一个leagcy rom制定vid和did打包生成我们需要的最终rom,烧到板卡里面就ok了。



转载请注明出处Cstyle.z.zhou@gmail.com//http://blog.csdn.net/CStyle_0x007
原创粉丝点击