2 Uses the services of the I/O Library to produce the CPU I/O Protocol
4 Copyright (c) 2004 - 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
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.
17 #include <Protocol/CpuIo.h>
19 #include <Library/BaseLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/IoLib.h>
22 #include <Library/UefiBootServicesTableLib.h>
24 #define MAX_IO_PORT_ADDRESS 0xFFFF
27 // Function Prototypes
31 CpuMemoryServiceRead (
32 IN EFI_CPU_IO_PROTOCOL
*This
,
33 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
41 CpuMemoryServiceWrite (
42 IN EFI_CPU_IO_PROTOCOL
*This
,
43 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
52 IN EFI_CPU_IO_PROTOCOL
*This
,
53 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
62 IN EFI_CPU_IO_PROTOCOL
*This
,
63 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
70 // Handle for the CPU I/O Protocol
72 EFI_HANDLE mHandle
= NULL
;
75 // CPU I/O Protocol inatance
77 EFI_CPU_IO_PROTOCOL mCpuIo
= {
89 // Lookup table for increment values based on transfer widths
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
107 // Lookup table for increment values based on transfer widths
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
125 Check parameters to a CPU I/O Protocol service request.
127 @param Width Signifies the width of the I/O or Memory operation.
128 @param Address The base address of the I/O or Memory operation.
129 @param Count The number of I/O or Memory operations to perform.
130 The number of bytes moved is Width size * Count, starting at Address.
131 @param Buffer For read operations, the destination buffer to store the results.
132 For write operations, the source buffer from which to write data.
133 @param MmioOperation TRUE for an MMIO operation, FALSE for I/O Port operation.
135 @retval EFI_SUCCESS The parameters for this request pass the checks.
136 @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is not valid.
137 @retval EFI_UNSUPPORTED The address range specified by Address, Width, and Count exceeds Limit.
138 The Buffer is not aligned for the given Width.
142 CpuIoCheckParameter (
143 IN BOOLEAN MmioOperation
,
144 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
154 // Check to see if Buffer is NULL
156 if (Buffer
== NULL
) {
157 return EFI_INVALID_PARAMETER
;
161 // Check to see if Width is in the valid range
163 if (Width
< 0 || Width
>= EfiCpuIoWidthMaximum
) {
164 return EFI_INVALID_PARAMETER
;
168 // For FIFO type, the target address won't increase during the access,
169 // so treat Count as 1
171 if (Width
>= EfiCpuIoWidthFifoUint8
&& Width
<= EfiCpuIoWidthFifoUint64
) {
176 // Check to see if Width is in the valid range for I/O Port operations
178 Width
= Width
& 0x03;
179 if (!MmioOperation
&& (Width
== EfiCpuIoWidthUint64
)) {
180 return EFI_INVALID_PARAMETER
;
184 // Check to see if any address associated with this transfer exceeds the maximum
185 // allowed address. The maximum address implied by the parameters passed in is
186 // Address + Size * Count. If the following condition is met, then the transfer
189 // Address + Size * Count > (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS) + 1
191 // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count
192 // can also be the maximum integer value supported by the CPU, this range
193 // check must be adjusted to avoid all oveflow conditions.
195 // The follwing form of the range check is equivalent but assumes that
196 // MAX_ADDRESS and MAX_IO_PORT_ADDRESS are of the form (2^n - 1).
198 Limit
= (MmioOperation
? MAX_ADDRESS
: MAX_IO_PORT_ADDRESS
);
200 if (Address
> Limit
) {
201 return EFI_UNSUPPORTED
;
204 MaxCount
= RShiftU64 (Limit
, Width
);
205 if (MaxCount
< (Count
- 1)) {
206 return EFI_UNSUPPORTED
;
208 if (Address
> LShiftU64 (MaxCount
- Count
+ 1, Width
)) {
209 return EFI_UNSUPPORTED
;
214 // Check to see if Buffer is alligned
216 if (((UINTN
)Buffer
& (mInStride
[Width
] - 1)) != 0) {
217 return EFI_UNSUPPORTED
;
224 Reads memory-mapped registers.
226 @param This A pointer to the EFI_CPU_IO_PROTOCOL instance.
227 @param Width Signifies the width of the I/O or Memory operation.
228 @param Address The base address of the I/O or Memoryoperation.
229 @param Count The number of I/O or Memory operations to perform.
230 The number of bytes moved is Width size * Count, starting at Address.
231 @param Buffer For read operations, the destination buffer to store the results.
232 For write operations, the source buffer from which to write data.
234 @retval EFI_SUCCESS The data was read from or written to the EFI system.
235 @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system.Or Buffer is NULL.
236 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
237 Or,The address range specified by Address, Width, and Count is not valid for this EFI system.
242 CpuMemoryServiceRead (
243 IN EFI_CPU_IO_PROTOCOL
*This
,
244 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
253 EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth
;
256 Status
= CpuIoCheckParameter (TRUE
, Width
, Address
, Count
, Buffer
);
257 if (EFI_ERROR (Status
)) {
262 // Select loop based on the width of the transfer
264 InStride
= mInStride
[Width
];
265 OutStride
= mOutStride
[Width
];
266 OperationWidth
= Width
& 0x03;
267 for (Uint8Buffer
= Buffer
; Count
> 0; Address
+= InStride
, Uint8Buffer
+= OutStride
, Count
--) {
268 if (OperationWidth
== EfiCpuIoWidthUint8
) {
269 *Uint8Buffer
= MmioRead8 ((UINTN
)Address
);
270 } else if (OperationWidth
== EfiCpuIoWidthUint16
) {
271 *((UINT16
*)Uint8Buffer
) = MmioRead16 ((UINTN
)Address
);
272 } else if (OperationWidth
== EfiCpuIoWidthUint32
) {
273 *((UINT32
*)Uint8Buffer
) = MmioRead32 ((UINTN
)Address
);
274 } else if (OperationWidth
== EfiCpuIoWidthUint64
) {
275 *((UINT64
*)Uint8Buffer
) = MmioRead64 ((UINTN
)Address
);
282 Writes memory-mapped registers.
284 @param This A pointer to the EFI_CPU_IO_PROTOCOL instance.
285 @param Width Signifies the width of the I/O or Memory operation.
286 @param Address The base address of the I/O or Memoryoperation.
287 @param Count The number of I/O or Memory operations to perform.
288 The number of bytes moved is Width size * Count, starting at Address.
289 @param Buffer For read operations, the destination buffer to store the results.
290 For write operations, the source buffer from which to write data.
292 @retval EFI_SUCCESS The data was read from or written to the EFI system.
293 @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system.Or Buffer is NULL.
294 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
295 Or,The address range specified by Address, Width, and Count is not valid for this EFI system.
300 CpuMemoryServiceWrite (
301 IN EFI_CPU_IO_PROTOCOL
*This
,
302 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
311 EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth
;
314 Status
= CpuIoCheckParameter (TRUE
, Width
, Address
, Count
, Buffer
);
315 if (EFI_ERROR (Status
)) {
320 // Select loop based on the width of the transfer
322 InStride
= mInStride
[Width
];
323 OutStride
= mOutStride
[Width
];
324 OperationWidth
= Width
& 0x03;
325 for (Uint8Buffer
= Buffer
; Count
> 0; Address
+= InStride
, Uint8Buffer
+= OutStride
, Count
--) {
326 if (OperationWidth
== EfiCpuIoWidthUint8
) {
327 MmioWrite8 ((UINTN
)Address
, *Uint8Buffer
);
328 } else if (OperationWidth
== EfiCpuIoWidthUint16
) {
329 MmioWrite16 ((UINTN
)Address
, *((UINT16
*)Uint8Buffer
));
330 } else if (OperationWidth
== EfiCpuIoWidthUint32
) {
331 MmioWrite32 ((UINTN
)Address
, *((UINT32
*)Uint8Buffer
));
332 } else if (OperationWidth
== EfiCpuIoWidthUint64
) {
333 MmioWrite64 ((UINTN
)Address
, *((UINT64
*)Uint8Buffer
));
342 @param This A pointer to the EFI_CPU_IO_PROTOCOL instance.
343 @param Width Signifies the width of the I/O or Memory operation.
344 @param Address The base address of the I/O or Memoryoperation.
345 @param Count The number of I/O or Memory operations to perform.
346 The number of bytes moved is Width size * Count, starting at Address.
347 @param Buffer For read operations, the destination buffer to store the results.
348 For write operations, the source buffer from which to write data.
350 @retval EFI_SUCCESS The data was read from or written to the EFI system.
351 @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system.Or Buffer is NULL.
352 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
353 Or,The address range specified by Address, Width, and Count is not valid for this EFI system.
359 IN EFI_CPU_IO_PROTOCOL
*This
,
360 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
369 EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth
;
372 Status
= CpuIoCheckParameter (FALSE
, Width
, Address
, Count
, Buffer
);
373 if (EFI_ERROR (Status
)) {
378 // Select loop based on the width of the transfer
380 InStride
= mInStride
[Width
];
381 OutStride
= mOutStride
[Width
];
382 OperationWidth
= Width
& 0x03;
383 for (Uint8Buffer
= Buffer
; Count
> 0; Address
+= InStride
, Uint8Buffer
+= OutStride
, Count
--) {
384 if (OperationWidth
== EfiCpuIoWidthUint8
) {
385 *Uint8Buffer
= IoRead8 ((UINTN
)Address
);
386 } else if (OperationWidth
== EfiCpuIoWidthUint16
) {
387 *((UINT16
*)Uint8Buffer
) = IoRead16 ((UINTN
)Address
);
388 } else if (OperationWidth
== EfiCpuIoWidthUint32
) {
389 *((UINT32
*)Uint8Buffer
) = IoRead32 ((UINTN
)Address
);
399 @param This A pointer to the EFI_CPU_IO_PROTOCOL instance.
400 @param Width Signifies the width of the I/O or Memory operation.
401 @param Address The base address of the I/O or Memoryoperation.
402 @param Count The number of I/O or Memory operations to perform.
403 The number of bytes moved is Width size * Count, starting at Address.
404 @param Buffer For read operations, the destination buffer to store the results.
405 For write operations, the source buffer from which to write data.
407 @retval EFI_SUCCESS The data was read from or written to the EFI system.
408 @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system.Or Buffer is NULL.
409 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
410 Or,The address range specified by Address, Width, and Count is not valid for this EFI system.
416 IN EFI_CPU_IO_PROTOCOL
*This
,
417 IN EFI_CPU_IO_PROTOCOL_WIDTH Width
,
426 EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth
;
430 // Make sure the parameters are valid
432 Status
= CpuIoCheckParameter (FALSE
, Width
, Address
, Count
, Buffer
);
433 if (EFI_ERROR (Status
)) {
438 // Select loop based on the width of the transfer
440 InStride
= mInStride
[Width
];
441 OutStride
= mOutStride
[Width
];
442 OperationWidth
= Width
& 0x03;
443 for (Uint8Buffer
= (UINT8
*)Buffer
; Count
> 0; Address
+= InStride
, Uint8Buffer
+= OutStride
, Count
--) {
444 if (OperationWidth
== EfiCpuIoWidthUint8
) {
445 IoWrite8 ((UINTN
)Address
, *Uint8Buffer
);
446 } else if (OperationWidth
== EfiCpuIoWidthUint16
) {
447 IoWrite16 ((UINTN
)Address
, *((UINT16
*)Uint8Buffer
));
448 } else if (OperationWidth
== EfiCpuIoWidthUint32
) {
449 IoWrite32 ((UINTN
)Address
, *((UINT32
*)Uint8Buffer
));
457 The user Entry Point for module CpuIo. The user code starts with this function.
459 @param[in] ImageHandle The firmware allocated handle for the EFI image.
460 @param[in] SystemTable A pointer to the EFI System Table.
462 @retval EFI_SUCCESS The entry point is executed successfully.
463 @retval other Some error occurs when executing this entry point.
469 IN EFI_HANDLE ImageHandle
,
470 IN EFI_SYSTEM_TABLE
*SystemTable
475 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL
, &gEfiCpuIoProtocolGuid
);
476 Status
= gBS
->InstallMultipleProtocolInterfaces (
478 &gEfiCpuIoProtocolGuid
, &mCpuIo
,
481 ASSERT_EFI_ERROR (Status
);