1 /** @file
2   Produces the CPU I/O 2 Protocol.
3 
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
9 
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.
12 
13 **/
14 
15 #include "CpuIo2Dxe.h"
16 
17 //
18 // Handle for the CPU I/O 2 Protocol
19 //
20 EFI_HANDLE  mHandle = NULL;
21 
22 //
23 // CPU I/O 2 Protocol instance
24 //
25 EFI_CPU_IO2_PROTOCOL mCpuIo2 = {
26   {
27     CpuMemoryServiceRead,
28     CpuMemoryServiceWrite
29   },
30   {
31     CpuIoServiceRead,
32     CpuIoServiceWrite
33   }
34 };
35 
36 //
37 // Lookup table for increment values based on transfer widths
38 //
39 UINT8 mInStride[] = {
40   1, // EfiCpuIoWidthUint8
41   2, // EfiCpuIoWidthUint16
42   4, // EfiCpuIoWidthUint32
43   8, // EfiCpuIoWidthUint64
44   0, // EfiCpuIoWidthFifoUint8
45   0, // EfiCpuIoWidthFifoUint16
46   0, // EfiCpuIoWidthFifoUint32
47   0, // EfiCpuIoWidthFifoUint64
48   1, // EfiCpuIoWidthFillUint8
49   2, // EfiCpuIoWidthFillUint16
50   4, // EfiCpuIoWidthFillUint32
51   8  // EfiCpuIoWidthFillUint64
52 };
53 
54 //
55 // Lookup table for increment values based on transfer widths
56 //
57 UINT8 mOutStride[] = {
58   1, // EfiCpuIoWidthUint8
59   2, // EfiCpuIoWidthUint16
60   4, // EfiCpuIoWidthUint32
61   8, // EfiCpuIoWidthUint64
62   1, // EfiCpuIoWidthFifoUint8
63   2, // EfiCpuIoWidthFifoUint16
64   4, // EfiCpuIoWidthFifoUint32
65   8, // EfiCpuIoWidthFifoUint64
66   0, // EfiCpuIoWidthFillUint8
67   0, // EfiCpuIoWidthFillUint16
68   0, // EfiCpuIoWidthFillUint32
69   0  // EfiCpuIoWidthFillUint64
70 };
71 
72 /**
73   Check parameters to a CPU I/O 2 Protocol service request.
74 
75   The I/O operations are carried out exactly as requested. The caller is responsible
76   for satisfying any alignment and I/O width restrictions that a PI System on a
77   platform might require. For example on some platforms, width requests of
78   EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
79   be handled by the driver.
80 
81   @param[in] MmioOperation  TRUE for an MMIO operation, FALSE for I/O Port operation.
82   @param[in] Width          Signifies the width of the I/O or Memory operation.
83   @param[in] Address        The base address of the I/O operation.
84   @param[in] Count          The number of I/O operations to perform. The number of
85                             bytes moved is Width size * Count, starting at Address.
86   @param[in] Buffer         For read operations, the destination buffer to store the results.
87                             For write operations, the source buffer from which to write data.
88 
89   @retval EFI_SUCCESS            The parameters for this request pass the checks.
90   @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
91   @retval EFI_INVALID_PARAMETER  Buffer is NULL.
92   @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
93   @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
94                                  and Count is not valid for this PI system.
95 
96 **/
97 EFI_STATUS
CpuIoCheckParameter(IN BOOLEAN MmioOperation,IN EFI_CPU_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINTN Count,IN VOID * Buffer)98 CpuIoCheckParameter (
99   IN BOOLEAN                    MmioOperation,
100   IN EFI_CPU_IO_PROTOCOL_WIDTH  Width,
101   IN UINT64                     Address,
102   IN UINTN                      Count,
103   IN VOID                       *Buffer
104   )
105 {
106   UINT64  MaxCount;
107   UINT64  Limit;
108 
109   //
110   // Check to see if Buffer is NULL
111   //
112   if (Buffer == NULL) {
113     return EFI_INVALID_PARAMETER;
114   }
115 
116   //
117   // Check to see if Width is in the valid range
118   //
119   if ((UINT32)Width >= EfiCpuIoWidthMaximum) {
120     return EFI_INVALID_PARAMETER;
121   }
122 
123   //
124   // For FIFO type, the target address won't increase during the access,
125   // so treat Count as 1
126   //
127   if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) {
128     Count = 1;
129   }
130 
131   //
132   // Check to see if Width is in the valid range for I/O Port operations
133   //
134   Width = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
135   if (!MmioOperation && (Width == EfiCpuIoWidthUint64)) {
136     return EFI_INVALID_PARAMETER;
137   }
138 
139   //
140   // Check to see if Address is aligned
141   //
142   if ((Address & (UINT64)(mInStride[Width] - 1)) != 0) {
143     return EFI_UNSUPPORTED;
144   }
145 
146   //
147   // Check to see if any address associated with this transfer exceeds the maximum
148   // allowed address.  The maximum address implied by the parameters passed in is
149   // Address + Size * Count.  If the following condition is met, then the transfer
150   // is not supported.
151   //
152   //    Address + Size * Count > (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS) + 1
153   //
154   // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count
155   // can also be the maximum integer value supported by the CPU, this range
156   // check must be adjusted to avoid all oveflow conditions.
157   //
158   // The following form of the range check is equivalent but assumes that
159   // MAX_ADDRESS and MAX_IO_PORT_ADDRESS are of the form (2^n - 1).
160   //
161   Limit = (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS);
162   if (Count == 0) {
163     if (Address > Limit) {
164       return EFI_UNSUPPORTED;
165     }
166   } else {
167     MaxCount = RShiftU64 (Limit, Width);
168     if (MaxCount < (Count - 1)) {
169       return EFI_UNSUPPORTED;
170     }
171     if (Address > LShiftU64 (MaxCount - Count + 1, Width)) {
172       return EFI_UNSUPPORTED;
173     }
174   }
175 
176   //
177   // Check to see if Buffer is aligned
178   // (IA-32 allows UINT64 and INT64 data types to be 32-bit aligned.)
179   //
180   if (((UINTN)Buffer & ((MIN (sizeof (UINTN), mInStride[Width])  - 1))) != 0) {
181     return EFI_UNSUPPORTED;
182   }
183 
184   return EFI_SUCCESS;
185 }
186 
187 /**
188   Reads memory-mapped registers.
189 
190   The I/O operations are carried out exactly as requested. The caller is responsible
191   for satisfying any alignment and I/O width restrictions that a PI System on a
192   platform might require. For example on some platforms, width requests of
193   EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
194   be handled by the driver.
195 
196   If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
197   or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
198   each of the Count operations that is performed.
199 
200   If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
201   EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
202   incremented for each of the Count operations that is performed. The read or
203   write operation is performed Count times on the same Address.
204 
205   If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
206   EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
207   incremented for each of the Count operations that is performed. The read or
208   write operation is performed Count times from the first element of Buffer.
209 
210   @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.
211   @param[in]  Width    Signifies the width of the I/O or Memory operation.
212   @param[in]  Address  The base address of the I/O operation.
213   @param[in]  Count    The number of I/O operations to perform. The number of
214                        bytes moved is Width size * Count, starting at Address.
215   @param[out] Buffer   For read operations, the destination buffer to store the results.
216                        For write operations, the source buffer from which to write data.
217 
218   @retval EFI_SUCCESS            The data was read from or written to the PI system.
219   @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
220   @retval EFI_INVALID_PARAMETER  Buffer is NULL.
221   @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
222   @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
223                                  and Count is not valid for this PI system.
224 
225 **/
226 EFI_STATUS
227 EFIAPI
CpuMemoryServiceRead(IN EFI_CPU_IO2_PROTOCOL * This,IN EFI_CPU_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINTN Count,OUT VOID * Buffer)228 CpuMemoryServiceRead (
229   IN  EFI_CPU_IO2_PROTOCOL       *This,
230   IN  EFI_CPU_IO_PROTOCOL_WIDTH  Width,
231   IN  UINT64                     Address,
232   IN  UINTN                      Count,
233   OUT VOID                       *Buffer
234   )
235 {
236   EFI_STATUS                 Status;
237   UINT8                      InStride;
238   UINT8                      OutStride;
239   EFI_CPU_IO_PROTOCOL_WIDTH  OperationWidth;
240   UINT8                      *Uint8Buffer;
241 
242   Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
243   if (EFI_ERROR (Status)) {
244     return Status;
245   }
246 
247   //
248   // Select loop based on the width of the transfer
249   //
250   InStride = mInStride[Width];
251   OutStride = mOutStride[Width];
252   OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
253   for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
254     if (OperationWidth == EfiCpuIoWidthUint8) {
255       *Uint8Buffer = MmioRead8 ((UINTN)Address);
256     } else if (OperationWidth == EfiCpuIoWidthUint16) {
257       *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address);
258     } else if (OperationWidth == EfiCpuIoWidthUint32) {
259       *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address);
260     } else if (OperationWidth == EfiCpuIoWidthUint64) {
261       *((UINT64 *)Uint8Buffer) = MmioRead64 ((UINTN)Address);
262     }
263   }
264   return EFI_SUCCESS;
265 }
266 
267 /**
268   Writes memory-mapped registers.
269 
270   The I/O operations are carried out exactly as requested. The caller is responsible
271   for satisfying any alignment and I/O width restrictions that a PI System on a
272   platform might require. For example on some platforms, width requests of
273   EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
274   be handled by the driver.
275 
276   If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
277   or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
278   each of the Count operations that is performed.
279 
280   If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
281   EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
282   incremented for each of the Count operations that is performed. The read or
283   write operation is performed Count times on the same Address.
284 
285   If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
286   EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
287   incremented for each of the Count operations that is performed. The read or
288   write operation is performed Count times from the first element of Buffer.
289 
290   @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.
291   @param[in]  Width    Signifies the width of the I/O or Memory operation.
292   @param[in]  Address  The base address of the I/O operation.
293   @param[in]  Count    The number of I/O operations to perform. The number of
294                        bytes moved is Width size * Count, starting at Address.
295   @param[in]  Buffer   For read operations, the destination buffer to store the results.
296                        For write operations, the source buffer from which to write data.
297 
298   @retval EFI_SUCCESS            The data was read from or written to the PI system.
299   @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
300   @retval EFI_INVALID_PARAMETER  Buffer is NULL.
301   @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
302   @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
303                                  and Count is not valid for this PI system.
304 
305 **/
306 EFI_STATUS
307 EFIAPI
CpuMemoryServiceWrite(IN EFI_CPU_IO2_PROTOCOL * This,IN EFI_CPU_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINTN Count,IN VOID * Buffer)308 CpuMemoryServiceWrite (
309   IN EFI_CPU_IO2_PROTOCOL       *This,
310   IN EFI_CPU_IO_PROTOCOL_WIDTH  Width,
311   IN UINT64                     Address,
312   IN UINTN                      Count,
313   IN VOID                       *Buffer
314   )
315 {
316   EFI_STATUS                 Status;
317   UINT8                      InStride;
318   UINT8                      OutStride;
319   EFI_CPU_IO_PROTOCOL_WIDTH  OperationWidth;
320   UINT8                      *Uint8Buffer;
321 
322   Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
323   if (EFI_ERROR (Status)) {
324     return Status;
325   }
326 
327   //
328   // Select loop based on the width of the transfer
329   //
330   InStride = mInStride[Width];
331   OutStride = mOutStride[Width];
332   OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
333   for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
334     if (OperationWidth == EfiCpuIoWidthUint8) {
335       MmioWrite8 ((UINTN)Address, *Uint8Buffer);
336     } else if (OperationWidth == EfiCpuIoWidthUint16) {
337       MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
338     } else if (OperationWidth == EfiCpuIoWidthUint32) {
339       MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
340     } else if (OperationWidth == EfiCpuIoWidthUint64) {
341       MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer));
342     }
343   }
344   return EFI_SUCCESS;
345 }
346 
347 /**
348   Reads I/O registers.
349 
350   The I/O operations are carried out exactly as requested. The caller is responsible
351   for satisfying any alignment and I/O width restrictions that a PI System on a
352   platform might require. For example on some platforms, width requests of
353   EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
354   be handled by the driver.
355 
356   If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
357   or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
358   each of the Count operations that is performed.
359 
360   If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
361   EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
362   incremented for each of the Count operations that is performed. The read or
363   write operation is performed Count times on the same Address.
364 
365   If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
366   EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
367   incremented for each of the Count operations that is performed. The read or
368   write operation is performed Count times from the first element of Buffer.
369 
370   @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.
371   @param[in]  Width    Signifies the width of the I/O or Memory operation.
372   @param[in]  Address  The base address of the I/O operation.
373   @param[in]  Count    The number of I/O operations to perform. The number of
374                        bytes moved is Width size * Count, starting at Address.
375   @param[out] Buffer   For read operations, the destination buffer to store the results.
376                        For write operations, the source buffer from which to write data.
377 
378   @retval EFI_SUCCESS            The data was read from or written to the PI system.
379   @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
380   @retval EFI_INVALID_PARAMETER  Buffer is NULL.
381   @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
382   @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
383                                  and Count is not valid for this PI system.
384 
385 **/
386 EFI_STATUS
387 EFIAPI
CpuIoServiceRead(IN EFI_CPU_IO2_PROTOCOL * This,IN EFI_CPU_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINTN Count,OUT VOID * Buffer)388 CpuIoServiceRead (
389   IN  EFI_CPU_IO2_PROTOCOL       *This,
390   IN  EFI_CPU_IO_PROTOCOL_WIDTH  Width,
391   IN  UINT64                     Address,
392   IN  UINTN                      Count,
393   OUT VOID                       *Buffer
394   )
395 {
396   EFI_STATUS                 Status;
397   UINT8                      InStride;
398   UINT8                      OutStride;
399   EFI_CPU_IO_PROTOCOL_WIDTH  OperationWidth;
400   UINT8                      *Uint8Buffer;
401 
402   Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);
403   if (EFI_ERROR (Status)) {
404     return Status;
405   }
406 
407   //
408   // Select loop based on the width of the transfer
409   //
410   InStride = mInStride[Width];
411   OutStride = mOutStride[Width];
412   OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
413   for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
414     if (OperationWidth == EfiCpuIoWidthUint8) {
415       *Uint8Buffer = IoRead8 ((UINTN)Address);
416     } else if (OperationWidth == EfiCpuIoWidthUint16) {
417       *((UINT16 *)Uint8Buffer) = IoRead16 ((UINTN)Address);
418     } else if (OperationWidth == EfiCpuIoWidthUint32) {
419       *((UINT32 *)Uint8Buffer) = IoRead32 ((UINTN)Address);
420     }
421   }
422 
423   return EFI_SUCCESS;
424 }
425 
426 /**
427   Write I/O registers.
428 
429   The I/O operations are carried out exactly as requested. The caller is responsible
430   for satisfying any alignment and I/O width restrictions that a PI System on a
431   platform might require. For example on some platforms, width requests of
432   EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
433   be handled by the driver.
434 
435   If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
436   or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
437   each of the Count operations that is performed.
438 
439   If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
440   EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
441   incremented for each of the Count operations that is performed. The read or
442   write operation is performed Count times on the same Address.
443 
444   If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
445   EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
446   incremented for each of the Count operations that is performed. The read or
447   write operation is performed Count times from the first element of Buffer.
448 
449   @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.
450   @param[in]  Width    Signifies the width of the I/O or Memory operation.
451   @param[in]  Address  The base address of the I/O operation.
452   @param[in]  Count    The number of I/O operations to perform. The number of
453                        bytes moved is Width size * Count, starting at Address.
454   @param[in]  Buffer   For read operations, the destination buffer to store the results.
455                        For write operations, the source buffer from which to write data.
456 
457   @retval EFI_SUCCESS            The data was read from or written to the PI system.
458   @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
459   @retval EFI_INVALID_PARAMETER  Buffer is NULL.
460   @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
461   @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
462                                  and Count is not valid for this PI system.
463 
464 **/
465 EFI_STATUS
466 EFIAPI
CpuIoServiceWrite(IN EFI_CPU_IO2_PROTOCOL * This,IN EFI_CPU_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINTN Count,IN VOID * Buffer)467 CpuIoServiceWrite (
468   IN EFI_CPU_IO2_PROTOCOL       *This,
469   IN EFI_CPU_IO_PROTOCOL_WIDTH  Width,
470   IN UINT64                     Address,
471   IN UINTN                      Count,
472   IN VOID                       *Buffer
473   )
474 {
475   EFI_STATUS                 Status;
476   UINT8                      InStride;
477   UINT8                      OutStride;
478   EFI_CPU_IO_PROTOCOL_WIDTH  OperationWidth;
479   UINT8                      *Uint8Buffer;
480 
481   //
482   // Make sure the parameters are valid
483   //
484   Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);
485   if (EFI_ERROR (Status)) {
486     return Status;
487   }
488 
489   //
490   // Select loop based on the width of the transfer
491   //
492   InStride = mInStride[Width];
493   OutStride = mOutStride[Width];
494   OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
495   for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
496     if (OperationWidth == EfiCpuIoWidthUint8) {
497       IoWrite8 ((UINTN)Address, *Uint8Buffer);
498     } else if (OperationWidth == EfiCpuIoWidthUint16) {
499       IoWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
500     } else if (OperationWidth == EfiCpuIoWidthUint32) {
501       IoWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
502     }
503   }
504 
505   return EFI_SUCCESS;
506 }
507 
508 /**
509   The user Entry Point for module CpuIo2Dxe. The user code starts with this function.
510 
511   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
512   @param[in] SystemTable    A pointer to the EFI System Table.
513 
514   @retval EFI_SUCCESS       The entry point is executed successfully.
515   @retval other             Some error occurs when executing this entry point.
516 
517 **/
518 EFI_STATUS
519 EFIAPI
CpuIo2Initialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)520 CpuIo2Initialize (
521   IN EFI_HANDLE        ImageHandle,
522   IN EFI_SYSTEM_TABLE  *SystemTable
523   )
524 {
525   EFI_STATUS Status;
526 
527   ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiCpuIo2ProtocolGuid);
528   Status = gBS->InstallMultipleProtocolInterfaces (
529                   &mHandle,
530                   &gEfiCpuIo2ProtocolGuid, &mCpuIo2,
531                   NULL
532                   );
533   ASSERT_EFI_ERROR (Status);
534 
535   return Status;
536 }
537