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