2020年5月6日 星期三

PCI Host Bridge Resource Allocation

Initialize Pci Host Bridge

Entry

PciHostBridgeDxe.inf
[Defines]
  BASE_NAME                      = PciHostBridgeDxe
  MODULE_TYPE                    = DXE_DRIVER
  ENTRY_POINT                    = InitializePciHostBridge
PciHostBridge.c
/**
  Entry point of this driver.
  @retval EFI_SUCCESS       Succeed.
  @retval EFI_DEVICE_ERROR  Fail to install PCI_ROOT_BRIDGE_IO protocol.
**/
EFI_STATUS
EFIAPI
InitializePciHostBridge (
  IN EFI_HANDLE         ImageHandle,
  IN EFI_SYSTEM_TABLE   *SystemTable
  )

Step

  1. 因為要給Host Bridge適當的resources所以需要先掃出Host Bridge下面有哪些Root Bridge
      RootBridges = PciHostBridgeGetRootBridges (&RootBridgeCount);
      if ((RootBridges == NULL) || (RootBridgeCount == 0)) {
        return EFI_UNSUPPORTED;
      }
    這邊就是把所有的Bus下面的Dev和Fun找一遍,如果有找到Vid且Header Type = 1才會把現在的Bus視為RootBridge。
  2. 找到了以後就要確定IO,Memory和MemAbove4G的Resources
    1Ch : IO Base
    1Dh : IO Limit
    20h : Memory Base
    22h : Memory Limit
    24h : Prefetchable Memory Base
    26h : Prefetchable Memory Limit
    要記得的是這邊是找到Base和Size,Limit = Base + Size - 1。
    這邊配完resources以後,會做兩件事情:
    a. 若是IDE controller, legacy VGA controller, PCI bridge的話會先加對應的Attributes
    b. 再來看是不是multi function(Header Type bit7),是的話要重新配resources,否的話就直接開始Initialize Root Bridge了。

  3. 接下來步驟的前提是有抓到Vid且分配好resources。
    但其實initialize root bridge就是把剛剛找到的,分配好的位置放進structure裡面,然後再allocatepool出一塊memory把所有的root bridge照順序放進去方便之後使用(Step1 return回來的RootBridge),我是覺得這邊比較像準備工作。
  4. 做了這麼多事情以後,終於要initialize HostBridge了:
      //
      // Most systems in the world including complex servers have only one Host Bridge.
      //
      HostBridge = AllocateZeroPool (sizeof (PCI_HOST_BRIDGE_INSTANCE));
      HostBridge->Signature        = PCI_HOST_BRIDGE_SIGNATURE; //SIGNATURE_32 ('p', 'h', 'b', 'g')
      HostBridge->CanRestarted     = TRUE;
      InitializeListHead (&HostBridge->RootBridges);
    看起來就是做了一個LinkList的頭,接下來就要拿出剛剛的RootBridges裡面的data,一個一個做成Root Bridge Device Handle,且一個一個掛在Host Bridge後面。
  5. 接下來要做的事情是把剛剛Root Bridge的結構拿出來處理然後一個一個掛在Host Bridge後面
      //
      // Create Root Bridge Device Handle in this Host Bridge
      //
      for (Index = 0; Index < RootBridgeCount; Index++) {
        //
        // Create Root Bridge Handle Instance
        //
        RootBridge = CreateRootBridge (&RootBridges[Index]);
        ASSERT (RootBridge != NULL);
        if (RootBridge == NULL) {
          continue;
        } . . .
        //
        // Insert Root Bridge Handle Instance
        //
        InsertTailList (&HostBridge->RootBridges, &RootBridge->Link);
      }
    CreateRootBridge會做下面這些事情:
    a. 確認resources的Limit >= Base
    b. 接著把該丟的丟進去
      RootBridge = AllocateZeroPool (sizeof (PCI_ROOT_BRIDGE_INSTANCE));
      ASSERT (RootBridge != NULL);
      RootBridge->Signature = PCI_ROOT_BRIDGE_SIGNATURE;
      RootBridge->Supports = Bridge->Supports;
      RootBridge->Attributes = Bridge->Attributes;
      RootBridge->DmaAbove4G = Bridge->DmaAbove4G;
      RootBridge->NoExtendedConfigSpace = Bridge->NoExtendedConfigSpace;
      RootBridge->AllocationAttributes = Bridge->AllocationAttributes;
      RootBridge->DevicePath = DuplicateDevicePath (Bridge->DevicePath);
      RootBridge->DevicePathStr = DevicePathStr;
      RootBridge->ConfigBuffer = AllocatePool (
        TypeMax * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)
        );
      ASSERT (RootBridge->ConfigBuffer != NULL);
      InitializeListHead (&RootBridge->Maps);
      CopyMem (&RootBridge->Bus, &Bridge->Bussizeof (PCI_ROOT_BRIDGE_APERTURE));
      CopyMem (&RootBridge->Io, &Bridge->Iosizeof (PCI_ROOT_BRIDGE_APERTURE));
      CopyMem (&RootBridge->Mem, &Bridge->Memsizeof (PCI_ROOT_BRIDGE_APERTURE));
      CopyMem (&RootBridge->MemAbove4G, &Bridge->MemAbove4Gsizeof (PCI_ROOT_BRIDGE_APERTURE));
      CopyMem (&RootBridge->PMem, &Bridge->PMemsizeof (PCI_ROOT_BRIDGE_APERTURE));
      CopyMem (&RootBridge->PMemAbove4G, &Bridge->PMemAbove4Gsizeof (PCI_ROOT_BRIDGE_APERTURE));
    c. 有了這些資訊後,在Allocate一塊Io或Memory space出來,最後就是InsertTailList了。
    PS.這邊要注意的是step2拿到的Base是device address,需要處理過變成host address才能allocate出一塊memory。
  6. 把HostBridge和RootBridge全部都install到protocol裡面,之後把剛剛Allocate給instance的空間free掉就完成InitializePciHostBridge的部分了。
        Status = gBS->InstallMultipleProtocolInterfaces (
                        &HostBridge->Handle,
                        &gEfiPciHostBridgeResourceAllocationProtocolGuid, &HostBridge->ResAlloc,
                        NULL
                        ); . . .
        Status = gBS->InstallMultipleProtocolInterfaces (
                        &RootBridge->Handle,
                        &gEfiDevicePathProtocolGuidRootBridge->DevicePath,
                        &gEfiPciRootBridgeIoProtocolGuid, &RootBridge->RootBridgeIo,
                        NULL
                        );

沒有留言:

張貼留言