2 Produces the CPU I/O PPI.
4 Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 // Instance of CPU I/O PPI
20 EFI_PEI_CPU_IO_PPI gCpuIoPpi
= {
48 // PPI Descriptor used to install the CPU I/O PPI
50 EFI_PEI_PPI_DESCRIPTOR gPpiList
= {
51 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
52 &gEfiPeiCpuIoPpiInstalledGuid
,
57 // Lookup table for increment values based on transfer widths
60 1, // EfiPeiCpuIoWidthUint8
61 2, // EfiPeiCpuIoWidthUint16
62 4, // EfiPeiCpuIoWidthUint32
63 8, // EfiPeiCpuIoWidthUint64
64 0, // EfiPeiCpuIoWidthFifoUint8
65 0, // EfiPeiCpuIoWidthFifoUint16
66 0, // EfiPeiCpuIoWidthFifoUint32
67 0, // EfiPeiCpuIoWidthFifoUint64
68 1, // EfiPeiCpuIoWidthFillUint8
69 2, // EfiPeiCpuIoWidthFillUint16
70 4, // EfiPeiCpuIoWidthFillUint32
71 8 // EfiPeiCpuIoWidthFillUint64
75 // Lookup table for increment values based on transfer widths
77 UINT8 mOutStride
[] = {
78 1, // EfiPeiCpuIoWidthUint8
79 2, // EfiPeiCpuIoWidthUint16
80 4, // EfiPeiCpuIoWidthUint32
81 8, // EfiPeiCpuIoWidthUint64
82 1, // EfiPeiCpuIoWidthFifoUint8
83 2, // EfiPeiCpuIoWidthFifoUint16
84 4, // EfiPeiCpuIoWidthFifoUint32
85 8, // EfiPeiCpuIoWidthFifoUint64
86 0, // EfiPeiCpuIoWidthFillUint8
87 0, // EfiPeiCpuIoWidthFillUint16
88 0, // EfiPeiCpuIoWidthFillUint32
89 0 // EfiPeiCpuIoWidthFillUint64
93 Check parameters to a CPU I/O PPI service request.
95 @param[in] MmioOperation TRUE for an MMIO operation, FALSE for I/O Port operation.
96 @param[in] Width The width of the access. Enumerated in bytes.
97 @param[in] Address The physical address of the access.
98 @param[in] Count The number of accesses to perform.
99 @param[in] Buffer A pointer to the buffer of data.
101 @retval EFI_SUCCESS The parameters for this request pass the checks.
102 @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system.
103 @retval EFI_INVALID_PARAMETER Buffer is NULL.
104 @retval EFI_UNSUPPORTED The address range specified by Address, Width,
105 and Count is not valid for this EFI system.
109 CpuIoCheckParameter (
110 IN BOOLEAN MmioOperation
,
111 IN EFI_PEI_CPU_IO_PPI_WIDTH Width
,
121 // Check to see if Buffer is NULL
123 if (Buffer
== NULL
) {
124 return EFI_INVALID_PARAMETER
;
128 // Check to see if Width is in the valid range
130 if ((UINT32
)Width
>= EfiPeiCpuIoWidthMaximum
) {
131 return EFI_INVALID_PARAMETER
;
135 // For FIFO type, the target address won't increase during the access,
136 // so treat Count as 1
138 if (Width
>= EfiPeiCpuIoWidthFifoUint8
&& Width
<= EfiPeiCpuIoWidthFifoUint64
) {
143 // Check to see if Width is in the valid range for I/O Port operations
145 Width
= (EFI_PEI_CPU_IO_PPI_WIDTH
) (Width
& 0x03);
146 if (!MmioOperation
&& (Width
== EfiPeiCpuIoWidthUint64
)) {
147 return EFI_INVALID_PARAMETER
;
151 // Check to see if any address associated with this transfer exceeds the maximum
152 // allowed address. The maximum address implied by the parameters passed in is
153 // Address + Size * Count. If the following condition is met, then the transfer
156 // Address + Size * Count > (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS) + 1
158 // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count
159 // can also be the maximum integer value supported by the CPU, this range
160 // check must be adjusted to avoid all overflow conditions.
162 // The following form of the range check is equivalent but assumes that
163 // MAX_ADDRESS and MAX_IO_PORT_ADDRESS are of the form (2^n - 1).
165 Limit
= (MmioOperation
? MAX_ADDRESS
: MAX_IO_PORT_ADDRESS
);
167 if (Address
> Limit
) {
168 return EFI_UNSUPPORTED
;
171 MaxCount
= RShiftU64 (Limit
, Width
);
172 if (MaxCount
< (Count
- 1)) {
173 return EFI_UNSUPPORTED
;
175 if (Address
> LShiftU64 (MaxCount
- Count
+ 1, Width
)) {
176 return EFI_UNSUPPORTED
;
184 Reads memory-mapped registers.
186 @param[in] PeiServices An indirect pointer to the PEI Services Table
187 published by the PEI Foundation.
188 @param[in] This Pointer to local data for the interface.
189 @param[in] Width The width of the access. Enumerated in bytes.
190 @param[in] Address The physical address of the access.
191 @param[in] Count The number of accesses to perform.
192 @param[out] Buffer A pointer to the buffer of data.
194 @retval EFI_SUCCESS The function completed successfully.
195 @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system.
196 @retval EFI_INVALID_PARAMETER Buffer is NULL.
197 @retval EFI_UNSUPPORTED The address range specified by Address, Width,
198 and Count is not valid for this EFI system.
203 CpuMemoryServiceRead (
204 IN CONST EFI_PEI_SERVICES
**PeiServices
,
205 IN CONST EFI_PEI_CPU_IO_PPI
*This
,
206 IN EFI_PEI_CPU_IO_PPI_WIDTH Width
,
215 EFI_PEI_CPU_IO_PPI_WIDTH OperationWidth
;
219 Status
= CpuIoCheckParameter (TRUE
, Width
, Address
, Count
, Buffer
);
220 if (EFI_ERROR (Status
)) {
225 // Select loop based on the width of the transfer
227 InStride
= mInStride
[Width
];
228 OutStride
= mOutStride
[Width
];
229 OperationWidth
= (EFI_PEI_CPU_IO_PPI_WIDTH
) (Width
& 0x03);
230 Aligned
= (BOOLEAN
)(((UINTN
)Buffer
& (mInStride
[OperationWidth
] - 1)) == 0x00);
231 for (Uint8Buffer
= Buffer
; Count
> 0; Address
+= InStride
, Uint8Buffer
+= OutStride
, Count
--) {
232 if (OperationWidth
== EfiPeiCpuIoWidthUint8
) {
233 *Uint8Buffer
= MmioRead8 ((UINTN
)Address
);
234 } else if (OperationWidth
== EfiPeiCpuIoWidthUint16
) {
236 *((UINT16
*)Uint8Buffer
) = MmioRead16 ((UINTN
)Address
);
238 WriteUnaligned16 ((UINT16
*)Uint8Buffer
, MmioRead16 ((UINTN
)Address
));
240 } else if (OperationWidth
== EfiPeiCpuIoWidthUint32
) {
242 *((UINT32
*)Uint8Buffer
) = MmioRead32 ((UINTN
)Address
);
244 WriteUnaligned32 ((UINT32
*)Uint8Buffer
, MmioRead32 ((UINTN
)Address
));
246 } else if (OperationWidth
== EfiPeiCpuIoWidthUint64
) {
248 *((UINT64
*)Uint8Buffer
) = MmioRead64 ((UINTN
)Address
);
250 WriteUnaligned64 ((UINT64
*)Uint8Buffer
, MmioRead64 ((UINTN
)Address
));
258 Writes memory-mapped registers.
260 @param[in] PeiServices An indirect pointer to the PEI Services Table
261 published by the PEI Foundation.
262 @param[in] This Pointer to local data for the interface.
263 @param[in] Width The width of the access. Enumerated in bytes.
264 @param[in] Address The physical address of the access.
265 @param[in] Count The number of accesses to perform.
266 @param[in] Buffer A pointer to the buffer of data.
268 @retval EFI_SUCCESS The function completed successfully.
269 @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system.
270 @retval EFI_INVALID_PARAMETER Buffer is NULL.
271 @retval EFI_UNSUPPORTED The address range specified by Address, Width,
272 and Count is not valid for this EFI system.
277 CpuMemoryServiceWrite (
278 IN CONST EFI_PEI_SERVICES
**PeiServices
,
279 IN CONST EFI_PEI_CPU_IO_PPI
*This
,
280 IN EFI_PEI_CPU_IO_PPI_WIDTH Width
,
289 EFI_PEI_CPU_IO_PPI_WIDTH OperationWidth
;
293 Status
= CpuIoCheckParameter (TRUE
, Width
, Address
, Count
, Buffer
);
294 if (EFI_ERROR (Status
)) {
299 // Select loop based on the width of the transfer
301 InStride
= mInStride
[Width
];
302 OutStride
= mOutStride
[Width
];
303 OperationWidth
= (EFI_PEI_CPU_IO_PPI_WIDTH
) (Width
& 0x03);
304 Aligned
= (BOOLEAN
)(((UINTN
)Buffer
& (mInStride
[OperationWidth
] - 1)) == 0x00);
305 for (Uint8Buffer
= Buffer
; Count
> 0; Address
+= InStride
, Uint8Buffer
+= OutStride
, Count
--) {
306 if (OperationWidth
== EfiPeiCpuIoWidthUint8
) {
307 MmioWrite8 ((UINTN
)Address
, *Uint8Buffer
);
308 } else if (OperationWidth
== EfiPeiCpuIoWidthUint16
) {
310 MmioWrite16 ((UINTN
)Address
, *((UINT16
*)Uint8Buffer
));
312 MmioWrite16 ((UINTN
)Address
, ReadUnaligned16 ((UINT16
*)Uint8Buffer
));
314 } else if (OperationWidth
== EfiPeiCpuIoWidthUint32
) {
316 MmioWrite32 ((UINTN
)Address
, *((UINT32
*)Uint8Buffer
));
318 MmioWrite32 ((UINTN
)Address
, ReadUnaligned32 ((UINT32
*)Uint8Buffer
));
320 } else if (OperationWidth
== EfiPeiCpuIoWidthUint64
) {
322 MmioWrite64 ((UINTN
)Address
, *((UINT64
*)Uint8Buffer
));
324 MmioWrite64 ((UINTN
)Address
, ReadUnaligned64 ((UINT64
*)Uint8Buffer
));
334 @param[in] PeiServices An indirect pointer to the PEI Services Table
335 published by the PEI Foundation.
336 @param[in] This Pointer to local data for the interface.
337 @param[in] Width The width of the access. Enumerated in bytes.
338 @param[in] Address The physical address of the access.
339 @param[in] Count The number of accesses to perform.
340 @param[out] Buffer A pointer to the buffer of data.
342 @retval EFI_SUCCESS The function completed successfully.
343 @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system.
344 @retval EFI_INVALID_PARAMETER Buffer is NULL.
345 @retval EFI_UNSUPPORTED The address range specified by Address, Width,
346 and Count is not valid for this EFI system.
352 IN CONST EFI_PEI_SERVICES
**PeiServices
,
353 IN CONST EFI_PEI_CPU_IO_PPI
*This
,
354 IN EFI_PEI_CPU_IO_PPI_WIDTH Width
,
363 EFI_PEI_CPU_IO_PPI_WIDTH OperationWidth
;
367 Status
= CpuIoCheckParameter (FALSE
, Width
, Address
, Count
, Buffer
);
368 if (EFI_ERROR (Status
)) {
373 // Select loop based on the width of the transfer
375 InStride
= mInStride
[Width
];
376 OutStride
= mOutStride
[Width
];
377 OperationWidth
= (EFI_PEI_CPU_IO_PPI_WIDTH
) (Width
& 0x03);
378 Aligned
= (BOOLEAN
)(((UINTN
)Buffer
& (mInStride
[OperationWidth
] - 1)) == 0x00);
379 for (Uint8Buffer
= Buffer
; Count
> 0; Address
+= InStride
, Uint8Buffer
+= OutStride
, Count
--) {
380 if (OperationWidth
== EfiPeiCpuIoWidthUint8
) {
381 *Uint8Buffer
= IoRead8 ((UINTN
)Address
);
382 } else if (OperationWidth
== EfiPeiCpuIoWidthUint16
) {
384 *((UINT16
*)Uint8Buffer
) = IoRead16 ((UINTN
)Address
);
386 WriteUnaligned16 ((UINT16
*)Uint8Buffer
, IoRead16 ((UINTN
)Address
));
388 } else if (OperationWidth
== EfiPeiCpuIoWidthUint32
) {
390 *((UINT32
*)Uint8Buffer
) = IoRead32 ((UINTN
)Address
);
392 WriteUnaligned32 ((UINT32
*)Uint8Buffer
, IoRead32 ((UINTN
)Address
));
403 @param[in] PeiServices An indirect pointer to the PEI Services Table
404 published by the PEI Foundation.
405 @param[in] This Pointer to local data for the interface.
406 @param[in] Width The width of the access. Enumerated in bytes.
407 @param[in] Address The physical address of the access.
408 @param[in] Count The number of accesses to perform.
409 @param[in] Buffer A pointer to the buffer of data.
411 @retval EFI_SUCCESS The function completed successfully.
412 @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system.
413 @retval EFI_INVALID_PARAMETER Buffer is NULL.
414 @retval EFI_UNSUPPORTED The address range specified by Address, Width,
415 and Count is not valid for this EFI system.
421 IN CONST EFI_PEI_SERVICES
**PeiServices
,
422 IN CONST EFI_PEI_CPU_IO_PPI
*This
,
423 IN EFI_PEI_CPU_IO_PPI_WIDTH Width
,
432 EFI_PEI_CPU_IO_PPI_WIDTH OperationWidth
;
437 // Make sure the parameters are valid
439 Status
= CpuIoCheckParameter (FALSE
, Width
, Address
, Count
, Buffer
);
440 if (EFI_ERROR (Status
)) {
445 // Select loop based on the width of the transfer
447 InStride
= mInStride
[Width
];
448 OutStride
= mOutStride
[Width
];
449 OperationWidth
= (EFI_PEI_CPU_IO_PPI_WIDTH
) (Width
& 0x03);
450 Aligned
= (BOOLEAN
)(((UINTN
)Buffer
& (mInStride
[OperationWidth
] - 1)) == 0x00);
451 for (Uint8Buffer
= (UINT8
*)Buffer
; Count
> 0; Address
+= InStride
, Uint8Buffer
+= OutStride
, Count
--) {
452 if (OperationWidth
== EfiPeiCpuIoWidthUint8
) {
453 IoWrite8 ((UINTN
)Address
, *Uint8Buffer
);
454 } else if (OperationWidth
== EfiPeiCpuIoWidthUint16
) {
456 IoWrite16 ((UINTN
)Address
, *((UINT16
*)Uint8Buffer
));
458 IoWrite16 ((UINTN
)Address
, ReadUnaligned16 ((UINT16
*)Uint8Buffer
));
460 } else if (OperationWidth
== EfiPeiCpuIoWidthUint32
) {
462 IoWrite32 ((UINTN
)Address
, *((UINT32
*)Uint8Buffer
));
464 IoWrite32 ((UINTN
)Address
, ReadUnaligned32 ((UINT32
*)Uint8Buffer
));
473 8-bit I/O read operations.
475 @param[in] PeiServices An indirect pointer to the PEI Services Table published
476 by the PEI Foundation.
477 @param[in] This Pointer to local data for the interface.
478 @param[in] Address The physical address of the access.
480 @return An 8-bit value returned from the I/O space.
485 IN CONST EFI_PEI_SERVICES
**PeiServices
,
486 IN CONST EFI_PEI_CPU_IO_PPI
*This
,
490 return IoRead8 ((UINTN
)Address
);
494 16-bit I/O read operations.
496 @param[in] PeiServices An indirect pointer to the PEI Services Table published
497 by the PEI Foundation.
498 @param[in] This Pointer to local data for the interface.
499 @param[in] Address The physical address of the access.
501 @return A 16-bit value returned from the I/O space.
507 IN CONST EFI_PEI_SERVICES
**PeiServices
,
508 IN CONST EFI_PEI_CPU_IO_PPI
*This
,
512 return IoRead16 ((UINTN
)Address
);
516 32-bit I/O read operations.
518 @param[in] PeiServices An indirect pointer to the PEI Services Table published
519 by the PEI Foundation.
520 @param[in] This Pointer to local data for the interface.
521 @param[in] Address The physical address of the access.
523 @return A 32-bit value returned from the I/O space.
529 IN CONST EFI_PEI_SERVICES
**PeiServices
,
530 IN CONST EFI_PEI_CPU_IO_PPI
*This
,
534 return IoRead32 ((UINTN
)Address
);
538 64-bit I/O read operations.
540 @param[in] PeiServices An indirect pointer to the PEI Services Table published
541 by the PEI Foundation.
542 @param[in] This Pointer to local data for the interface.
543 @param[in] Address The physical address of the access.
545 @return A 64-bit value returned from the I/O space.
551 IN CONST EFI_PEI_SERVICES
**PeiServices
,
552 IN CONST EFI_PEI_CPU_IO_PPI
*This
,
556 return IoRead64 ((UINTN
)Address
);
560 8-bit I/O write operations.
562 @param[in] PeiServices An indirect pointer to the PEI Services Table published
563 by the PEI Foundation.
564 @param[in] This Pointer to local data for the interface.
565 @param[in] Address The physical address of the access.
566 @param[in] Data The data to write.
572 IN CONST EFI_PEI_SERVICES
**PeiServices
,
573 IN CONST EFI_PEI_CPU_IO_PPI
*This
,
578 IoWrite8 ((UINTN
)Address
, Data
);
582 16-bit I/O write operations.
584 @param[in] PeiServices An indirect pointer to the PEI Services Table published
585 by the PEI Foundation.
586 @param[in] This Pointer to local data for the interface.
587 @param[in] Address The physical address of the access.
588 @param[in] Data The data to write.
594 IN CONST EFI_PEI_SERVICES
**PeiServices
,
595 IN CONST EFI_PEI_CPU_IO_PPI
*This
,
600 IoWrite16 ((UINTN
)Address
, Data
);
604 32-bit I/O write operations.
606 @param[in] PeiServices An indirect pointer to the PEI Services Table published
607 by the PEI Foundation.
608 @param[in] This Pointer to local data for the interface.
609 @param[in] Address The physical address of the access.
610 @param[in] Data The data to write.
616 IN CONST EFI_PEI_SERVICES
**PeiServices
,
617 IN CONST EFI_PEI_CPU_IO_PPI
*This
,
622 IoWrite32 ((UINTN
)Address
, Data
);
626 64-bit I/O write operations.
628 @param[in] PeiServices An indirect pointer to the PEI Services Table published
629 by the PEI Foundation.
630 @param[in] This Pointer to local data for the interface.
631 @param[in] Address The physical address of the access.
632 @param[in] Data The data to write.
638 IN CONST EFI_PEI_SERVICES
**PeiServices
,
639 IN CONST EFI_PEI_CPU_IO_PPI
*This
,
644 IoWrite64 ((UINTN
)Address
, Data
);
648 8-bit memory read operations.
650 @param[in] PeiServices An indirect pointer to the PEI Services Table published
651 by the PEI Foundation.
652 @param[in] This Pointer to local data for the interface.
653 @param[in] Address The physical address of the access.
655 @return An 8-bit value returned from the memory space.
661 IN CONST EFI_PEI_SERVICES
**PeiServices
,
662 IN CONST EFI_PEI_CPU_IO_PPI
*This
,
666 return MmioRead8 ((UINTN
)Address
);
670 16-bit memory read operations.
672 @param[in] PeiServices An indirect pointer to the PEI Services Table published
673 by the PEI Foundation.
674 @param[in] This Pointer to local data for the interface.
675 @param[in] Address The physical address of the access.
677 @return A 16-bit value returned from the memory space.
683 IN CONST EFI_PEI_SERVICES
**PeiServices
,
684 IN CONST EFI_PEI_CPU_IO_PPI
*This
,
688 return MmioRead16 ((UINTN
)Address
);
692 32-bit memory read operations.
694 @param[in] PeiServices An indirect pointer to the PEI Services Table published
695 by the PEI Foundation.
696 @param[in] This Pointer to local data for the interface.
697 @param[in] Address The physical address of the access.
699 @return A 32-bit value returned from the memory space.
705 IN CONST EFI_PEI_SERVICES
**PeiServices
,
706 IN CONST EFI_PEI_CPU_IO_PPI
*This
,
710 return MmioRead32 ((UINTN
)Address
);
714 64-bit memory read operations.
716 @param[in] PeiServices An indirect pointer to the PEI Services Table published
717 by the PEI Foundation.
718 @param[in] This Pointer to local data for the interface.
719 @param[in] Address The physical address of the access.
721 @return A 64-bit value returned from the memory space.
727 IN CONST EFI_PEI_SERVICES
**PeiServices
,
728 IN CONST EFI_PEI_CPU_IO_PPI
*This
,
732 return MmioRead64 ((UINTN
)Address
);
736 8-bit memory write operations.
738 @param[in] PeiServices An indirect pointer to the PEI Services Table published
739 by the PEI Foundation.
740 @param[in] This Pointer to local data for the interface.
741 @param[in] Address The physical address of the access.
742 @param[in] Data The data to write.
748 IN CONST EFI_PEI_SERVICES
**PeiServices
,
749 IN CONST EFI_PEI_CPU_IO_PPI
*This
,
754 MmioWrite8 ((UINTN
)Address
, Data
);
758 16-bit memory write operations.
760 @param[in] PeiServices An indirect pointer to the PEI Services Table published
761 by the PEI Foundation.
762 @param[in] This Pointer to local data for the interface.
763 @param[in] Address The physical address of the access.
764 @param[in] Data The data to write.
770 IN CONST EFI_PEI_SERVICES
**PeiServices
,
771 IN CONST EFI_PEI_CPU_IO_PPI
*This
,
776 MmioWrite16 ((UINTN
)Address
, Data
);
780 32-bit memory write operations.
782 @param[in] PeiServices An indirect pointer to the PEI Services Table published
783 by the PEI Foundation.
784 @param[in] This Pointer to local data for the interface.
785 @param[in] Address The physical address of the access.
786 @param[in] Data The data to write.
792 IN CONST EFI_PEI_SERVICES
**PeiServices
,
793 IN CONST EFI_PEI_CPU_IO_PPI
*This
,
798 MmioWrite32 ((UINTN
)Address
, Data
);
802 64-bit memory write operations.
804 @param[in] PeiServices An indirect pointer to the PEI Services Table published
805 by the PEI Foundation.
806 @param[in] This Pointer to local data for the interface.
807 @param[in] Address The physical address of the access.
808 @param[in] Data The data to write.
814 IN CONST EFI_PEI_SERVICES
**PeiServices
,
815 IN CONST EFI_PEI_CPU_IO_PPI
*This
,
820 MmioWrite64 ((UINTN
)Address
, Data
);
824 The Entry point of the CPU I/O PEIM
826 This function is the Entry point of the CPU I/O PEIM which installs CpuIoPpi.
828 @param[in] FileHandle Pointer to image file handle.
829 @param[in] PeiServices Pointer to PEI Services Table
831 @retval EFI_SUCCESS CPU I/O PPI successfully installed
837 IN EFI_PEI_FILE_HANDLE FileHandle
,
838 IN CONST EFI_PEI_SERVICES
**PeiServices
844 // Register so it will be automatically shadowed to memory
846 Status
= PeiServicesRegisterForShadow (FileHandle
);
849 // Make CpuIo pointer in PeiService table point to gCpuIoPpi
851 (*((EFI_PEI_SERVICES
**)PeiServices
))->CpuIo
= &gCpuIoPpi
;
853 if (Status
== EFI_ALREADY_STARTED
) {
855 // Shadow completed and running from memory
857 DEBUG ((EFI_D_INFO
, "CpuIO PPI has been loaded into memory. Reinstalled PPI=0x%x\n", &gCpuIoPpi
));
859 Status
= PeiServicesInstallPpi (&gPpiList
);
860 ASSERT_EFI_ERROR (Status
);