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