• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
GetBarResource(IN NON_DISCOVERABLE_PCI_DEVICE * Dev,IN UINT8 BarIndex,OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR ** Descriptor)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
PciIoPollMem(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT8 BarIndex,IN UINT64 Offset,IN UINT64 Mask,IN UINT64 Value,IN UINT64 Delay,OUT UINT64 * Result)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
PciIoPollIo(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT8 BarIndex,IN UINT64 Offset,IN UINT64 Mask,IN UINT64 Value,IN UINT64 Delay,OUT UINT64 * Result)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
PciIoMemRW(IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINTN Count,IN UINTN DstStride,IN VOID * Dst,IN UINTN SrcStride,OUT CONST VOID * Src)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
PciIoMemRead(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT8 BarIndex,IN UINT64 Offset,IN UINTN Count,IN OUT VOID * Buffer)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
PciIoMemWrite(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT8 BarIndex,IN UINT64 Offset,IN UINTN Count,IN OUT VOID * Buffer)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
PciIoIoRead(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT8 BarIndex,IN UINT64 Offset,IN UINTN Count,IN OUT VOID * Buffer)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
PciIoIoWrite(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT8 BarIndex,IN UINT64 Offset,IN UINTN Count,IN OUT VOID * Buffer)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
PciIoPciRead(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT32 Offset,IN UINTN Count,IN OUT VOID * Buffer)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
PciIoPciWrite(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT32 Offset,IN UINTN Count,IN OUT VOID * Buffer)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
PciIoCopyMem(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT8 DestBarIndex,IN UINT64 DestOffset,IN UINT8 SrcBarIndex,IN UINT64 SrcOffset,IN UINTN Count)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
CoherentPciIoMap(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,IN VOID * HostAddress,IN OUT UINTN * NumberOfBytes,OUT EFI_PHYSICAL_ADDRESS * DeviceAddress,OUT VOID ** Mapping)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
CoherentPciIoUnmap(IN EFI_PCI_IO_PROTOCOL * This,IN VOID * Mapping)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
CoherentPciIoAllocateBuffer(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_ALLOCATE_TYPE Type,IN EFI_MEMORY_TYPE MemoryType,IN UINTN Pages,OUT VOID ** HostAddress,IN UINT64 Attributes)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
CoherentPciIoFreeBuffer(IN EFI_PCI_IO_PROTOCOL * This,IN UINTN Pages,IN VOID * HostAddress)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
NonCoherentPciIoFreeBuffer(IN EFI_PCI_IO_PROTOCOL * This,IN UINTN Pages,IN VOID * HostAddress)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
NonCoherentPciIoAllocateBuffer(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_ALLOCATE_TYPE Type,IN EFI_MEMORY_TYPE MemoryType,IN UINTN Pages,OUT VOID ** HostAddress,IN UINT64 Attributes)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
NonCoherentPciIoMap(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,IN VOID * HostAddress,IN OUT UINTN * NumberOfBytes,OUT EFI_PHYSICAL_ADDRESS * DeviceAddress,OUT VOID ** Mapping)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
NonCoherentPciIoUnmap(IN EFI_PCI_IO_PROTOCOL * This,IN VOID * Mapping)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
PciIoFlush(IN EFI_PCI_IO_PROTOCOL * This)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
PciIoGetLocation(IN EFI_PCI_IO_PROTOCOL * This,OUT UINTN * SegmentNumber,OUT UINTN * BusNumber,OUT UINTN * DeviceNumber,OUT UINTN * FunctionNumber)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
PciIoAttributes(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,IN UINT64 Attributes,OUT UINT64 * Result OPTIONAL)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
PciIoGetBarAttributes(IN EFI_PCI_IO_PROTOCOL * This,IN UINT8 BarIndex,OUT UINT64 * Supports OPTIONAL,OUT VOID ** Resources OPTIONAL)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
PciIoSetBarAttributes(IN EFI_PCI_IO_PROTOCOL * This,IN UINT64 Attributes,IN UINT8 BarIndex,IN OUT UINT64 * Offset,IN OUT UINT64 * Length)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
InitializePciIoProtocol(NON_DISCOVERABLE_PCI_DEVICE * Dev)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