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