Home | History | Annotate | Download | only in NonDiscoverablePciDeviceDxe
      1 /** @file
      2 
      3   Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
      4   Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>
      5 
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "NonDiscoverablePciDeviceIo.h"
     17 
     18 #include <Library/DxeServicesTableLib.h>
     19 
     20 #include <IndustryStandard/Acpi.h>
     21 
     22 #include <Protocol/PciRootBridgeIo.h>
     23 
     24 typedef struct {
     25   EFI_PHYSICAL_ADDRESS            AllocAddress;
     26   VOID                            *HostAddress;
     27   EFI_PCI_IO_PROTOCOL_OPERATION   Operation;
     28   UINTN                           NumberOfBytes;
     29 } NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO;
     30 
     31 /**
     32   Get the resource associated with BAR number 'BarIndex'.
     33 
     34   @param  Dev           Point to the NON_DISCOVERABLE_PCI_DEVICE instance.
     35   @param  BarIndex      The BAR index of the standard PCI Configuration header to use as the
     36                         base address for the memory operation to perform.
     37   @param  Descriptor    Points to the address space descriptor
     38 **/
     39 STATIC
     40 EFI_STATUS
     41 GetBarResource (
     42   IN  NON_DISCOVERABLE_PCI_DEVICE         *Dev,
     43   IN  UINT8                               BarIndex,
     44   OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   **Descriptor
     45   )
     46 {
     47   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Desc;
     48 
     49   if (BarIndex < Dev->BarOffset) {
     50     return EFI_NOT_FOUND;
     51   }
     52 
     53   BarIndex -= (UINT8)Dev->BarOffset;
     54 
     55   for (Desc = Dev->Device->Resources;
     56        Desc->Desc != ACPI_END_TAG_DESCRIPTOR;
     57        Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {
     58 
     59     if (BarIndex == 0) {
     60       *Descriptor = Desc;
     61       return EFI_SUCCESS;
     62     }
     63 
     64     BarIndex -= 1;
     65   }
     66   return EFI_NOT_FOUND;
     67 }
     68 
     69 /**
     70   Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is
     71   satisfied or after a defined duration.
     72 
     73   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
     74   @param  Width                 Signifies the width of the memory or I/O operations.
     75   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
     76                                 base address for the memory operation to perform.
     77   @param  Offset                The offset within the selected BAR to start the memory operation.
     78   @param  Mask                  Mask used for the polling criteria.
     79   @param  Value                 The comparison value used for the polling exit criteria.
     80   @param  Delay                 The number of 100 ns units to poll.
     81   @param  Result                Pointer to the last value read from the memory location.
     82 
     83 **/
     84 STATIC
     85 EFI_STATUS
     86 EFIAPI
     87 PciIoPollMem (
     88   IN  EFI_PCI_IO_PROTOCOL         *This,
     89   IN  EFI_PCI_IO_PROTOCOL_WIDTH   Width,
     90   IN  UINT8                       BarIndex,
     91   IN  UINT64                      Offset,
     92   IN  UINT64                      Mask,
     93   IN  UINT64                      Value,
     94   IN  UINT64                      Delay,
     95   OUT UINT64                      *Result
     96   )
     97 {
     98   ASSERT (FALSE);
     99   return EFI_UNSUPPORTED;
    100 }
    101 
    102 /**
    103   Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is
    104   satisfied or after a defined duration.
    105 
    106   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    107   @param  Width                 Signifies the width of the memory or I/O operations.
    108   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
    109                                 base address for the memory operation to perform.
    110   @param  Offset                The offset within the selected BAR to start the memory operation.
    111   @param  Mask                  Mask used for the polling criteria.
    112   @param  Value                 The comparison value used for the polling exit criteria.
    113   @param  Delay                 The number of 100 ns units to poll.
    114   @param  Result                Pointer to the last value read from the memory location.
    115 
    116 **/
    117 STATIC
    118 EFI_STATUS
    119 EFIAPI
    120 PciIoPollIo (
    121   IN  EFI_PCI_IO_PROTOCOL         *This,
    122   IN  EFI_PCI_IO_PROTOCOL_WIDTH   Width,
    123   IN  UINT8                       BarIndex,
    124   IN  UINT64                      Offset,
    125   IN  UINT64                      Mask,
    126   IN  UINT64                      Value,
    127   IN  UINT64                      Delay,
    128   OUT UINT64                      *Result
    129   )
    130 {
    131   ASSERT (FALSE);
    132   return EFI_UNSUPPORTED;
    133 }
    134 
    135 /**
    136   Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
    137 
    138   @param  Width         Signifies the width of the memory or I/O operations.
    139   @param  Count         The number of memory or I/O operations to perform.
    140   @param  DstStride     The stride of the destination buffer.
    141   @param  Dst           For read operations, the destination buffer to store the results. For write
    142                         operations, the destination buffer to write data to.
    143   @param  SrcStride     The stride of the source buffer.
    144   @param  Src           For read operations, the source buffer to read data from. For write
    145                         operations, the source buffer to write data from.
    146 
    147   @retval EFI_SUCCESS            The data was read from or written to the PCI controller.
    148   @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.
    149 
    150 **/
    151 STATIC
    152 EFI_STATUS
    153 EFIAPI
    154 PciIoMemRW (
    155   IN  EFI_PCI_IO_PROTOCOL_WIDTH   Width,
    156   IN  UINTN                       Count,
    157   IN  UINTN                       DstStride,
    158   IN  VOID                        *Dst,
    159   IN  UINTN                       SrcStride,
    160   OUT CONST VOID                  *Src
    161   )
    162 {
    163   volatile UINT8             *Dst8;
    164   volatile UINT16            *Dst16;
    165   volatile UINT32            *Dst32;
    166   volatile CONST UINT8       *Src8;
    167   volatile CONST UINT16      *Src16;
    168   volatile CONST UINT32      *Src32;
    169 
    170   //
    171   // Loop for each iteration and move the data
    172   //
    173   switch (Width & 0x3) {
    174   case EfiPciWidthUint8:
    175     Dst8 = (UINT8 *)Dst;
    176     Src8 = (UINT8 *)Src;
    177     for (;Count > 0; Count--, Dst8 += DstStride, Src8 += SrcStride) {
    178       *Dst8 = *Src8;
    179     }
    180     break;
    181   case EfiPciWidthUint16:
    182     Dst16 = (UINT16 *)Dst;
    183     Src16 = (UINT16 *)Src;
    184     for (;Count > 0; Count--, Dst16 += DstStride, Src16 += SrcStride) {
    185       *Dst16 = *Src16;
    186     }
    187     break;
    188   case EfiPciWidthUint32:
    189     Dst32 = (UINT32 *)Dst;
    190     Src32 = (UINT32 *)Src;
    191     for (;Count > 0; Count--, Dst32 += DstStride, Src32 += SrcStride) {
    192       *Dst32 = *Src32;
    193     }
    194     break;
    195   default:
    196     return EFI_INVALID_PARAMETER;
    197   }
    198 
    199   return EFI_SUCCESS;
    200 }
    201 
    202 /**
    203   Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
    204 
    205   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    206   @param  Width                 Signifies the width of the memory or I/O operations.
    207   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
    208                                 base address for the memory or I/O operation to perform.
    209   @param  Offset                The offset within the selected BAR to start the memory or I/O operation.
    210   @param  Count                 The number of memory or I/O operations to perform.
    211   @param  Buffer                For read operations, the destination buffer to store the results. For write
    212                                 operations, the source buffer to write data from.
    213 
    214   @retval EFI_SUCCESS           The data was read from or written to the PCI controller.
    215   @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
    216   @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not
    217                                 valid for the PCI BAR specified by BarIndex.
    218   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
    219   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    220 
    221 **/
    222 STATIC
    223 EFI_STATUS
    224 EFIAPI
    225 PciIoMemRead (
    226   IN     EFI_PCI_IO_PROTOCOL          *This,
    227   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
    228   IN     UINT8                        BarIndex,
    229   IN     UINT64                       Offset,
    230   IN     UINTN                        Count,
    231   IN OUT VOID                         *Buffer
    232   )
    233 {
    234   NON_DISCOVERABLE_PCI_DEVICE         *Dev;
    235   UINTN                               AlignMask;
    236   VOID                                *Address;
    237   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Desc;
    238   EFI_STATUS                          Status;
    239 
    240   if (Buffer == NULL) {
    241     return EFI_INVALID_PARAMETER;
    242   }
    243 
    244   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
    245 
    246   //
    247   // Only allow accesses to the BARs we emulate
    248   //
    249   Status = GetBarResource (Dev, BarIndex, &Desc);
    250   if (EFI_ERROR (Status)) {
    251     return Status;
    252   }
    253 
    254   if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {
    255     return EFI_UNSUPPORTED;
    256   }
    257 
    258   Address = (VOID *)(UINTN)(Desc->AddrRangeMin + Offset);
    259   AlignMask = (1 << (Width & 0x03)) - 1;
    260   if ((UINTN)Address & AlignMask) {
    261     return EFI_INVALID_PARAMETER;
    262   }
    263 
    264   switch (Width) {
    265   case EfiPciIoWidthUint8:
    266   case EfiPciIoWidthUint16:
    267   case EfiPciIoWidthUint32:
    268   case EfiPciIoWidthUint64:
    269     return PciIoMemRW (Width, Count, 1, Buffer, 1, Address);
    270 
    271   case EfiPciIoWidthFifoUint8:
    272   case EfiPciIoWidthFifoUint16:
    273   case EfiPciIoWidthFifoUint32:
    274   case EfiPciIoWidthFifoUint64:
    275     return PciIoMemRW (Width, Count, 1, Buffer, 0, Address);
    276 
    277   case EfiPciIoWidthFillUint8:
    278   case EfiPciIoWidthFillUint16:
    279   case EfiPciIoWidthFillUint32:
    280   case EfiPciIoWidthFillUint64:
    281     return PciIoMemRW (Width, Count, 0, Buffer, 1, Address);
    282 
    283   default:
    284     break;
    285   }
    286   return EFI_INVALID_PARAMETER;
    287 }
    288 
    289 /**
    290   Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
    291 
    292   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    293   @param  Width                 Signifies the width of the memory or I/O operations.
    294   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
    295                                 base address for the memory or I/O operation to perform.
    296   @param  Offset                The offset within the selected BAR to start the memory or I/O operation.
    297   @param  Count                 The number of memory or I/O operations to perform.
    298   @param  Buffer                For read operations, the destination buffer to store the results. For write
    299                                 operations, the source buffer to write data from.
    300 
    301   @retval EFI_SUCCESS           The data was read from or written to the PCI controller.
    302   @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
    303   @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not
    304                                 valid for the PCI BAR specified by BarIndex.
    305   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
    306   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    307 
    308 **/
    309 STATIC
    310 EFI_STATUS
    311 EFIAPI
    312 PciIoMemWrite (
    313   IN     EFI_PCI_IO_PROTOCOL          *This,
    314   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
    315   IN     UINT8                        BarIndex,
    316   IN     UINT64                       Offset,
    317   IN     UINTN                        Count,
    318   IN OUT VOID                         *Buffer
    319   )
    320 {
    321   NON_DISCOVERABLE_PCI_DEVICE         *Dev;
    322   UINTN                               AlignMask;
    323   VOID                                *Address;
    324   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Desc;
    325   EFI_STATUS                          Status;
    326 
    327   if (Buffer == NULL) {
    328     return EFI_INVALID_PARAMETER;
    329   }
    330 
    331   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
    332 
    333   //
    334   // Only allow accesses to the BARs we emulate
    335   //
    336   Status = GetBarResource (Dev, BarIndex, &Desc);
    337   if (EFI_ERROR (Status)) {
    338     return Status;
    339   }
    340 
    341   if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {
    342     return EFI_UNSUPPORTED;
    343   }
    344 
    345   Address = (VOID *)(UINTN)(Desc->AddrRangeMin + Offset);
    346   AlignMask = (1 << (Width & 0x03)) - 1;
    347   if ((UINTN)Address & AlignMask) {
    348     return EFI_INVALID_PARAMETER;
    349   }
    350 
    351   switch (Width) {
    352   case EfiPciIoWidthUint8:
    353   case EfiPciIoWidthUint16:
    354   case EfiPciIoWidthUint32:
    355   case EfiPciIoWidthUint64:
    356     return PciIoMemRW (Width, Count, 1, Address, 1, Buffer);
    357 
    358   case EfiPciIoWidthFifoUint8:
    359   case EfiPciIoWidthFifoUint16:
    360   case EfiPciIoWidthFifoUint32:
    361   case EfiPciIoWidthFifoUint64:
    362     return PciIoMemRW (Width, Count, 0, Address, 1, Buffer);
    363 
    364   case EfiPciIoWidthFillUint8:
    365   case EfiPciIoWidthFillUint16:
    366   case EfiPciIoWidthFillUint32:
    367   case EfiPciIoWidthFillUint64:
    368     return PciIoMemRW (Width, Count, 1, Address, 0, Buffer);
    369 
    370   default:
    371     break;
    372   }
    373   return EFI_INVALID_PARAMETER;
    374 }
    375 
    376 /**
    377   Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
    378 
    379   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    380   @param  Width                 Signifies the width of the memory or I/O operations.
    381   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
    382                                 base address for the memory or I/O operation to perform.
    383   @param  Offset                The offset within the selected BAR to start the memory or I/O operation.
    384   @param  Count                 The number of memory or I/O operations to perform.
    385   @param  Buffer                For read operations, the destination buffer to store the results. For write
    386                                 operations, the source buffer to write data from.
    387 
    388 **/
    389 STATIC
    390 EFI_STATUS
    391 EFIAPI
    392 PciIoIoRead (
    393   IN EFI_PCI_IO_PROTOCOL              *This,
    394   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
    395   IN     UINT8                        BarIndex,
    396   IN     UINT64                       Offset,
    397   IN     UINTN                        Count,
    398   IN OUT VOID                         *Buffer
    399   )
    400 {
    401   ASSERT (FALSE);
    402   return EFI_UNSUPPORTED;
    403 }
    404 
    405 /**
    406   Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
    407 
    408   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    409   @param  Width                 Signifies the width of the memory or I/O operations.
    410   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
    411                                 base address for the memory or I/O operation to perform.
    412   @param  Offset                The offset within the selected BAR to start the memory or I/O operation.
    413   @param  Count                 The number of memory or I/O operations to perform.
    414   @param  Buffer                For read operations, the destination buffer to store the results. For write
    415                                 operations, the source buffer to write data from.
    416 
    417 **/
    418 STATIC
    419 EFI_STATUS
    420 EFIAPI
    421 PciIoIoWrite (
    422   IN     EFI_PCI_IO_PROTOCOL          *This,
    423   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
    424   IN     UINT8                        BarIndex,
    425   IN     UINT64                       Offset,
    426   IN     UINTN                        Count,
    427   IN OUT VOID                         *Buffer
    428   )
    429 {
    430   ASSERT (FALSE);
    431   return EFI_UNSUPPORTED;
    432 }
    433 
    434 /**
    435   Enable a PCI driver to access PCI config space.
    436 
    437   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    438   @param  Width                 Signifies the width of the memory or I/O operations.
    439   @param  Offset                The offset within the selected BAR to start the memory or I/O operation.
    440   @param  Count                 The number of memory or I/O operations to perform.
    441   @param  Buffer                For read operations, the destination buffer to store the results. For write
    442                                 operations, the source buffer to write data from.
    443 
    444 **/
    445 STATIC
    446 EFI_STATUS
    447 EFIAPI
    448 PciIoPciRead (
    449   IN     EFI_PCI_IO_PROTOCOL        *This,
    450   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
    451   IN     UINT32                     Offset,
    452   IN     UINTN                      Count,
    453   IN OUT VOID                       *Buffer
    454   )
    455 {
    456   NON_DISCOVERABLE_PCI_DEVICE   *Dev;
    457   VOID                          *Address;
    458   UINTN                         Length;
    459 
    460   if (Width < 0 || Width >= EfiPciIoWidthMaximum || Buffer == NULL) {
    461     return EFI_INVALID_PARAMETER;
    462   }
    463 
    464   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
    465   Address = (UINT8 *)&Dev->ConfigSpace + Offset;
    466   Length = Count << ((UINTN)Width & 0x3);
    467 
    468   if (Offset + Length > sizeof (Dev->ConfigSpace)) {
    469     //
    470     // Read all zeroes for config space accesses beyond the first
    471     // 64 bytes
    472     //
    473     Length -= sizeof (Dev->ConfigSpace) - Offset;
    474     ZeroMem ((UINT8 *)Buffer + sizeof (Dev->ConfigSpace) - Offset, Length);
    475 
    476     Count -= Length >> ((UINTN)Width & 0x3);
    477   }
    478   return PciIoMemRW (Width, Count, 1, Buffer, 1, Address);
    479 }
    480 
    481 /**
    482   Enable a PCI driver to access PCI config space.
    483 
    484   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    485   @param  Width                 Signifies the width of the memory or I/O operations.
    486   @param  Offset                The offset within the selected BAR to start the memory or I/O operation.
    487   @param  Count                 The number of memory or I/O operations to perform.
    488   @param  Buffer                For read operations, the destination buffer to store the results. For write
    489                                 operations, the source buffer to write data from
    490 
    491   @retval EFI_SUCCESS           The data was read from or written to the PCI controller.
    492   @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not
    493                                 valid for the PCI BAR specified by BarIndex.
    494   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    495 
    496 **/
    497 STATIC
    498 EFI_STATUS
    499 EFIAPI
    500 PciIoPciWrite (
    501   IN EFI_PCI_IO_PROTOCOL              *This,
    502   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
    503   IN     UINT32                       Offset,
    504   IN     UINTN                        Count,
    505   IN OUT VOID                         *Buffer
    506   )
    507 {
    508   NON_DISCOVERABLE_PCI_DEVICE   *Dev;
    509   VOID                          *Address;
    510 
    511   if (Width < 0 || Width >= EfiPciIoWidthMaximum || Buffer == NULL) {
    512     return EFI_INVALID_PARAMETER;
    513   }
    514 
    515   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
    516   Address = (UINT8 *)&Dev->ConfigSpace + Offset;
    517 
    518   if (Offset + (Count << ((UINTN)Width & 0x3)) > sizeof (Dev->ConfigSpace)) {
    519     return EFI_UNSUPPORTED;
    520   }
    521 
    522   return PciIoMemRW (Width, Count, 1, Address, 1, Buffer);
    523 }
    524 
    525 /**
    526   Enables a PCI driver to copy one region of PCI memory space to another region of PCI
    527   memory space.
    528 
    529   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    530   @param  Width                 Signifies the width of the memory operations.
    531   @param  DestBarIndex          The BAR index in the standard PCI Configuration header to use as the
    532                                 base address for the memory operation to perform.
    533   @param  DestOffset            The destination offset within the BAR specified by DestBarIndex to
    534                                 start the memory writes for the copy operation.
    535   @param  SrcBarIndex           The BAR index in the standard PCI Configuration header to use as the
    536                                 base address for the memory operation to perform.
    537   @param  SrcOffset             The source offset within the BAR specified by SrcBarIndex to start
    538                                 the memory reads for the copy operation.
    539   @param  Count                 The number of memory operations to perform. Bytes moved is Width
    540                                 size * Count, starting at DestOffset and SrcOffset.
    541 
    542 **/
    543 STATIC
    544 EFI_STATUS
    545 EFIAPI
    546 PciIoCopyMem (
    547   IN EFI_PCI_IO_PROTOCOL              *This,
    548   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
    549   IN     UINT8                        DestBarIndex,
    550   IN     UINT64                       DestOffset,
    551   IN     UINT8                        SrcBarIndex,
    552   IN     UINT64                       SrcOffset,
    553   IN     UINTN                        Count
    554   )
    555 {
    556   ASSERT (FALSE);
    557   return EFI_UNSUPPORTED;
    558 }
    559 
    560 /**
    561   Provides the PCI controller-specific addresses needed to access system memory.
    562 
    563   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    564   @param  Operation             Indicates if the bus master is going to read or write to system memory.
    565   @param  HostAddress           The system memory address to map to the PCI controller.
    566   @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes
    567                                 that were mapped.
    568   @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to
    569                                 access the hosts HostAddress.
    570   @param  Mapping               A resulting value to pass to Unmap().
    571 
    572   @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.
    573   @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.
    574   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    575   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
    576   @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.
    577 
    578 **/
    579 STATIC
    580 EFI_STATUS
    581 EFIAPI
    582 CoherentPciIoMap (
    583   IN     EFI_PCI_IO_PROTOCOL            *This,
    584   IN     EFI_PCI_IO_PROTOCOL_OPERATION  Operation,
    585   IN     VOID                           *HostAddress,
    586   IN OUT UINTN                          *NumberOfBytes,
    587   OUT    EFI_PHYSICAL_ADDRESS           *DeviceAddress,
    588   OUT    VOID                           **Mapping
    589   )
    590 {
    591   NON_DISCOVERABLE_PCI_DEVICE           *Dev;
    592   EFI_STATUS                            Status;
    593   NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO  *MapInfo;
    594 
    595   //
    596   // If HostAddress exceeds 4 GB, and this device does not support 64-bit DMA
    597   // addressing, we need to allocate a bounce buffer and copy over the data.
    598   //
    599   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
    600   if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&
    601       (UINTN)HostAddress + *NumberOfBytes > SIZE_4GB) {
    602 
    603     //
    604     // Bounce buffering is not possible for consistent mappings
    605     //
    606     if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {
    607       return EFI_UNSUPPORTED;
    608     }
    609 
    610     MapInfo = AllocatePool (sizeof *MapInfo);
    611     if (MapInfo == NULL) {
    612       return EFI_OUT_OF_RESOURCES;
    613     }
    614 
    615     MapInfo->AllocAddress = MAX_UINT32;
    616     MapInfo->HostAddress = HostAddress;
    617     MapInfo->Operation = Operation;
    618     MapInfo->NumberOfBytes = *NumberOfBytes;
    619 
    620     Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData,
    621                     EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
    622                     &MapInfo->AllocAddress);
    623     if (EFI_ERROR (Status)) {
    624       //
    625       // If we fail here, it is likely because the system has no memory below
    626       // 4 GB to begin with. There is not much we can do about that other than
    627       // fail the map request.
    628       //
    629       FreePool (MapInfo);
    630       return EFI_DEVICE_ERROR;
    631     }
    632     if (Operation == EfiPciIoOperationBusMasterRead) {
    633       gBS->CopyMem ((VOID *)(UINTN)MapInfo->AllocAddress, HostAddress,
    634              *NumberOfBytes);
    635     }
    636     *DeviceAddress = MapInfo->AllocAddress;
    637     *Mapping = MapInfo;
    638   } else {
    639     *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
    640     *Mapping = NULL;
    641   }
    642   return EFI_SUCCESS;
    643 }
    644 
    645 /**
    646   Completes the Map() operation and releases any corresponding resources.
    647 
    648   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    649   @param  Mapping               The mapping value returned from Map().
    650 
    651   @retval EFI_SUCCESS           The range was unmapped.
    652 
    653 **/
    654 STATIC
    655 EFI_STATUS
    656 EFIAPI
    657 CoherentPciIoUnmap (
    658   IN  EFI_PCI_IO_PROTOCOL          *This,
    659   IN  VOID                         *Mapping
    660   )
    661 {
    662   NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO  *MapInfo;
    663 
    664   MapInfo = Mapping;
    665   if (MapInfo != NULL) {
    666     if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {
    667       gBS->CopyMem (MapInfo->HostAddress, (VOID *)(UINTN)MapInfo->AllocAddress,
    668              MapInfo->NumberOfBytes);
    669     }
    670     gBS->FreePages (MapInfo->AllocAddress,
    671            EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes));
    672     FreePool (MapInfo);
    673   }
    674   return EFI_SUCCESS;
    675 }
    676 
    677 /**
    678   Allocates pages.
    679 
    680   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    681   @param  Type                  This parameter is not used and must be ignored.
    682   @param  MemoryType            The type of memory to allocate, EfiBootServicesData or
    683                                 EfiRuntimeServicesData.
    684   @param  Pages                 The number of pages to allocate.
    685   @param  HostAddress           A pointer to store the base system memory address of the
    686                                 allocated range.
    687   @param  Attributes            The requested bit mask of attributes for the allocated range.
    688 
    689   @retval EFI_SUCCESS           The requested memory pages were allocated.
    690   @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are
    691                                 MEMORY_WRITE_COMBINE and MEMORY_CACHED.
    692   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    693   @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
    694 
    695 **/
    696 STATIC
    697 EFI_STATUS
    698 EFIAPI
    699 CoherentPciIoAllocateBuffer (
    700   IN  EFI_PCI_IO_PROTOCOL         *This,
    701   IN  EFI_ALLOCATE_TYPE           Type,
    702   IN  EFI_MEMORY_TYPE             MemoryType,
    703   IN  UINTN                       Pages,
    704   OUT VOID                        **HostAddress,
    705   IN  UINT64                      Attributes
    706   )
    707 {
    708   NON_DISCOVERABLE_PCI_DEVICE       *Dev;
    709   EFI_PHYSICAL_ADDRESS              AllocAddress;
    710   EFI_ALLOCATE_TYPE                 AllocType;
    711   EFI_STATUS                        Status;
    712 
    713   if ((Attributes & ~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE |
    714                       EFI_PCI_ATTRIBUTE_MEMORY_CACHED)) != 0) {
    715     return EFI_UNSUPPORTED;
    716   }
    717 
    718   //
    719   // Allocate below 4 GB if the dual address cycle attribute has not
    720   // been set. If the system has no memory available below 4 GB, there
    721   // is little we can do except propagate the error.
    722   //
    723   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
    724   if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {
    725     AllocAddress = MAX_UINT32;
    726     AllocType = AllocateMaxAddress;
    727   } else {
    728     AllocType = AllocateAnyPages;
    729   }
    730 
    731   Status = gBS->AllocatePages (AllocType, MemoryType, Pages, &AllocAddress);
    732   if (!EFI_ERROR (Status)) {
    733     *HostAddress = (VOID *)(UINTN)AllocAddress;
    734   }
    735   return Status;
    736 }
    737 
    738 /**
    739   Frees memory that was allocated in function CoherentPciIoAllocateBuffer ().
    740 
    741   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    742   @param  Pages                 The number of pages to free.
    743   @param  HostAddress           The base system memory address of the allocated range.
    744 
    745   @retval EFI_SUCCESS           The requested memory pages were freed.
    746 
    747 **/
    748 STATIC
    749 EFI_STATUS
    750 EFIAPI
    751 CoherentPciIoFreeBuffer (
    752   IN  EFI_PCI_IO_PROTOCOL         *This,
    753   IN  UINTN                       Pages,
    754   IN  VOID                        *HostAddress
    755   )
    756 {
    757   FreePages (HostAddress, Pages);
    758   return EFI_SUCCESS;
    759 }
    760 
    761 /**
    762   Frees memory that was allocated in function NonCoherentPciIoAllocateBuffer ().
    763 
    764   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    765   @param  Pages                 The number of pages to free.
    766   @param  HostAddress           The base system memory address of the allocated range.
    767 
    768   @retval EFI_SUCCESS           The requested memory pages were freed.
    769   @retval others                The operation contain some errors.
    770 
    771 **/
    772 STATIC
    773 EFI_STATUS
    774 EFIAPI
    775 NonCoherentPciIoFreeBuffer (
    776   IN  EFI_PCI_IO_PROTOCOL         *This,
    777   IN  UINTN                       Pages,
    778   IN  VOID                        *HostAddress
    779   )
    780 {
    781   NON_DISCOVERABLE_PCI_DEVICE                   *Dev;
    782   LIST_ENTRY                                    *Entry;
    783   EFI_STATUS                                    Status;
    784   NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION   *Alloc;
    785   BOOLEAN                                       Found;
    786 
    787   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
    788 
    789   Found = FALSE;
    790   Alloc = NULL;
    791 
    792   //
    793   // Find the uncached allocation list entry associated
    794   // with this allocation
    795   //
    796   for (Entry = Dev->UncachedAllocationList.ForwardLink;
    797        Entry != &Dev->UncachedAllocationList;
    798        Entry = Entry->ForwardLink) {
    799 
    800     Alloc = BASE_CR (Entry, NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION, List);
    801     if (Alloc->HostAddress == HostAddress && Alloc->NumPages == Pages) {
    802       //
    803       // We are freeing the exact allocation we were given
    804       // before by AllocateBuffer()
    805       //
    806       Found = TRUE;
    807       break;
    808     }
    809   }
    810 
    811   if (!Found) {
    812     ASSERT_EFI_ERROR (EFI_NOT_FOUND);
    813     return EFI_NOT_FOUND;
    814   }
    815 
    816   RemoveEntryList (&Alloc->List);
    817 
    818   Status = gDS->SetMemorySpaceAttributes (
    819                   (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
    820                   EFI_PAGES_TO_SIZE (Pages),
    821                   Alloc->Attributes);
    822   if (EFI_ERROR (Status)) {
    823     goto FreeAlloc;
    824   }
    825 
    826   //
    827   // If we fail to restore the original attributes, it is better to leak the
    828   // memory than to return it to the heap
    829   //
    830   FreePages (HostAddress, Pages);
    831 
    832 FreeAlloc:
    833   FreePool (Alloc);
    834   return Status;
    835 }
    836 
    837 /**
    838   Allocates pages.
    839 
    840   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    841   @param  Type                  This parameter is not used and must be ignored.
    842   @param  MemoryType            The type of memory to allocate, EfiBootServicesData or
    843                                 EfiRuntimeServicesData.
    844   @param  Pages                 The number of pages to allocate.
    845   @param  HostAddress           A pointer to store the base system memory address of the
    846                                 allocated range.
    847   @param  Attributes            The requested bit mask of attributes for the allocated range.
    848 
    849   @retval EFI_SUCCESS           The requested memory pages were allocated.
    850   @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are
    851                                 MEMORY_WRITE_COMBINE and MEMORY_CACHED.
    852   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    853   @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
    854 
    855 **/
    856 STATIC
    857 EFI_STATUS
    858 EFIAPI
    859 NonCoherentPciIoAllocateBuffer (
    860   IN  EFI_PCI_IO_PROTOCOL         *This,
    861   IN  EFI_ALLOCATE_TYPE           Type,
    862   IN  EFI_MEMORY_TYPE             MemoryType,
    863   IN  UINTN                       Pages,
    864   OUT VOID                        **HostAddress,
    865   IN  UINT64                      Attributes
    866   )
    867 {
    868   NON_DISCOVERABLE_PCI_DEVICE                 *Dev;
    869   EFI_GCD_MEMORY_SPACE_DESCRIPTOR             GcdDescriptor;
    870   EFI_STATUS                                  Status;
    871   UINT64                                      MemType;
    872   NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION *Alloc;
    873   VOID                                        *AllocAddress;
    874 
    875   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
    876 
    877   Status = CoherentPciIoAllocateBuffer (This, Type, MemoryType, Pages,
    878              &AllocAddress, Attributes);
    879   if (EFI_ERROR (Status)) {
    880     return Status;
    881   }
    882 
    883   Status = gDS->GetMemorySpaceDescriptor (
    884                   (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,
    885                   &GcdDescriptor);
    886   if (EFI_ERROR (Status)) {
    887     goto FreeBuffer;
    888   }
    889 
    890   if ((GcdDescriptor.Capabilities & (EFI_MEMORY_WC | EFI_MEMORY_UC)) == 0) {
    891     Status = EFI_UNSUPPORTED;
    892     goto FreeBuffer;
    893   }
    894 
    895   //
    896   // Set the preferred memory attributes
    897   //
    898   if ((Attributes & EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE) != 0 ||
    899       (GcdDescriptor.Capabilities & EFI_MEMORY_UC) == 0) {
    900     //
    901     // Use write combining if it was requested, or if it is the only
    902     // type supported by the region.
    903     //
    904     MemType = EFI_MEMORY_WC;
    905   } else {
    906     MemType = EFI_MEMORY_UC;
    907   }
    908 
    909   Alloc = AllocatePool (sizeof *Alloc);
    910   if (Alloc == NULL) {
    911     goto FreeBuffer;
    912   }
    913 
    914   Alloc->HostAddress = AllocAddress;
    915   Alloc->NumPages = Pages;
    916   Alloc->Attributes = GcdDescriptor.Attributes;
    917 
    918   //
    919   // Record this allocation in the linked list, so we
    920   // can restore the memory space attributes later
    921   //
    922   InsertHeadList (&Dev->UncachedAllocationList, &Alloc->List);
    923 
    924   Status = gDS->SetMemorySpaceAttributes (
    925                   (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,
    926                   EFI_PAGES_TO_SIZE (Pages),
    927                   MemType);
    928   if (EFI_ERROR (Status)) {
    929     goto RemoveList;
    930   }
    931 
    932   Status = mCpu->FlushDataCache (
    933                    mCpu,
    934                    (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,
    935                    EFI_PAGES_TO_SIZE (Pages),
    936                    EfiCpuFlushTypeInvalidate);
    937   if (EFI_ERROR (Status)) {
    938     goto RemoveList;
    939   }
    940 
    941   *HostAddress = AllocAddress;
    942 
    943   return EFI_SUCCESS;
    944 
    945 RemoveList:
    946   RemoveEntryList (&Alloc->List);
    947   FreePool (Alloc);
    948 
    949 FreeBuffer:
    950   CoherentPciIoFreeBuffer (This, Pages, AllocAddress);
    951   return Status;
    952 }
    953 
    954 /**
    955   Provides the PCI controller-specific addresses needed to access system memory.
    956 
    957   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
    958   @param  Operation             Indicates if the bus master is going to read or write to system memory.
    959   @param  HostAddress           The system memory address to map to the PCI controller.
    960   @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes
    961                                 that were mapped.
    962   @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to
    963                                 access the hosts HostAddress.
    964   @param  Mapping               A resulting value to pass to Unmap().
    965 
    966   @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.
    967   @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.
    968   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    969   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
    970   @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.
    971 
    972 **/
    973 STATIC
    974 EFI_STATUS
    975 EFIAPI
    976 NonCoherentPciIoMap (
    977   IN     EFI_PCI_IO_PROTOCOL            *This,
    978   IN     EFI_PCI_IO_PROTOCOL_OPERATION  Operation,
    979   IN     VOID                           *HostAddress,
    980   IN OUT UINTN                          *NumberOfBytes,
    981   OUT    EFI_PHYSICAL_ADDRESS           *DeviceAddress,
    982   OUT    VOID                           **Mapping
    983   )
    984 {
    985   NON_DISCOVERABLE_PCI_DEVICE           *Dev;
    986   EFI_STATUS                            Status;
    987   NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO  *MapInfo;
    988   UINTN                                 AlignMask;
    989   VOID                                  *AllocAddress;
    990   EFI_GCD_MEMORY_SPACE_DESCRIPTOR       GcdDescriptor;
    991   BOOLEAN                               Bounce;
    992 
    993   MapInfo = AllocatePool (sizeof *MapInfo);
    994   if (MapInfo == NULL) {
    995     return EFI_OUT_OF_RESOURCES;
    996   }
    997 
    998   MapInfo->HostAddress = HostAddress;
    999   MapInfo->Operation = Operation;
   1000   MapInfo->NumberOfBytes = *NumberOfBytes;
   1001 
   1002   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
   1003 
   1004   //
   1005   // If this device does not support 64-bit DMA addressing, we need to allocate
   1006   // a bounce buffer and copy over the data in case HostAddress >= 4 GB.
   1007   //
   1008   Bounce = ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&
   1009             (UINTN)HostAddress + *NumberOfBytes > SIZE_4GB);
   1010 
   1011   if (!Bounce) {
   1012     switch (Operation) {
   1013     case EfiPciIoOperationBusMasterRead:
   1014     case EfiPciIoOperationBusMasterWrite:
   1015       //
   1016       // For streaming DMA, it is sufficient if the buffer is aligned to
   1017       // the CPUs DMA buffer alignment.
   1018       //
   1019       AlignMask = mCpu->DmaBufferAlignment - 1;
   1020       if ((((UINTN) HostAddress | *NumberOfBytes) & AlignMask) == 0) {
   1021         break;
   1022       }
   1023       // fall through
   1024 
   1025     case EfiPciIoOperationBusMasterCommonBuffer:
   1026       //
   1027       // Check whether the host address refers to an uncached mapping.
   1028       //
   1029       Status = gDS->GetMemorySpaceDescriptor (
   1030                       (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
   1031                       &GcdDescriptor);
   1032       if (EFI_ERROR (Status) ||
   1033           (GcdDescriptor.Attributes & (EFI_MEMORY_WB|EFI_MEMORY_WT)) != 0) {
   1034         Bounce = TRUE;
   1035       }
   1036       break;
   1037 
   1038     default:
   1039       ASSERT (FALSE);
   1040     }
   1041   }
   1042 
   1043   if (Bounce) {
   1044     if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {
   1045       Status = EFI_DEVICE_ERROR;
   1046       goto FreeMapInfo;
   1047     }
   1048 
   1049     Status = NonCoherentPciIoAllocateBuffer (This, AllocateAnyPages,
   1050                EfiBootServicesData, EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
   1051                &AllocAddress, EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE);
   1052     if (EFI_ERROR (Status)) {
   1053       goto FreeMapInfo;
   1054     }
   1055     MapInfo->AllocAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress;
   1056     if (Operation == EfiPciIoOperationBusMasterRead) {
   1057       gBS->CopyMem (AllocAddress, HostAddress, *NumberOfBytes);
   1058     }
   1059     *DeviceAddress = MapInfo->AllocAddress;
   1060   } else {
   1061     MapInfo->AllocAddress = 0;
   1062     *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
   1063 
   1064     //
   1065     // We are not using a bounce buffer: the mapping is sufficiently
   1066     // aligned to allow us to simply flush the caches. Note that cleaning
   1067     // the caches is necessary for both data directions:
   1068     // - for bus master read, we want the latest data to be present
   1069     //   in main memory
   1070     // - for bus master write, we don't want any stale dirty cachelines that
   1071     //   may be written back unexpectedly, and clobber the data written to
   1072     //   main memory by the device.
   1073     //
   1074     mCpu->FlushDataCache (mCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
   1075             *NumberOfBytes, EfiCpuFlushTypeWriteBack);
   1076   }
   1077 
   1078   *Mapping = MapInfo;
   1079   return EFI_SUCCESS;
   1080 
   1081 FreeMapInfo:
   1082   FreePool (MapInfo);
   1083 
   1084   return Status;
   1085 }
   1086 
   1087 /**
   1088   Completes the Map() operation and releases any corresponding resources.
   1089 
   1090   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
   1091   @param  Mapping               The mapping value returned from Map().
   1092 
   1093   @retval EFI_SUCCESS           The range was unmapped.
   1094 
   1095 **/
   1096 STATIC
   1097 EFI_STATUS
   1098 EFIAPI
   1099 NonCoherentPciIoUnmap (
   1100   IN  EFI_PCI_IO_PROTOCOL          *This,
   1101   IN  VOID                         *Mapping
   1102   )
   1103 {
   1104   NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO  *MapInfo;
   1105 
   1106   if (Mapping == NULL) {
   1107     return EFI_DEVICE_ERROR;
   1108   }
   1109 
   1110   MapInfo = Mapping;
   1111   if (MapInfo->AllocAddress != 0) {
   1112     //
   1113     // We are using a bounce buffer: copy back the data if necessary,
   1114     // and free the buffer.
   1115     //
   1116     if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {
   1117       gBS->CopyMem (MapInfo->HostAddress, (VOID *)(UINTN)MapInfo->AllocAddress,
   1118              MapInfo->NumberOfBytes);
   1119     }
   1120     NonCoherentPciIoFreeBuffer (This,
   1121       EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
   1122       (VOID *)(UINTN)MapInfo->AllocAddress);
   1123   } else {
   1124     //
   1125     // We are *not* using a bounce buffer: if this is a bus master write,
   1126     // we have to invalidate the caches so the CPU will see the uncached
   1127     // data written by the device.
   1128     //
   1129     if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {
   1130       mCpu->FlushDataCache (mCpu,
   1131               (EFI_PHYSICAL_ADDRESS)(UINTN)MapInfo->HostAddress,
   1132               MapInfo->NumberOfBytes, EfiCpuFlushTypeInvalidate);
   1133     }
   1134   }
   1135   FreePool (MapInfo);
   1136   return EFI_SUCCESS;
   1137 }
   1138 
   1139 /**
   1140   Flushes all PCI posted write transactions from a PCI host bridge to system memory.
   1141 
   1142   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
   1143 
   1144 **/
   1145 STATIC
   1146 EFI_STATUS
   1147 EFIAPI
   1148 PciIoFlush (
   1149   IN EFI_PCI_IO_PROTOCOL          *This
   1150   )
   1151 {
   1152   return EFI_SUCCESS;
   1153 }
   1154 
   1155 /**
   1156   Retrieves this PCI controller's current PCI bus number, device number, and function number.
   1157 
   1158   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
   1159   @param  SegmentNumber         The PCI controller's current PCI segment number.
   1160   @param  BusNumber             The PCI controller's current PCI bus number.
   1161   @param  DeviceNumber          The PCI controller's current PCI device number.
   1162   @param  FunctionNumber        The PCI controller's current PCI function number.
   1163 
   1164   @retval EFI_SUCCESS           The PCI controller location was returned.
   1165   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
   1166 
   1167 **/
   1168 STATIC
   1169 EFI_STATUS
   1170 EFIAPI
   1171 PciIoGetLocation (
   1172   IN   EFI_PCI_IO_PROTOCOL  *This,
   1173   OUT  UINTN                *SegmentNumber,
   1174   OUT  UINTN                *BusNumber,
   1175   OUT  UINTN                *DeviceNumber,
   1176   OUT  UINTN                *FunctionNumber
   1177   )
   1178 {
   1179   if (SegmentNumber == NULL ||
   1180       BusNumber == NULL ||
   1181       DeviceNumber == NULL ||
   1182       FunctionNumber == NULL) {
   1183     return EFI_INVALID_PARAMETER;
   1184   }
   1185 
   1186   *SegmentNumber  = 0;
   1187   *BusNumber      = 0xff;
   1188   *DeviceNumber   = 0;
   1189   *FunctionNumber = 0;
   1190 
   1191   return EFI_SUCCESS;
   1192 }
   1193 
   1194 /**
   1195   Performs an operation on the attributes that this PCI controller supports. The operations include
   1196   getting the set of supported attributes, retrieving the current attributes, setting the current
   1197   attributes, enabling attributes, and disabling attributes.
   1198 
   1199   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
   1200   @param  Operation             The operation to perform on the attributes for this PCI controller.
   1201   @param  Attributes            The mask of attributes that are used for Set, Enable, and Disable
   1202                                 operations.
   1203   @param  Result                A pointer to the result mask of attributes that are returned for the Get
   1204                                 and Supported operations.
   1205 
   1206   @retval EFI_SUCCESS           The operation on the PCI controller's attributes was completed.
   1207   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
   1208   @retval EFI_UNSUPPORTED       one or more of the bits set in
   1209                                 Attributes are not supported by this PCI controller or one of
   1210                                 its parent bridges when Operation is Set, Enable or Disable.
   1211 
   1212 **/
   1213 STATIC
   1214 EFI_STATUS
   1215 EFIAPI
   1216 PciIoAttributes (
   1217   IN  EFI_PCI_IO_PROTOCOL                      *This,
   1218   IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation,
   1219   IN  UINT64                                   Attributes,
   1220   OUT UINT64                                   *Result OPTIONAL
   1221   )
   1222 {
   1223   NON_DISCOVERABLE_PCI_DEVICE   *Dev;
   1224   BOOLEAN                       Enable;
   1225 
   1226   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
   1227 
   1228   Enable = FALSE;
   1229   switch (Operation) {
   1230   case EfiPciIoAttributeOperationGet:
   1231     if (Result == NULL) {
   1232       return EFI_INVALID_PARAMETER;
   1233     }
   1234     *Result = Dev->Attributes;
   1235     break;
   1236 
   1237   case EfiPciIoAttributeOperationSupported:
   1238     if (Result == NULL) {
   1239       return EFI_INVALID_PARAMETER;
   1240     }
   1241     *Result = EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE;
   1242     break;
   1243 
   1244   case EfiPciIoAttributeOperationEnable:
   1245     Attributes |= Dev->Attributes;
   1246   case EfiPciIoAttributeOperationSet:
   1247     Enable = ((~Dev->Attributes & Attributes) & EFI_PCI_DEVICE_ENABLE) != 0;
   1248     Dev->Attributes = Attributes;
   1249     break;
   1250 
   1251   case EfiPciIoAttributeOperationDisable:
   1252     Dev->Attributes &= ~Attributes;
   1253     break;
   1254 
   1255   default:
   1256     return EFI_INVALID_PARAMETER;
   1257   };
   1258 
   1259   //
   1260   // If we're setting any of the EFI_PCI_DEVICE_ENABLE bits, perform
   1261   // the device specific initialization now.
   1262   //
   1263   if (Enable && !Dev->Enabled && Dev->Device->Initialize != NULL) {
   1264     Dev->Device->Initialize (Dev->Device);
   1265     Dev->Enabled = TRUE;
   1266   }
   1267   return EFI_SUCCESS;
   1268 }
   1269 
   1270 /**
   1271   Gets the attributes that this PCI controller supports setting on a BAR using
   1272   SetBarAttributes(), and retrieves the list of resource descriptors for a BAR.
   1273 
   1274   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
   1275   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
   1276                                 base address for resource range. The legal range for this field is 0..5.
   1277   @param  Supports              A pointer to the mask of attributes that this PCI controller supports
   1278                                 setting for this BAR with SetBarAttributes().
   1279   @param  Resources             A pointer to the ACPI 2.0 resource descriptors that describe the current
   1280                                 configuration of this BAR of the PCI controller.
   1281 
   1282   @retval EFI_SUCCESS           If Supports is not NULL, then the attributes that the PCI
   1283                                 controller supports are returned in Supports. If Resources
   1284                                 is not NULL, then the ACPI 2.0 resource descriptors that the PCI
   1285                                 controller is currently using are returned in Resources.
   1286   @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
   1287   @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
   1288   @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to allocate
   1289                                 Resources.
   1290 
   1291 **/
   1292 STATIC
   1293 EFI_STATUS
   1294 EFIAPI
   1295 PciIoGetBarAttributes (
   1296   IN EFI_PCI_IO_PROTOCOL             *This,
   1297   IN  UINT8                          BarIndex,
   1298   OUT UINT64                         *Supports OPTIONAL,
   1299   OUT VOID                           **Resources OPTIONAL
   1300   )
   1301 {
   1302   NON_DISCOVERABLE_PCI_DEVICE       *Dev;
   1303   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
   1304   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc;
   1305   EFI_ACPI_END_TAG_DESCRIPTOR       *End;
   1306   EFI_STATUS                        Status;
   1307 
   1308   if (Supports == NULL && Resources == NULL) {
   1309     return EFI_INVALID_PARAMETER;
   1310   }
   1311 
   1312   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
   1313 
   1314   Status = GetBarResource (Dev, BarIndex, &BarDesc);
   1315   if (EFI_ERROR (Status)) {
   1316     return Status;
   1317   }
   1318 
   1319   //
   1320   // Don't expose any configurable attributes for our emulated BAR
   1321   //
   1322   if (Supports != NULL) {
   1323     *Supports = 0;
   1324   }
   1325 
   1326   if (Resources != NULL) {
   1327     Descriptor = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) +
   1328                                sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
   1329     if (Descriptor == NULL) {
   1330       return EFI_OUT_OF_RESOURCES;
   1331     }
   1332 
   1333     CopyMem (Descriptor, BarDesc, sizeof *Descriptor);
   1334 
   1335     End           = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);
   1336     End->Desc     = ACPI_END_TAG_DESCRIPTOR;
   1337     End->Checksum = 0;
   1338 
   1339     *Resources = Descriptor;
   1340   }
   1341   return EFI_SUCCESS;
   1342 }
   1343 
   1344 /**
   1345   Sets the attributes for a range of a BAR on a PCI controller.
   1346 
   1347   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
   1348   @param  Attributes            The mask of attributes to set for the resource range specified by
   1349                                 BarIndex, Offset, and Length.
   1350   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
   1351                                 base address for resource range. The legal range for this field is 0..5.
   1352   @param  Offset                A pointer to the BAR relative base address of the resource range to be
   1353                                 modified by the attributes specified by Attributes.
   1354   @param  Length                A pointer to the length of the resource range to be modified by the
   1355                                 attributes specified by Attributes.
   1356 **/
   1357 STATIC
   1358 EFI_STATUS
   1359 EFIAPI
   1360 PciIoSetBarAttributes (
   1361   IN     EFI_PCI_IO_PROTOCOL          *This,
   1362   IN     UINT64                       Attributes,
   1363   IN     UINT8                        BarIndex,
   1364   IN OUT UINT64                       *Offset,
   1365   IN OUT UINT64                       *Length
   1366   )
   1367 {
   1368   ASSERT (FALSE);
   1369   return EFI_UNSUPPORTED;
   1370 }
   1371 
   1372 STATIC CONST EFI_PCI_IO_PROTOCOL PciIoTemplate =
   1373 {
   1374   PciIoPollMem,
   1375   PciIoPollIo,
   1376   { PciIoMemRead, PciIoMemWrite },
   1377   { PciIoIoRead,  PciIoIoWrite },
   1378   { PciIoPciRead, PciIoPciWrite },
   1379   PciIoCopyMem,
   1380   CoherentPciIoMap,
   1381   CoherentPciIoUnmap,
   1382   CoherentPciIoAllocateBuffer,
   1383   CoherentPciIoFreeBuffer,
   1384   PciIoFlush,
   1385   PciIoGetLocation,
   1386   PciIoAttributes,
   1387   PciIoGetBarAttributes,
   1388   PciIoSetBarAttributes,
   1389   0,
   1390   0
   1391 };
   1392 
   1393 /**
   1394   Initialize PciIo Protocol.
   1395 
   1396   @param  Dev      Point to NON_DISCOVERABLE_PCI_DEVICE instance.
   1397 
   1398 **/
   1399 VOID
   1400 InitializePciIoProtocol (
   1401   NON_DISCOVERABLE_PCI_DEVICE     *Dev
   1402   )
   1403 {
   1404   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Desc;
   1405   INTN                                Idx;
   1406 
   1407   InitializeListHead (&Dev->UncachedAllocationList);
   1408 
   1409   Dev->ConfigSpace.Hdr.VendorId = PCI_ID_VENDOR_UNKNOWN;
   1410   Dev->ConfigSpace.Hdr.DeviceId = PCI_ID_DEVICE_DONTCARE;
   1411 
   1412   // Copy protocol structure
   1413   CopyMem(&Dev->PciIo, &PciIoTemplate, sizeof PciIoTemplate);
   1414 
   1415   if (Dev->Device->DmaType == NonDiscoverableDeviceDmaTypeNonCoherent) {
   1416     Dev->PciIo.AllocateBuffer   = NonCoherentPciIoAllocateBuffer;
   1417     Dev->PciIo.FreeBuffer       = NonCoherentPciIoFreeBuffer;
   1418     Dev->PciIo.Map              = NonCoherentPciIoMap;
   1419     Dev->PciIo.Unmap            = NonCoherentPciIoUnmap;
   1420   }
   1421 
   1422   if (CompareGuid (Dev->Device->Type, &gEdkiiNonDiscoverableAhciDeviceGuid)) {
   1423     Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_MASS_STORAGE_AHCI;
   1424     Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_MASS_STORAGE_SATADPA;
   1425     Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;
   1426     Dev->BarOffset = 5;
   1427   } else if (CompareGuid (Dev->Device->Type,
   1428                           &gEdkiiNonDiscoverableEhciDeviceGuid)) {
   1429     Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_EHCI;
   1430     Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
   1431     Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
   1432     Dev->BarOffset = 0;
   1433   } else if (CompareGuid (Dev->Device->Type,
   1434                           &gEdkiiNonDiscoverableNvmeDeviceGuid)) {
   1435     Dev->ConfigSpace.Hdr.ClassCode[0] = 0x2; // PCI_IF_NVMHCI
   1436     Dev->ConfigSpace.Hdr.ClassCode[1] = 0x8; // PCI_CLASS_MASS_STORAGE_NVM
   1437     Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;
   1438     Dev->BarOffset = 0;
   1439   } else if (CompareGuid (Dev->Device->Type,
   1440                           &gEdkiiNonDiscoverableOhciDeviceGuid)) {
   1441     Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_OHCI;
   1442     Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
   1443     Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
   1444     Dev->BarOffset = 0;
   1445   } else if (CompareGuid (Dev->Device->Type,
   1446                           &gEdkiiNonDiscoverableSdhciDeviceGuid)) {
   1447     Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care
   1448     Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_SUBCLASS_SD_HOST_CONTROLLER;
   1449     Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SYSTEM_PERIPHERAL;
   1450     Dev->BarOffset = 0;
   1451   } else if (CompareGuid (Dev->Device->Type,
   1452                           &gEdkiiNonDiscoverableXhciDeviceGuid)) {
   1453     Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_XHCI;
   1454     Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
   1455     Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
   1456     Dev->BarOffset = 0;
   1457   } else if (CompareGuid (Dev->Device->Type,
   1458                           &gEdkiiNonDiscoverableUhciDeviceGuid)) {
   1459     Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_UHCI;
   1460     Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
   1461     Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
   1462     Dev->BarOffset = 0;
   1463   } else if (CompareGuid (Dev->Device->Type,
   1464                           &gEdkiiNonDiscoverableUfsDeviceGuid)) {
   1465     Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care
   1466     Dev->ConfigSpace.Hdr.ClassCode[1] = 0x9; // UFS controller subclass;
   1467     Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;
   1468     Dev->BarOffset = 0;
   1469   } else {
   1470     ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
   1471   }
   1472 
   1473   //
   1474   // Iterate over the resources to populate the virtual BARs
   1475   //
   1476   Idx = Dev->BarOffset;
   1477   for (Desc = Dev->Device->Resources, Dev->BarCount = 0;
   1478        Desc->Desc != ACPI_END_TAG_DESCRIPTOR;
   1479        Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {
   1480 
   1481     ASSERT (Desc->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR);
   1482     ASSERT (Desc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM);
   1483 
   1484     if (Idx >= PCI_MAX_BARS ||
   1485         (Idx == PCI_MAX_BARS - 1 && Desc->AddrSpaceGranularity == 64)) {
   1486       DEBUG ((DEBUG_ERROR,
   1487         "%a: resource count exceeds number of emulated BARs\n",
   1488         __FUNCTION__));
   1489       ASSERT (FALSE);
   1490       break;
   1491     }
   1492 
   1493     Dev->ConfigSpace.Device.Bar[Idx] = (UINT32)Desc->AddrRangeMin;
   1494     Dev->BarCount++;
   1495 
   1496     if (Desc->AddrSpaceGranularity == 64) {
   1497       Dev->ConfigSpace.Device.Bar[Idx] |= 0x4;
   1498       Dev->ConfigSpace.Device.Bar[++Idx] = (UINT32)RShiftU64 (
   1499                                                      Desc->AddrRangeMin, 32);
   1500     }
   1501   }
   1502 }
   1503