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