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