X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdeModulePkg%2FBus%2FPci%2FPciHostBridgeDxe%2FPciRootBridgeIo.c;h=4c908fad885190877f0717efc4b730ecd776744b;hb=69b40465048e4289854d881e90007811c09d42d8;hp=332860eb3819a8fbd1f83975cce8efc74c7c0ee1;hpb=63b90643afb19f84e4cd3681a9a402ec65b1cf8d;p=mirror_edk2.git diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c index 332860eb38..4c908fad88 100644 --- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c +++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c @@ -2,7 +2,7 @@ PCI Root Bridge Io Protocol code. -Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.
+Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -19,6 +19,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #define NO_MAPPING (VOID *) (UINTN) -1 +#define RESOURCE_VALID(Resource) ((Resource)->Base <= (Resource)->Limit) + // // Lookup table for increment values based on transfer widths // @@ -59,92 +61,119 @@ UINT8 mOutStride[] = { Construct the Pci Root Bridge instance. @param Bridge The root bridge instance. - @param HostBridgeHandle Handle to the HostBridge. @return The pointer to PCI_ROOT_BRIDGE_INSTANCE just created or NULL if creation fails. **/ PCI_ROOT_BRIDGE_INSTANCE * CreateRootBridge ( - IN PCI_ROOT_BRIDGE *Bridge, - IN EFI_HANDLE HostBridgeHandle + IN PCI_ROOT_BRIDGE *Bridge ) { PCI_ROOT_BRIDGE_INSTANCE *RootBridge; PCI_RESOURCE_TYPE Index; CHAR16 *DevicePathStr; + PCI_ROOT_BRIDGE_APERTURE *Aperture; DevicePathStr = NULL; DEBUG ((EFI_D_INFO, "RootBridge: ")); DEBUG ((EFI_D_INFO, "%s\n", DevicePathStr = ConvertDevicePathToText (Bridge->DevicePath, FALSE, FALSE))); - DEBUG ((EFI_D_INFO, "Support/Attr: %lx / %lx\n", Bridge->Supports, Bridge->Attributes)); - DEBUG ((EFI_D_INFO, " DmaAbove4G: %s\n", Bridge->DmaAbove4G ? L"Yes" : L"No")); - DEBUG ((EFI_D_INFO, " AllocAttr: %lx (%s%s)\n", Bridge->AllocationAttributes, + DEBUG ((EFI_D_INFO, " Support/Attr: %lx / %lx\n", Bridge->Supports, Bridge->Attributes)); + DEBUG ((EFI_D_INFO, " DmaAbove4G: %s\n", Bridge->DmaAbove4G ? L"Yes" : L"No")); + DEBUG ((EFI_D_INFO, "NoExtConfSpace: %s\n", Bridge->NoExtendedConfigSpace ? L"Yes" : L"No")); + DEBUG ((EFI_D_INFO, " AllocAttr: %lx (%s%s)\n", Bridge->AllocationAttributes, (Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0 ? L"CombineMemPMem " : L"", (Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) != 0 ? L"Mem64Decode" : L"" )); - DEBUG ((EFI_D_INFO, " Bus: %lx - %lx\n", Bridge->Bus.Base, Bridge->Bus.Limit)); - DEBUG ((EFI_D_INFO, " Io: %lx - %lx\n", Bridge->Io.Base, Bridge->Io.Limit)); - DEBUG ((EFI_D_INFO, " Mem: %lx - %lx\n", Bridge->Mem.Base, Bridge->Mem.Limit)); - DEBUG ((EFI_D_INFO, " MemAbove4G: %lx - %lx\n", Bridge->MemAbove4G.Base, Bridge->MemAbove4G.Limit)); - DEBUG ((EFI_D_INFO, " PMem: %lx - %lx\n", Bridge->PMem.Base, Bridge->PMem.Limit)); - DEBUG ((EFI_D_INFO, " PMemAbove4G: %lx - %lx\n", Bridge->PMemAbove4G.Base, Bridge->PMemAbove4G.Limit)); + DEBUG (( + EFI_D_INFO, " Bus: %lx - %lx Translation=%lx\n", + Bridge->Bus.Base, Bridge->Bus.Limit, Bridge->Bus.Translation + )); + // + // Translation for bus is not supported. + // + ASSERT (Bridge->Bus.Translation == 0); + if (Bridge->Bus.Translation != 0) { + return NULL; + } + + DEBUG (( + DEBUG_INFO, " Io: %lx - %lx Translation=%lx\n", + Bridge->Io.Base, Bridge->Io.Limit, Bridge->Io.Translation + )); + DEBUG (( + DEBUG_INFO, " Mem: %lx - %lx Translation=%lx\n", + Bridge->Mem.Base, Bridge->Mem.Limit, Bridge->Mem.Translation + )); + DEBUG (( + DEBUG_INFO, " MemAbove4G: %lx - %lx Translation=%lx\n", + Bridge->MemAbove4G.Base, Bridge->MemAbove4G.Limit, Bridge->MemAbove4G.Translation + )); + DEBUG (( + DEBUG_INFO, " PMem: %lx - %lx Translation=%lx\n", + Bridge->PMem.Base, Bridge->PMem.Limit, Bridge->PMem.Translation + )); + DEBUG (( + DEBUG_INFO, " PMemAbove4G: %lx - %lx Translation=%lx\n", + Bridge->PMemAbove4G.Base, Bridge->PMemAbove4G.Limit, Bridge->PMemAbove4G.Translation + )); // // Make sure Mem and MemAbove4G apertures are valid // - if (Bridge->Mem.Base < Bridge->Mem.Limit) { + if (RESOURCE_VALID (&Bridge->Mem)) { ASSERT (Bridge->Mem.Limit < SIZE_4GB); if (Bridge->Mem.Limit >= SIZE_4GB) { return NULL; } } - if (Bridge->MemAbove4G.Base < Bridge->MemAbove4G.Limit) { + if (RESOURCE_VALID (&Bridge->MemAbove4G)) { ASSERT (Bridge->MemAbove4G.Base >= SIZE_4GB); if (Bridge->MemAbove4G.Base < SIZE_4GB) { return NULL; } } - if (Bridge->PMem.Base < Bridge->PMem.Limit) { + if (RESOURCE_VALID (&Bridge->PMem)) { ASSERT (Bridge->PMem.Limit < SIZE_4GB); if (Bridge->PMem.Limit >= SIZE_4GB) { return NULL; } } - if (Bridge->PMemAbove4G.Base < Bridge->PMemAbove4G.Limit) { + if (RESOURCE_VALID (&Bridge->PMemAbove4G)) { ASSERT (Bridge->PMemAbove4G.Base >= SIZE_4GB); if (Bridge->PMemAbove4G.Base < SIZE_4GB) { return NULL; } } - if ((Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0) { - // - // If this bit is set, then the PCI Root Bridge does not - // support separate windows for Non-prefetchable and Prefetchable - // memory. - // - ASSERT (Bridge->PMem.Base >= Bridge->PMem.Limit); - ASSERT (Bridge->PMemAbove4G.Base >= Bridge->PMemAbove4G.Limit); - if ((Bridge->PMem.Base < Bridge->PMem.Limit) || - (Bridge->PMemAbove4G.Base < Bridge->PMemAbove4G.Limit) - ) { - return NULL; + // + // Ignore AllocationAttributes when resources were already assigned. + // + if (!Bridge->ResourceAssigned) { + if ((Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0) { + // + // If this bit is set, then the PCI Root Bridge does not + // support separate windows for Non-prefetchable and Prefetchable + // memory. + // + ASSERT (!RESOURCE_VALID (&Bridge->PMem)); + ASSERT (!RESOURCE_VALID (&Bridge->PMemAbove4G)); + if (RESOURCE_VALID (&Bridge->PMem) || RESOURCE_VALID (&Bridge->PMemAbove4G)) { + return NULL; + } } - } - if ((Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) == 0) { - // - // If this bit is not set, then the PCI Root Bridge does not support - // 64 bit memory windows. - // - ASSERT (Bridge->MemAbove4G.Base >= Bridge->MemAbove4G.Limit); - ASSERT (Bridge->PMemAbove4G.Base >= Bridge->PMemAbove4G.Limit); - if ((Bridge->MemAbove4G.Base < Bridge->MemAbove4G.Limit) || - (Bridge->PMemAbove4G.Base < Bridge->PMemAbove4G.Limit) - ) { - return NULL; + if ((Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) == 0) { + // + // If this bit is not set, then the PCI Root Bridge does not support + // 64 bit memory windows. + // + ASSERT (!RESOURCE_VALID (&Bridge->MemAbove4G)); + ASSERT (!RESOURCE_VALID (&Bridge->PMemAbove4G)); + if (RESOURCE_VALID (&Bridge->MemAbove4G) || RESOURCE_VALID (&Bridge->PMemAbove4G)) { + return NULL; + } } } @@ -155,6 +184,7 @@ CreateRootBridge ( 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; @@ -168,17 +198,52 @@ CreateRootBridge ( CopyMem (&RootBridge->Io, &Bridge->Io, sizeof (PCI_ROOT_BRIDGE_APERTURE)); CopyMem (&RootBridge->Mem, &Bridge->Mem, sizeof (PCI_ROOT_BRIDGE_APERTURE)); CopyMem (&RootBridge->MemAbove4G, &Bridge->MemAbove4G, sizeof (PCI_ROOT_BRIDGE_APERTURE)); - + CopyMem (&RootBridge->PMem, &Bridge->PMem, sizeof (PCI_ROOT_BRIDGE_APERTURE)); + CopyMem (&RootBridge->PMemAbove4G, &Bridge->PMemAbove4G, sizeof (PCI_ROOT_BRIDGE_APERTURE)); for (Index = TypeIo; Index < TypeMax; Index++) { - RootBridge->ResAllocNode[Index].Type = Index; - RootBridge->ResAllocNode[Index].Base = 0; - RootBridge->ResAllocNode[Index].Length = 0; - RootBridge->ResAllocNode[Index].Status = ResNone; + switch (Index) { + case TypeBus: + Aperture = &RootBridge->Bus; + break; + case TypeIo: + Aperture = &RootBridge->Io; + break; + case TypeMem32: + Aperture = &RootBridge->Mem; + break; + case TypeMem64: + Aperture = &RootBridge->MemAbove4G; + break; + case TypePMem32: + Aperture = &RootBridge->PMem; + break; + case TypePMem64: + Aperture = &RootBridge->PMemAbove4G; + break; + default: + ASSERT (FALSE); + Aperture = NULL; + break; + } + RootBridge->ResAllocNode[Index].Type = Index; + if (Bridge->ResourceAssigned && (Aperture->Limit >= Aperture->Base)) { + // + // Base in ResAllocNode is a host address, while Base in Aperture is a + // device address. + // + RootBridge->ResAllocNode[Index].Base = TO_HOST_ADDRESS (Aperture->Base, + Aperture->Translation); + RootBridge->ResAllocNode[Index].Length = Aperture->Limit - Aperture->Base + 1; + RootBridge->ResAllocNode[Index].Status = ResAllocated; + } else { + RootBridge->ResAllocNode[Index].Base = 0; + RootBridge->ResAllocNode[Index].Length = 0; + RootBridge->ResAllocNode[Index].Status = ResNone; + } } RootBridge->RootBridgeIo.SegmentNumber = Bridge->Segment; - RootBridge->RootBridgeIo.ParentHandle = HostBridgeHandle; RootBridge->RootBridgeIo.PollMem = RootBridgeIoPollMem; RootBridge->RootBridgeIo.PollIo = RootBridgeIoPollIo; RootBridge->RootBridgeIo.Mem.Read = RootBridgeIoMemRead; @@ -232,6 +297,8 @@ CreateRootBridge ( @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_INVALID_PARAMETER Address or Count is invalid. + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. @retval EFI_UNSUPPORTED The address range specified by Address, Width, @@ -252,6 +319,7 @@ RootBridgeIoCheckParameter ( UINT64 Base; UINT64 Limit; UINT32 Size; + UINT64 Length; // // Check to see if Buffer is NULL @@ -268,7 +336,7 @@ RootBridgeIoCheckParameter ( } // - // For FIFO type, the target address won't increase during the access, + // For FIFO type, the device address won't increase during the access, // so treat Count as 1 // if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { @@ -278,6 +346,13 @@ RootBridgeIoCheckParameter ( Width = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (Width & 0x03); Size = 1 << Width; + // + // Make sure (Count * Size) doesn't exceed MAX_UINT64 + // + if (Count > DivU64x32 (MAX_UINT64, Size)) { + return EFI_INVALID_PARAMETER; + } + // // Check to see if Address is aligned // @@ -285,6 +360,14 @@ RootBridgeIoCheckParameter ( return EFI_UNSUPPORTED; } + // + // Make sure (Address + Count * Size) doesn't exceed MAX_UINT64 + // + Length = MultU64x32 (Count, Size); + if (Address > MAX_UINT64 - Length) { + return EFI_INVALID_PARAMETER; + } + RootBridge = ROOT_BRIDGE_FROM_THIS (This); // @@ -303,7 +386,7 @@ RootBridgeIoCheckParameter ( // // Allow Legacy IO access // - if (Address + MultU64x32 (Count, Size) <= 0x1000) { + if (Address + Length <= 0x1000) { if ((RootBridge->Attributes & ( EFI_PCI_ATTRIBUTE_ISA_IO | EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_ATTRIBUTE_VGA_IO | EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO | @@ -317,7 +400,7 @@ RootBridgeIoCheckParameter ( // // Allow Legacy MMIO access // - if ((Address >= 0xA0000) && (Address + MultU64x32 (Count, Size)) <= 0xC0000) { + if ((Address >= 0xA0000) && (Address + Length) <= 0xC0000) { if ((RootBridge->Attributes & EFI_PCI_ATTRIBUTE_VGA_MEMORY) != 0) { return EFI_SUCCESS; } @@ -326,12 +409,18 @@ RootBridgeIoCheckParameter ( // By comparing the Address against Limit we know which range to be used // for checking // - if (Address + MultU64x32 (Count, Size) <= RootBridge->Mem.Limit + 1) { - Base = RootBridge->Mem.Base; + if ((Address >= RootBridge->Mem.Base) && (Address + Length <= RootBridge->Mem.Limit + 1)) { + Base = RootBridge->Mem.Base; Limit = RootBridge->Mem.Limit; - } else { - Base = RootBridge->MemAbove4G.Base; + } else if ((Address >= RootBridge->PMem.Base) && (Address + Length <= RootBridge->PMem.Limit + 1)) { + Base = RootBridge->PMem.Base; + Limit = RootBridge->PMem.Limit; + } else if ((Address >= RootBridge->MemAbove4G.Base) && (Address + Length <= RootBridge->MemAbove4G.Limit + 1)) { + Base = RootBridge->MemAbove4G.Base; Limit = RootBridge->MemAbove4G.Limit; + } else { + Base = RootBridge->PMemAbove4G.Base; + Limit = RootBridge->PMemAbove4G.Limit; } } else { PciRbAddr = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*) &Address; @@ -351,20 +440,133 @@ RootBridgeIoCheckParameter ( Address = PciRbAddr->Register; } Base = 0; - Limit = 0xFFF; + Limit = RootBridge->NoExtendedConfigSpace ? 0xFF : 0xFFF; } if (Address < Base) { return EFI_INVALID_PARAMETER; } - if (Address + MultU64x32 (Count, Size) > Limit + 1) { + if (Address + Length > Limit + 1) { return EFI_INVALID_PARAMETER; } return EFI_SUCCESS; } +/** + Use address to match apertures of memory type and then get the corresponding + translation. + + @param RootBridge The root bridge instance. + @param Address The address used to match aperture. + @param Translation Pointer containing the output translation. + + @return EFI_SUCCESS Get translation successfully. + @return EFI_INVALID_PARAMETER No matched memory aperture; the input Address + must be invalid. +**/ +EFI_STATUS +RootBridgeIoGetMemTranslationByAddress ( + IN PCI_ROOT_BRIDGE_INSTANCE *RootBridge, + IN UINT64 Address, + IN OUT UINT64 *Translation + ) +{ + if (Address >= RootBridge->Mem.Base && Address <= RootBridge->Mem.Limit) { + *Translation = RootBridge->Mem.Translation; + } else if (Address >= RootBridge->PMem.Base && Address <= RootBridge->PMem.Limit) { + *Translation = RootBridge->PMem.Translation; + } else if (Address >= RootBridge->MemAbove4G.Base && Address <= RootBridge->MemAbove4G.Limit) { + *Translation = RootBridge->MemAbove4G.Translation; + } else if (Address >= RootBridge->PMemAbove4G.Base && Address <= RootBridge->PMemAbove4G.Limit) { + *Translation = RootBridge->PMemAbove4G.Translation; + } else { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +/** + Return the result of (Multiplicand * Multiplier / Divisor). + + @param Multiplicand A 64-bit unsigned value. + @param Multiplier A 64-bit unsigned value. + @param Divisor A 32-bit unsigned value. + @param Remainder A pointer to a 32-bit unsigned value. This parameter is + optional and may be NULL. + + @return Multiplicand * Multiplier / Divisor. +**/ +UINT64 +MultThenDivU64x64x32 ( + IN UINT64 Multiplicand, + IN UINT64 Multiplier, + IN UINT32 Divisor, + OUT UINT32 *Remainder OPTIONAL + ) +{ + UINT64 Uint64; + UINT32 LocalRemainder; + UINT32 Uint32; + if (Multiplicand > DivU64x64Remainder (MAX_UINT64, Multiplier, NULL)) { + // + // Make sure Multiplicand is the bigger one. + // + if (Multiplicand < Multiplier) { + Uint64 = Multiplicand; + Multiplicand = Multiplier; + Multiplier = Uint64; + } + // + // Because Multiplicand * Multiplier overflows, + // Multiplicand * Multiplier / Divisor + // = (2 * Multiplicand' + 1) * Multiplier / Divisor + // = 2 * (Multiplicand' * Multiplier / Divisor) + Multiplier / Divisor + // + Uint64 = MultThenDivU64x64x32 (RShiftU64 (Multiplicand, 1), Multiplier, Divisor, &LocalRemainder); + Uint64 = LShiftU64 (Uint64, 1); + Uint32 = 0; + if ((Multiplicand & 0x1) == 1) { + Uint64 += DivU64x32Remainder (Multiplier, Divisor, &Uint32); + } + return Uint64 + DivU64x32Remainder (Uint32 + LShiftU64 (LocalRemainder, 1), Divisor, Remainder); + } else { + return DivU64x32Remainder (MultU64x64 (Multiplicand, Multiplier), Divisor, Remainder); + } +} + +/** + Return the elapsed tick count from CurrentTick. + + @param CurrentTick On input, the previous tick count. + On output, the current tick count. + @param StartTick The value the performance counter starts with when it + rolls over. + @param EndTick The value that the performance counter ends with before + it rolls over. + + @return The elapsed tick count from CurrentTick. +**/ +UINT64 +GetElapsedTick ( + UINT64 *CurrentTick, + UINT64 StartTick, + UINT64 EndTick + ) +{ + UINT64 PreviousTick; + + PreviousTick = *CurrentTick; + *CurrentTick = GetPerformanceCounter(); + if (StartTick < EndTick) { + return *CurrentTick - PreviousTick; + } else { + return PreviousTick - *CurrentTick; + } +} + /** Polls an address in memory mapped I/O space until an exit condition is met, or a timeout occurs. @@ -414,6 +616,11 @@ RootBridgeIoPollMem ( EFI_STATUS Status; UINT64 NumberOfTicks; UINT32 Remainder; + UINT64 StartTick; + UINT64 EndTick; + UINT64 CurrentTick; + UINT64 ElapsedTick; + UINT64 Frequency; if (Result == NULL) { return EFI_INVALID_PARAMETER; @@ -439,28 +646,18 @@ RootBridgeIoPollMem ( return EFI_SUCCESS; } else { - // - // Determine the proper # of metronome ticks to wait for polling the - // location. The nuber of ticks is Roundup (Delay / - // mMetronome->TickPeriod)+1 - // The "+1" to account for the possibility of the first tick being short - // because we started in the middle of a tick. + // NumberOfTicks = Frenquency * Delay / EFI_TIMER_PERIOD_SECONDS(1) // - // BugBug: overriding mMetronome->TickPeriod with UINT32 until Metronome - // protocol definition is updated. - // - NumberOfTicks = DivU64x32Remainder (Delay, (UINT32) mMetronome->TickPeriod, - &Remainder); - if (Remainder != 0) { - NumberOfTicks += 1; + Frequency = GetPerformanceCounterProperties (&StartTick, &EndTick); + NumberOfTicks = MultThenDivU64x64x32 (Frequency, Delay, (UINT32)EFI_TIMER_PERIOD_SECONDS(1), &Remainder); + if (Remainder >= (UINTN)EFI_TIMER_PERIOD_SECONDS(1) / 2) { + NumberOfTicks++; } - NumberOfTicks += 1; - - while (NumberOfTicks != 0) { - - mMetronome->WaitForTick (mMetronome, 1); - + for ( ElapsedTick = 0, CurrentTick = GetPerformanceCounter() + ; ElapsedTick <= NumberOfTicks + ; ElapsedTick += GetElapsedTick (&CurrentTick, StartTick, EndTick) + ) { Status = This->Mem.Read (This, Width, Address, 1, Result); if (EFI_ERROR (Status)) { return Status; @@ -469,8 +666,6 @@ RootBridgeIoPollMem ( if ((*Result & Mask) == Value) { return EFI_SUCCESS; } - - NumberOfTicks -= 1; } } return EFI_TIMEOUT; @@ -523,6 +718,11 @@ RootBridgeIoPollIo ( EFI_STATUS Status; UINT64 NumberOfTicks; UINT32 Remainder; + UINT64 StartTick; + UINT64 EndTick; + UINT64 CurrentTick; + UINT64 ElapsedTick; + UINT64 Frequency; // // No matter what, always do a single poll. @@ -548,25 +748,18 @@ RootBridgeIoPollIo ( return EFI_SUCCESS; } else { - // - // Determine the proper # of metronome ticks to wait for polling the - // location. The number of ticks is Roundup (Delay / - // mMetronome->TickPeriod)+1 - // The "+1" to account for the possibility of the first tick being short - // because we started in the middle of a tick. + // NumberOfTicks = Frenquency * Delay / EFI_TIMER_PERIOD_SECONDS(1) // - NumberOfTicks = DivU64x32Remainder (Delay, (UINT32)mMetronome->TickPeriod, - &Remainder); - if (Remainder != 0) { - NumberOfTicks += 1; + Frequency = GetPerformanceCounterProperties (&StartTick, &EndTick); + NumberOfTicks = MultThenDivU64x64x32 (Frequency, Delay, (UINT32)EFI_TIMER_PERIOD_SECONDS(1), &Remainder); + if (Remainder >= (UINTN)EFI_TIMER_PERIOD_SECONDS(1) / 2) { + NumberOfTicks++; } - NumberOfTicks += 1; - - while (NumberOfTicks != 0) { - - mMetronome->WaitForTick (mMetronome, 1); - + for ( ElapsedTick = 0, CurrentTick = GetPerformanceCounter() + ; ElapsedTick <= NumberOfTicks + ; ElapsedTick += GetElapsedTick (&CurrentTick, StartTick, EndTick) + ) { Status = This->Io.Read (This, Width, Address, 1, Result); if (EFI_ERROR (Status)) { return Status; @@ -575,8 +768,6 @@ RootBridgeIoPollIo ( if ((*Result & Mask) == Value) { return EFI_SUCCESS; } - - NumberOfTicks -= 1; } } return EFI_TIMEOUT; @@ -620,13 +811,25 @@ RootBridgeIoMemRead ( ) { EFI_STATUS Status; + PCI_ROOT_BRIDGE_INSTANCE *RootBridge; + UINT64 Translation; Status = RootBridgeIoCheckParameter (This, MemOperation, Width, Address, Count, Buffer); if (EFI_ERROR (Status)) { return Status; } - return mCpuIo->Mem.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer); + + RootBridge = ROOT_BRIDGE_FROM_THIS (This); + Status = RootBridgeIoGetMemTranslationByAddress (RootBridge, Address, &Translation); + if (EFI_ERROR (Status)) { + return Status; + } + + // Address passed to CpuIo->Mem.Read needs to be a host address instead of + // device address. + return mCpuIo->Mem.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, + TO_HOST_ADDRESS (Address, Translation), Count, Buffer); } /** @@ -667,13 +870,25 @@ RootBridgeIoMemWrite ( ) { EFI_STATUS Status; + PCI_ROOT_BRIDGE_INSTANCE *RootBridge; + UINT64 Translation; Status = RootBridgeIoCheckParameter (This, MemOperation, Width, Address, Count, Buffer); if (EFI_ERROR (Status)) { return Status; } - return mCpuIo->Mem.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer); + + RootBridge = ROOT_BRIDGE_FROM_THIS (This); + Status = RootBridgeIoGetMemTranslationByAddress (RootBridge, Address, &Translation); + if (EFI_ERROR (Status)) { + return Status; + } + + // Address passed to CpuIo->Mem.Write needs to be a host address instead of + // device address. + return mCpuIo->Mem.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, + TO_HOST_ADDRESS (Address, Translation), Count, Buffer); } /** @@ -708,6 +923,8 @@ RootBridgeIoIoRead ( ) { EFI_STATUS Status; + PCI_ROOT_BRIDGE_INSTANCE *RootBridge; + Status = RootBridgeIoCheckParameter ( This, IoOperation, Width, Address, Count, Buffer @@ -715,7 +932,13 @@ RootBridgeIoIoRead ( if (EFI_ERROR (Status)) { return Status; } - return mCpuIo->Io.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer); + + RootBridge = ROOT_BRIDGE_FROM_THIS (This); + + // Address passed to CpuIo->Io.Read needs to be a host address instead of + // device address. + return mCpuIo->Io.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, + TO_HOST_ADDRESS (Address, RootBridge->Io.Translation), Count, Buffer); } /** @@ -750,6 +973,8 @@ RootBridgeIoIoWrite ( ) { EFI_STATUS Status; + PCI_ROOT_BRIDGE_INSTANCE *RootBridge; + Status = RootBridgeIoCheckParameter ( This, IoOperation, Width, Address, Count, Buffer @@ -757,7 +982,13 @@ RootBridgeIoIoWrite ( if (EFI_ERROR (Status)) { return Status; } - return mCpuIo->Io.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer); + + RootBridge = ROOT_BRIDGE_FROM_THIS (This); + + // Address passed to CpuIo->Io.Write needs to be a host address instead of + // device address. + return mCpuIo->Io.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, + TO_HOST_ADDRESS (Address, RootBridge->Io.Translation), Count, Buffer); } /** @@ -1036,11 +1267,36 @@ RootBridgeIoMap ( RootBridge = ROOT_BRIDGE_FROM_THIS (This); + if (mIoMmu != NULL) { + if (!RootBridge->DmaAbove4G) { + // + // Clear 64bit support + // + if (Operation > EfiPciOperationBusMasterCommonBuffer) { + Operation = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION) (Operation - EfiPciOperationBusMasterRead64); + } + } + Status = mIoMmu->Map ( + mIoMmu, + (EDKII_IOMMU_OPERATION) Operation, + HostAddress, + NumberOfBytes, + DeviceAddress, + Mapping + ); + return Status; + } + PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress; - if (!RootBridge->DmaAbove4G && ((PhysicalAddress + *NumberOfBytes) > SIZE_4GB)) { + if ((!RootBridge->DmaAbove4G || + (Operation != EfiPciOperationBusMasterRead64 && + Operation != EfiPciOperationBusMasterWrite64 && + Operation != EfiPciOperationBusMasterCommonBuffer64)) && + ((PhysicalAddress + *NumberOfBytes) > SIZE_4GB)) { + // - // If the root bridge can not handle performing DMA above 4GB but - // any part of the DMA transfer being mapped is above 4GB, then + // If the root bridge or the device cannot handle performing DMA above + // 4GB but any part of the DMA transfer being mapped is above 4GB, then // map the DMA transfer to a buffer below 4GB. // @@ -1153,8 +1409,18 @@ RootBridgeIoUnmap ( MAP_INFO *MapInfo; LIST_ENTRY *Link; PCI_ROOT_BRIDGE_INSTANCE *RootBridge; + EFI_STATUS Status; + + if (mIoMmu != NULL) { + Status = mIoMmu->Unmap ( + mIoMmu, + Mapping + ); + return Status; + } RootBridge = ROOT_BRIDGE_FROM_THIS (This); + // // See if the Map() operation associated with this Unmap() required a mapping // buffer. If a mapping buffer was not required, then this function simply @@ -1271,8 +1537,27 @@ RootBridgeIoAllocateBuffer ( RootBridge = ROOT_BRIDGE_FROM_THIS (This); + if (mIoMmu != NULL) { + if (!RootBridge->DmaAbove4G) { + // + // Clear DUAL_ADDRESS_CYCLE + // + Attributes &= ~((UINT64) EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE); + } + Status = mIoMmu->AllocateBuffer ( + mIoMmu, + Type, + MemoryType, + Pages, + HostAddress, + Attributes + ); + return Status; + } + AllocateType = AllocateAnyPages; - if (!RootBridge->DmaAbove4G) { + if (!RootBridge->DmaAbove4G || + (Attributes & EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) { // // Limit allocations to memory below 4GB // @@ -1314,6 +1599,17 @@ RootBridgeIoFreeBuffer ( OUT VOID *HostAddress ) { + EFI_STATUS Status; + + if (mIoMmu != NULL) { + Status = mIoMmu->FreeBuffer ( + mIoMmu, + Pages, + HostAddress + ); + return Status; + } + return gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress, Pages); } @@ -1457,20 +1753,19 @@ RootBridgeIoSetAttributes ( /** Retrieves the current resource settings of this PCI root bridge in the form - of a set of ACPI 2.0 resource descriptors. + of a set of ACPI resource descriptors. There are only two resource descriptor types from the ACPI Specification that may be used to describe the current resources allocated to a PCI root bridge. - These are the QWORD Address Space Descriptor (ACPI 2.0 Section 6.4.3.5.1), - and the End Tag (ACPI 2.0 Section 6.4.2.8). The QWORD Address Space - Descriptor can describe memory, I/O, and bus number ranges for dynamic or - fixed resources. The configuration of a PCI root bridge is described with one - or more QWORD Address Space Descriptors followed by an End Tag. + These are the QWORD Address Space Descriptor, and the End Tag. The QWORD + Address Space Descriptor can describe memory, I/O, and bus number ranges for + dynamic or fixed resources. The configuration of a PCI root bridge is described + with one or more QWORD Address Space Descriptors followed by an End Tag. @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. - @param[out] Resources A pointer to the ACPI 2.0 resource descriptors that + @param[out] Resources A pointer to the resource descriptors that describe the current configuration of this PCI root - bridge. The storage for the ACPI 2.0 resource + bridge. The storage for the resource descriptors is allocated by this function. The caller must treat the return buffer as read-only data, and the buffer must not be freed by the @@ -1513,9 +1808,17 @@ RootBridgeIoConfiguration ( Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3; + // According to UEFI 2.7, RootBridgeIo->Configuration should return address + // range in CPU view (host address), and ResAllocNode->Base is already a CPU + // view address (host address). Descriptor->AddrRangeMin = ResAllocNode->Base; Descriptor->AddrRangeMax = ResAllocNode->Base + ResAllocNode->Length - 1; Descriptor->AddrLen = ResAllocNode->Length; + Descriptor->AddrTranslationOffset = GetTranslationByResourceType ( + RootBridge, + ResAllocNode->Type + ); + switch (ResAllocNode->Type) { case TypeIo: