Regards,
Ray


>-----Original Message-----
>From: edk2-devel [mailto:edk2-devel-boun...@lists.01.org] On Behalf Of Laszlo 
>Ersek
>Sent: Friday, February 26, 2016 1:31 AM
>To: Ni, Ruiyu <ruiyu...@intel.com>
>Cc: edk2-de...@ml01.01.org
>Subject: Re: [edk2] [Patch] MdeModulePkg/PciHostBridge: Don't assume resources 
>are added already
>
>Hi Ray,
>
>thanks a lot for the quick patch. I have comments:
>
>(1) I think the subject is misleading. It should say:
>
>  Don't assume resources are completely missing
Or don't assume resources are completely nonexistent.
Background: The initialization of GCD database will create a single
range [0, 2^36) with type nonexistent if the CPU address line is maximally 36.

>
>Because that's what the current code does -- it assumes resources are
>missing, and therefore it insist on adding them.
>
>On 02/25/16 10:13, Ruiyu Ni wrote:
>> The patch removes the assumption that the resources claimed by root
>> bridges should not exist. Because resources might have been added:
>
>Yes, this wording is correct.
>
>> 1. by platform modules either in PEI through resource HOB or earlier
>>    in DXE.
>
>(2) "earlier" is misleading here, I think. It seems to imply that "in
>DXE" is earlier than "in PEI".
>
>I understand that you mean "or in DXE, earlier than dispatching the PCI
>host bridge driver". Please clarify the wording.
Agree.
>
>> 2. Resources claimed by different root bridges may overlap so that
>>    resource adding operation for latter root bridges may fail if
>>    we assume the resource should not exist.
>>
>> In real world, this patch is to fit OVMF platform needs because
>> different root bridges in OVMF platform shares the same resources.
>
>Great. I have some code comments as well:
>
>>
>> Contributed-under: TianoCore Contribution Agreement 1.0
>> Signed-off-by: Ruiyu Ni <ruiyu...@intel.com>
>> Cc: Laszlo Ersek <ler...@redhat.com>
>> ---
>>  .../Bus/Pci/PciHostBridgeDxe/PciHostBridge.c       | 186 
>> +++++++++++++++++++--
>>  .../Bus/Pci/PciHostBridgeDxe/PciHostBridge.h       |   1 +
>>  .../Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf  |   1 +
>>  3 files changed, 177 insertions(+), 11 deletions(-)
>>
>> diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c
>b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c
>> index edf042c..3365b81 100644
>> --- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c
>> +++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c
>> @@ -29,6 +29,171 @@ GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 
>> *mPciResourceTypeStr[] = {
>>  };
>>
>>  /**
>> +  Comparator for memory or IO space descriptor.
>> +  Because the comparator only compares BaseAddress and both
>> +  EFI_GCD_MEMORY_SPACE_DESCRIPTOR and EFI_GCD_IO_SPACE_DESCRIPTOR
>> +  put the BaseAddress in the same offset (0), this comparator can be
>> +  used by both structures.
>> +
>> +  @param Left  Pointer to the memory or IO space descriptor.
>> +  @param Right Pointer to the memory or IO space descriptor.
>> +
>> +  @retval 0   Left equal to Right.
>> +  @return -1  Left is less than Right.
>> +  @return 1   Left is greater than Right.
>> +**/
>> +INTN
>> +EFIAPI
>> +DescriptorComparator (
>> +  IN  CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Left,
>> +  IN  CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Right
>> +  )
>> +{
>> +  if (Left->BaseAddress < Right->BaseAddress) {
>> +    return -1;
>> +  } else if (Left->BaseAddress == Right->BaseAddress) {
>> +    return 0;
>> +  } else {
>> +    return 1;
>> +  }
>> +}
>
>(3) The function prototype for comparators seems to be
>
>typedef
>INTN
>(EFIAPI *SORT_COMPARE)(
>  IN CONST VOID                 *Buffer1,
>  IN CONST VOID                 *Buffer2
>  );
>
>The above doesn't match it on the language level. In addition, I propose
>that instead of casting the pointer-to-const-void to
>pointer-to-descriptor-structure; we should cast the pointer-to-void to
>pointer-to-EFI_PHYSICAL_ADDRESS. This will remain compliant with both
>structures even on the language level, not just in practice.
>

Yes I guess the GCC build may break though VS2015 build pass.
>> +
>> +/**
>> +  Add IO space to GCD.
>> +  The routine checks the GCD database and only adds those which are
>> +  not added in the specified range to GCD.
>> +
>> +  @param Base   Base address of the IO space.
>> +  @param Length Length of the IO space.
>> +
>> +  @retval EFI_SUCCES The IO space was added successfully.
>> +**/
>> +EFI_STATUS
>> +AddIoSpace (
>> +  UINT64                          Base,
>> +  UINT64                          Length
>> +  )
>> +{
>> +  EFI_STATUS                      Status;
>> +  UINTN                           Index;
>> +  UINTN                           NumberOfDescriptors;
>> +  EFI_GCD_IO_SPACE_DESCRIPTOR     *IoSpaceMap;
>> +  UINT64                          DescriptorLimit;
>> +  UINT64                          FreeBase;
>> +
>> +  Status = gDS->GetIoSpaceMap (&NumberOfDescriptors, &IoSpaceMap);
>> +  ASSERT_EFI_ERROR (Status);
>> +
>> +  PerformQuickSort (IoSpaceMap, NumberOfDescriptors, sizeof 
>> (EFI_GCD_IO_SPACE_DESCRIPTOR),
>DescriptorComparator);
>> +
>> +  for (Index = 0, FreeBase = Base; Index < NumberOfDescriptors && FreeBase 
>> < Base + Length; Index++) {
>> +    DescriptorLimit = IoSpaceMap[Index].BaseAddress + 
>> IoSpaceMap[Index].Length;
>
>(4) Just a side note: I think we should rather call this DescriptorEnd.
>Limit is usually meant as an inclusive bound, but here we have an
>exclusive bound. Anyway, this is not too important.
>

Agree.

>> +    if (((DescriptorLimit >= FreeBase) && (DescriptorLimit < Base + 
>> Length)) ||
>> +        ((IoSpaceMap[Index].BaseAddress >= FreeBase) && 
>> (IoSpaceMap[Index].BaseAddress < Base + Length))
>> +        ) {
>> +      //
>> +      // For descriptors which overlap with [Base, Base + Length), we need 
>> to make sure
>> +      // it's IO type.
>> +      // Assertion is enough because failed to start PCI Host Bridge is a 
>> fatal error.
>> +      //
>> +      if (IoSpaceMap[Index].GcdIoType != EfiGcdIoTypeNonExistent) {
>> +        ASSERT (IoSpaceMap[Index].GcdIoType == EfiGcdIoTypeIo);
>> +        if (IoSpaceMap[Index].BaseAddress > FreeBase) {
>> +          Status = gDS->AddIoSpace (EfiGcdIoTypeIo, FreeBase, 
>> IoSpaceMap[Index].BaseAddress - FreeBase);
>> +          DEBUG ((EFI_D_INFO, "[PciHostBridge]: Add IO Space [%lx, %lx)\n", 
>> FreeBase, IoSpaceMap[Index].BaseAddress));
>> +          ASSERT_EFI_ERROR (Status);
>> +        }
>> +        FreeBase = DescriptorLimit;
>> +      }
>> +    }
>> +  }
>
>After thinking a lot about this function :), I think I understand it. I
>can see two problems with it.
>
>(5) The overlap check itself. It seems to investigate whether the base
>of the descriptor falls into the remaining interval, or the end of the
>descriptor falls within the remaining interval.
>
>The relation operators don't seem to be correct:
>
>- (DescriptorLimit >= FreeBase) is not a good comparison, because
>DescriptorLimit is exclusive, while FreeBase is inclusive. So, if they
>are equal (satisfying the condition), that means they do *not* overlap.
>
>- (DescriptorLimit < Base + Length) is also not a good comparison. Both
>of these are exclusive limits, so when they are equal (falsifying the
>condiiotn), then the overlap *does* exist.

Yes >= should be > while < should be <=.

>
>Etc.
>
>Instead of fixing the relation operators, I will have a different
>proposal, please read on.
>
>(6) Because, even if we assume that the overlap check is fixed, I see
>another problem with the algorithm. Consider the following scenario:
>
>                            ................
>                            IO descriptor #2
>                            ----------------
>  ........... Base+Length
>                            Nonexistent desc
>
>                            ................
>                            IO descriptor #1
>  ----------- Base          ----------------
>
>On the left side, we have the aperture we'd like to cover. On the right
>side, we have two IO descriptors that already exist. (And a nonexistent
>type descriptor in the middle, optionally.)

nonexistent descriptor in the middle is not optionally. Please see the GCD 
background
I mentioned in the very above.

>
>Assume that IO descriptor #1 starts exactly at Base, and ends somewhere
>in the middle.
>
>Assume that IO descriptor #2 starts strictly above Base+Length.

Do you mean IO#2_Base == Base + Length?
The overlap check for IO#2 is FALSE.

>
>In this case, the algorithm will see that IO desc #1 starts exactly at
>FreeBase, so no AddIoSpace() is made. FreeBase is then advanced to the
>top of IO#1.
>
>In the next iteration, the nonexistent type desc (if it exists in the
>array) is skipped; FreeBase is left unchanged.
>
>In the next iteration, the range between FreeBase (= the top of IO#1)
>and the bottom of IO#2 is added to the IO space map. However, the top of
>IO#2 exceeds Base+Length -- it overshoots the requested aperture. If
>there is anything else already above Base+Length, the addition will
>fail, and the ASSERT() will be triggered.

yes I see the problem. But the problem is not what you described here.
The problem is the range between [IO#1_End, Base + Length) is not added
to GCD. Because the IO#2 cannot meet the overlap check.
So my code actually needs additional code to add [IO#1_End, Base+Length)
when for-loop ends but FreeBase < Base + Length.

>
>
>** Now consider a simple modification of the above example, for a
>different failure mode -- remove IO#2 from the picture. In this case,
>the range between the top of IO#1 and Base+Length will never be covered.
>The algorithm will report success, but the aperture will not be complete.
>

The 2nd example is the same as the 1st example I think.

>
>(7) Here's what I propose instead. The sorting of the descriptors at the
>beginning is fine. We should then loop over the descriptors. If there is
>a *gap* in the descriptor list (that is, the end of the previous
>descriptor does not exactly equal the start of the next descriptor),
>then we shall *simulate* a descriptor that has type "nonexistent". With
>this out the way, let's see what we will do in the loop body:
>
>Calculate the *intersection* of the descriptor and the aperture. This is
>done by taking the maximum of the minima, and the minimum of the maxima:
>
>IntersectionBase = MAX (Descriptor->Base, ApertureBase);
>IntersectionEnd = MIN (Descriptor->Base + Descriptor->Length,
>                    ApertureBase + ApertureLength);
>
>(Note that IntersectionBase is inclusive, and IntersectionEnd is exclusive.)
>
>Now, if the intersection is the null set:
>
>  (IntersectionBase >= IntersectionEnd)
>
>then there is no overlap between the aperture and the descriptor -- great.
>
>If there is overlap between them, then the intersection gives us
>*exactly* that overlap. So we just have to investigate the type:
>
>- IO: that's fine already, do nothing.
>- Nonexistent: either explicitly, or by way of the simulation above:
>  add it as IO -- it *must* succeed
>- otherwise: ABORT.
>
>Actually, we wouldn't even have to sort the list of descriptors, if we
>were sure that there are no gaps in it. Because there may be gaps, we
>must simulate nonexistent descriptors, and for that simulation we need
>to adjacency check, hence the sorting.

There is no gap. Every byte is covered by a descriptor. So your algorithm
can just check every range which overlaps with [Base, Base + Length).
I have checked your proposed patch. I think with the assumption that every
byte is covered by a descriptor. Sorting can be avoided and your patch can be
simplified further, not only removing sorting, but also others.

>
>For MMIO, the type investigation is a bit different (stolen from your
>code below):
>- MMIO with a superset of capabilities: already okay, skip it
>- nonexistent: either explicitly or by way of simulation (i.e., gap):
> add it as MMIO with the right capabilities -- it must succeed
>- otherwise: ABORT
>
>> +
>> +  FreePool (IoSpaceMap);
>> +
>> +  DEBUG_CODE (
>> +    //
>> +    // Make sure there is a descriptor covering [Base, Base + Length).
>> +    //
>> +    EFI_GCD_IO_SPACE_DESCRIPTOR Descriptor;
>> +    Status = gDS->GetIoSpaceDescriptor (Base, &Descriptor);
>> +    ASSERT_EFI_ERROR (Status);
>> +    ASSERT (Descriptor.BaseAddress <= Base && Descriptor.BaseAddress + 
>> Descriptor.Length >= Base + Length);
>> +    ASSERT (Descriptor.GcdIoType == EfiGcdIoTypeIo);
>> +  );
>> +  return EFI_SUCCESS;
>> +}
>
>This looks good.
>
>Ray, are you okay if I modify your patch to show what I mean, and I post
>it? I will keep your Signed-off-by in the first position.
>
>Thanks
>Laszlo
>
>> +
>> +/**
>> +  Add MMIO space to GCD.
>> +  The routine checks the GCD database and only adds those which are
>> +  not added in the specified range to GCD.
>> +
>> +  @param Base         Base address of the MMIO space.
>> +  @param Length       Length of the MMIO space.
>> +  @param Capabilities Capabilities of the MMIO space.
>> +
>> +  @retval EFI_SUCCES The MMIO space was added successfully.
>> +**/
>> +EFI_STATUS
>> +AddMemoryMappedIoSpace (
>> +  UINT64                          Base,
>> +  UINT64                          Length,
>> +  UINT64                          Capabilities
>> +  )
>> +{
>> +  EFI_STATUS                      Status;
>> +  UINTN                           Index;
>> +  UINTN                           NumberOfDescriptors;
>> +  EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
>> +  UINT64                          DescriptorLimit;
>> +  UINT64                          FreeBase;
>> +
>> +  Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
>> +  ASSERT_EFI_ERROR (Status);
>> +
>> +  PerformQuickSort (MemorySpaceMap, NumberOfDescriptors, sizeof 
>> (EFI_GCD_MEMORY_SPACE_DESCRIPTOR),
>DescriptorComparator);
>> +
>> +  for (Index = 0, FreeBase = Base; Index < NumberOfDescriptors && FreeBase 
>> < Base + Length; Index++) {
>> +    DescriptorLimit = MemorySpaceMap[Index].BaseAddress + 
>> MemorySpaceMap[Index].Length;
>> +    if (((DescriptorLimit >= FreeBase) && (DescriptorLimit < Base + 
>> Length)) ||
>> +        ((MemorySpaceMap[Index].BaseAddress >= FreeBase) && 
>> (MemorySpaceMap[Index].BaseAddress < Base +
>Length))
>> +        ) {
>> +      //
>> +      // For descriptors which overlap with [Base, Base + Length), we need 
>> to make sure
>> +      // it's MMIO type and its capabilities matches what we want.
>> +      // Assertion is enough because failed to start PCI Host Bridge is a 
>> fatal error.
>> +      //
>> +      if (MemorySpaceMap[Index].GcdMemoryType != 
>> EfiGcdMemoryTypeNonExistent) {
>> +        ASSERT (MemorySpaceMap[Index].GcdMemoryType == 
>> EfiGcdMemoryTypeMemoryMappedIo);
>> +        ASSERT ((MemorySpaceMap[Index].Capabilities & Capabilities) == 
>> Capabilities);
>> +        if (MemorySpaceMap[Index].BaseAddress > FreeBase) {
>> +          Status = gDS->AddMemorySpace (EfiGcdMemoryTypeMemoryMappedIo, 
>> FreeBase,
>MemorySpaceMap[Index].BaseAddress - FreeBase, Capabilities);
>> +          DEBUG ((EFI_D_INFO, "[PciHostBridge]: Add MMIO Space [%lx, 
>> %lx)\n", FreeBase,
>MemorySpaceMap[Index].BaseAddress));
>> +          ASSERT_EFI_ERROR (Status);
>> +        }
>> +        FreeBase = DescriptorLimit;
>> +      }
>> +    }
>> +  }
>> +
>> +  FreePool (MemorySpaceMap);
>> +
>> +  DEBUG_CODE (
>> +    //
>> +    // Make sure there is a descriptor covering [Base, Base + Length).
>> +    //
>> +    EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
>> +    Status = gDS->GetMemorySpaceDescriptor (Base, &Descriptor);
>> +    ASSERT_EFI_ERROR (Status);
>> +    ASSERT (Descriptor.BaseAddress <= Base && Descriptor.BaseAddress + 
>> Descriptor.Length >= Base + Length);
>> +    ASSERT (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo);
>> +    ASSERT ((Descriptor.Capabilities & Capabilities) == Capabilities);
>> +    );
>> +
>> +  return Status;
>> +}
>> +
>> +/**
>>
>>    Entry point of this driver.
>>
>> @@ -89,6 +254,7 @@ InitializePciHostBridge (
>>                    &gEfiPciHostBridgeResourceAllocationProtocolGuid, 
>> &HostBridge->ResAlloc,
>>                    NULL
>>                    );
>> +  ASSERT_EFI_ERROR (Status);
>>    if (EFI_ERROR (Status)) {
>>      FreePool (HostBridge);
>>      PciHostBridgeFreeRootBridges (RootBridges, RootBridgeCount);
>> @@ -109,11 +275,10 @@ InitializePciHostBridge (
>>      }
>>
>>      if (RootBridges[Index].Io.Limit > RootBridges[Index].Io.Base) {
>> -      Status = gDS->AddIoSpace (
>> -                      EfiGcdIoTypeIo,
>> -                      RootBridges[Index].Io.Base,
>> -                      RootBridges[Index].Io.Limit - 
>> RootBridges[Index].Io.Base + 1
>> -                      );
>> +      Status = AddIoSpace (
>> +                 RootBridges[Index].Io.Base,
>> +                 RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 
>> 1
>> +                 );
>>        ASSERT_EFI_ERROR (Status);
>>      }
>>
>> @@ -130,12 +295,11 @@ InitializePciHostBridge (
>>
>>      for (MemApertureIndex = 0; MemApertureIndex < sizeof (MemApertures) / 
>> sizeof (MemApertures[0]);
>MemApertureIndex++) {
>>        if (MemApertures[MemApertureIndex]->Limit > 
>> MemApertures[MemApertureIndex]->Base) {
>> -        Status = gDS->AddMemorySpace (
>> -                        EfiGcdMemoryTypeMemoryMappedIo,
>> -                        MemApertures[MemApertureIndex]->Base,
>> -                        MemApertures[MemApertureIndex]->Limit - 
>> MemApertures[MemApertureIndex]->Base +
>1,
>> -                        EFI_MEMORY_UC
>> -                        );
>> +        Status = AddMemoryMappedIoSpace (
>> +                   MemApertures[MemApertureIndex]->Base,
>> +                   MemApertures[MemApertureIndex]->Limit - 
>> MemApertures[MemApertureIndex]->Base + 1,
>> +                   EFI_MEMORY_UC
>> +                   );
>>          ASSERT_EFI_ERROR (Status);
>>          Status = gDS->SetMemorySpaceAttributes (
>>                          MemApertures[MemApertureIndex]->Base,
>> diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.h
>b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.h
>> index 9a8ca21..6a9bb0a 100644
>> --- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.h
>> +++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.h
>> @@ -22,6 +22,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER 
>> EXPRESS OR IMPLIED.
>>  #include <Library/UefiDriverEntryPoint.h>
>>  #include <Library/MemoryAllocationLib.h>
>>  #include <Library/PciHostBridgeLib.h>
>> +#include <Library/SortLib.h>
>>  #include <Protocol/PciHostBridgeResourceAllocation.h>
>>
>>  #include "PciRootBridge.h"
>> diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
>b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
>> index ab5d87e..a11f5a4 100644
>> --- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
>> +++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
>> @@ -42,6 +42,7 @@
>>    BaseLib
>>    PciSegmentLib
>>    PciHostBridgeLib
>> +  SortLib
>>
>>  [Protocols]
>>    gEfiMetronomeArchProtocolGuid                   ## CONSUMES
>>
>
>_______________________________________________
>edk2-devel mailing list
>edk2-devel@lists.01.org
>https://lists.01.org/mailman/listinfo/edk2-devel
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to