On 02/26/16 13:36, Ni, Ruiyu wrote: > Will you start to change the OVMF platform to use the core PciHostBridge next > week? > I am still not quite sure it's the only gap:)
I'm going to resume that work (well, hobby, but don't tell my manager! :)) today. Thanks! Laszlo > > Regards, > Ray > > >> -----Original Message----- >> From: Laszlo Ersek [mailto:[email protected]] >> Sent: Friday, February 26, 2016 8:34 PM >> To: Ni, Ruiyu <[email protected]>; [email protected] >> Subject: Re: [PATCH v3] MdeModulePkg/PciHostBridge: Don't assume resources >> are fully NonExistent >> >> On 02/26/16 13:15, Ni, Ruiyu wrote: >>> Thanks for the quick patch. >>> >>> Reviewed-by: Ruiyu Ni <[email protected]> >> >> Thanks a lot! >> >> Committed & pushed as 6474f1f156eefa6886e594039f4d562e374ba344. >> >> Laszlo >> >>> >>> >>>> -----Original Message----- >>>> From: Laszlo Ersek [mailto:[email protected]] >>>> Sent: Friday, February 26, 2016 7:16 PM >>>> To: [email protected] >>>> Cc: Ni, Ruiyu <[email protected]> >>>> Subject: [PATCH v3] MdeModulePkg/PciHostBridge: Don't assume resources are >>>> fully NonExistent >>>> >>>> From: Ruiyu Ni <[email protected]> >>>> >>>> The patch removes the assumption that the resources claimed by root >>>> bridges should not exist. Because resources might have been added: >>>> 1. by platform modules either in PEI through resource HOB, or in DXE, >>>> before the PCI host bridge driver runs. >>>> 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. >>>> >>>> Contributed-under: TianoCore Contribution Agreement 1.0 >>>> Signed-off-by: Ruiyu Ni <[email protected]> >>>> [[email protected]: intersection-based implementation] >>>> Contributed-under: TianoCore Contribution Agreement 1.0 >>>> Signed-off-by: Laszlo Ersek <[email protected]> >>>> Cc: Ruiyu Ni <[email protected]> >>>> --- >>>> >>>> Notes: >>>> v3: >>>> - replace "completely missing" with "fully NonExistent" in the subject >>>> [Ray] >>>> >>>> - sorting is only necessary for gap checking, but there are no gaps -- >>>> drop both gap checking and sorting [Ray] >>>> >>>> - comment in the code that (IntersectionBase >= IntersectionEnd) means >>>> "no overlap" [Ray] >>>> >>>> - log errors when incompatible descriptors are encountered >>>> >>>> - log an error when GetIoSpaceMap() / GetMemorySpaceMap() fails >>>> >>>> - remove useless ASSERT()s on the descriptors returned by >>>> GetIoSpaceDescriptor() and GetMemorySpaceDescriptor() [Ray] >>>> >>>> - eliminate the Remaining, DescriptorLeft and Step variables, >>>> simplifying the verification loops [Ray] >>>> >>>> - the verification loops should assert on CheckStatus, not Status >>>> >>>> MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c | 305 >>>> +++++++++++++++++++- >>>> 1 file changed, 294 insertions(+), 11 deletions(-) >>>> >>>> diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c >>>> b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c >>>> index edf042cc2547..ef0c4f2a5e7b 100644 >>>> --- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c >>>> +++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c >>>> @@ -29,6 +29,290 @@ GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 >>>> *mPciResourceTypeStr[] = { >>>> }; >>>> >>>> /** >>>> + Ensure the compatibility of an IO space descriptor with the IO aperture. >>>> + >>>> + The IO space descriptor can come from the GCD IO space map, or it can >>>> + represent a gap between two neighboring IO space descriptors. In the >>>> latter >>>> + case, the GcdIoType field is expected to be EfiGcdIoTypeNonExistent. >>>> + >>>> + If the IO space descriptor already has type EfiGcdIoTypeIo, then no >>>> action is >>>> + taken -- it is by definition compatible with the aperture. >>>> + >>>> + Otherwise, the intersection of the IO space descriptor is calculated >>>> with the >>>> + aperture. If the intersection is the empty set (no overlap), no action >>>> is >>>> + taken; the IO space descriptor is compatible with the aperture. >>>> + >>>> + Otherwise, the type of the descriptor is investigated again. If the >>>> type is >>>> + EfiGcdIoTypeNonExistent (representing a gap, or a genuine descriptor >>>> with >>>> + such a type), then an attempt is made to add the intersection as IO >>>> space to >>>> + the GCD IO space map. This ensures continuity for the aperture, and the >>>> + descriptor is deemed compatible with the aperture. >>>> + >>>> + Otherwise, the IO space descriptor is incompatible with the IO aperture. >>>> + >>>> + @param[in] Base Base address of the aperture. >>>> + @param[in] Length Length of the aperture. >>>> + @param[in] Descriptor The descriptor to ensure compatibility with the >>>> + aperture for. >>>> + >>>> + @retval EFI_SUCCESS The descriptor is compatible. The GCD IO >>>> space >>>> + map may have been updated, for continuity >>>> + within the aperture. >>>> + @retval EFI_INVALID_PARAMETER The descriptor is incompatible. >>>> + @return Error codes from gDS->AddIoSpace(). >>>> +**/ >>>> +EFI_STATUS >>>> +IntersectIoDescriptor ( >>>> + IN UINT64 Base, >>>> + IN UINT64 Length, >>>> + IN CONST EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor >>>> + ) >>>> +{ >>>> + UINT64 IntersectionBase; >>>> + UINT64 IntersectionEnd; >>>> + EFI_STATUS Status; >>>> + >>>> + if (Descriptor->GcdIoType == EfiGcdIoTypeIo) { >>>> + return EFI_SUCCESS; >>>> + } >>>> + >>>> + IntersectionBase = MAX (Base, Descriptor->BaseAddress); >>>> + IntersectionEnd = MIN (Base + Length, >>>> + Descriptor->BaseAddress + Descriptor->Length); >>>> + if (IntersectionBase >= IntersectionEnd) { >>>> + // >>>> + // The descriptor and the aperture don't overlap. >>>> + // >>>> + return EFI_SUCCESS; >>>> + } >>>> + >>>> + if (Descriptor->GcdIoType == EfiGcdIoTypeNonExistent) { >>>> + Status = gDS->AddIoSpace (EfiGcdIoTypeIo, IntersectionBase, >>>> + IntersectionEnd - IntersectionBase); >>>> + >>>> + DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE, >>>> + "%a: %a: add [%Lx, %Lx): %r\n", gEfiCallerBaseName, __FUNCTION__, >>>> + IntersectionBase, IntersectionEnd, Status)); >>>> + return Status; >>>> + } >>>> + >>>> + DEBUG ((EFI_D_ERROR, "%a: %a: desc [%Lx, %Lx) type %u conflicts with " >>>> + "aperture [%Lx, %Lx)\n", gEfiCallerBaseName, __FUNCTION__, >>>> + Descriptor->BaseAddress, Descriptor->BaseAddress + Descriptor->Length, >>>> + (UINT32)Descriptor->GcdIoType, Base, Base + Length)); >>>> + return EFI_INVALID_PARAMETER; >>>> +} >>>> + >>>> +/** >>>> + 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 ( >>>> + IN UINT64 Base, >>>> + IN UINT64 Length >>>> + ) >>>> +{ >>>> + EFI_STATUS Status; >>>> + UINTN Index; >>>> + UINTN NumberOfDescriptors; >>>> + EFI_GCD_IO_SPACE_DESCRIPTOR *IoSpaceMap; >>>> + >>>> + Status = gDS->GetIoSpaceMap (&NumberOfDescriptors, &IoSpaceMap); >>>> + if (EFI_ERROR (Status)) { >>>> + DEBUG ((EFI_D_ERROR, "%a: %a: GetIoSpaceMap(): %r\n", >>>> + gEfiCallerBaseName, __FUNCTION__, Status)); >>>> + return Status; >>>> + } >>>> + >>>> + for (Index = 0; Index < NumberOfDescriptors; Index++) { >>>> + Status = IntersectIoDescriptor (Base, Length, &IoSpaceMap[Index]); >>>> + if (EFI_ERROR (Status)) { >>>> + goto FreeIoSpaceMap; >>>> + } >>>> + } >>>> + >>>> + DEBUG_CODE ( >>>> + // >>>> + // Make sure there are adjacent descriptors covering [Base, Base + >>>> Length). >>>> + // It is possible that they have not been merged; merging can be >>>> prevented >>>> + // by allocation. >>>> + // >>>> + UINT64 CheckBase; >>>> + EFI_STATUS CheckStatus; >>>> + EFI_GCD_IO_SPACE_DESCRIPTOR Descriptor; >>>> + >>>> + for (CheckBase = Base; >>>> + CheckBase < Base + Length; >>>> + CheckBase = Descriptor.BaseAddress + Descriptor.Length) { >>>> + CheckStatus = gDS->GetIoSpaceDescriptor (CheckBase, &Descriptor); >>>> + ASSERT_EFI_ERROR (CheckStatus); >>>> + ASSERT (Descriptor.GcdIoType == EfiGcdIoTypeIo); >>>> + } >>>> + ); >>>> + >>>> +FreeIoSpaceMap: >>>> + FreePool (IoSpaceMap); >>>> + >>>> + return Status; >>>> +} >>>> + >>>> +/** >>>> + Ensure the compatibility of a memory space descriptor with the MMIO >>>> aperture. >>>> + >>>> + The memory space descriptor can come from the GCD memory space map, or >>>> it can >>>> + represent a gap between two neighboring memory space descriptors. In the >>>> + latter case, the GcdMemoryType field is expected to be >>>> + EfiGcdMemoryTypeNonExistent. >>>> + >>>> + If the memory space descriptor already has type >>>> + EfiGcdMemoryTypeMemoryMappedIo, and its capabilities are a superset of >>>> the >>>> + required capabilities, then no action is taken -- it is by definition >>>> + compatible with the aperture. >>>> + >>>> + Otherwise, the intersection of the memory space descriptor is >>>> calculated with >>>> + the aperture. If the intersection is the empty set (no overlap), no >>>> action is >>>> + taken; the memory space descriptor is compatible with the aperture. >>>> + >>>> + Otherwise, the type of the descriptor is investigated again. If the >>>> type is >>>> + EfiGcdMemoryTypeNonExistent (representing a gap, or a genuine >>>> descriptor with >>>> + such a type), then an attempt is made to add the intersection as MMIO >>>> space >>>> + to the GCD memory space map, with the specified capabilities. This >>>> ensures >>>> + continuity for the aperture, and the descriptor is deemed compatible >>>> with the >>>> + aperture. >>>> + >>>> + Otherwise, the memory space descriptor is incompatible with the MMIO >>>> + aperture. >>>> + >>>> + @param[in] Base Base address of the aperture. >>>> + @param[in] Length Length of the aperture. >>>> + @param[in] Capabilities Capabilities required by the aperture. >>>> + @param[in] Descriptor The descriptor to ensure compatibility with the >>>> + aperture for. >>>> + >>>> + @retval EFI_SUCCESS The descriptor is compatible. The GCD >>>> memory >>>> + space map may have been updated, for >>>> + continuity within the aperture. >>>> + @retval EFI_INVALID_PARAMETER The descriptor is incompatible. >>>> + @return Error codes from gDS->AddMemorySpace(). >>>> +**/ >>>> +EFI_STATUS >>>> +IntersectMemoryDescriptor ( >>>> + IN UINT64 Base, >>>> + IN UINT64 Length, >>>> + IN UINT64 Capabilities, >>>> + IN CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor >>>> + ) >>>> +{ >>>> + UINT64 IntersectionBase; >>>> + UINT64 IntersectionEnd; >>>> + EFI_STATUS Status; >>>> + >>>> + if (Descriptor->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo && >>>> + (Descriptor->Capabilities & Capabilities) == Capabilities) { >>>> + return EFI_SUCCESS; >>>> + } >>>> + >>>> + IntersectionBase = MAX (Base, Descriptor->BaseAddress); >>>> + IntersectionEnd = MIN (Base + Length, >>>> + Descriptor->BaseAddress + Descriptor->Length); >>>> + if (IntersectionBase >= IntersectionEnd) { >>>> + // >>>> + // The descriptor and the aperture don't overlap. >>>> + // >>>> + return EFI_SUCCESS; >>>> + } >>>> + >>>> + if (Descriptor->GcdMemoryType == EfiGcdMemoryTypeNonExistent) { >>>> + Status = gDS->AddMemorySpace (EfiGcdMemoryTypeMemoryMappedIo, >>>> + IntersectionBase, IntersectionEnd - IntersectionBase, >>>> + Capabilities); >>>> + >>>> + DEBUG ((EFI_ERROR (Status) ? EFI_D_ERROR : EFI_D_VERBOSE, >>>> + "%a: %a: add [%Lx, %Lx): %r\n", gEfiCallerBaseName, __FUNCTION__, >>>> + IntersectionBase, IntersectionEnd, Status)); >>>> + return Status; >>>> + } >>>> + >>>> + DEBUG ((EFI_D_ERROR, "%a: %a: desc [%Lx, %Lx) type %u cap %Lx conflicts >>>> " >>>> + "with aperture [%Lx, %Lx) cap %Lx\n", gEfiCallerBaseName, >>>> __FUNCTION__, >>>> + Descriptor->BaseAddress, Descriptor->BaseAddress + Descriptor->Length, >>>> + (UINT32)Descriptor->GcdMemoryType, Descriptor->Capabilities, >>>> + Base, Base + Length, Capabilities)); >>>> + return EFI_INVALID_PARAMETER; >>>> +} >>>> + >>>> +/** >>>> + 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 ( >>>> + IN UINT64 Base, >>>> + IN UINT64 Length, >>>> + IN UINT64 Capabilities >>>> + ) >>>> +{ >>>> + EFI_STATUS Status; >>>> + UINTN Index; >>>> + UINTN NumberOfDescriptors; >>>> + EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap; >>>> + >>>> + Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap); >>>> + if (EFI_ERROR (Status)) { >>>> + DEBUG ((EFI_D_ERROR, "%a: %a: GetMemorySpaceMap(): %r\n", >>>> + gEfiCallerBaseName, __FUNCTION__, Status)); >>>> + return Status; >>>> + } >>>> + >>>> + for (Index = 0; Index < NumberOfDescriptors; Index++) { >>>> + Status = IntersectMemoryDescriptor (Base, Length, Capabilities, >>>> + &MemorySpaceMap[Index]); >>>> + if (EFI_ERROR (Status)) { >>>> + goto FreeMemorySpaceMap; >>>> + } >>>> + } >>>> + >>>> + DEBUG_CODE ( >>>> + // >>>> + // Make sure there are adjacent descriptors covering [Base, Base + >>>> Length). >>>> + // It is possible that they have not been merged; merging can be >>>> prevented >>>> + // by allocation and different capabilities. >>>> + // >>>> + UINT64 CheckBase; >>>> + EFI_STATUS CheckStatus; >>>> + EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor; >>>> + >>>> + for (CheckBase = Base; >>>> + CheckBase < Base + Length; >>>> + CheckBase = Descriptor.BaseAddress + Descriptor.Length) { >>>> + CheckStatus = gDS->GetMemorySpaceDescriptor (CheckBase, >>>> &Descriptor); >>>> + ASSERT_EFI_ERROR (CheckStatus); >>>> + ASSERT (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo); >>>> + ASSERT ((Descriptor.Capabilities & Capabilities) == Capabilities); >>>> + } >>>> + ); >>>> + >>>> +FreeMemorySpaceMap: >>>> + FreePool (MemorySpaceMap); >>>> + >>>> + return Status; >>>> +} >>>> + >>>> +/** >>>> >>>> Entry point of this driver. >>>> >>>> @@ -89,6 +373,7 @@ InitializePciHostBridge ( >>>> &gEfiPciHostBridgeResourceAllocationProtocolGuid, >>>> &HostBridge->ResAlloc, >>>> NULL >>>> ); >>>> + ASSERT_EFI_ERROR (Status); >>>> if (EFI_ERROR (Status)) { >>>> FreePool (HostBridge); >>>> PciHostBridgeFreeRootBridges (RootBridges, RootBridgeCount); >>>> @@ -109,11 +394,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 +414,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, >>>> -- >>>> 1.8.3.1 >>> _______________________________________________ edk2-devel mailing list [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

