pcidevicesupport.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 974 行 · 第 1/2 页

C
974
字号
                           EfiPciIoWidthUint8,
                           0,
                           sizeof (PciData),
                           &PciData
                           );

  if ((((PciData.Bridge.IoBase & 0xF) == 0) &&
        (PciData.Bridge.IoBase != 0 || PciData.Bridge.IoLimit != 0)) ||
      (((PciData.Bridge.IoBase & 0xF) == 1) &&
        ((PciData.Bridge.IoBase & 0xF0) != 0 || (PciData.Bridge.IoLimit & 0xF0) != 0 || PciData.Bridge.IoBaseUpper16 != 0 || PciData.Bridge.IoLimitUpper16 != 0))) {
    PciIoDevice->PciIo.Attributes(
                         &(PciIoDevice->PciIo),
                         EfiPciIoAttributeOperationEnable,
                         (EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
                         NULL
                         );
  }
  if ((PciData.Bridge.MemoryBase & 0xFFF0) != 0 || (PciData.Bridge.MemoryLimit & 0xFFF0) != 0) {
    PciIoDevice->PciIo.Attributes(
                         &(PciIoDevice->PciIo),
                         EfiPciIoAttributeOperationEnable,
                         (EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
                         NULL
                         );
  }
  if ((((PciData.Bridge.PrefetchableMemoryBase & 0xF) == 0) &&
        (PciData.Bridge.PrefetchableMemoryBase != 0 || PciData.Bridge.PrefetchableMemoryLimit != 0)) ||
      (((PciData.Bridge.PrefetchableMemoryBase & 0xF) == 1) &&
        ((PciData.Bridge.PrefetchableMemoryBase & 0xFFF0) != 0 || (PciData.Bridge.PrefetchableMemoryLimit & 0xFFF0) != 0 || PciData.Bridge.PrefetchableBaseUpper32 != 0 || PciData.Bridge.PrefetchableLimitUpper32 != 0))) {
    PciIoDevice->PciIo.Attributes(
                         &(PciIoDevice->PciIo),
                         EfiPciIoAttributeOperationEnable,
                         (EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
                         NULL
                         );
  }

  return EFI_SUCCESS;
}

EFI_STATUS 
StartPciDevicesOnBridge (
  IN EFI_HANDLE                          Controller,
  IN PCI_IO_DEVICE                       *RootBridge,
  IN EFI_DEVICE_PATH_PROTOCOL            *RemainingDevicePath 
  )
/*++

Routine Description:

  Start to manage the PCI device on specified the root bridge or PCI-PCI Bridge

Arguments:

  Controller          - An efi handle.
  RootBridge          - A pointer to the PCI_IO_DEVICE.
  RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.
  NumberOfChildren    - Children number.
  ChildHandleBuffer   - A pointer to the child handle buffer.

Returns:

  None

--*/
{
  PCI_IO_DEVICE             *Temp;
  PCI_IO_DEVICE             *PciIoDevice;
  EFI_DEV_PATH_PTR          Node;
  EFI_DEVICE_PATH_PROTOCOL  *CurrentDevicePath;
  EFI_STATUS                Status;
  EFI_LIST_ENTRY            *CurrentLink;

  CurrentLink = RootBridge->ChildList.ForwardLink;

  while (CurrentLink && CurrentLink != &RootBridge->ChildList) {

    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
    if (RemainingDevicePath != NULL) {

      Node.DevPath = RemainingDevicePath;

      if (Node.Pci->Device != Temp->DeviceNumber || 
          Node.Pci->Function != Temp->FunctionNumber) {
        CurrentLink = CurrentLink->ForwardLink;
        continue;
      }

      //
      // Check if the device has been assigned with required resource
      //
      if (!Temp->Allocated) {
        return EFI_NOT_READY;
      }
      
      //
      // Check if the current node has been registered before
      // If it is not, register it
      //
      if (!Temp->Registered) {
        PciIoDevice = Temp;

        Status = RegisterPciDevice (
                  Controller,
                  PciIoDevice,
                  NULL
                  );

      }
      
      //
      // Get the next device path
      //
      CurrentDevicePath = EfiNextDevicePathNode (RemainingDevicePath);
      if (EfiIsDevicePathEnd (CurrentDevicePath)) {
        return EFI_SUCCESS;
      }
  
      //
      // If it is a PPB
      //
      if (IS_PCI_BRIDGE (&(Temp->Pci))) {
        Status = StartPciDevicesOnBridge (
                  Controller,
                  Temp,
                  CurrentDevicePath
                  );
        EnableBridgeAttributes (Temp);

        return Status;
      } else {

        //
        // Currently, the PCI bus driver only support PCI-PCI bridge
        //
        return EFI_UNSUPPORTED;
      }

    } else {

      //
      // If remaining device path is NULL,
      // try to enable all the pci devices under this bridge
      //

      if (!Temp->Registered && Temp->Allocated) {

        PciIoDevice = Temp;

        Status = RegisterPciDevice (
                  Controller,
                  PciIoDevice,
                  NULL
                  );

      }

      if (IS_PCI_BRIDGE (&(Temp->Pci))) {
        Status = StartPciDevicesOnBridge ( 
                   Controller,
                   Temp,
                   RemainingDevicePath
                   );
        EnableBridgeAttributes (Temp);
      }

      CurrentLink = CurrentLink->ForwardLink;
      continue;
    }
  }

  return EFI_NOT_FOUND;
}

EFI_STATUS
StartPciDevices (
  IN EFI_HANDLE                         Controller,
  IN EFI_DEVICE_PATH_PROTOCOL           *RemainingDevicePath
  )
/*++

Routine Description:

  Start to manage the PCI device according to RemainingDevicePath
  If RemainingDevicePath == NULL, the PCI bus driver will start 
  to manage all the PCI devices it found previously

Arguments:
  Controller          - An efi handle.
  RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.

Returns:

  None

--*/
{
  EFI_DEV_PATH_PTR  Node;
  PCI_IO_DEVICE     *RootBridge;
  EFI_LIST_ENTRY    *CurrentLink;

  if (RemainingDevicePath != NULL) {

    //
    // Check if the RemainingDevicePath is valid
    //
    Node.DevPath = RemainingDevicePath;
    if (Node.DevPath->Type != HARDWARE_DEVICE_PATH ||
        Node.DevPath->SubType != HW_PCI_DP         &&
        DevicePathNodeLength (Node.DevPath) != sizeof (PCI_DEVICE_PATH)
        ) {
      return EFI_UNSUPPORTED;
    }
  }

  CurrentLink = gPciDevicePool.ForwardLink;

  while (CurrentLink && CurrentLink != &gPciDevicePool) {

    RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
    //
    // Locate the right root bridge to start
    //
    if (RootBridge->Handle == Controller) {
      StartPciDevicesOnBridge (
        Controller,
        RootBridge,
        RemainingDevicePath
        );
    }

    CurrentLink = CurrentLink->ForwardLink;
  }

  return EFI_SUCCESS;
}

PCI_IO_DEVICE *
CreateRootBridge (
  IN EFI_HANDLE RootBridgeHandle
  )
/*++

Routine Description:


Arguments:
  RootBridgeHandle   - An efi handle.

Returns:

  None

--*/
{

  EFI_STATUS                      Status;
  PCI_IO_DEVICE                   *Dev;

  Dev = NULL;
  Status = gBS->AllocatePool (
                  EfiBootServicesData,
                  sizeof (PCI_IO_DEVICE),
                  (VOID **) &Dev
                  );

  if (EFI_ERROR (Status)) {
    return NULL;
  }

  EfiZeroMem (Dev, sizeof (PCI_IO_DEVICE));
  Dev->Signature  = PCI_IO_DEVICE_SIGNATURE;
  Dev->Handle     = RootBridgeHandle;
  InitializeListHead (&Dev->ChildList);

  return Dev;
}

PCI_IO_DEVICE *
GetRootBridgeByHandle (
  EFI_HANDLE RootBridgeHandle
  )
/*++

Routine Description:


Arguments:

  RootBridgeHandle    - An efi handle.

Returns:

  None

--*/
{
  PCI_IO_DEVICE   *RootBridgeDev;
  EFI_LIST_ENTRY  *CurrentLink;

  CurrentLink = gPciDevicePool.ForwardLink;

  while (CurrentLink && CurrentLink != &gPciDevicePool) {

    RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
    if (RootBridgeDev->Handle == RootBridgeHandle) {
      return RootBridgeDev;
    }

    CurrentLink = CurrentLink->ForwardLink;
  }

  return NULL;
}

BOOLEAN
RootBridgeExisted (
  IN EFI_HANDLE RootBridgeHandle
  )
/*++

Routine Description:

  This function searches if RootBridgeHandle has already existed
  in current device pool.

  If so, it means the given root bridge has been already enumerated.

Arguments:

  RootBridgeHandle   - An efi handle.

Returns:

  None

--*/
{
  PCI_IO_DEVICE *Bridge;

  Bridge = GetRootBridgeByHandle (RootBridgeHandle);

  if (Bridge != NULL) {
    return TRUE;
  }

  return FALSE;
}

BOOLEAN
PciDeviceExisted (
  IN PCI_IO_DEVICE    *Bridge,
  IN PCI_IO_DEVICE    *PciIoDevice
  )
/*++

Routine Description:
  
Arguments:

  Bridge       - A pointer to the PCI_IO_DEVICE.
  PciIoDevice  - A pointer to the PCI_IO_DEVICE.

Returns:

  None

--*/
{

  PCI_IO_DEVICE   *Temp;
  EFI_LIST_ENTRY  *CurrentLink;

  CurrentLink = Bridge->ChildList.ForwardLink;

  while (CurrentLink && CurrentLink != &Bridge->ChildList) {

    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);

    if (Temp == PciIoDevice) {
      return TRUE;
    }

    if (!IsListEmpty (&Temp->ChildList)) {
      if (PciDeviceExisted (Temp, PciIoDevice)) {
        return TRUE;
      }
    }

    CurrentLink = CurrentLink->ForwardLink;
  }

  return FALSE;
}

PCI_IO_DEVICE *
ActiveVGADeviceOnTheSameSegment (
  IN PCI_IO_DEVICE        *VgaDevice
  )
/*++

Routine Description:

Arguments:

  VgaDevice    - A pointer to the PCI_IO_DEVICE.
  
Returns:

  None

--*/
{
  EFI_LIST_ENTRY  *CurrentLink;
  PCI_IO_DEVICE   *Temp;

  CurrentLink = gPciDevicePool.ForwardLink;

  while (CurrentLink && CurrentLink != &gPciDevicePool) {

    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);

    if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) {

      Temp = ActiveVGADeviceOnTheRootBridge (Temp);

      if (Temp != NULL) {
        return Temp;
      }
    }

    CurrentLink = CurrentLink->ForwardLink;
  }

  return NULL;
}

PCI_IO_DEVICE *
ActiveVGADeviceOnTheRootBridge (
  IN PCI_IO_DEVICE        *RootBridge
  )
/*++

Routine Description:

Arguments:

  RootBridge    - A pointer to the PCI_IO_DEVICE.

Returns:

  None

--*/
{
  EFI_LIST_ENTRY  *CurrentLink;
  PCI_IO_DEVICE   *Temp;

  CurrentLink = RootBridge->ChildList.ForwardLink;

  while (CurrentLink && CurrentLink != &RootBridge->ChildList) {

    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);

    if (IS_PCI_VGA(&Temp->Pci) && 
        (Temp->Attributes &
         (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |
          EFI_PCI_IO_ATTRIBUTE_VGA_IO     |
          EFI_PCI_IO_ATTRIBUTE_VGA_IO_16))) {
      return Temp;
    }

    if (IS_PCI_BRIDGE (&Temp->Pci)) {

      Temp = ActiveVGADeviceOnTheRootBridge (Temp);

      if (Temp != NULL) {
        return Temp;
      }
    }

    CurrentLink = CurrentLink->ForwardLink;
  }

  return NULL;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?