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
CpuIoCheckParameter(IN BOOLEAN MmioOperation,IN EFI_CPU_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINTN Count,IN VOID * Buffer)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
CpuMemoryServiceRead(IN EFI_CPU_IO2_PROTOCOL * This,IN EFI_CPU_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINTN Count,OUT VOID * Buffer)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
CpuMemoryServiceWrite(IN EFI_CPU_IO2_PROTOCOL * This,IN EFI_CPU_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINTN Count,IN VOID * Buffer)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
CpuIoServiceRead(IN EFI_CPU_IO2_PROTOCOL * This,IN EFI_CPU_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINTN Count,OUT VOID * Buffer)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
CpuIoServiceWrite(IN EFI_CPU_IO2_PROTOCOL * This,IN EFI_CPU_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINTN Count,IN VOID * Buffer)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
CpuIo2Initialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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 }
586