Beispiel #1
0
/**
  Always enable the VTd page attribute for the device in the DeviceScope.

  @param[in]  DeviceScope  the input device scope data structure

  @retval EFI_SUCCESS           The VTd entry is updated to always enable all DMA access for the specific device in the device scope.
**/
EFI_STATUS
AlwaysEnablePageAttributeDeviceScope (
  IN  EDKII_PLATFORM_VTD_DEVICE_SCOPE   *DeviceScope
  )
{
  UINT8                             Bus;
  UINT8                             Device;
  UINT8                             Function;
  VTD_SOURCE_ID                     SourceId;
  UINT8                             SecondaryBusNumber;
  EFI_STATUS                        Status;

  Status = GetPciBusDeviceFunction (DeviceScope->SegmentNumber, &DeviceScope->DeviceScope, &Bus, &Device, &Function);

  if (DeviceScope->DeviceScope.Type == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE) {
    //
    // Need scan the bridge and add all devices.
    //
    SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(DeviceScope->SegmentNumber, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
    Status = ScanPciBus (NULL, DeviceScope->SegmentNumber, SecondaryBusNumber, ScanBusCallbackAlwaysEnablePageAttribute);
    return Status;
  } else {
    SourceId.Bits.Bus      = Bus;
    SourceId.Bits.Device   = Device;
    SourceId.Bits.Function = Function;
    Status = AlwaysEnablePageAttribute (DeviceScope->SegmentNumber, SourceId);
    return Status;
  }
}
Beispiel #2
0
/**
  Scan PCI bus and invoke callback function for each PCI devices under the bus.

  @param[in]  Context               The context of the callback function.
  @param[in]  Segment               The segment of the source.
  @param[in]  Bus                   The bus of the source.
  @param[in]  Callback              The callback function in PCI scan.

  @retval EFI_SUCCESS           The PCI devices under the bus are scaned.
**/
EFI_STATUS
ScanPciBus (
  IN VOID                         *Context,
  IN UINT16                       Segment,
  IN UINT8                        Bus,
  IN SCAN_BUS_FUNC_CALLBACK_FUNC  Callback
  )
{
  UINT8                   Device;
  UINT8                   Function;
  UINT8                   SecondaryBusNumber;
  UINT8                   HeaderType;
  UINT8                   BaseClass;
  UINT8                   SubClass;
  UINT32                  MaxFunction;
  UINT16                  VendorID;
  UINT16                  DeviceID;
  EFI_STATUS              Status;

  // Scan the PCI bus for devices
  for (Device = 0; Device < PCI_MAX_DEVICE + 1; Device++) {
    HeaderType = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, 0, PCI_HEADER_TYPE_OFFSET));
    MaxFunction = PCI_MAX_FUNC + 1;
    if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00) {
      MaxFunction = 1;
    }
    for (Function = 0; Function < MaxFunction; Function++) {
      VendorID  = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_VENDOR_ID_OFFSET));
      DeviceID  = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_DEVICE_ID_OFFSET));
      if (VendorID == 0xFFFF && DeviceID == 0xFFFF) {
        continue;
      }

      Status = Callback (Context, Segment, Bus, Device, Function);
      if (EFI_ERROR (Status)) {
        return Status;
      }

      BaseClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2));
      if (BaseClass == PCI_CLASS_BRIDGE) {
        SubClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1));
        if (SubClass == PCI_CLASS_BRIDGE_P2P) {
          SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
          DEBUG ((DEBUG_INFO,"  ScanPciBus: PCI bridge S%04x B%02x D%02x F%02x (SecondBus:%02x)\n", Segment, Bus, Device, Function, SecondaryBusNumber));
          if (SecondaryBusNumber != 0) {
            Status = ScanPciBus (Context, Segment, SecondaryBusNumber, Callback);
            if (EFI_ERROR (Status)) {
              return Status;
            }
          }
        }
      }
    }
  }

  return EFI_SUCCESS;
}
Beispiel #3
0
/**

  This function scan PCI bus.

  @param VtdIndex      VTd engine index
  @param Bus           Pci bus

  @retval EFI_SUCCESS  scan PCI bus successfully.

**/
EFI_STATUS
ScanPciBus (
  IN UINTN          VtdIndex,
  IN UINT8          Bus
  )
{
  UINT8                   Device;
  UINT8                   Function;
  UINT8                   SecondaryBusNumber;
  UINT8                   HeaderType;
  UINT8                   BaseClass;
  UINT8                   SubClass;
  UINT32                  MaxFunction;
  UINT16                  VendorID;
  UINT16                  DeviceID;
  EFI_STATUS              Status;

  // Scan the PCI bus for devices
  for (Device = 0; Device < PCI_MAX_DEVICE + 1; Device++) {
    HeaderType = PciRead8 (PCI_LIB_ADDRESS(Bus, Device, 0, PCI_HEADER_TYPE_OFFSET));
    MaxFunction = PCI_MAX_FUNC + 1;
    if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00) {
      MaxFunction = 1;
    }
    for (Function = 0; Function < MaxFunction; Function++) {
      VendorID  = PciRead16 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_VENDOR_ID_OFFSET));
      DeviceID  = PciRead16 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_DEVICE_ID_OFFSET));
      if (VendorID == 0xFFFF && DeviceID == 0xFFFF) {
        continue;
      }

      Status = RegisterPciDevice (VtdIndex, Bus, Device, Function, FALSE);
      if (EFI_ERROR (Status)) {
        return Status;
      }

      BaseClass = PciRead8 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2));
      if (BaseClass == PCI_CLASS_BRIDGE) {
        SubClass = PciRead8 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1));
        if (SubClass == PCI_CLASS_BRIDGE_P2P) {
          SecondaryBusNumber = PciRead8 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
          DEBUG ((EFI_D_INFO,"  ScanPciBus: PCI bridge B%02x D%02x F%02x (SecondBus:%02x)\n", Bus, Device, Function, SecondaryBusNumber));
          if (SecondaryBusNumber != 0) {
            ScanPciBus (VtdIndex, SecondaryBusNumber);
          }
        }
      }
    }
  }

  return EFI_SUCCESS;
}
Beispiel #4
0
EFI_STATUS
ScanPciRootBridgeForRoms(
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *IoDev
  )
  
{
  EFI_STATUS                                 Status;
  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR          *Descriptors; 
  UINT16                                     MinBus;
  UINT16                                     MaxBus;
  UINT64                                     RootWindowBase;
  UINT64                                     RootWindowLimit;
  PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT  Context;

  if (mPciOptionRomTableInstalled == FALSE) {
    gBS->InstallConfigurationTable(&gEfiPciOptionRomTableGuid, &mPciOptionRomTable);
    mPciOptionRomTableInstalled = TRUE;
  }

  Status = IoDev->Configuration(IoDev, (VOID **)&Descriptors);
  if (EFI_ERROR (Status) || Descriptors == NULL) {
    return EFI_NOT_FOUND;
  }

  MinBus = 0xffff;
  MaxBus = 0xffff;
  RootWindowBase  = 0;
  RootWindowLimit = 0;
  while (Descriptors->Desc != ACPI_END_TAG_DESCRIPTOR) {
    //
    // Find bus range
    //
    if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {
      MinBus = (UINT16)Descriptors->AddrRangeMin;
      MaxBus = (UINT16)Descriptors->AddrRangeMax;
    }
    //
    // Find memory descriptors that are not prefetchable
    //
    if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM && Descriptors->SpecificFlag == 0) {
      //
      // Find Memory Descriptors that are less than 4GB, so the PPB Memory Window can be used for downstream devices
      //
      if (Descriptors->AddrRangeMax < 0x100000000ULL) {
        //
        // Find the largest Non-Prefetchable Memory Descriptor that is less than 4GB
        //
        if ((Descriptors->AddrRangeMax - Descriptors->AddrRangeMin) > (RootWindowLimit - RootWindowBase)) {
          RootWindowBase  = Descriptors->AddrRangeMin;
          RootWindowLimit = Descriptors->AddrRangeMax;
        }
      }
    }
    Descriptors ++;
  }

  //
  // Make sure a bus range was found
  //
  if (MinBus == 0xffff || MaxBus == 0xffff) {
    return EFI_NOT_FOUND;
  }

  //
  // Make sure a non-prefetchable memory region was found
  //
  if (RootWindowBase == 0 && RootWindowLimit == 0) {
    return EFI_NOT_FOUND;
  }

  //
  // Round the Base and Limit values to 1 MB boudaries
  //
  RootWindowBase  = ((RootWindowBase - 1) & 0xfff00000) + 0x00100000;
  RootWindowLimit = ((RootWindowLimit + 1) & 0xfff00000) - 1;

  //
  // Make sure that the size of the rounded window is greater than zero
  //
  if (RootWindowLimit <= RootWindowBase) {
    return EFI_NOT_FOUND;
  }

  //
  // Allocate buffer to save the Command register from all the PCI devices
  //
  Context.CommandRegisterBuffer = NULL;
  Status = gBS->AllocatePool(
                  EfiBootServicesData,
                  sizeof(UINT16) * (MaxBus - MinBus + 1) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1),
                  (VOID **)&Context.CommandRegisterBuffer
                  );

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

  Context.PpbMemoryWindow   = (((UINT32)RootWindowBase) >> 16) | ((UINT32)RootWindowLimit & 0xffff0000);

  //
  // Save the Command register from all the PCI devices, and disable the I/O, Mem, and BusMaster bits
  //
  ScanPciBus(
    IoDev,
    MinBus, MaxBus, 
    0, PCI_MAX_DEVICE, 
    0, PCI_MAX_FUNC, 
    SaveCommandRegister, &Context
    );

  //
  // Recursively scan all the busses for PCI Option ROMs
  //
  ScanPciBus(
    IoDev,
    MinBus, MinBus, 
    0, PCI_MAX_DEVICE, 
    0, PCI_MAX_FUNC, 
    CheckForRom, &Context
    );

  //
  // Restore the Command register in all the PCI devices
  //
  ScanPciBus(
    IoDev,
    MinBus, MaxBus, 
    0, PCI_MAX_DEVICE, 
    0, PCI_MAX_FUNC, 
    RestoreCommandRegister, &Context
    );

  //
  // Free the buffer used to save all the Command register values
  //
  gBS->FreePool(Context.CommandRegisterBuffer);

  return EFI_SUCCESS;
}
Beispiel #5
0
VOID
CheckForRom (
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *IoDev,
  UINT16                           MinBus,
  UINT16                           MaxBus,
  UINT16                           MinDevice,
  UINT16                           MaxDevice,
  UINT16                           MinFunc,
  UINT16                           MaxFunc,
  UINT16                           Bus,
  UINT16                           Device,
  UINT16                           Func,
  IN VOID                          *VoidContext
  )
{
  EFI_STATUS                                 Status;
  PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT  *Context;
  UINT64                                     Address;
  PCI_TYPE00                                 PciHeader;
  PCI_TYPE01                                 *PciBridgeHeader;
  UINT32                                     Register;
  UINT32                                     RomBar;
  UINT32                                     RomBarSize;
  EFI_PHYSICAL_ADDRESS                       RomBuffer;
  UINT32                                     MaxRomSize;
  EFI_PCI_EXPANSION_ROM_HEADER               EfiRomHeader;
  PCI_DATA_STRUCTURE                         Pcir;
  EFI_PCI_OPTION_ROM_DESCRIPTOR              *TempPciOptionRomDescriptors;
  BOOLEAN                                    LastImage;

  Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext;

  Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);

  //
  // Save the contents of the PCI Configuration Header
  //
  IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader);

  if (IS_PCI_BRIDGE(&PciHeader)) {

    PciBridgeHeader = (PCI_TYPE01 *)(&PciHeader);

    //
    // See if the PCI-PCI Bridge has its secondary interface enabled.
    //
    if (PciBridgeHeader->Bridge.SubordinateBus >= PciBridgeHeader->Bridge.SecondaryBus) {

      //
      // Disable the Prefetchable Memory Window
      //
      Register = 0x00000000;
      IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x26, 1, &Register);
      IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x2c, 1, &Register);
      Register = 0xffffffff;
      IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x24, 1, &Register);
      IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x28, 1, &Register);

      //
      // Program Memory Window to the PCI Root Bridge Memory Window
      //
      IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x20, 4, &Context->PpbMemoryWindow);

      //
      // Enable the Memory decode for the PCI-PCI Bridge
      //
      IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
      Register |= 0x02;
      IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);

      //
      // Recurse on the Secondary Bus Number
      //
      ScanPciBus(
        IoDev,
        PciBridgeHeader->Bridge.SecondaryBus, PciBridgeHeader->Bridge.SecondaryBus, 
        0, PCI_MAX_DEVICE, 
        0, PCI_MAX_FUNC, 
        CheckForRom, Context
        );
    }
  } else {

    //
    // Check if an Option ROM Register is present and save the Option ROM Window Register
    //
    RomBar = 0xffffffff;
    IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);
    IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);

    RomBarSize = (~(RomBar & 0xfffff800)) + 1;

    //
    // Make sure the size of the ROM is between 0 and 16 MB
    //
    if (RomBarSize > 0 && RomBarSize <= 0x01000000) {

      //
      // Program Option ROM Window Register to the PCI Root Bridge Window and Enable the Option ROM Window
      //
      RomBar = (Context->PpbMemoryWindow & 0xffff) << 16;
      RomBar = ((RomBar - 1) & (~(RomBarSize - 1))) + RomBarSize;
      if (RomBar < (Context->PpbMemoryWindow & 0xffff0000)) {
        MaxRomSize = (Context->PpbMemoryWindow & 0xffff0000) - RomBar;
        RomBar = RomBar + 1;
        IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);
        IoDev->Pci.Read  (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar);
        RomBar = RomBar - 1;

        //
        // Enable the Memory decode for the PCI Device
        //
        IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
        Register |= 0x02;
        IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);

        //
        // Follow the chain of images to determine the size of the Option ROM present
        // Keep going until the last image is found by looking at the Indicator field
        // or the size of an image is 0, or the size of all the images is bigger than the
        // size of the window programmed into the PPB.
        //
        RomBarSize = 0;
        do {

          LastImage = TRUE;

          ZeroMem (&EfiRomHeader, sizeof(EfiRomHeader));
          IoDev->Mem.Read (
            IoDev, 
            EfiPciWidthUint8, 
            RomBar + RomBarSize, 
            sizeof(EfiRomHeader),
            &EfiRomHeader
            );

          Pcir.ImageLength = 0;

          if (EfiRomHeader.Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE &&
              EfiRomHeader.PcirOffset != 0 &&
              (EfiRomHeader.PcirOffset & 3) == 0 &&
              RomBarSize + EfiRomHeader.PcirOffset + sizeof (PCI_DATA_STRUCTURE) <= MaxRomSize) {
            ZeroMem (&Pcir, sizeof(Pcir));
            IoDev->Mem.Read (
              IoDev, 
              EfiPciWidthUint8, 
              RomBar + RomBarSize + EfiRomHeader.PcirOffset, 
              sizeof(Pcir),
              &Pcir
              );

            if (Pcir.Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
              break;
            }
            if (RomBarSize + Pcir.ImageLength * 512 > MaxRomSize) {
              break;
            }
            if ((Pcir.Indicator & 0x80) == 0x00) {
              LastImage = FALSE;
            }

            RomBarSize += Pcir.ImageLength * 512;
          }
        } while (!LastImage && RomBarSize < MaxRomSize && Pcir.ImageLength !=0);

        if (RomBarSize > 0) {

          //
          // Allocate a memory buffer for the Option ROM contents.
          //
          Status = gBS->AllocatePages(
                          AllocateAnyPages,
                          EfiBootServicesData,
                          EFI_SIZE_TO_PAGES(RomBarSize),
                          &RomBuffer
                          );

          if (!EFI_ERROR (Status)) {

            //
            // Copy the contents of the Option ROM to the memory buffer
            //
            IoDev->Mem.Read (IoDev, EfiPciWidthUint32, RomBar, RomBarSize / sizeof(UINT32), (VOID *)(UINTN)RomBuffer);

            Status = gBS->AllocatePool(
                            EfiBootServicesData,
                            ((UINT32)mPciOptionRomTable.PciOptionRomCount + 1) * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR),
                            (VOID*)&TempPciOptionRomDescriptors
                            );
            if (mPciOptionRomTable.PciOptionRomCount > 0) {
              CopyMem(
                TempPciOptionRomDescriptors, 
                mPciOptionRomTable.PciOptionRomDescriptors, 
                (UINT32)mPciOptionRomTable.PciOptionRomCount * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR)
                );

              gBS->FreePool(mPciOptionRomTable.PciOptionRomDescriptors);
            }

            mPciOptionRomTable.PciOptionRomDescriptors = TempPciOptionRomDescriptors; 

            TempPciOptionRomDescriptors = &(mPciOptionRomTable.PciOptionRomDescriptors[(UINT32)mPciOptionRomTable.PciOptionRomCount]);

            TempPciOptionRomDescriptors->RomAddress              = RomBuffer;
            TempPciOptionRomDescriptors->MemoryType              = EfiBootServicesData;
            TempPciOptionRomDescriptors->RomLength               = RomBarSize;
            TempPciOptionRomDescriptors->Seg                     = (UINT32)IoDev->SegmentNumber;
            TempPciOptionRomDescriptors->Bus                     = (UINT8)Bus;
            TempPciOptionRomDescriptors->Dev                     = (UINT8)Device;
            TempPciOptionRomDescriptors->Func                    = (UINT8)Func;
            TempPciOptionRomDescriptors->ExecutedLegacyBiosImage = TRUE;
            TempPciOptionRomDescriptors->DontLoadEfiRom          = FALSE;

            mPciOptionRomTable.PciOptionRomCount++;
          }
        }

        //
        // Disable the Memory decode for the PCI-PCI Bridge
        //
        IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
        Register &= (~0x02);
        IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register);
      }
    }
  }

  //
  // Restore the PCI Configuration Header 
  //
  IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader);
}